1 /*
2 * $Id: FreeMarkerPageFilter.java 651946 2008-04-27 13:41:38Z apetrelli $
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
22 package org.apache.struts2.sitemesh;
23
24 import java.io.IOException;
25 import java.util.Locale;
26
27 import javax.servlet.ServletContext;
28 import javax.servlet.ServletException;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.apache.struts2.views.freemarker.FreemarkerManager;
33
34 import com.opensymphony.module.sitemesh.Decorator;
35 import com.opensymphony.module.sitemesh.HTMLPage;
36 import com.opensymphony.module.sitemesh.Page;
37 import com.opensymphony.xwork2.ActionContext;
38 import com.opensymphony.xwork2.ActionInvocation;
39 import com.opensymphony.xwork2.LocaleProvider;
40 import com.opensymphony.xwork2.inject.Inject;
41 import com.opensymphony.xwork2.util.logging.Logger;
42 import com.opensymphony.xwork2.util.logging.LoggerFactory;
43 import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
44
45 import freemarker.template.Configuration;
46 import freemarker.template.SimpleHash;
47 import freemarker.template.Template;
48
49 /**
50 * Applies FreeMarker-based sitemesh decorators.
51 *
52 * <!-- START SNIPPET: javadoc -->
53 *
54 * The following variables are available to the decorating freemarker page :-
55 * <ul>
56 * <li>${title} - content of <title> tag in the decorated page</li>
57 * <li>${head} - content of <head> tag in the decorated page</li>
58 * <li>${body} - content of t<body> tag in the decorated page</li>
59 * <li>${page.properties} - content of the page properties</li>
60 * </ul>
61 * <p/>
62 * With the following decorated page :-
63 * <pre>
64 * <html>
65 * <meta name="author" content="tm_jee" />
66 * <head>
67 * <title>My Title</title>
68 * <link rel="stylesheet" type="text/css" href="mycss.css" />
69 * <style type="text/javascript" language="javascript" src="myjavascript.js"></script>
70 * </head>
71 * <body<
72 * <h1>Sample</h1>
73 * </body>
74 * </html>
75 * </pre>
76 * <p/>
77 * <table border="1">
78 * <tr>
79 * <td>Properties</td>
80 * <td>Content</td>
81 * </tr>
82 * <tr>
83 * <td>${title}</td>
84 * <td>My Title</td>
85 * </tr>
86 * <tr>
87 * <td>${head}</td>
88 * <td>
89 * <link rel="stylesheet" type="text/css" href="mycss.css" />
90 * <style type="text/javascript" language="javascript" src="myjavascript.js"></script>
91 * </td>
92 * </tr>
93 * <tr>
94 * <td>${body}</td>
95 * <td>
96 * <h1>Sample</h1>
97 * </td>
98 * </tr>
99 * <tr>
100 * <td>${page.properties.meta.author}</td>
101 * <td>tm_jee</td>
102 * </tr>
103 * </table>
104 *
105 * <!-- END SNIPPET: javadoc -->
106 *
107 * @version $Date: 2008-04-27 09:41:38 -0400 (Sun, 27 Apr 2008) $ $Id: FreeMarkerPageFilter.java 651946 2008-04-27 13:41:38Z apetrelli $
108 */
109 public class FreeMarkerPageFilter extends TemplatePageFilter {
110 private static final Logger LOG = LoggerFactory.getLogger(FreeMarkerPageFilter.class);
111
112 private static FreemarkerManager freemarkerManager;
113
114 @Inject(required=false)
115 public static void setFreemarkerManager(FreemarkerManager mgr) {
116 freemarkerManager = mgr;
117 }
118
119 /**
120 * Applies the decorator, using the relevent contexts
121 *
122 * @param page The page
123 * @param decorator The decorator
124 * @param req The servlet request
125 * @param res The servlet response
126 * @param servletContext The servlet context
127 * @param ctx The action context for this request, populated with the server state
128 */
129 protected void applyDecorator(Page page, Decorator decorator,
130 HttpServletRequest req, HttpServletResponse res,
131 ServletContext servletContext, ActionContext ctx)
132 throws ServletException, IOException {
133
134 String timerKey = "FreemarkerPageFilter_applyDecorator: ";
135 if (freemarkerManager == null) {
136 throw new ServletException("Missing freemarker dependency");
137 }
138
139 try {
140 UtilTimerStack.push(timerKey);
141
142 // get the configuration and template
143 Configuration config = freemarkerManager.getConfiguration(servletContext);
144 Template template = config.getTemplate(decorator.getPage(), getLocale(ctx.getActionInvocation(), config)); // WW-1181
145
146 // get the main hash
147 SimpleHash model = freemarkerManager.buildTemplateModel(ctx.getValueStack(), null, servletContext, req, res, config.getObjectWrapper());
148
149 // populate the hash with the page
150 model.put("page", page);
151 if (page instanceof HTMLPage) {
152 HTMLPage htmlPage = ((HTMLPage) page);
153 model.put("head", htmlPage.getHead());
154 }
155 model.put("title",page.getTitle());
156 model.put("body",page.getBody());
157 model.put("page.properties", new SimpleHash(page.getProperties()));
158
159 // finally, render it
160 template.process(model, res.getWriter());
161 } catch (Exception e) {
162 String msg = "Error applying decorator: " + e.getMessage();
163 LOG.error(msg, e);
164 throw new ServletException(msg, e);
165 }
166 finally {
167 UtilTimerStack.pop(timerKey);
168 }
169 }
170
171 /**
172 * Returns the locale used for the {@link Configuration#getTemplate(String, Locale)} call. The base implementation
173 * simply returns the locale setting of the action (assuming the action implements {@link LocaleProvider}) or, if
174 * the action does not the configuration's locale is returned. Override this method to provide different behaviour,
175 */
176 protected Locale getLocale(ActionInvocation invocation, Configuration configuration) {
177 if (invocation.getAction() instanceof LocaleProvider) {
178 return ((LocaleProvider) invocation.getAction()).getLocale();
179 } else {
180 return configuration.getLocale();
181 }
182 }
183
184 }