dlr         2003/08/31 11:09:59

  Modified:    src/java/org/apache/velocity/servlet VelocityServlet.java
               build    testcases.xml
               xdocs    changes.xml
  Added:       src/java/org/apache/velocity/test VelocityServletTest.java
  Log:
  * src/java/org/apache/velocity/servlet/VelocityServlet.java
    REQUEST, RESPONSE, doGet(), doPost(): Improved JavaDoc.
  
    encoding: Removed unnecessary class field.
  
    defaultContentType: Added a touch more JavaDoc.
  
    init(): No longer set encoding field.
  
    doRequest(): Moved call to requestCleanup() down into a finally
    block.  This is a minor change in behavior to supply a much more
    useful cleanup hook for cases where unexpected exceptions are
    thrown.
  
    mergeTemplate(): Get the character encoding from the
    HttpServletResponse object.  The assumption is that it has already
    been set via a charset= parameter on the Content-Type header.
  
    setContentType(), chooseCharacterEncoding(): Added support for
    dynamic selection of response character encoding.
  
    error(): Output tweak.
  
  * build/testcases.xml
    test-all, test-servlet: Added new test-servlet target.
  
  * src/java/org/apache/velocity/test/VelocityServletTest.java
    A test case for VelocityServlet, currently covering only its newly
    improved encoding behavior.  There is a lot of mocked-up Servlet API
    implementation in this class which should be replaced by a
    supporting library which already does this sort of thing.
  
  * xdocs/changes.xml
    Noted addition of support for dynamic selection of output character
    encoding in VelocityServlet.
  
  Revision  Changes    Path
  1.51      +76 -41    
jakarta-velocity/src/java/org/apache/velocity/servlet/VelocityServlet.java
  
  Index: VelocityServlet.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-velocity/src/java/org/apache/velocity/servlet/VelocityServlet.java,v
  retrieving revision 1.50
  retrieving revision 1.51
  diff -u -u -r1.50 -r1.51
  --- VelocityServlet.java      22 Aug 2003 23:23:47 -0000      1.50
  +++ VelocityServlet.java      31 Aug 2003 18:09:58 -0000      1.51
  @@ -74,6 +74,7 @@
   import javax.servlet.http.HttpServletResponse;
   
   import org.apache.velocity.Template;
  +import org.apache.velocity.runtime.RuntimeConstants;
   import org.apache.velocity.runtime.RuntimeSingleton;
   import org.apache.velocity.io.VelocityWriter;
   import org.apache.velocity.util.SimplePool;
  @@ -130,12 +131,12 @@
   public abstract class VelocityServlet extends HttpServlet
   {
       /**
  -     * The HTTP request object context key.
  +     * The context key for the HTTP request object.
        */
       public static final String REQUEST = "req";
   
       /**
  -     * The HTTP response object context key.
  +     * The context key for the HTTP response object.
        */
       public static final String RESPONSE = "res";
   
  @@ -154,14 +155,10 @@
        *  Encoding for the output stream
        */
       public static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
  - 
  -    /**
  -     * The encoding to use when generating outputing.
  -     */
  -    private static String encoding = null;
   
       /**
  -     * The default content type.
  +     * The default content type, itself defaulting to [EMAIL PROTECTED]
  +     * #DEFAULT_CONTENT_TYPE} if not configured.
        */
       private static String defaultContentType;
   
  @@ -203,11 +200,10 @@
           initVelocity( config );
   
           /*
  -         *  we can get these now that velocity is initialized
  +         *  Now that Velocity is initialized, cache some config.
            */
  -        defaultContentType = RuntimeSingleton.getString( CONTENT_TYPE, 
DEFAULT_CONTENT_TYPE);
  -        encoding = RuntimeSingleton.getString( RuntimeSingleton.OUTPUT_ENCODING, 
  -                        DEFAULT_OUTPUT_ENCODING);
  +        defaultContentType = RuntimeSingleton.getString(CONTENT_TYPE,
  +                                                        DEFAULT_CONTENT_TYPE);
       }
   
       /**
  @@ -350,7 +346,8 @@
       }
             
       /**
  -     * Handles GET - calls doRequest()
  +     * Handles HTTP <code>GET</code> requests by calling [EMAIL PROTECTED]
  +     * #doRequest()}.
        */
       public void doGet( HttpServletRequest request, HttpServletResponse response )
           throws ServletException, IOException
  @@ -359,7 +356,8 @@
       }
   
       /**
  -     * Handle a POST request - calls doRequest()
  +     * Handles HTTP <code>POST</code> requests by calling [EMAIL PROTECTED]
  +     * #doRequest()}.
        */
       public void doPost( HttpServletRequest request, HttpServletResponse response )
           throws ServletException, IOException
  @@ -368,7 +366,7 @@
       }
   
       /**
  -     *   Handles all requests 
  +     *  Handles all requests (by default).
        *
        *  @param request  HttpServletRequest object containing client request
        *  @param response HttpServletResponse object for the response
  @@ -376,13 +374,14 @@
       protected void doRequest(HttpServletRequest request, HttpServletResponse 
response )
            throws ServletException, IOException
       {
  +        Context context = null;
           try
           {
               /*
                *  first, get a context
                */
   
  -            Context context = createContext( request, response );
  +            context = createContext( request, response );
               
               /*
                *   set the content type 
  @@ -409,12 +408,6 @@
                */
   
               mergeTemplate( template, context, response );
  -
  -            /*
  -             *  call cleanup routine to let a derived class do some cleanup
  -             */
  -
  -            requestCleanup( request, response, context );
           }
           catch (Exception e)
           {
  @@ -425,12 +418,21 @@
   
               error( request, response, e);
           }
  +        finally
  +        {
  +            /*
  +             *  call cleanup routine to let a derived class do some cleanup
  +             */
  +
  +            requestCleanup( request, response, context );
  +        }
       }
   
       /**
  -     *  cleanup routine called at the end of the request processing sequence
  -     *  allows a derived class to do resource cleanup or other end of 
  -     *  process cycle tasks
  +     *  A cleanup routine which is called at the end of the [EMAIL PROTECTED]
  +     *  #doRequest(HttpServletRequest, HttpServletResponse)}
  +     *  processing sequence, allowing a derived class to do resource
  +     *  cleanup or other end of process cycle tasks.
        *
        *  @param request servlet request from client 
        *  @param response servlet reponse 
  @@ -455,6 +457,8 @@
       {
           ServletOutputStream output = response.getOutputStream();
           VelocityWriter vw = null;
  +        // ASSUMPTION: response.setContentType() has been called.
  +        String encoding = response.getCharacterEncoding();
           
           try
           {
  @@ -462,14 +466,16 @@
               
               if (vw == null)
               {
  -                vw = new VelocityWriter( new OutputStreamWriter(output, encoding), 
4*1024, true);
  +                vw = new VelocityWriter(new OutputStreamWriter(output,
  +                                                               encoding),
  +                                        4 * 1024, true);
               }
               else
               {
                   vw.recycle(new OutputStreamWriter(output, encoding));
               }
              
  -            template.merge( context, vw);
  +            template.merge(context, vw);
           }
           finally
           {
  @@ -502,22 +508,51 @@
       }
   
       /**
  -     *  Sets the content type of the response.  This is available to be overriden
  -     *  by a derived class.
  -     *
  -     *  The default implementation is :
  -     *
  -     *     response.setContentType( defaultContentType );
  -     * 
  -     *  where defaultContentType is set to the value of the default.contentType
  -     *  property, or "text/html" if that is not set.
  +     * Sets the content type of the response, defaulting to [EMAIL PROTECTED]
  +     * #defaultContentType} if not overriden.  Delegates to [EMAIL PROTECTED]
  +     * #chooseCharacterEncoding(HttpServletRequest)} to select the
  +     * appropriate character encoding.
  +     *
  +     * @param request The servlet request from the client.
  +     * @param response The servlet reponse to the client.
  +     */
  +    protected void setContentType(HttpServletRequest request,
  +                                  HttpServletResponse response)
  +    {
  +        String contentType = defaultContentType;
  +        int index = contentType.lastIndexOf(';') + 1;
  +        if (0 <= index || (index < contentType.length() &&
  +                           contentType.indexOf("charset", index) == -1))
  +        {
  +            // Append the character encoding which we'd like to use.
  +            String encoding = chooseCharacterEncoding(request);
  +            //System.out.println("Chose output encoding of '" +
  +            //                   encoding + '\'');
  +            if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
  +            {
  +                contentType += "; charset=" + encoding;
  +            }
  +        }
  +        response.setContentType(contentType);
  +        //System.out.println("Response Content-Type set to '" +
  +        //                   contentType + '\'');
  +    }
  +
  +    /**
  +     * Chooses the output character encoding to be used as the value
  +     * for the "charset=" portion of the HTTP Content-Type header (and
  +     * thus returned by <code>response.getCharacterEncoding()</code>).
  +     * Called by [EMAIL PROTECTED] #setContentType(HttpServletRequest,
  +     * HttpServletResponse)} if an encoding isn't already specified by
  +     * Content-Type.  By default, chooses the value of
  +     * RuntimeSingleton's <code>output.encoding</code> property.
        *
  -     *  @param request servlet request from client
  -     *  @param response servlet reponse to client
  +     * @param request The servlet request from the client.
        */
  -    protected void setContentType( HttpServletRequest request, HttpServletResponse 
response )
  +    protected String chooseCharacterEncoding(HttpServletRequest request)
       {
  -        response.setContentType( defaultContentType );
  +        return RuntimeSingleton.getString(RuntimeConstants.OUTPUT_ENCODING,
  +                                          DEFAULT_OUTPUT_ENCODING);
       }
   
       /**
  @@ -673,7 +708,7 @@
           html.append("<html>");
           html.append("<title>Error</title>");
           html.append("<body bgcolor=\"#ffffff\">");
  -        html.append("<h2>VelocityServlet : Error processing the template</h2>");
  +        html.append("<h2>VelocityServlet: Error processing the template</h2>");
           html.append("<pre>");
           String why = cause.getMessage();
           if (why != null && why.trim().length() > 0)
  
  
  
  1.29      +12 -0     jakarta-velocity/build/testcases.xml
  
  Index: testcases.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-velocity/build/testcases.xml,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -u -r1.28 -r1.29
  --- testcases.xml     25 Mar 2002 00:49:22 -0000      1.28
  +++ testcases.xml     31 Aug 2003 18:09:58 -0000      1.29
  @@ -72,6 +72,7 @@
                                      test-texen,
                                      test-texen-classpath,
                                      test-misc,
  +                                   test-servlet,
                                      test-parser
                                      "/>
   
  @@ -282,6 +283,17 @@
         </classpath>
       </java>
     </target>
  +
  +  <target name="test-servlet">
  +    <echo message="Running VelocityServlet tests..."/>
  +
  +    <java classname="${velocity.test.runner}" fork="yes" 
failonerror="${testbed.failonerror}">
  +      <arg value="org.apache.velocity.test.VelocityServletTest"/>
  +      <classpath>
  +        <path refid="classpath"/>
  +      </classpath>
  +    </java>
  +   </target>
   
     <!-- ================================================================ -->
     <!-- T E X E N  T E S T                                               -->
  
  
  
  1.1                  
jakarta-velocity/src/java/org/apache/velocity/test/VelocityServletTest.java
  
  Index: VelocityServletTest.java
  ===================================================================
  package org.apache.velocity.test;
  
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.io.InputStream;
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Enumeration;
  import java.util.Properties;
  import javax.servlet.RequestDispatcher;
  import javax.servlet.Servlet;
  import javax.servlet.ServletConfig;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import org.apache.velocity.app.Velocity;
  import org.apache.velocity.runtime.RuntimeSingleton;
  import org.apache.velocity.runtime.RuntimeConstants;
  import org.apache.velocity.servlet.VelocityServlet;
  
  import junit.framework.TestCase;
  
  /**
   * Tests our VelocityServlet implementation.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a>
   */
  public class VelocityServletTest extends TestCase
  {
      /**
       * Default constructor.
       */
      public VelocityServletTest()
      {
          super("VelocityServletTest");
      }
  
      public static junit.framework.Test suite ()
      {
          return new VelocityServletTest();
      }
  
      /**
       * Runs the test.
       */
      public void runTest()
      {
          /*
           * Assure we have the encoding we think we should.
           */
  
          MockVelocityServlet servlet = new MockVelocityServlet();
          try
          {
              servlet.init(new MockServletConfig());
          }
          catch (ServletException e)
          {
              e.printStackTrace();
          }
          System.out.println(RuntimeConstants.OUTPUT_ENCODING + "=" +
                             RuntimeSingleton.getProperty
                             (RuntimeConstants.OUTPUT_ENCODING));
          HttpServletResponse res = new MockHttpServletResponse();
          servlet.visibleSetContentType(null, res);
          assertEquals("Character encoding not set to UTF-8",
                       "UTF-8", res.getCharacterEncoding());
      }
  
      class MockVelocityServlet extends VelocityServlet
      {
          void visibleSetContentType(HttpServletRequest req,
                                     HttpServletResponse res)
          {
              setContentType(req, res);
          }
  
          protected Properties loadConfiguration(ServletConfig config)
              throws IOException
          {
              Properties p = new Properties();
              p.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
              return p;
          }
  
          public ServletConfig getServletConfig()
          {
              return new MockServletConfig();
          }
      }
  
      static class MockServletConfig implements ServletConfig
      {
          public String getInitParameter(String ignored)
          {
              return null;
          }
  
          public Enumeration getInitParameterNames()
          {
              return null;
          }
  
          public ServletContext getServletContext()
          {
              return new MockServletContext();
          }
  
          public String getServletName()
          {
              return "VelocityServlet";
          }            
      }
  
      static class MockServletContext implements ServletContext
      {
          public Object getAttribute(String ignored)
          {
              return null;
          }
  
          public Enumeration getAttributeNames()
          {
              return null;
          }
  
          public ServletContext getContext(String ignored)
          {
              return this;
          }
  
          public String getInitParameter(String ignored)
          {
              return null;
          }
  
          public Enumeration getInitParameterNames()
          {
              return null;
          }
  
          public int getMajorVersion()
          {
              return -1;
          }
  
          public String getMimeType(String ignored)
          {
              return null;
          }
  
          public int getMinorVersion()
          {
              return -1;
          }
  
          public RequestDispatcher getNamedDispatcher(String ignored)
          {
              return null;
          }
  
          public String getRealPath(String ignored)
          {
              return null;
          }
  
          public RequestDispatcher getRequestDispatcher(String ignored)
          {
              return null;
          }
  
          public URL getResource(String ignored)
              throws MalformedURLException
          {
              return null;
          }
  
          public InputStream getResourceAsStream(String ignored)
          {
              return null;
          }
  
          public String getServerInfo()
          {
              return "Velocity Test Suite";
          }
  
          public Servlet getServlet(String ignored)
              throws ServletException
          {
              return null;
          }
  
          public Enumeration getServletNames()
          {
              return null;
          }
  
          public Enumeration getServlets()
          {
              return null;
          }
  
          public void log(Exception e, String msg)
          {
          }
  
          public void log(String msg)
          {
          }
  
          public void log(String msg, Throwable t)
          {
          }
  
          public void removeAttribute(String name)
          {
          }
  
          public void setAttribute(String name, Object value)
          {
          }
      }
  
      static class MockHttpServletResponse implements HttpServletResponse
      {
          private String encoding;
  
          // ---- ServletResponse implementation -----------------------------
  
          public void flushBuffer() throws IOException
          {
          }
  
          public int getBufferSize()
          {
              return -1;
          }
  
          public String getCharacterEncoding()
          {
              return (encoding != null ? encoding : "ISO-8859-1");
          }
  
          public java.util.Locale getLocale()
          {
              return null;
          }
  
          public javax.servlet.ServletOutputStream getOutputStream()
              throws IOException
          {
              return null;
          }
  
          public java.io.PrintWriter getWriter() throws IOException
          {
              return null;
          }
  
          public boolean isCommitted()
          {
              return false;
          }
  
          public void reset()
          {
          }
  
          public void setBufferSize(int i)
          {
          }
  
          public void setContentLength(int i)
          {
          }
  
          /**
           * Records the character encoding.
           */
          public void setContentType(String contentType)
          {
              if (contentType != null)
              {
                  int index = contentType.lastIndexOf(';') + 1;
                  if (0 <= index || index < contentType.length())
                  {
                      index = contentType.indexOf("charset=", index);
                      if (index != -1)
                      {
                          index += 8;
                          this.encoding = contentType.substring(index).trim();
                      }
                  }
              }
          }
  
          public void setLocale(java.util.Locale l)
          {
          }
  
  
          // ---- HttpServletResponse implementation ------------------------- 
  
          public void addCookie(javax.servlet.http.Cookie c)
          {
          }
  
          public void addDateHeader(String s, long l)
          {
          }
  
          public void addHeader(String name, String value)
          {
          }
  
          public void addIntHeader(String name, int value)
          {
          }
  
          public boolean containsHeader(String name)
          {
              return false;
          }
  
          public String encodeRedirectURL(String url)
          {
              return url;
          }
  
          public String encodeRedirectUrl(String url)
          {
              return url;
          }
  
          public String encodeURL(String url)
          {
              return url;
          }
  
          public String encodeUrl(String url)
          {
              return url;
          }
  
          public void sendError(int i) throws IOException
          {
          }
  
          public void sendError(int i, String s) throws IOException
          {
          }
  
          public void sendRedirect(String s) throws IOException
          {
          }
  
          public void setDateHeader(String s, long l)
          {
          }
  
          public void setHeader(String name, String value)
          {
          }
  
          public void setIntHeader(String s, int i)
          {
          }
  
          public void setStatus(int i)
          {
          }
  
          public void setStatus(int i , String s)
          {
          }
      }
  }
  
  
  
  1.90      +6 -0      jakarta-velocity/xdocs/changes.xml
  
  Index: changes.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-velocity/xdocs/changes.xml,v
  retrieving revision 1.89
  retrieving revision 1.90
  diff -u -u -r1.89 -r1.90
  --- changes.xml       23 Aug 2003 00:22:11 -0000      1.89
  +++ changes.xml       31 Aug 2003 18:09:59 -0000      1.90
  @@ -23,6 +23,12 @@
   
   <ul>
   <li>
  +Added support for dynamic selection of output character encoding to
  +VelocityServlet.  By default, the selected encoding is the value of
  +the output.encoding Velocity property, but can be made dynamic by
  +overriding the new chooseCharacterEncoding() method. (dlr)
  +</li>
  +<li>
   Bill Boland pointed out that VelocityServlet's pooling of
   VelocityWriter was preventing the underlying OutputStreamWriter from
   being garbage collected.  This was fixed by clearing the
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to