1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.tiles.freemarker.context;
23
24 import java.io.IOException;
25 import java.io.StringWriter;
26
27 import javax.servlet.http.HttpServletRequest;
28
29 import org.apache.tiles.ArrayStack;
30 import org.apache.tiles.TilesContainer;
31 import org.apache.tiles.access.TilesAccess;
32 import org.apache.tiles.freemarker.FreeMarkerTilesException;
33 import org.apache.tiles.freemarker.io.NullWriter;
34 import org.apache.tiles.impl.NoSuchContainerException;
35 import org.apache.tiles.servlet.context.ServletUtil;
36
37 import freemarker.core.Environment;
38 import freemarker.ext.servlet.FreemarkerServlet;
39 import freemarker.ext.servlet.HttpRequestHashModel;
40 import freemarker.ext.servlet.ServletContextHashModel;
41 import freemarker.template.TemplateDirectiveBody;
42 import freemarker.template.TemplateException;
43 import freemarker.template.TemplateModel;
44 import freemarker.template.TemplateModelException;
45 import freemarker.template.utility.DeepUnwrap;
46
47 /***
48 * Utilities for FreeMarker usage in Tiles.
49 *
50 * @version $Rev: 797765 $ $Date: 2009-07-25 15:20:26 +0200 (sab, 25 lug 2009) $
51 * @since 2.2.0
52 */
53 public final class FreeMarkerUtil {
54
55 /***
56 * The name of the attribute that holds the compose stack.
57 */
58 public static final String COMPOSE_STACK_ATTRIBUTE_NAME = "org.apache.tiles.template.COMPOSE_STACK";
59
60 /***
61 * Private constructor to avoid instantiation.
62 */
63 private FreeMarkerUtil() {
64 }
65
66 /***
67 * Returns true if forced include of the result is needed.
68 *
69 * @param env The current FreeMarker environment.
70 * @return If <code>true</code> the include operation must be forced.
71 * @since 2.2.0
72 */
73 public static boolean isForceInclude(Environment env) {
74 return ServletUtil
75 .isForceInclude(getRequestHashModel(env).getRequest());
76 }
77
78 /***
79 * Sets the option that enables the forced include of the response.
80 *
81 * @param env The current FreeMarker environment.
82 * @param forceInclude If <code>true</code> the include operation must be
83 * forced.
84 * @since 2.2.0
85 */
86 public static void setForceInclude(Environment env, boolean forceInclude) {
87 ServletUtil.setForceInclude(getRequestHashModel(env).getRequest(),
88 forceInclude);
89 }
90
91 /***
92 * Returns a specific Tiles container.
93 *
94 * @param env The current FreeMarker environment.
95 * @param key The key under which the container is stored. If null, the
96 * default container will be returned.
97 * @return The requested Tiles container.
98 * @since 2.2.0
99 */
100 public static TilesContainer getContainer(Environment env, String key) {
101 if (key == null) {
102 key = TilesAccess.CONTAINER_ATTRIBUTE;
103 }
104 return (TilesContainer) getServletContextHashModel(env).getServlet()
105 .getServletContext().getAttribute(key);
106 }
107
108 /***
109 * Sets the current container to use in web pages.
110 *
111 * @param env The current FreeMarker environment.
112 * @param key The key under which the container is stored.
113 * @since 2.2.0
114 */
115 public static void setCurrentContainer(Environment env, String key) {
116 TilesContainer container = getContainer(env, key);
117 if (container != null) {
118 getRequestHashModel(env).getRequest().setAttribute(
119 ServletUtil.CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
120 } else {
121 throw new NoSuchContainerException("The container with the key '"
122 + key + "' cannot be found");
123 }
124 }
125
126 /***
127 * Sets the current container to use in web pages.
128 *
129 * @param env The current FreeMarker environment.
130 * @param container The container to use as the current container.
131 * @since 2.2.0
132 */
133 public static void setCurrentContainer(Environment env,
134 TilesContainer container) {
135 ServletUtil.setCurrentContainer(getRequestHashModel(env).getRequest(),
136 getServletContextHashModel(env).getServlet()
137 .getServletContext(), container);
138 }
139
140 /***
141 * Returns the current container that has been set, or the default one.
142 *
143 * @param env The current FreeMarker environment.
144 * @return The current Tiles container to use in web pages.
145 * @since 2.2.0
146 */
147 public static TilesContainer getCurrentContainer(Environment env) {
148 return ServletUtil.getCurrentContainer(getRequestHashModel(env)
149 .getRequest(), getServletContextHashModel(env).getServlet()
150 .getServletContext());
151 }
152
153 /***
154 * Returns the HTTP request hash model.
155 *
156 * @param env The current FreeMarker environment.
157 * @return The request hash model.
158 * @since 2.2.0
159 */
160 public static HttpRequestHashModel getRequestHashModel(Environment env) {
161 try {
162 return (HttpRequestHashModel) env.getDataModel().get(
163 FreemarkerServlet.KEY_REQUEST);
164 } catch (TemplateModelException e) {
165 throw new FreeMarkerTilesException(
166 "Exception got when obtaining the request hash model", e);
167 }
168 }
169
170 /***
171 * Returns the servlet context hash model.
172 *
173 * @param env The current FreeMarker environment.
174 * @return The servlet context hash model.
175 * @since 2.2.0
176 */
177 public static ServletContextHashModel getServletContextHashModel(
178 Environment env) {
179 try {
180 return (ServletContextHashModel) env.getDataModel().get(
181 FreemarkerServlet.KEY_APPLICATION);
182 } catch (TemplateModelException e) {
183 throw new FreeMarkerTilesException(
184 "Exception got when obtaining the application hash model",
185 e);
186 }
187 }
188
189 /***
190 * Unwraps a TemplateModel to extract a string.
191 *
192 * @param model The TemplateModel to unwrap.
193 * @return The unwrapped string.
194 * @since 2.2.0
195 */
196 public static String getAsString(TemplateModel model) {
197 try {
198 return (String) DeepUnwrap.unwrap(model);
199 } catch (TemplateModelException e) {
200 throw new FreeMarkerTilesException("Cannot unwrap a model", e);
201 }
202 }
203
204 /***
205 * Unwraps a TemplateModel to extract a boolean.
206 *
207 * @param model The TemplateModel to unwrap.
208 * @param defaultValue If the value is null, this value will be returned.
209 * @return The unwrapped boolean.
210 * @since 2.2.0
211 */
212 public static boolean getAsBoolean(TemplateModel model, boolean defaultValue) {
213 try {
214 Boolean retValue = (Boolean) DeepUnwrap.unwrap(model);
215 return retValue != null ? retValue : defaultValue;
216 } catch (TemplateModelException e) {
217 throw new FreeMarkerTilesException("Cannot unwrap a model", e);
218 }
219 }
220
221 /***
222 * Unwraps a TemplateModel to extract an object.
223 *
224 * @param model The TemplateModel to unwrap.
225 * @return The unwrapped object.
226 * @since 2.2.0
227 */
228 public static Object getAsObject(TemplateModel model) {
229 try {
230 return DeepUnwrap.unwrap(model);
231 } catch (TemplateModelException e) {
232 throw new FreeMarkerTilesException("Cannot unwrap a model", e);
233 }
234 }
235
236 /***
237 * Sets an attribute in the desired scope.
238 *
239 * @param env The FreeMarker current environment.
240 * @param name The name of the attribute.
241 * @param obj The value of the attribute.
242 * @param scope The scope. It can be <code>page</code>, <code>request</code>
243 * , <code>session</code>, <code>application</code>.
244 * @since 2.2.0
245 */
246 public static void setAttribute(Environment env, String name, Object obj,
247 String scope) {
248 if (scope == null) {
249 scope = "page";
250 }
251 if ("page".equals(scope)) {
252 try {
253 TemplateModel model = env.getObjectWrapper().wrap(obj);
254 env.setVariable(name, model);
255 } catch (TemplateModelException e) {
256 throw new FreeMarkerTilesException(
257 "Error when wrapping an object", e);
258 }
259 } else if ("request".equals(scope)) {
260 getRequestHashModel(env).getRequest().setAttribute(name, obj);
261 } else if ("session".equals(scope)) {
262 getRequestHashModel(env).getRequest().getSession().setAttribute(
263 name, obj);
264 } else if ("application".equals(scope)) {
265 getServletContextHashModel(env).getServlet().getServletContext()
266 .setAttribute(name, obj);
267 }
268 }
269
270 /***
271 * Returns the current compose stack, or creates a new one if not present.
272 *
273 * @param env The current FreeMarker environment.
274 * @return The compose stack.
275 * @since 2.2.0
276 */
277 @SuppressWarnings("unchecked")
278 public static ArrayStack<Object> getComposeStack(Environment env) {
279 HttpServletRequest request = getRequestHashModel(env).getRequest();
280 ArrayStack<Object> composeStack = (ArrayStack<Object>) request
281 .getAttribute(COMPOSE_STACK_ATTRIBUTE_NAME);
282 if (composeStack == null) {
283 composeStack = new ArrayStack<Object>();
284 request.setAttribute(COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
285 }
286 return composeStack;
287 }
288
289 /***
290 * Evaluates the body without rendering it.
291 *
292 * @param body The body to evaluate.
293 * @throws TemplateException If something goes wrong during evaluation.
294 * @throws IOException If something goes wrong during writing the result.
295 * @since 2.2.0
296 */
297 public static void evaluateBody(TemplateDirectiveBody body)
298 throws TemplateException, IOException {
299 if (body != null) {
300 NullWriter writer = new NullWriter();
301 try {
302 body.render(writer);
303 } finally {
304 writer.close();
305 }
306 }
307 }
308
309 /***
310 * Renders the body as a string.
311 *
312 * @param body The body to render.
313 * @return The rendered string.
314 * @throws TemplateException If something goes wrong during evaluation.
315 * @throws IOException If something goes wrong during writing the result.
316 * @since 2.2.0
317 */
318 public static String renderAsString(TemplateDirectiveBody body)
319 throws TemplateException, IOException {
320 String bodyString = null;
321 if (body != null) {
322 StringWriter stringWriter = new StringWriter();
323 try {
324 body.render(stringWriter);
325 } finally {
326 stringWriter.close();
327 }
328 bodyString = stringWriter.toString();
329 }
330 return bodyString;
331 }
332 }