Save This Page
Home » click-2.1.0 » org.apache.velocity.tools » view » servlet » [javadoc | source]
    1   /*
    2    * Copyright 2003 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.apache.velocity.tools.view.servlet;
   18   
   19   
   20   import java.io.IOException;
   21   import java.io.OutputStreamWriter;
   22   import java.io.PrintWriter;
   23   import java.io.StringWriter;
   24   import java.io.UnsupportedEncodingException;
   25   import java.io.Writer;
   26   
   27   import javax.servlet.ServletConfig;
   28   import javax.servlet.ServletContext;
   29   import javax.servlet.ServletException;
   30   import javax.servlet.http.HttpServlet;
   31   import javax.servlet.http.HttpServletRequest;
   32   import javax.servlet.http.HttpServletResponse;
   33   
   34   import org.apache.commons.collections.ExtendedProperties;
   35   
   36   import org.apache.velocity.Template;
   37   import org.apache.velocity.app.VelocityEngine;
   38   import org.apache.velocity.context.Context;
   39   import org.apache.velocity.exception.ResourceNotFoundException;
   40   import org.apache.velocity.exception.ParseErrorException;
   41   import org.apache.velocity.exception.MethodInvocationException;
   42   import org.apache.velocity.io.VelocityWriter;
   43   import org.apache.velocity.runtime.RuntimeConstants;
   44   import org.apache.velocity.util.SimplePool;
   45   
   46   import org.apache.velocity.tools.generic.log.LogSystemCommonsLog;
   47   import org.apache.velocity.tools.view.ToolboxManager;
   48   import org.apache.velocity.tools.view.context.ToolboxContext;
   49   import org.apache.velocity.tools.view.context.ChainedContext;
   50   import org.apache.velocity.tools.view.servlet.ServletToolboxManager;
   51   import org.apache.velocity.tools.view.servlet.WebappLoader;
   52   
   53   
   54   /**
   55    * <p>A servlet to process Velocity templates. This is comparable to the
   56    * the JspServlet for JSP-based applications.</p>
   57    *
   58    * <p>The servlet provides the following features:</p>
   59    * <ul>
   60    *   <li>renders Velocity templates</li>
   61    *   <li>provides support for an auto-loaded, configurable toolbox</li>
   62    *   <li>provides transparent access to the servlet request attributes,
   63    *       servlet session attributes and servlet context attributes by
   64    *       auto-searching them</li>
   65    *   <li>logs to the logging facility of the servlet API</li>
   66    * </ul>
   67    *
   68    * <p>VelocityViewServlet supports the following configuration parameters
   69    * in web.xml:</p>
   70    * <dl>
   71    *   <dt>org.apache.velocity.toolbox</dt>
   72    *   <dd>Path and name of the toolbox configuration file. The path must be
   73    *     relative to the web application root directory. If this parameter is
   74    *     not found, no toolbox is instantiated.</dd>
   75    *   <dt>org.apache.velocity.properties</dt>
   76    *   <dd>Path and name of the Velocity configuration file. The path must be
   77    *     relative to the web application root directory. If this parameter
   78    *     is not present, Velocity is initialized with default settings.</dd>
   79    * </dl>
   80    * 
   81    * <p>There are methods you may wish to override to access, alter or control
   82    * any part of the request processing chain.  Please see the javadocs for
   83    * more information on :
   84    * <ul>
   85    * <li> {@link #loadConfiguration} : <br>for loading Velocity properties and
   86    *                                     configuring the Velocity runtime
   87    * <li> {@link #setContentType} : <br>for changing the content type on a request
   88    *                                  by request basis
   89    * <li> {@link #requestCleanup} : <br>post rendering resource or other cleanup
   90    * <li> {@link #error} : <br>error handling
   91    * </ul>
   92    * </p>
   93    *
   94    * @author Dave Bryson
   95    * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
   96    * @author <a href="mailto:sidler@teamup.com">Gabe Sidler</a>
   97    * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   98    * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
   99    * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
  100    * @author <a href="mailto:nathan@esha.com">Nathan Bubna</a>
  101    *
  102    * @version $Id: VelocityViewServlet.java 321237 2005-10-14 22:52:17Z nbubna $
  103    */
  104   
  105   public class VelocityViewServlet extends HttpServlet
  106   {
  107   
  108       /** The HTTP content type context key. */
  109       public static final String CONTENT_TYPE = "default.contentType";
  110   
  111       /** The default content type for the response */
  112       public static final String DEFAULT_CONTENT_TYPE = "text/html";
  113     
  114       /** Default encoding for the output stream */
  115       public static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
  116   
  117       /**
  118        * Key used to access the ServletContext in 
  119        * the Velocity application attributes.
  120        */
  121       public static final String SERVLET_CONTEXT_KEY = 
  122           ServletContext.class.getName();
  123   
  124   
  125       /**
  126        * Key used to access the toolbox configuration file path from the
  127        * Servlet or webapp init parameters ("org.apache.velocity.toolbox").
  128        */
  129       protected static final String TOOLBOX_KEY = 
  130           "org.apache.velocity.toolbox";
  131   
  132       /**
  133        * This is the string that is looked for when getInitParameter is
  134        * called ("org.apache.velocity.properties").
  135        */
  136       protected static final String INIT_PROPS_KEY =
  137           "org.apache.velocity.properties";
  138   
  139       /** A reference to the toolbox manager. */
  140       protected ToolboxManager toolboxManager = null;
  141   
  142   
  143       /** Cache of writers */
  144       private static SimplePool writerPool = new SimplePool(40);
  145   
  146       /* The engine used to process templates. */
  147       private VelocityEngine velocity = null;
  148   
  149       /**
  150        * The default content type.  When necessary, includes the
  151        * character set to use when encoding textual output.
  152        */
  153       private String defaultContentType;
  154   
  155       /**
  156        * Whether we've logged a deprecation warning for
  157        * ServletResponse's <code>getOutputStream()</code>.
  158        * @since VelocityTools 1.1
  159        */
  160       private boolean warnOfOutputStreamDeprecation = true;
  161   
  162   
  163   
  164       /**
  165        * <p>Initializes servlet, toolbox and Velocity template engine.
  166        * Called by the servlet container on loading.</p>
  167        *
  168        * <p>NOTE: If no charset is specified in the default.contentType
  169        * property (in your velocity.properties) and you have specified
  170        * an output.encoding property, then that will be used as the
  171        * charset for the default content-type of pages served by this
  172        * servlet.</p>
  173        *
  174        * @param config servlet configuation
  175        */
  176       public void init(ServletConfig config) throws ServletException
  177       {
  178           super.init(config);
  179   
  180           // do whatever we have to do to init Velocity
  181           initVelocity(config);
  182   
  183           // init this servlet's toolbox (if any)
  184           initToolbox(config);
  185   
  186           // we can get these now that velocity is initialized
  187           defaultContentType = 
  188               (String)getVelocityProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
  189   
  190           String encoding = 
  191               (String)getVelocityProperty(RuntimeConstants.OUTPUT_ENCODING,
  192                                           DEFAULT_OUTPUT_ENCODING);
  193   
  194           // For non Latin-1 encodings, ensure that the charset is
  195           // included in the Content-Type header.
  196           if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
  197           {
  198               int index = defaultContentType.lastIndexOf("charset");
  199               if (index < 0)
  200               {
  201                   // the charset specifier is not yet present in header.
  202                   // append character encoding to default content-type
  203                   defaultContentType += "; charset=" + encoding;
  204               }
  205               else
  206               {
  207                   // The user may have configuration issues.
  208                   velocity.warn("VelocityViewServlet: Charset was already " +
  209                                 "specified in the Content-Type property.  " +
  210                                 "Output encoding property will be ignored.");
  211               }
  212           }
  213   
  214           velocity.info("VelocityViewServlet: Default content-type is: " + 
  215                         defaultContentType);
  216       }
  217   
  218   
  219       /**
  220        * Looks up an init parameter with the specified key in either the
  221        * ServletConfig or, failing that, in the ServletContext.
  222        */
  223       protected String findInitParameter(ServletConfig config, String key)
  224       {
  225           // check the servlet config
  226           String param = config.getInitParameter(key);
  227   
  228           if (param == null || param.length() == 0) 
  229           {
  230               // check the servlet context
  231               ServletContext servletContext = config.getServletContext();
  232               param = servletContext.getInitParameter(key);
  233           }
  234           return param;
  235       }
  236   
  237   
  238       /**
  239        * Simplifies process of getting a property from VelocityEngine,
  240        * because the VelocityEngine interface sucks compared to the singleton's.
  241        * Use of this method assumes that {@link #initVelocity(ServletConfig)}
  242        * has already been called.
  243        */
  244       protected String getVelocityProperty(String key, String alternate)
  245       {
  246           String prop = (String)velocity.getProperty(key);
  247           if (prop == null || prop.length() == 0)
  248           {
  249               return alternate;
  250           }
  251           return prop;
  252       }
  253   
  254   
  255       /**
  256        * Returns the underlying VelocityEngine being used.
  257        */
  258       protected VelocityEngine getVelocityEngine()
  259       {
  260           return velocity;
  261       }
  262   
  263       /**
  264        * Sets the underlying VelocityEngine
  265        */
  266       protected void setVelocityEngine(VelocityEngine ve)
  267       {
  268           if (ve == null)
  269           {
  270               throw new NullPointerException("Cannot set the VelocityEngine to null");
  271           }
  272           this.velocity = ve;
  273       }
  274   
  275   
  276       /**
  277        * Initializes the ServletToolboxManager for this servlet's
  278        * toolbox (if any).
  279        *
  280        * @param config servlet configuation
  281        */
  282       protected void initToolbox(ServletConfig config) throws ServletException
  283       {
  284           /* check the servlet config and context for a toolbox param */
  285           String file = findInitParameter(config, TOOLBOX_KEY);
  286   
  287           /* if we have a toolbox, get a manager for it */
  288           if (file != null)
  289           {
  290               toolboxManager = 
  291                   ServletToolboxManager.getInstance(getServletContext(), file);
  292           }
  293           else
  294           {
  295               velocity.info("VelocityViewServlet: No toolbox entry in configuration.");
  296           }
  297       }
  298   
  299   
  300       /**
  301        * Initializes the Velocity runtime, first calling 
  302        * loadConfiguration(ServletConfig) to get a 
  303        * org.apache.commons.collections.ExtendedProperties
  304        * of configuration information
  305        * and then calling velocityEngine.init().  Override this
  306        * to do anything to the environment before the 
  307        * initialization of the singleton takes place, or to 
  308        * initialize the singleton in other ways.
  309        *
  310        * @param config servlet configuration parameters
  311        */
  312       protected void initVelocity(ServletConfig config) throws ServletException
  313       {
  314           velocity = new VelocityEngine();
  315           setVelocityEngine(velocity);
  316   
  317           // register this engine to be the default handler of log messages
  318           // if the user points commons-logging to the LogSystemCommonsLog
  319           LogSystemCommonsLog.setVelocityEngine(velocity);
  320   
  321           velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY, getServletContext());
  322   
  323           // default to servletlogger, which logs to the servlet engines log
  324           velocity.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, 
  325                                ServletLogger.class.getName());
  326   
  327           // by default, load resources with webapp resource loader
  328           velocity.setProperty(RuntimeConstants.RESOURCE_LOADER, "webapp");
  329           velocity.setProperty("webapp.resource.loader.class", 
  330                                WebappLoader.class.getName());
  331   
  332           // Try reading an overriding Velocity configuration
  333           try
  334           {
  335               ExtendedProperties p = loadConfiguration(config);
  336               velocity.setExtendedProperties(p);
  337           }
  338           catch(Exception e)
  339           {
  340               getServletContext().log("VelocityViewServlet: Unable to read Velocity configuration file: "+e);
  341               getServletContext().log("VelocityViewServlet: Using default Velocity configuration.");
  342           }   
  343   
  344           // now all is ready - init Velocity
  345           try
  346           {
  347               velocity.init();
  348           }
  349           catch(Exception e)
  350           {
  351               getServletContext().log("VelocityViewServlet: PANIC! unable to init() - "+e);
  352               throw new ServletException(e);
  353           }
  354       }
  355   
  356        
  357       /**
  358        *  Loads the configuration information and returns that 
  359        *  information as an ExtendedProperties, which will be used to 
  360        *  initialize the Velocity runtime.
  361        *  <br><br>
  362        *  Currently, this method gets the initialization parameter
  363        *  VelocityServlet.INIT_PROPS_KEY, which should be a file containing
  364        *  the configuration information.
  365        *  <br><br>
  366        *  To configure your Servlet Spec 2.2 compliant servlet runner to pass
  367        *  this to you, put the following in your WEB-INF/web.xml file
  368        *  <br>
  369        *  <pre>
  370        *    &lt;servlet&gt;
  371        *      &lt;servlet-name&gt; YourServlet &lt/servlet-name&gt;
  372        *      &lt;servlet-class&gt; your.package.YourServlet &lt;/servlet-class&gt;
  373        *      &lt;init-param&gt;
  374        *         &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
  375        *         &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
  376        *      &lt;/init-param&gt;
  377        *    &lt;/servlet&gt;
  378        *   </pre>
  379        *
  380        * Alternately, if you wish to configure an entire context in this
  381        * fashion, you may use the following:
  382        *  <br>
  383        *  <pre>
  384        *    &lt;context-param&gt;
  385        *       &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
  386        *       &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
  387        *       &lt;description&gt; Path to Velocity configuration &lt;/description&gt;
  388        *    &lt;/context-param&gt;
  389        *   </pre>
  390        * 
  391        *  Derived classes may do the same, or take advantage of this code to do the loading for them via :
  392        *   <pre>
  393        *      ExtendedProperties p = super.loadConfiguration(config);
  394        *   </pre>
  395        *  and then add or modify the configuration values from the file.
  396        *  <br>
  397        *
  398        *  @param config ServletConfig passed to the servlets init() function
  399        *                Can be used to access the real path via ServletContext (hint)
  400        *  @return ExtendedProperties loaded with configuration values to be used
  401        *          to initialize the Velocity runtime.
  402        *  @throws IOException I/O problem accessing the specified file, if specified.
  403        */
  404       protected ExtendedProperties loadConfiguration(ServletConfig config)
  405           throws IOException
  406       {
  407           // grab the path to the custom props file (if any)
  408           String propsFile = findInitParameter(config, INIT_PROPS_KEY);
  409           
  410           ExtendedProperties p = new ExtendedProperties();
  411           if (propsFile != null)
  412           {
  413               p.load(getServletContext().getResourceAsStream(propsFile));
  414   
  415               velocity.info("VelocityViewServlet: Custom Properties File: "+propsFile);
  416           }
  417           else
  418           {
  419               velocity.info("VelocityViewServlet: No custom properties found. " +
  420                             "Using default Velocity configuration.");
  421           }
  422   
  423           return p;
  424       }
  425   
  426             
  427       /**
  428        * Handles GET - calls doRequest()
  429        */
  430       public void doGet(HttpServletRequest request, HttpServletResponse response)
  431           throws ServletException, IOException
  432       {
  433           doRequest(request, response);
  434       }
  435   
  436   
  437       /**
  438        * Handle a POST request - calls doRequest()
  439        */
  440       public void doPost(HttpServletRequest request, HttpServletResponse response)
  441           throws ServletException, IOException
  442       {
  443           doRequest(request, response);
  444       }
  445   
  446   
  447       /**
  448        *  Handles with both GET and POST requests
  449        *
  450        *  @param request  HttpServletRequest object containing client request
  451        *  @param response HttpServletResponse object for the response
  452        */
  453       protected void doRequest(HttpServletRequest request, 
  454                                HttpServletResponse response)
  455            throws ServletException, IOException
  456       {
  457           Context context = null;
  458           try
  459           {
  460               // first, get a context
  461               context = createContext(request, response);
  462               
  463               // set the content type 
  464               setContentType(request, response);
  465   
  466               // get the template
  467               Template template = handleRequest(request, response, context);        
  468   
  469               // bail if we can't find the template
  470               if (template == null)
  471               {
  472                   velocity.warn("VelocityViewServlet: couldn't find template to match request.");
  473                   return;
  474               }
  475   
  476               // merge the template and context
  477               mergeTemplate(template, context, response);
  478           }
  479           catch (Exception e)
  480           {
  481               // log the exception
  482               velocity.error("VelocityViewServlet: Exception processing the template: "+e);
  483   
  484               // call the error handler to let the derived class
  485               // do something useful with this failure.
  486               error(request, response, e);
  487           }
  488           finally
  489           {
  490               // call cleanup routine to let a derived class do some cleanup
  491               requestCleanup(request, response, context);
  492           }
  493       }
  494   
  495   
  496       /**
  497        * Cleanup routine called at the end of the request processing sequence
  498        * allows a derived class to do resource cleanup or other end of 
  499        * process cycle tasks.  This default implementation does nothing.
  500        *
  501        * @param request servlet request from client 
  502        * @param response servlet reponse 
  503        * @param context Context created by the {@link #createContext}
  504        */
  505       protected void requestCleanup(HttpServletRequest request, 
  506                                     HttpServletResponse response, 
  507                                     Context context)
  508       {
  509       }
  510   
  511   
  512       /**
  513        * <p>Handle the template processing request.</p> 
  514        *
  515        * @param request client request
  516        * @param response client response
  517        * @param ctx  VelocityContext to fill
  518        *
  519        * @return Velocity Template object or null
  520        */
  521       protected Template handleRequest(HttpServletRequest request, 
  522                                        HttpServletResponse response, 
  523                                        Context ctx)
  524           throws Exception
  525       {
  526           // If we get here from RequestDispatcher.include(), getServletPath()
  527           // will return the original (wrong) URI requested.  The following special
  528           // attribute holds the correct path.  See section 8.3 of the Servlet
  529           // 2.3 specification.
  530           String path = (String)request.getAttribute("javax.servlet.include.servlet_path");
  531           // also take into account the PathInfo stated on SRV.4.4 Request Path Elements
  532           String info = (String)request.getAttribute("javax.servlet.include.path_info");
  533           if (path == null)
  534           {
  535               path = request.getServletPath();
  536               info = request.getPathInfo();
  537           }
  538           if (info != null)
  539           {
  540               path += info;
  541           }
  542           return getTemplate(path);
  543       }
  544   
  545   
  546       /**
  547        * Sets the content type of the response.  This is available to be overriden
  548        * by a derived class.
  549        *
  550        * <p>The default implementation is :
  551        * <pre>
  552        *
  553        *    response.setContentType(defaultContentType);
  554        * 
  555        * </pre>
  556        * where defaultContentType is set to the value of the default.contentType
  557        * property, or "text/html" if that is not set.</p>
  558        *
  559        * @param request servlet request from client
  560        * @param response servlet reponse to client
  561        */
  562       protected void setContentType(HttpServletRequest request, 
  563                                     HttpServletResponse response)
  564       {
  565           response.setContentType(defaultContentType);
  566       }
  567   
  568   
  569       /**
  570        * <p>Creates and returns an initialized Velocity context.</p> 
  571        * 
  572        * A new context of class {@link ChainedContext} is created and 
  573        * initialized.
  574        *
  575        * @param request servlet request from client
  576        * @param response servlet reponse to client
  577        */
  578       protected Context createContext(HttpServletRequest request, 
  579                                       HttpServletResponse response)
  580       {
  581           ChainedContext ctx = 
  582               new ChainedContext(velocity, request, response, getServletContext());
  583   
  584           /* if we have a toolbox manager, get a toolbox from it */
  585           if (toolboxManager != null)
  586           {
  587               ctx.setToolbox(toolboxManager.getToolbox(ctx));
  588           }
  589           return ctx;
  590       }
  591   
  592   
  593       /**
  594        * Retrieves the requested template.
  595        *
  596        * @param name The file name of the template to retrieve relative to the 
  597        *             template root.
  598        * @return The requested template.
  599        * @throws ResourceNotFoundException if template not found
  600        *          from any available source.
  601        * @throws ParseErrorException if template cannot be parsed due
  602        *          to syntax (or other) error.
  603        * @throws Exception if an error occurs in template initialization
  604        */
  605       public Template getTemplate(String name)
  606           throws ResourceNotFoundException, ParseErrorException, Exception
  607       {
  608           return velocity.getTemplate(name);
  609       }
  610   
  611       
  612       /**
  613        * Retrieves the requested template with the specified character encoding.
  614        *
  615        * @param name The file name of the template to retrieve relative to the 
  616        *             template root.
  617        * @param encoding the character encoding of the template
  618        * @return The requested template.
  619        * @throws ResourceNotFoundException if template not found
  620        *          from any available source.
  621        * @throws ParseErrorException if template cannot be parsed due
  622        *          to syntax (or other) error.
  623        * @throws Exception if an error occurs in template initialization
  624        */
  625       public Template getTemplate(String name, String encoding)
  626           throws ResourceNotFoundException, ParseErrorException, Exception
  627       {
  628           return velocity.getTemplate(name, encoding);
  629       }
  630   
  631   
  632       /**
  633        * Merges the template with the context.  Only override this if you really, really
  634        * really need to. (And don't call us with questions if it breaks :)
  635        *
  636        * @param template template object returned by the handleRequest() method
  637        * @param context Context created by the {@link #createContext}
  638        * @param response servlet reponse (used to get a Writer)
  639        */
  640       protected void mergeTemplate(Template template, 
  641                                    Context context, 
  642                                    HttpServletResponse response)
  643           throws ResourceNotFoundException, ParseErrorException, 
  644                  MethodInvocationException, IOException, 
  645                  UnsupportedEncodingException, Exception
  646       {
  647           VelocityWriter vw = null;
  648           Writer writer = getResponseWriter(response);
  649           try
  650           {
  651               vw = (VelocityWriter)writerPool.get();
  652               if (vw == null)
  653               {
  654                   vw = new VelocityWriter(writer, 4 * 1024, true);
  655               }
  656               else
  657               {
  658                   vw.recycle(writer);
  659               }
  660               performMerge(template, context, vw);
  661           }
  662           finally
  663           {
  664               if (vw != null)
  665               {
  666                   try
  667                   {
  668                       // flush and put back into the pool
  669                       // don't close to allow us to play
  670                       // nicely with others.
  671                       vw.flush();
  672                       /* This hack sets the VelocityWriter's internal ref to the 
  673                        * PrintWriter to null to keep memory free while
  674                        * the writer is pooled. See bug report #18951 */
  675                       vw.recycle(null);
  676                       writerPool.put(vw);
  677                   }
  678                   catch (Exception e)
  679                   {
  680                       velocity.debug("VelocityViewServlet: " + 
  681                                      "Trouble releasing VelocityWriter: " +
  682                                      e.getMessage());
  683                   }                
  684               }
  685           }
  686       }
  687   
  688   
  689       /**
  690        * This is here so developers may override it and gain access to the 
  691        * Writer which the template will be merged into.  See
  692        * <a href="http://issues.apache.org/jira/browse/VELTOOLS-7">VELTOOLS-7</a>
  693        * for discussion of this.
  694        *
  695        * @param template template object returned by the handleRequest() method
  696        * @param context Context created by the {@link #createContext}
  697        * @param writer a VelocityWriter that the template is merged into
  698        */
  699       protected void performMerge(Template template, Context context, Writer writer)
  700           throws ResourceNotFoundException, ParseErrorException,
  701                  MethodInvocationException, Exception
  702       {
  703           template.merge(context, writer);
  704       }
  705   
  706    
  707       /**
  708        * Invoked when there is an error thrown in any part of doRequest() processing.
  709        * <br><br>
  710        * Default will send a simple HTML response indicating there was a problem.
  711        * 
  712        * @param request original HttpServletRequest from servlet container.
  713        * @param response HttpServletResponse object from servlet container.
  714        * @param e  Exception that was thrown by some other part of process.
  715        */
  716       protected void error(HttpServletRequest request, 
  717                            HttpServletResponse response, 
  718                            Exception e)
  719           throws ServletException
  720       {
  721           try
  722           {
  723               StringBuffer html = new StringBuffer();
  724               html.append("<html>\n");
  725               html.append("<head><title>Error</title></head>\n");
  726               html.append("<body>\n");
  727               html.append("<h2>VelocityViewServlet : Error processing the template</h2>\n");
  728   
  729               Throwable cause = e;
  730   
  731               String why = cause.getMessage();
  732               if (why != null && why.trim().length() > 0)
  733               {
  734                   html.append(why);
  735                   html.append("\n<br>\n");
  736               }
  737   
  738               // if it's an MIE, i want the real stack trace!
  739               if (cause instanceof MethodInvocationException) 
  740               {
  741                   // get the real cause
  742                   cause = ((MethodInvocationException)cause).getWrappedThrowable();
  743               }
  744   
  745               StringWriter sw = new StringWriter();
  746               cause.printStackTrace(new PrintWriter(sw));
  747   
  748               html.append("<pre>\n");
  749               html.append(sw.toString());
  750               html.append("</pre>\n");
  751               html.append("</body>\n");
  752               html.append("</html>");
  753               getResponseWriter(response).write(html.toString());
  754           }
  755           catch (Exception e2)
  756           {
  757               // clearly something is quite wrong.
  758               // let's log the new exception then give up and
  759               // throw a servlet exception that wraps the first one
  760               velocity.error("VelocityViewServlet: Exception while printing error screen: "+e2);
  761               throw new ServletException(e);
  762           }
  763       }
  764   
  765       /**
  766        * <p>Procure a Writer with correct encoding which can be used
  767        * even if HttpServletResponse's <code>getOutputStream()</code> method
  768        * has already been called.</p>
  769        *
  770        * <p>This is a transitional method which will be removed in a
  771        * future version of Velocity.  It is not recommended that you
  772        * override this method.</p>
  773        *
  774        * @param response The response.
  775        * @return A <code>Writer</code>, possibly created using the
  776        *        <code>getOutputStream()</code>.
  777        */
  778       protected Writer getResponseWriter(HttpServletResponse response)
  779           throws UnsupportedEncodingException, IOException
  780       {
  781           Writer writer = null;
  782           try
  783           {
  784               writer = response.getWriter();
  785           }
  786           catch (IllegalStateException e)
  787           {
  788               // ASSUMPTION: We already called getOutputStream(), so
  789               // calls to getWriter() fail.  Use of OutputStreamWriter
  790               // assures our desired character set
  791               if (this.warnOfOutputStreamDeprecation)
  792               {
  793                   this.warnOfOutputStreamDeprecation = false;
  794                   velocity.warn("VelocityViewServlet: " +
  795                                 "Use of ServletResponse's getOutputStream() " +
  796                                 "method with VelocityViewServlet is " +
  797                                 "deprecated -- support will be removed in " +
  798                                 "an upcoming release");
  799               }
  800               // Assume the encoding has been set via setContentType().
  801               String encoding = response.getCharacterEncoding();
  802               if (encoding == null)
  803               {
  804                   encoding = DEFAULT_OUTPUT_ENCODING;
  805               }
  806               writer = new OutputStreamWriter(response.getOutputStream(),
  807                                               encoding);
  808           }
  809           return writer;
  810       }
  811   
  812   }

Save This Page
Home » click-2.1.0 » org.apache.velocity.tools » view » servlet » [javadoc | source]