View Javadoc

1   /*
2    * $Id: FreeMarkerPageFilter.java 475637 2006-11-16 08:32:03Z mrdon $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts2.sitemesh;
22  
23  import java.io.IOException;
24  import java.util.Locale;
25  
26  import javax.servlet.ServletContext;
27  import javax.servlet.ServletException;
28  import javax.servlet.http.HttpServletRequest;
29  import javax.servlet.http.HttpServletResponse;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.struts2.views.freemarker.FreemarkerManager;
34  
35  import com.opensymphony.module.sitemesh.Decorator;
36  import com.opensymphony.module.sitemesh.HTMLPage;
37  import com.opensymphony.module.sitemesh.Page;
38  import com.opensymphony.xwork2.ActionContext;
39  import com.opensymphony.xwork2.ActionInvocation;
40  import com.opensymphony.xwork2.LocaleProvider;
41  import com.opensymphony.xwork2.inject.Inject;
42  import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
43  
44  import freemarker.template.Configuration;
45  import freemarker.template.SimpleHash;
46  import freemarker.template.Template;
47  
48  /***
49   *  Applies FreeMarker-based sitemesh decorators.
50   *
51   *  <!-- START SNIPPET: javadoc -->
52   *
53   *  The following variables are available to the decorating freemarker page :-
54   *  <ul>
55   *      <li>${title}           - content of &lt;title&gt; tag in the decorated page</li>
56   *      <li>${head}            - content of &lt;head&gt; tag in the decorated page</li>
57   *      <li>${body}            - content of t&lt;body&gt; tag in the decorated page</li>
58   *      <li>${page.properties} - content of the page properties</li>
59   *  </ul>
60   *  <p/>
61   *  With the following decorated page :-
62   *  <pre>
63   *  &lt;html&gt;
64   *      &lt;meta name="author" content="tm_jee" /&gt;
65   *      &lt;head&gt;
66   *          &lt;title&gt;My Title&lt;/title&gt;
67   *          &lt;link rel="stylesheet" type="text/css" href="mycss.css" /&gt;
68   *          &lt;style type="text/javascript" language="javascript" src="myjavascript.js"&gt;&lt;/script&gt;
69   *      &lt;/head&gt;
70   *      &lt;body&lt;
71   *          &lt;h1&gt;Sample&lt;/h1&gt;
72   *      &lt;/body&gt;
73   *  &lt;/html&gt;
74   *  </pre>
75   *  <p/>
76   *  <table border="1">
77   *      <tr>
78   *          <td>Properties</td>
79   *          <td>Content</td>
80   *      </tr>
81   *      <tr>
82   *          <td>${title}</td>
83   *          <td>My Title</td>
84   *      </tr>
85   *      <tr>
86   *          <td>${head}</td>
87   *          <td>
88   *              &lt;link rel="stylesheet" type="text/css" href="mycss.css" /&gt;
89   *              &lt;style type="text/javascript" language="javascript" src="myjavascript.js"&gt;&lt;/script&gt;
90   *          </td>
91   *      </tr>
92   *      <tr>
93   *          <td>${body}</td>
94   *          <td>
95   *              &lt;h1&gt;Sample&lt;/h1&gt;
96   *          </td>
97   *      </tr>
98   *      <tr>
99   *          <td>${page.properties.meta.author}</td>
100  *          <td>tm_jee</td>
101  *      </tr>
102  *  </table>
103  *
104  *  <!-- END SNIPPET: javadoc -->
105  *
106  *  @version $Date: 2006-11-16 03:32:03 -0500 (Thu, 16 Nov 2006) $ $Id: FreeMarkerPageFilter.java 475637 2006-11-16 08:32:03Z mrdon $
107  */
108 public class FreeMarkerPageFilter extends TemplatePageFilter {
109     private static final Log LOG = LogFactory.getLog(FreeMarkerPageFilter.class);
110     
111     private static FreemarkerManager freemarkerManager;
112     
113     @Inject(required=false)
114     public static void setFreemarkerManager(FreemarkerManager mgr) {
115         freemarkerManager = mgr;
116     }
117 
118     /***
119      *  Applies the decorator, using the relevent contexts
120      *
121      * @param page The page
122      * @param decorator The decorator
123      * @param req The servlet request
124      * @param res The servlet response
125      * @param servletContext The servlet context
126      * @param ctx The action context for this request, populated with the server state
127      */
128     protected void applyDecorator(Page page, Decorator decorator,
129                                   HttpServletRequest req, HttpServletResponse res,
130                                   ServletContext servletContext, ActionContext ctx)
131             throws ServletException, IOException {
132 
133         String timerKey = "FreemarkerPageFilter_applyDecorator: ";
134         if (freemarkerManager == null) {
135             throw new ServletException("Missing freemarker dependency");
136         }
137         
138         try {
139             UtilTimerStack.push(timerKey);
140 
141             // get the configuration and template
142             Configuration config = freemarkerManager.getConfiguration(servletContext);
143             Template template = config.getTemplate(decorator.getPage(), getLocale(ctx.getActionInvocation(), config)); // WW-1181
144 
145             // get the main hash
146             SimpleHash model = freemarkerManager.buildTemplateModel(ctx.getValueStack(), null, servletContext, req, res, config.getObjectWrapper());
147 
148             // populate the hash with the page
149             model.put("page", page);
150             if (page instanceof HTMLPage) {
151                 HTMLPage htmlPage = ((HTMLPage) page);
152                 model.put("head", htmlPage.getHead());
153             }
154             model.put("title",page.getTitle());
155             model.put("body",page.getBody());
156             model.put("page.properties", new SimpleHash(page.getProperties()));
157 
158             // finally, render it
159             template.process(model, res.getWriter());
160         } catch (Exception e) {
161             String msg = "Error applying decorator: " + e.getMessage();
162             LOG.error(msg, e);
163             throw new ServletException(msg, e);
164         }
165         finally {
166             UtilTimerStack.pop(timerKey);
167         }
168     }
169 
170     /***
171      * Returns the locale used for the {@link Configuration#getTemplate(String, Locale)} call. The base implementation
172      * simply returns the locale setting of the action (assuming the action implements {@link LocaleProvider}) or, if
173      * the action does not the configuration's locale is returned. Override this method to provide different behaviour,
174      */
175     protected Locale getLocale(ActionInvocation invocation, Configuration configuration) {
176         if (invocation.getAction() instanceof LocaleProvider) {
177             return ((LocaleProvider) invocation.getAction()).getLocale();
178         } else {
179             return configuration.getLocale();
180         }
181     }
182 
183 }