KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > ext > servlet > FreemarkerServlet


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.ext.servlet;
54
55 import java.io.File JavaDoc;
56 import java.io.FileNotFoundException JavaDoc;
57 import java.io.IOException JavaDoc;
58 import java.text.SimpleDateFormat JavaDoc;
59 import java.util.Calendar JavaDoc;
60 import java.util.Enumeration JavaDoc;
61 import java.util.GregorianCalendar JavaDoc;
62
63 import javax.servlet.ServletContext JavaDoc;
64 import javax.servlet.ServletException JavaDoc;
65 import javax.servlet.http.HttpServlet JavaDoc;
66 import javax.servlet.http.HttpServletRequest JavaDoc;
67 import javax.servlet.http.HttpServletResponse JavaDoc;
68 import javax.servlet.http.HttpSession JavaDoc;
69
70 import freemarker.cache.WebappTemplateLoader;
71 import freemarker.core.Configurable;
72 import freemarker.ext.jsp.TaglibFactory;
73 import freemarker.log.Logger;
74 import freemarker.template.Configuration;
75 import freemarker.template.ObjectWrapper;
76 import freemarker.template.Template;
77 import freemarker.template.TemplateException;
78 import freemarker.template.TemplateExceptionHandler;
79 import freemarker.template.TemplateModel;
80 import freemarker.template.TemplateModelException;
81 import freemarker.template.utility.StringUtil;
82 import java.util.Locale JavaDoc;
83
84 /**
85  * <p>This is a general-purpose FreeMarker view servlet.</p>
86  *
87  * <p>The main features are:
88  *
89  * <ul>
90  *
91  * <li>It makes all request, request parameters, session, and servlet
92  * context attributes available to templates through <code>Request</code>,
93  * <code>RequestParameters</code>, <code>Session</code>, and <code>Application</code>
94  * variables.
95  *
96  * <li>The scope variables are also available via automatic scope discovery. That is,
97  * writing <code>Application.attrName</code>, <code>Session.attrName</code>,
98  * <code>Request.attrName</code> is not mandatory; it's enough to write <code>attrName</code>,
99  * and if no such variable was created in the template, it will search the
100  * variable in <code>Request</code>, and then in <code>Session</code>,
101  * and finally in <code>Application</code>.
102  *
103  * <li>It creates a variable with name <code>JspTaglibs</code>, that can be used
104  * to load JSP taglibs. For example:<br>
105  * <code>&lt;#assign tiles=JspTaglibs["/WEB-INF/struts-tiles.tld"]></code>
106  *
107  * </ul>
108  *
109  * <p>The servlet will rethrow the errors occurring during template processing,
110  * wrapped into <code>ServletException</code>, except if the class name of the
111  * class set by the <code>template_exception_handler</code> contains the
112  * substring <code>"Debug"</code>. If it contains <code>"Debug"</code>, then it
113  * is assumed that the template exception handler prints the error message to the
114  * page, thus <code>FreemarkerServlet</code> will suppress the exception, and
115  * logs the problem with the servlet logger
116  * (<code>javax.servlet.GenericServlet.log(...)</code>).
117  *
118  * <p>Supported init-params are:</p>
119  *
120  * <ul>
121  *
122  * <li><strong>TemplatePath</strong> specifies the location of the templates.
123  * By default, this is interpreted as web application directory relative URI.<br>
124  * Alternatively, you can prepend it with <tt>file://</tt> to indicate a literal
125  * path in the file system (i.e. <tt>file:///var/www/project/templates/</tt>).
126  * Note that three slashes were used to specify an absolute path.<br>
127  * Also, you can prepend it with <tt>class://path/to/template/package</tt> to
128  * indicate that you want to load templates from the specified package
129  * accessible through the classloader of the servlet.<br>
130  * Default value is <tt>class://</tt> (that is, the root of the class hierarchy).
131  * <i>Note that this default is different than the default in FreeMarker 1.x, when
132  * it defaulted <tt>/</tt>, that is to loading from the webapp root directory.</i></li>
133  *
134  * <li><strong>NoCache</strong> if set to true, generates headers in the response
135  * that advise the HTTP client not to cache the returned page.
136  * The default is <tt>false</tt>.</li>
137  *
138  * <li><strong>ContentType</strong> if specified, response uses the specified
139  * Content-type HTTP header. The value may include the charset (e.g.
140  * <tt>"text/html; charset=ISO-8859-1"</tt>). If not specified, <tt>"text/html"</tt>
141  * is used. If the charset is not specified in this init-param, then the charset
142  * (encoding) of the actual template file will be used (in the response HTTP header
143  * and for encoding the output stream). Note that this setting can be overridden
144  * on a per-template basis by specifying a custom attribute named
145  * <tt>content_type</tt> in the <tt>attributes</tt> parameter of the
146  * <tt>&lt;#ftl></tt> directive.
147  * </li>
148  *
149  * <li>The following init-params are supported only for backward compatibility, and
150  * their usage is discouraged: TemplateUpdateInterval, DefaultEncoding,
151  * ObjectWrapper, TemplateExceptionHandler. Use setting init-params such as
152  * object_wrapper instead.
153  *
154  * <li>Any other init-param will be interpreted as <code>Configuration</code>
155  * level setting. See {@link Configuration#setSetting}</li>
156  *
157  * </ul>
158  *
159  * @author Attila Szegedi
160  * @version $Id: FreemarkerServlet.java,v 1.81 2004/10/06 19:58:42 szegedia Exp $
161  */

162
163 public class FreemarkerServlet extends HttpServlet JavaDoc
164 {
165     private static final Logger logger = Logger.getLogger("freemarker.servlet");
166     
167     public static final long serialVersionUID = -2440216393145762479L;
168
169     private static final String JavaDoc INITPARAM_TEMPLATE_PATH = "TemplatePath";
170     private static final String JavaDoc INITPARAM_NOCACHE = "NoCache";
171     private static final String JavaDoc INITPARAM_CONTENT_TYPE = "ContentType";
172     private static final String JavaDoc DEFAULT_CONTENT_TYPE = "text/html";
173     private static final String JavaDoc INITPARAM_DEBUG = "Debug";
174     
175     private static final String JavaDoc DEPR_INITPARAM_TEMPLATE_DELAY = "TemplateDelay";
176     private static final String JavaDoc DEPR_INITPARAM_ENCODING = "DefaultEncoding";
177     private static final String JavaDoc DEPR_INITPARAM_OBJECT_WRAPPER = "ObjectWrapper";
178     private static final String JavaDoc DEPR_INITPARAM_WRAPPER_SIMPLE = "simple";
179     private static final String JavaDoc DEPR_INITPARAM_WRAPPER_BEANS = "beans";
180     private static final String JavaDoc DEPR_INITPARAM_WRAPPER_JYTHON = "jython";
181     private static final String JavaDoc DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER = "TemplateExceptionHandler";
182     private static final String JavaDoc DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW = "rethrow";
183     private static final String JavaDoc DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_DEBUG = "debug";
184     private static final String JavaDoc DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_HTML_DEBUG = "htmlDebug";
185     private static final String JavaDoc DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_IGNORE = "ignore";
186     private static final String JavaDoc DEPR_INITPARAM_DEBUG = "debug";
187
188     public static final String JavaDoc KEY_REQUEST = "Request";
189     public static final String JavaDoc KEY_REQUEST_PARAMETERS = "RequestParameters";
190     public static final String JavaDoc KEY_SESSION = "Session";
191     public static final String JavaDoc KEY_APPLICATION = "Application";
192     public static final String JavaDoc KEY_JSP_TAGLIBS = "JspTaglibs";
193
194     // Note these names start with dot, so they're essentially invisible from
195
// a freemarker script.
196
private static final String JavaDoc ATTR_REQUEST_MODEL = ".freemarker.Request";
197     private static final String JavaDoc ATTR_REQUEST_PARAMETERS_MODEL =
198         ".freemarker.RequestParameters";
199     private static final String JavaDoc ATTR_SESSION_MODEL = ".freemarker.Session";
200     private static final String JavaDoc ATTR_APPLICATION_MODEL =
201         ".freemarker.Application";
202     private static final String JavaDoc ATTR_JSP_TAGLIBS_MODEL =
203         ".freemarker.JspTaglibs";
204
205     private static final String JavaDoc EXPIRATION_DATE;
206
207     static {
208         // Generate expiration date that is one year from now in the past
209
GregorianCalendar JavaDoc expiration = new GregorianCalendar JavaDoc();
210         expiration.roll(Calendar.YEAR, -1);
211         SimpleDateFormat JavaDoc httpDate =
212             new SimpleDateFormat JavaDoc(
213                 "EEE, dd MMM yyyy HH:mm:ss z",
214                 java.util.Locale.US);
215         EXPIRATION_DATE = httpDate.format(expiration.getTime());
216     }
217
218     private String JavaDoc templatePath;
219     private boolean nocache;
220     protected boolean debug;
221     private Configuration config;
222     private ObjectWrapper wrapper;
223     private String JavaDoc contentType;
224     private boolean noCharsetInContentType;
225     
226     public void init() throws ServletException JavaDoc {
227         try {
228             config = createConfiguration();
229             
230             // Set defaults:
231
config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
232             contentType = DEFAULT_CONTENT_TYPE;
233             
234             // Process object_wrapper init-param out of order:
235
wrapper = createObjectWrapper();
236             if (logger.isDebugEnabled()) {
237                 logger.debug("Using object wrapper of class " + wrapper.getClass().getName());
238             }
239             config.setObjectWrapper(wrapper);
240             
241             // Process TemplatePath init-param out of order:
242
templatePath = getInitParameter(INITPARAM_TEMPLATE_PATH);
243             if (templatePath == null)
244                 templatePath = "class://";
245             if (templatePath.startsWith("class://")) {
246                 // substring(7) is intentional as we "reuse" the last slash
247
config.setClassForTemplateLoading(
248                         getClass(),
249                         templatePath.substring(7));
250             } else {
251                 if (templatePath.startsWith("file://")) {
252                     templatePath = templatePath.substring(7);
253                     config.setDirectoryForTemplateLoading(new File JavaDoc(templatePath));
254                 } else {
255                     config.setTemplateLoader(new WebappTemplateLoader(this.getServletContext(), templatePath));
256                 }
257             }
258
259             // Process all other init-params:
260
Enumeration JavaDoc initpnames = getServletConfig().getInitParameterNames();
261             while (initpnames.hasMoreElements()) {
262                 String JavaDoc name = (String JavaDoc) initpnames.nextElement();
263                 String JavaDoc value = getInitParameter(name);
264                 
265                 if (name == null) {
266                     throw new ServletException JavaDoc(
267                             "init-param without param-name. "
268                             + "Maybe the web.xml is not well-formed?");
269                 }
270                 if (value == null) {
271                     throw new ServletException JavaDoc(
272                             "init-param without param-value. "
273                             + "Maybe the web.xml is not well-formed?");
274                 }
275                 
276                 if (name.equals(DEPR_INITPARAM_OBJECT_WRAPPER)
277                         || name.equals(Configurable.OBJECT_WRAPPER_KEY)
278                         || name.equals(INITPARAM_TEMPLATE_PATH)) {
279                     // ignore: we have already processed these
280
} else if (name.equals(DEPR_INITPARAM_ENCODING)) { // BC
281
if (getInitParameter(Configuration.DEFAULT_ENCODING_KEY) != null) {
282                         throw new ServletException JavaDoc(
283                                 "Conflicting init-params: "
284                                 + Configuration.DEFAULT_ENCODING_KEY + " and "
285                                 + DEPR_INITPARAM_ENCODING);
286                     }
287                     config.setDefaultEncoding(value);
288                 } else if (name.equals(DEPR_INITPARAM_TEMPLATE_DELAY)) { // BC
289
if (getInitParameter(Configuration.TEMPLATE_UPDATE_DELAY_KEY) != null) {
290                         throw new ServletException JavaDoc(
291                                 "Conflicting init-params: "
292                                 + Configuration.TEMPLATE_UPDATE_DELAY_KEY + " and "
293                                 + DEPR_INITPARAM_TEMPLATE_DELAY);
294                     }
295                     try {
296                         config.setTemplateUpdateDelay(Integer.parseInt(value));
297                     } catch (NumberFormatException JavaDoc e) {
298                         // Intentionally ignored
299
}
300                 } else if (name.equals(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER)) { // BC
301
if (getInitParameter(Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY) != null) {
302                         throw new ServletException JavaDoc(
303                                 "Conflicting init-params: "
304                                 + Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY + " and "
305                                 + DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER);
306                     }
307
308                     if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW.equals(value)) {
309                         config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
310                     } else if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_DEBUG.equals(value)) {
311                         config.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
312                     } else if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_HTML_DEBUG.equals(value)) {
313                         config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
314                     } else if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_IGNORE.equals(value)) {
315                         config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
316                     } else {
317                         throw new ServletException JavaDoc(
318                                 "Invalid value for servlet init-param "
319                                 + DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER + ": " + value);
320                     }
321                 } else if (name.equals(INITPARAM_NOCACHE)) {
322                     nocache = StringUtil.getYesNo(value);
323                 } else if (name.equals(DEPR_INITPARAM_DEBUG)) { // BC
324
if (getInitParameter(INITPARAM_DEBUG) != null) {
325                         throw new ServletException JavaDoc(
326                                 "Conflicting init-params: "
327                                 + INITPARAM_DEBUG + " and "
328                                 + DEPR_INITPARAM_DEBUG);
329                     }
330                     debug = StringUtil.getYesNo(value);
331                 } else if (name.equals(INITPARAM_DEBUG)) {
332                     debug = StringUtil.getYesNo(value);
333                 } else if (name.equals(INITPARAM_CONTENT_TYPE)) {
334                     contentType = value;
335                 } else {
336                     config.setSetting(name, value);
337                 }
338             } // while initpnames
339

340             noCharsetInContentType = true;
341             int i = contentType.toLowerCase().indexOf("charset=");
342             if (i != -1) {
343                 char c = ' ';
344                 i--;
345                 while (i >= 0) {
346                     c = contentType.charAt(i);
347                     if (!Character.isWhitespace(c)) break;
348                     i--;
349                 }
350                 if (i == -1 || c == ';') {
351                     noCharsetInContentType = false;
352                 }
353             }
354         } catch (ServletException JavaDoc e) {
355             throw e;
356         } catch (Exception JavaDoc e) {
357             throw new ServletException JavaDoc(e);
358         }
359     }
360
361     public void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
362         throws ServletException JavaDoc, IOException JavaDoc
363     {
364         process(request, response);
365     }
366
367     public void doPost(
368         HttpServletRequest JavaDoc request,
369         HttpServletResponse JavaDoc response)
370         throws ServletException JavaDoc, IOException JavaDoc
371     {
372         process(request, response);
373     }
374
375     private void process(
376         HttpServletRequest JavaDoc request,
377         HttpServletResponse JavaDoc response)
378         throws ServletException JavaDoc, IOException JavaDoc
379     {
380         // Give chance to subclasses to perform preprocessing
381
if (preprocessRequest(request, response)) {
382             return;
383         }
384
385         String JavaDoc path = requestUrlToTemplatePath(request);
386
387         if (debug) {
388             log("Requested template: " + path);
389         }
390
391         Template template = null;
392         try {
393             template = config.getTemplate(
394                     path,
395                     deduceLocale(path, request, response));
396         } catch (FileNotFoundException JavaDoc e) {
397             response.sendError(HttpServletResponse.SC_NOT_FOUND);
398             return;
399         }
400         
401         Object JavaDoc attrContentType = template.getCustomAttribute("content_type");
402         if(attrContentType != null) {
403             response.setContentType(attrContentType.toString());
404         }
405         else {
406             if (noCharsetInContentType) {
407                 response.setContentType(
408                         contentType + "; charset=" + template.getEncoding());
409             } else {
410                 response.setContentType(contentType);
411             }
412         }
413
414         // Set cache policy
415
setBrowserCachingPolicy(response);
416
417         ServletContext JavaDoc servletContext = getServletContext();
418         try {
419             TemplateModel model = createModel(wrapper, servletContext, request, response);
420
421             // Give subclasses a chance to hook into preprocessing
422
if (preTemplateProcess(request, response, template, model)) {
423                 try {
424                     // Process the template
425
template.process(model, response.getWriter());
426                 } finally {
427                     // Give subclasses a chance to hook into postprocessing
428
postTemplateProcess(request, response, template, model);
429                 }
430             }
431         } catch (TemplateException te) {
432             if (config.getTemplateExceptionHandler()
433                         .getClass().getName().indexOf("Debug") != -1) {
434                 this.log("Error executing FreeMarker template", te);
435             } else {
436                 throw new ServletException JavaDoc("Error executing FreeMarker template", te);
437             }
438         }
439     }
440     
441     /**
442      * Returns the locale used for the
443      * {@link Configuration#getTemplate(String, Locale)} call.
444      * The base implementation simply returns the locale setting of the
445      * configuration. Override this method to provide different behaviour, i.e.
446      * to use the locale indicated in the request.
447      */

448     protected Locale JavaDoc deduceLocale(
449             String JavaDoc templatePath, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) {
450         return config.getLocale();
451     }
452
453     protected TemplateModel createModel(ObjectWrapper wrapper,
454                                         ServletContext JavaDoc servletContext,
455                                         HttpServletRequest JavaDoc request,
456                                         HttpServletResponse JavaDoc response) throws TemplateModelException {
457         try {
458             AllHttpScopesHashModel params = new AllHttpScopesHashModel(wrapper, servletContext, request);
459     
460             // Create hash model wrapper for servlet context (the application)
461
ServletContextHashModel servletContextModel =
462                 (ServletContextHashModel) servletContext.getAttribute(
463                     ATTR_APPLICATION_MODEL);
464             if (servletContextModel == null)
465             {
466                 servletContextModel = new ServletContextHashModel(this, wrapper);
467                 servletContext.setAttribute(
468                     ATTR_APPLICATION_MODEL,
469                     servletContextModel);
470                 TaglibFactory taglibs = new TaglibFactory(servletContext);
471                 servletContext.setAttribute(
472                     ATTR_JSP_TAGLIBS_MODEL,
473                     taglibs);
474                 initializeServletContext(request, response);
475             }
476             params.putUnlistedModel(KEY_APPLICATION, servletContextModel);
477             params.putUnlistedModel(KEY_JSP_TAGLIBS, (TemplateModel)servletContext.getAttribute(ATTR_JSP_TAGLIBS_MODEL));
478             // Create hash model wrapper for session
479
HttpSessionHashModel sessionModel;
480             HttpSession JavaDoc session = request.getSession(false);
481             if(session != null) {
482                 sessionModel = (HttpSessionHashModel) session.getAttribute(ATTR_SESSION_MODEL);
483                 if (sessionModel == null) {
484                     sessionModel = new HttpSessionHashModel(session, wrapper);
485                     session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
486                     initializeSession(request, response);
487                 }
488             }
489             else {
490                 sessionModel = new HttpSessionHashModel(this, request, response, wrapper);
491             }
492             params.putUnlistedModel(KEY_SESSION, sessionModel);
493     
494             // Create hash model wrapper for request
495
HttpRequestHashModel requestModel =
496                 (HttpRequestHashModel) request.getAttribute(ATTR_REQUEST_MODEL);
497             if (requestModel == null || requestModel.getRequest() != request)
498             {
499                 requestModel = new HttpRequestHashModel(request, response, wrapper);
500                 request.setAttribute(ATTR_REQUEST_MODEL, requestModel);
501                 request.setAttribute(
502                     ATTR_REQUEST_PARAMETERS_MODEL,
503                     createRequestParametersHashModel(request));
504             }
505             params.putUnlistedModel(KEY_REQUEST, requestModel);
506     
507             // Create hash model wrapper for request parameters
508
HttpRequestParametersHashModel requestParametersModel =
509                 (HttpRequestParametersHashModel) request.getAttribute(
510                     ATTR_REQUEST_PARAMETERS_MODEL);
511             params.putUnlistedModel(KEY_REQUEST_PARAMETERS, requestParametersModel);
512             return params;
513         } catch (ServletException JavaDoc e) {
514             throw new TemplateModelException(e);
515         } catch (IOException JavaDoc e) {
516             throw new TemplateModelException(e);
517         }
518     }
519
520     /**
521      * Maps the request URL to a template path that is passed to
522      * {@link Configuration#getTemplate(String, Locale)}. You can override it
523      * (i.e. to provide advanced rewriting capabilities), but you are strongly
524      * encouraged to call the overridden method first, then only modify its
525      * return value.
526      * @param request the currently processed request
527      * @return a String representing the template path
528      */

529     protected String JavaDoc requestUrlToTemplatePath(HttpServletRequest JavaDoc request)
530     {
531         // First, see if it is an included request
532
String JavaDoc includeServletPath = (String JavaDoc) request.getAttribute("javax.servlet.include.servlet_path");
533         if(includeServletPath != null)
534         {
535             // Try path info; only if that's null (servlet is mapped to an
536
// URL extension instead of to prefix) use servlet path.
537
String JavaDoc includePathInfo = (String JavaDoc) request.getAttribute("javax.servlet.include.path_info");
538             return includePathInfo == null ? includeServletPath : includePathInfo;
539         }
540         // Seems that the servlet was not called as the result of a
541
// RequestDispatcher.include(...). Try pathInfo then servletPath again,
542
// only now directly on the request object:
543
String JavaDoc path = request.getPathInfo();
544         if (path != null) return path;
545         path = request.getServletPath();
546         if (path != null) return path;
547         // Seems that it is a servlet mapped with prefix, and there was no extra path info.
548
return "";
549     }
550
551     /**
552      * Called as the first step in request processing, before the templating mechanism
553      * is put to work. By default does nothing and returns false. This method is
554      * typically overridden to manage serving of non-template resources (i.e. images)
555      * that reside in the template directory.
556      * @param request the HTTP request
557      * @param response the HTTP response
558      * @return true to indicate this method has processed the request entirely,
559      * and that the further request processing should not take place.
560      */

561     protected boolean preprocessRequest(
562         HttpServletRequest JavaDoc request,
563         HttpServletResponse JavaDoc response)
564             throws ServletException JavaDoc, IOException JavaDoc {
565         return false;
566     }
567
568     /**
569      * This method is called from {@link #init()} to create the
570      * FreeMarker configuration object that this servlet will use
571      * for template loading. This is a hook that allows you
572      * to custom-configure the configuration object in a subclass.
573      * The default implementation returns a new {@link Configuration}
574      * instance.
575      */

576     protected Configuration createConfiguration() {
577         return new Configuration();
578     }
579     
580     /**
581      * This method is called from {@link #init()} to create the
582      * FreeMarker object wrapper object that this servlet will use
583      * for adapting request, session, and servlet context attributes into
584      * template models.. This is a hook that allows you
585      * to custom-configure the wrapper object in a subclass.
586      * The default implementation returns a wrapper that depends on the value
587      * of <code>ObjectWrapper</code> init parameter. If <code>simple</code> is
588      * specified, {@link ObjectWrapper#SIMPLE_WRAPPER} is used; if <code>jython</code>
589      * is specified, {@link freemarker.ext.jython.JythonWrapper} is used. In
590      * every other case {@link ObjectWrapper#DEFAULT_WRAPPER} is used.
591      */

592     protected ObjectWrapper createObjectWrapper() {
593         String JavaDoc wrapper = getServletConfig().getInitParameter(DEPR_INITPARAM_OBJECT_WRAPPER);
594         if (wrapper != null) { // BC
595
if (getInitParameter(Configurable.OBJECT_WRAPPER_KEY) != null) {
596                 throw new RuntimeException JavaDoc("Conflicting init-params: "
597                         + Configurable.OBJECT_WRAPPER_KEY + " and "
598                         + DEPR_INITPARAM_OBJECT_WRAPPER);
599             }
600             if (DEPR_INITPARAM_WRAPPER_BEANS.equals(wrapper)) {
601                 return ObjectWrapper.BEANS_WRAPPER;
602             }
603             if(DEPR_INITPARAM_WRAPPER_SIMPLE.equals(wrapper)) {
604                 return ObjectWrapper.SIMPLE_WRAPPER;
605             }
606             if(DEPR_INITPARAM_WRAPPER_JYTHON.equals(wrapper)) {
607                 // Avoiding compile-time dependency on Jython package
608
try {
609                     return (ObjectWrapper) Class.forName("freemarker.ext.jython.JythonWrapper")
610                             .newInstance();
611                 } catch (InstantiationException JavaDoc e) {
612                     throw new InstantiationError JavaDoc(e.getMessage());
613                 } catch (IllegalAccessException JavaDoc e) {
614                     throw new IllegalAccessError JavaDoc(e.getMessage());
615                 } catch (ClassNotFoundException JavaDoc e) {
616                     throw new NoClassDefFoundError JavaDoc(e.getMessage());
617                 }
618             }
619 // return BeansWrapper.getDefaultInstance();
620
return ObjectWrapper.DEFAULT_WRAPPER;
621         } else {
622             wrapper = getInitParameter(Configurable.OBJECT_WRAPPER_KEY);
623             if (wrapper == null) {
624 // return BeansWrapper.getDefaultInstance();
625
return ObjectWrapper.DEFAULT_WRAPPER;
626             } else {
627                 try {
628                     config.setSetting(Configurable.OBJECT_WRAPPER_KEY, wrapper);
629                 } catch (TemplateException e) {
630                     throw new RuntimeException JavaDoc(e.toString());
631                 }
632                 return config.getObjectWrapper();
633             }
634         }
635     }
636     
637     protected ObjectWrapper getObjectWrapper() {
638         return wrapper;
639     }
640     
641     protected final String JavaDoc getTemplatePath() {
642         return templatePath;
643     }
644
645     protected HttpRequestParametersHashModel createRequestParametersHashModel(HttpServletRequest JavaDoc request) {
646         return new HttpRequestParametersHashModel(request);
647     }
648
649     /**
650      * Called when servlet detects in a request processing that
651      * application-global (that is, ServletContext-specific) attributes are not yet
652      * set.
653      * This is a generic hook you might use in subclasses to perform a specific
654      * action on first request in the context. By default it does nothing.
655      * @param request the actual HTTP request
656      * @param response the actual HTTP response
657      */

658     protected void initializeServletContext(
659         HttpServletRequest JavaDoc request,
660         HttpServletResponse JavaDoc response)
661             throws ServletException JavaDoc, IOException JavaDoc {
662     }
663
664     /**
665      * Called when servlet detects in a request processing that
666      * session-global (that is, HttpSession-specific) attributes are not yet
667      * set.
668      * This is a generic hook you might use in subclasses to perform a specific
669      * action on first request in the session. By default it does nothing.
670      *
671      * @param request the actual HTTP request
672      * @param response the actual HTTP response
673      */

674     protected void initializeSession(
675         HttpServletRequest JavaDoc request,
676         HttpServletResponse JavaDoc response)
677         throws ServletException JavaDoc, IOException JavaDoc
678     {
679     }
680
681     /**
682      * Called before the execution is passed to template.process().
683      * This is a generic hook you might use in subclasses to perform a specific
684      * action before the template is processed. By default does nothing.
685      * A typical action to perform here is to inject application-specific
686      * objects into the model root
687      * @param request the actual HTTP request
688      * @param response the actual HTTP response
689      * @param template the template that will get executed
690      * @param data the data that will be passed to the template
691      * @return true to process the template, false to suppress template processing.
692      */

693     protected boolean preTemplateProcess(
694         HttpServletRequest JavaDoc request,
695         HttpServletResponse JavaDoc response,
696         Template template,
697         TemplateModel data)
698         throws ServletException JavaDoc, IOException JavaDoc
699     {
700         return true;
701     }
702
703     /**
704      * Called after the execution returns from template.process().
705      * This is a generic hook you might use in subclasses to perform a specific
706      * action after the template is processed. It will be invoked even if the
707      * template processing throws an exception. By default does nothing.
708      * @param request the actual HTTP request
709      * @param response the actual HTTP response
710      * @param template the template that was executed
711      * @param data the data that was passed to the template
712      */

713     protected void postTemplateProcess(
714         HttpServletRequest JavaDoc request,
715         HttpServletResponse JavaDoc response,
716         Template template,
717         TemplateModel data)
718         throws ServletException JavaDoc, IOException JavaDoc
719     {
720     }
721     
722     /**
723      * Returns the {@link freemarker.template.Configuration} object used by this servlet.
724      * Please don't forget that {@link freemarker.template.Configuration} is not thread-safe
725      * when you modify it.
726      */

727     protected Configuration getConfiguration() {
728         return config;
729     }
730
731     /**
732      * If the parameter "nocache" was set to true, generate a set of headers
733      * that will advise the HTTP client not to cache the returned page.
734      */

735     private void setBrowserCachingPolicy(HttpServletResponse JavaDoc res)
736     {
737         if (nocache)
738         {
739             // HTTP/1.1 + IE extensions
740
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, "
741                     + "post-check=0, pre-check=0");
742             // HTTP/1.0
743
res.setHeader("Pragma", "no-cache");
744             // Last resort for those that ignore all of the above
745
res.setHeader("Expires", EXPIRATION_DATE);
746         }
747     }
748 }
749
Popular Tags