EMMA Coverage Report (generated Tue May 18 22:13:27 CDT 2004)
[all classes][org.apache.velocity.servlet]

COVERAGE SUMMARY FOR SOURCE FILE [VelocityServlet.java]

nameclass, %method, %block, %line, %
VelocityServlet.java100% (1/1)33%  (6/18)16%  (65/399)18%  (18.5/102)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class VelocityServlet100% (1/1)33%  (6/18)16%  (65/399)18%  (18.5/102)
createContext (HttpServletRequest, HttpServletResponse): Context 0%   (0/1)0%   (0/16)0%   (0/4)
doGet (HttpServletRequest, HttpServletResponse): void 0%   (0/1)0%   (0/5)0%   (0/2)
doPost (HttpServletRequest, HttpServletResponse): void 0%   (0/1)0%   (0/5)0%   (0/2)
doRequest (HttpServletRequest, HttpServletResponse): void 0%   (0/1)0%   (0/57)0%   (0/11)
error (HttpServletRequest, HttpServletResponse, Exception): void 0%   (0/1)0%   (0/74)0%   (0/18)
getTemplate (String): Template 0%   (0/1)0%   (0/3)0%   (0/1)
getTemplate (String, String): Template 0%   (0/1)0%   (0/4)0%   (0/1)
handleRequest (Context): Template 0%   (0/1)0%   (0/5)0%   (0/1)
handleRequest (HttpServletRequest, HttpServletResponse, Context): Template 0%   (0/1)0%   (0/13)0%   (0/4)
loadConfiguration (ServletConfig): Properties 0%   (0/1)0%   (0/69)0%   (0/18)
mergeTemplate (Template, Context, HttpServletResponse): void 0%   (0/1)0%   (0/58)0%   (0/18)
requestCleanup (HttpServletRequest, HttpServletResponse, Context): void 0%   (0/1)0%   (0/1)0%   (0/1)
initVelocity (ServletConfig): void 100% (1/1)36%  (8/22)67%  (4/6)
setContentType (HttpServletRequest, HttpServletResponse): void 100% (1/1)77%  (33/43)94%  (7.5/8)
<static initializer> 100% (1/1)100% (6/6)100% (1/1)
VelocityServlet (): void 100% (1/1)100% (3/3)100% (1/1)
chooseCharacterEncoding (HttpServletRequest): String 100% (1/1)100% (4/4)100% (1/1)
init (ServletConfig): void 100% (1/1)100% (11/11)100% (4/4)

1package org.apache.velocity.servlet;
2 
3/*
4 * Copyright 2000-2001,2004 The Apache Software Foundation.
5 * 
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 * 
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 * 
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 
19import java.io.IOException;
20import java.io.PrintWriter;
21import java.io.StringWriter;
22import java.io.OutputStreamWriter;
23import java.io.FileInputStream;
24import java.io.FileNotFoundException;
25import java.io.UnsupportedEncodingException;
26 
27import java.util.Properties;
28 
29import javax.servlet.ServletConfig;
30import javax.servlet.ServletContext;
31import javax.servlet.ServletException;
32import javax.servlet.ServletOutputStream;
33 
34import javax.servlet.http.HttpServlet;
35import javax.servlet.http.HttpServletRequest;
36import javax.servlet.http.HttpServletResponse;
37 
38import org.apache.velocity.Template;
39import org.apache.velocity.runtime.RuntimeConstants;
40import org.apache.velocity.runtime.RuntimeSingleton;
41import org.apache.velocity.io.VelocityWriter;
42import org.apache.velocity.util.SimplePool;
43 
44import org.apache.velocity.context.Context;
45import org.apache.velocity.VelocityContext;
46 
47import org.apache.velocity.app.Velocity;
48 
49import org.apache.velocity.exception.ResourceNotFoundException;
50import org.apache.velocity.exception.ParseErrorException;
51import org.apache.velocity.exception.MethodInvocationException;
52 
53/**
54 * Base class which simplifies the use of Velocity with Servlets.
55 * Extend this class, implement the <code>handleRequest()</code> method, 
56 * and add your data to the context.  Then call 
57 * <code>getTemplate("myTemplate.wm")</code>.
58 * 
59 * This class puts some things into the context object that you should
60 * be aware of:
61 * <pre>
62 * "req" - The HttpServletRequest object
63 * "res" - The HttpServletResponse object
64 * </pre>
65 *
66 * There are other methods you can override to access, alter or control
67 * any part of the request processing chain.  Please see the javadocs for
68 * more information on :
69 * <ul>
70 * <li> loadConfiguration() : for setting up the Velocity runtime
71 * <li> createContext() : for creating and loading the Context
72 * <li> setContentType() : for changing the content type on a request
73 *                         by request basis
74 * <li> handleRequest() : you <b>must</b> implement this 
75 * <li> mergeTemplate()  : the template rendering process
76 * <li> requestCleanup() : post rendering resource or other cleanup
77 * <li> error() : error handling
78 * </ul>
79 * <br>
80 * If you put a contentType object into the context within either your
81 * serlvet or within your template, then that will be used to override
82 * the default content type specified in the properties file.
83 *
84 * "contentType" - The value for the Content-Type: header
85 *
86 * @author Dave Bryson
87 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
88 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
89 * @author <a href="kjohnson@transparent.com">Kent Johnson</a>
90 * @author <a href="dlr@finemaltcoding.com">Daniel Rall</a>
91 * $Id: VelocityServlet.java,v 1.52.4.1 2004/03/03 23:23:03 geirm Exp $
92 */
93public abstract class VelocityServlet extends HttpServlet
94{
95    /**
96     * The context key for the HTTP request object.
97     */
98    public static final String REQUEST = "req";
99 
100    /**
101     * The context key for the HTTP response object.
102     */
103    public static final String RESPONSE = "res";
104 
105    /**
106     * The HTTP content type context key.
107     */
108    public static final String CONTENT_TYPE = "default.contentType";
109 
110    /**
111     *  The default content type for the response
112     */
113    public static final String DEFAULT_CONTENT_TYPE = "text/html";
114    
115  
116    /**
117     *  Encoding for the output stream
118     */
119    public static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
120 
121    /**
122     * The default content type, itself defaulting to {@link
123     * #DEFAULT_CONTENT_TYPE} if not configured.
124     */
125    private static String defaultContentType;
126 
127    /**
128     * This is the string that is looked for when getInitParameter is
129     * called (<code>org.apache.velocity.properties</code>).
130     */
131    protected static final String INIT_PROPS_KEY =
132        "org.apache.velocity.properties";
133 
134    /**
135     * Use of this properties key has been deprecated, and will be
136     * removed in Velocity version 1.5.
137     */
138    private static final String OLD_INIT_PROPS_KEY = "properties";
139 
140    /**
141     * Cache of writers
142     */
143   
144    private static SimplePool writerPool = new SimplePool(40);
145   
146    /** 
147     * Performs initialization of this servlet.  Called by the servlet 
148     * container on loading.
149     *
150     * @param config The servlet configuration to apply.
151     *
152     * @exception ServletException
153     */
154    public void init( ServletConfig config )
155        throws ServletException
156    {
157        super.init( config );
158 
159        /*
160         *  do whatever we have to do to init Velocity
161         */                
162        initVelocity( config );
163 
164        /*
165         *  Now that Velocity is initialized, cache some config.
166         */
167        defaultContentType = RuntimeSingleton.getString(CONTENT_TYPE,
168                                                        DEFAULT_CONTENT_TYPE);
169    }
170 
171    /**
172     *  Initializes the Velocity runtime, first calling 
173     *  loadConfiguration(ServletConvig) to get a 
174     *  java.util.Properties of configuration information
175     *  and then calling Velocity.init().  Override this
176     *  to do anything to the environment before the 
177     *  initialization of the singelton takes place, or to 
178     *  initialize the singleton in other ways.
179     */
180    protected void initVelocity( ServletConfig config )
181         throws ServletException
182    {
183        try
184        {
185            /*
186             *  call the overridable method to allow the 
187             *  derived classes a shot at altering the configuration
188             *  before initializing Runtime
189             */
190 
191            Properties props = loadConfiguration( config );
192  
193            Velocity.init( props );
194        }
195        catch( Exception e )
196        {
197            throw new ServletException("Error initializing Velocity: " + e, e);
198        }   
199    }    
200     
201    /**
202     *  Loads the configuration information and returns that 
203     *  information as a Properties, which will be used to 
204     *  initialize the Velocity runtime.
205     *  <br><br>
206     *  Currently, this method gets the initialization parameter
207     *  VelocityServlet.INIT_PROPS_KEY, which should be a file containing
208     *  the configuration information.
209     *  <br><br>
210     *  To configure your Servlet Spec 2.2 compliant servlet runner to pass
211     *  this to you, put the following in your WEB-INF/web.xml file
212     *  <br>
213     *  <pre>
214     *    &lt;servlet&gt;
215     *      &lt;servlet-name&gt; YourServlet &lt/servlet-name&gt;
216     *      &lt;servlet-class&gt; your.package.YourServlet &lt;/servlet-class&gt;
217     *      &lt;init-param&gt;
218     *         &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
219     *         &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
220     *      &lt;/init-param&gt;
221     *    &lt;/servlet&gt;
222     *   </pre>
223     *
224     * Alternately, if you wish to configure an entire context in this
225     * fashion, you may use the following:
226     *  <br>
227     *  <pre>
228     *    &lt;context-param&gt;
229     *       &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
230     *       &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
231     *       &lt;description&gt; Path to Velocity configuration &lt;/description&gt;
232     *    &lt;/context-param&gt;
233     *   </pre>
234     * 
235     *  Derived classes may do the same, or take advantage of this code to do the loading for them via :
236     *   <pre>
237     *      Properties p = super.loadConfiguration( config );
238     *   </pre>
239     *  and then add or modify the configuration values from the file.
240     *  <br>
241     *
242     *  @param config ServletConfig passed to the servlets init() function
243     *                Can be used to access the real path via ServletContext (hint)
244     *  @return java.util.Properties loaded with configuration values to be used
245     *          to initialize the Velocity runtime.
246     *  @throws FileNotFoundException if a specified file is not found.
247     *  @throws IOException I/O problem accessing the specified file, if specified.
248     */
249    protected Properties loadConfiguration(ServletConfig config)
250        throws IOException, FileNotFoundException
251    {
252        // This is a little overly complex because of legacy support
253        // for the initialization properties key "properties".
254        // References to OLD_INIT_PROPS_KEY should be removed at
255        // Velocity version 1.5.
256        String propsFile = config.getInitParameter(INIT_PROPS_KEY);
257        if (propsFile == null || propsFile.length() == 0)
258        {
259            ServletContext sc = config.getServletContext();
260            propsFile = config.getInitParameter(OLD_INIT_PROPS_KEY);
261            if (propsFile == null || propsFile.length() == 0)
262            {
263                propsFile = sc.getInitParameter(INIT_PROPS_KEY);
264                if (propsFile == null || propsFile.length() == 0)
265                {
266                    propsFile = sc.getInitParameter(OLD_INIT_PROPS_KEY);
267                    if (propsFile != null && propsFile.length() > 0)
268                    {
269                        sc.log("Use of the properties initialization " +
270                               "parameter '" + OLD_INIT_PROPS_KEY + "' has " +
271                               "been deprecated by '" + INIT_PROPS_KEY + '\'');
272                    }
273                }
274            }
275            else
276            {
277                sc.log("Use of the properties initialization parameter '" +
278                       OLD_INIT_PROPS_KEY + "' has been deprecated by '" +
279                       INIT_PROPS_KEY + '\'');
280            }
281        }
282        
283        /*
284         * This will attempt to find the location of the properties
285         * file from the relative path to the WAR archive (ie:
286         * docroot). Since JServ returns null for getRealPath()
287         * because it was never implemented correctly, then we know we
288         * will not have an issue with using it this way. I don't know
289         * if this will break other servlet engines, but it probably
290         * shouldn't since WAR files are the future anyways.
291         */
292 
293        Properties p = new Properties();
294        
295        if ( propsFile != null )
296        {
297            String realPath = getServletContext().getRealPath(propsFile);
298        
299            if ( realPath != null )
300            {
301                propsFile = realPath;
302            }
303 
304            p.load( new FileInputStream(propsFile) );
305        }
306 
307        return p;
308    }
309          
310    /**
311     * Handles HTTP <code>GET</code> requests by calling {@link
312     * #doRequest()}.
313     */
314    public void doGet( HttpServletRequest request, HttpServletResponse response )
315        throws ServletException, IOException
316    {
317        doRequest(request, response);
318    }
319 
320    /**
321     * Handles HTTP <code>POST</code> requests by calling {@link
322     * #doRequest()}.
323     */
324    public void doPost( HttpServletRequest request, HttpServletResponse response )
325        throws ServletException, IOException
326    {
327        doRequest(request, response);
328    }
329 
330    /**
331     *  Handles all requests (by default).
332     *
333     *  @param request  HttpServletRequest object containing client request
334     *  @param response HttpServletResponse object for the response
335     */
336    protected void doRequest(HttpServletRequest request, HttpServletResponse response )
337         throws ServletException, IOException
338    {
339        Context context = null;
340        try
341        {
342            /*
343             *  first, get a context
344             */
345 
346            context = createContext( request, response );
347            
348            /*
349             *   set the content type 
350             */
351 
352            setContentType( request, response );
353 
354            /*
355             *  let someone handle the request
356             */
357 
358            Template template = handleRequest( request, response, context );        
359            /*
360             *  bail if we can't find the template
361             */
362 
363            if ( template == null )
364            {
365                return;
366            }
367 
368            /*
369             *  now merge it
370             */
371 
372            mergeTemplate( template, context, response );
373        }
374        catch (Exception e)
375        {
376            /*
377             *  call the error handler to let the derived class
378             *  do something useful with this failure.
379             */
380 
381            error( request, response, e);
382        }
383        finally
384        {
385            /*
386             *  call cleanup routine to let a derived class do some cleanup
387             */
388 
389            requestCleanup( request, response, context );
390        }
391    }
392 
393    /**
394     *  A cleanup routine which is called at the end of the {@link
395     *  #doRequest(HttpServletRequest, HttpServletResponse)}
396     *  processing sequence, allowing a derived class to do resource
397     *  cleanup or other end of process cycle tasks.
398     *
399     *  @param request servlet request from client 
400     *  @param response servlet reponse 
401     *  @param context  context created by the createContext() method
402     */
403    protected void requestCleanup( HttpServletRequest request, HttpServletResponse response, Context context )
404    {
405        return;
406    }
407 
408    /**
409     *  merges the template with the context.  Only override this if you really, really
410     *  really need to. (And don't call us with questions if it breaks :)
411     *
412     *  @param template template object returned by the handleRequest() method
413     *  @param context  context created by the createContext() method
414     *  @param response servlet reponse (use this to get the output stream or Writer
415     */
416    protected void mergeTemplate( Template template, Context context, HttpServletResponse response )
417        throws ResourceNotFoundException, ParseErrorException, 
418               MethodInvocationException, IOException, UnsupportedEncodingException, Exception
419    {
420        ServletOutputStream output = response.getOutputStream();
421        VelocityWriter vw = null;
422        // ASSUMPTION: response.setContentType() has been called.
423        String encoding = response.getCharacterEncoding();
424        
425        try
426        {
427            vw = (VelocityWriter) writerPool.get();
428            
429            if (vw == null)
430            {
431                vw = new VelocityWriter(new OutputStreamWriter(output,
432                                                               encoding),
433                                        4 * 1024, true);
434            }
435            else
436            {
437                vw.recycle(new OutputStreamWriter(output, encoding));
438            }
439           
440            template.merge(context, vw);
441        }
442        finally
443        {
444            try
445            {
446                if (vw != null)
447                {
448                    /*
449                     *  flush and put back into the pool
450                     *  don't close to allow us to play
451                     *  nicely with others.
452                     */
453                    vw.flush();
454 
455                    /*
456                     * Clear the VelocityWriter's reference to its
457                     * internal OutputStreamWriter to allow the latter
458                     * to be GC'd while vw is pooled.
459                     */
460                    vw.recycle(null);
461 
462                    writerPool.put(vw);
463                }
464            }
465            catch (Exception e)
466            {
467                // do nothing
468            }
469        }
470    }
471 
472    /**
473     * Sets the content type of the response, defaulting to {@link
474     * #defaultContentType} if not overriden.  Delegates to {@link
475     * #chooseCharacterEncoding(HttpServletRequest)} to select the
476     * appropriate character encoding.
477     *
478     * @param request The servlet request from the client.
479     * @param response The servlet reponse to the client.
480     */
481    protected void setContentType(HttpServletRequest request,
482                                  HttpServletResponse response)
483    {
484        String contentType = defaultContentType;
485        int index = contentType.lastIndexOf(';') + 1;
486        if (index <= 0 || (index < contentType.length() &&
487                           contentType.indexOf("charset", index) == -1))
488        {
489            // Append the character encoding which we'd like to use.
490            String encoding = chooseCharacterEncoding(request);
491            //System.out.println("Chose output encoding of '" +
492            //                   encoding + '\'');
493            if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
494            {
495                contentType += "; charset=" + encoding;
496            }
497        }
498        response.setContentType(contentType);
499        //System.out.println("Response Content-Type set to '" +
500        //                   contentType + '\'');
501    }
502 
503    /**
504     * Chooses the output character encoding to be used as the value
505     * for the "charset=" portion of the HTTP Content-Type header (and
506     * thus returned by <code>response.getCharacterEncoding()</code>).
507     * Called by {@link #setContentType(HttpServletRequest,
508     * HttpServletResponse)} if an encoding isn't already specified by
509     * Content-Type.  By default, chooses the value of
510     * RuntimeSingleton's <code>output.encoding</code> property.
511     *
512     * @param request The servlet request from the client.
513     */
514    protected String chooseCharacterEncoding(HttpServletRequest request)
515    {
516        return RuntimeSingleton.getString(RuntimeConstants.OUTPUT_ENCODING,
517                                          DEFAULT_OUTPUT_ENCODING);
518    }
519 
520    /**
521     *  Returns a context suitable to pass to the handleRequest() method
522     *  <br><br>
523     *  Default implementation will create a VelocityContext object,
524     *   put the HttpServletRequest and HttpServletResponse
525     *  into the context accessable via the keys VelocityServlet.REQUEST and
526     *  VelocityServlet.RESPONSE, respectively.
527     *
528     *  @param request servlet request from client
529     *  @param response servlet reponse to client
530     *
531     *  @return context
532     */
533    protected Context createContext(HttpServletRequest request,  HttpServletResponse response )
534    {
535        /*
536         *   create a new context
537         */
538 
539        VelocityContext context = new VelocityContext();
540        
541        /*
542         *   put the request/response objects into the context
543         *   wrap the HttpServletRequest to solve the introspection
544         *   problems 
545         */
546           
547        context.put( REQUEST,  request );
548        context.put( RESPONSE, response );
549 
550        return context;
551    }
552 
553    /**
554     * Retrieves the requested template.
555     *
556     * @param name The file name of the template to retrieve relative to the 
557     *             template root.
558     * @return     The requested template.
559     * @throws ResourceNotFoundException if template not found
560     *          from any available source.
561     * @throws ParseErrorException if template cannot be parsed due
562     *          to syntax (or other) error.
563     * @throws Exception if an error occurs in template initialization
564     */
565    public Template getTemplate( String name )
566        throws ResourceNotFoundException, ParseErrorException, Exception
567    {
568        return RuntimeSingleton.getTemplate(name);
569    }
570    
571    /**
572     * Retrieves the requested template with the specified
573     * character encoding.
574     *
575     * @param name The file name of the template to retrieve relative to the 
576     *             template root.
577     * @param encoding the character encoding of the template
578     *
579     * @return     The requested template.
580     * @throws ResourceNotFoundException if template not found
581     *          from any available source.
582     * @throws ParseErrorException if template cannot be parsed due
583     *          to syntax (or other) error.
584     * @throws Exception if an error occurs in template initialization
585     *     
586     *  @since Velocity v1.1
587     */
588    public Template getTemplate( String name, String encoding )
589        throws ResourceNotFoundException, ParseErrorException, Exception
590    {
591        return RuntimeSingleton.getTemplate( name, encoding );
592    }
593 
594    /**
595     * Implement this method to add your application data to the context, 
596     * calling the <code>getTemplate()</code> method to produce your return 
597     * value.
598     * <br><br>
599     * In the event of a problem, you may handle the request directly
600     * and return <code>null</code> or throw a more meaningful exception
601     * for the error handler to catch.
602     *
603     *  @param request servlet request from client 
604     *  @param response servlet reponse 
605     *  @param ctx The context to add your data to.
606     *  @return    The template to merge with your context or null, indicating
607     *    that you handled the processing.
608     *
609     *  @since Velocity v1.1
610     */
611    protected Template handleRequest( HttpServletRequest request, HttpServletResponse response, Context ctx ) 
612        throws Exception
613    {
614        /*
615         * invoke handleRequest
616         */
617 
618        Template t =  handleRequest( ctx );
619 
620        /*
621         *  if it returns null, this is the 'old' deprecated 
622         *  way, and we want to mimic the behavior for a little 
623         *  while anyway
624         */
625 
626        if (t == null)
627        {
628            throw new Exception ("handleRequest(Context) returned null - no template selected!" );
629        }
630 
631        return t;
632    }
633 
634    /**
635     * Implement this method to add your application data to the context, 
636     * calling the <code>getTemplate()</code> method to produce your return 
637     * value.
638     * <br><br>
639     * In the event of a problem, you may simple return <code>null</code>
640     * or throw a more meaningful exception.
641     *
642     * @deprecated Use
643     * {@link #handleRequest( HttpServletRequest request, 
644     * HttpServletResponse response, Context ctx )}
645     *
646     * @param ctx The context to add your data to.
647     * @return    The template to merge with your context.
648     */
649    protected Template handleRequest( Context ctx ) 
650        throws Exception
651    {
652        throw new Exception ("You must override VelocityServlet.handleRequest( Context) "
653                             + " or VelocityServlet.handleRequest( HttpServletRequest, "
654                             + " HttpServletResponse, Context)" );
655    }
656 
657    /**
658     * Invoked when there is an error thrown in any part of doRequest() processing.
659     * <br><br>
660     * Default will send a simple HTML response indicating there was a problem.
661     * 
662     * @param request original HttpServletRequest from servlet container.
663     * @param response HttpServletResponse object from servlet container.
664     * @param cause  Exception that was thrown by some other part of process.
665     */
666    protected void error( HttpServletRequest request, HttpServletResponse response, Exception cause )
667        throws ServletException, IOException
668    {
669        StringBuffer html = new StringBuffer();
670        html.append("<html>");
671        html.append("<title>Error</title>");
672        html.append("<body bgcolor=\"#ffffff\">");
673        html.append("<h2>VelocityServlet: Error processing the template</h2>");
674        html.append("<pre>");
675        String why = cause.getMessage();
676        if (why != null && why.trim().length() > 0)
677        {
678            html.append(why);
679            html.append("<br>");
680        }
681 
682        StringWriter sw = new StringWriter();
683        cause.printStackTrace( new PrintWriter( sw ) );
684 
685        html.append( sw.toString()  );
686        html.append("</pre>");
687        html.append("</body>");
688        html.append("</html>");
689        response.getOutputStream().print( html.toString() );
690    }
691}

[all classes][org.apache.velocity.servlet]
EMMA 2.0.4015 (stable) (C) Vladimir Roubtsov