1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.taglib.util;
16  
17  import com.liferay.portal.freemarker.FreeMarkerVariables;
18  import com.liferay.portal.kernel.freemarker.FreeMarkerContext;
19  import com.liferay.portal.kernel.freemarker.FreeMarkerEngineUtil;
20  import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
21  import com.liferay.portal.kernel.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.servlet.StringServletResponse;
24  import com.liferay.portal.kernel.util.GetterUtil;
25  import com.liferay.portal.kernel.util.StringBundler;
26  import com.liferay.portal.kernel.util.StringPool;
27  import com.liferay.portal.kernel.util.WebKeys;
28  import com.liferay.portal.kernel.velocity.VelocityContext;
29  import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
30  import com.liferay.portal.model.Theme;
31  import com.liferay.portal.theme.ThemeDisplay;
32  import com.liferay.portal.velocity.VelocityContextPool;
33  import com.liferay.portal.velocity.VelocityVariables;
34  
35  import freemarker.ext.jsp.TaglibFactory;
36  import freemarker.ext.servlet.HttpRequestHashModel;
37  
38  import freemarker.template.ObjectWrapper;
39  
40  import javax.servlet.RequestDispatcher;
41  import javax.servlet.ServletContext;
42  import javax.servlet.http.HttpServletRequest;
43  import javax.servlet.http.HttpServletResponse;
44  import javax.servlet.jsp.PageContext;
45  
46  import org.apache.struts.taglib.tiles.ComponentConstants;
47  import org.apache.struts.tiles.ComponentContext;
48  
49  /**
50   * <a href="ThemeUtil.java.html"><b><i>View Source</i></b></a>
51   *
52   * @author Brian Wing Shun Chan
53   * @author Brian Myunghun Kim
54   * @author Raymond Augé
55   * @author Mika Koivisto
56   */
57  public class ThemeUtil {
58  
59      public static void include(
60              ServletContext servletContext, HttpServletRequest request,
61              HttpServletResponse response, PageContext pageContext, String page,
62              Theme theme)
63          throws Exception {
64  
65          String extension = theme.getTemplateExtension();
66  
67          if (extension.equals(_TEMPLATE_EXTENSION_FTL)) {
68              includeFTL(servletContext, request, pageContext, page, theme, true);
69          }
70          else if (extension.equals(_TEMPLATE_EXTENSION_VM)) {
71              includeVM(servletContext, request, pageContext, page, theme, true);
72          }
73          else {
74              String path =
75                  theme.getTemplatesPath() + StringPool.SLASH + page;
76  
77              includeJSP(servletContext, request, response, path, theme);
78          }
79      }
80  
81      public static String includeFTL(
82              ServletContext servletContext, HttpServletRequest request,
83              PageContext pageContext, String page, Theme theme, boolean write)
84          throws Exception {
85  
86          // The servlet context name will be null when the theme is deployed to
87          // the root directory in Tomcat. See
88          // com.liferay.portal.servlet.MainServlet and
89          // com.liferay.portlet.PortletContextImpl for other cases where a null
90          // servlet context name is also converted to an empty string.
91  
92          String ctxName = GetterUtil.getString(theme.getServletContextName());
93  
94          if (VelocityContextPool.get(ctxName) == null) {
95  
96              // This should only happen if the FreeMarker template is the first
97              // page to be accessed in the system
98  
99              VelocityContextPool.put(ctxName, servletContext);
100         }
101 
102         int pos = page.lastIndexOf(StringPool.PERIOD);
103 
104         StringBundler sb = new StringBundler(7);
105 
106         sb.append(ctxName);
107         sb.append(theme.getFreeMarkerTemplateLoader());
108         sb.append(theme.getTemplatesPath());
109         sb.append(StringPool.SLASH);
110         sb.append(page.substring(0, pos));
111         sb.append(StringPool.PERIOD);
112         sb.append(_TEMPLATE_EXTENSION_FTL);
113 
114         String source = sb.toString();
115 
116         if (!FreeMarkerEngineUtil.resourceExists(source)) {
117             _log.error(source + " does not exist");
118 
119             return null;
120         }
121 
122         UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter(true);
123 
124         FreeMarkerContext freeMarkerContext =
125             FreeMarkerEngineUtil.getWrappedStandardToolsContext();
126 
127         // FreeMarker variables
128 
129         FreeMarkerVariables.insertVariables(freeMarkerContext, request);
130 
131         // Theme servlet context
132 
133         ServletContext themeServletContext = VelocityContextPool.get(ctxName);
134 
135         // liferay:include tag library
136 
137         StringServletResponse stringResponse = new StringServletResponse(
138             (HttpServletResponse)pageContext.getResponse());
139 
140         VelocityTaglib velocityTaglib = new VelocityTaglib(
141             servletContext, request, stringResponse, pageContext);
142 
143         request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
144 
145         freeMarkerContext.put("themeServletContext", themeServletContext);
146         freeMarkerContext.put("taglibLiferay", velocityTaglib);
147         freeMarkerContext.put("theme", velocityTaglib);
148 
149         // Portal JSP tag library factory
150 
151         TaglibFactory portalTaglib = new TaglibFactory(servletContext);
152 
153         freeMarkerContext.put("PortalJspTagLibs", portalTaglib);
154 
155         // Theme JSP tag library factory
156 
157         TaglibFactory themeTaglib = new TaglibFactory(themeServletContext);
158 
159         freeMarkerContext.put("ThemeJspTaglibs", themeTaglib);
160 
161         // FreeMarker JSP tag library support
162 
163         HttpServletResponse response =
164             (HttpServletResponse)pageContext.getResponse();
165 
166         HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
167             request, response, ObjectWrapper.DEFAULT_WRAPPER);
168 
169         freeMarkerContext.put("Request", httpRequestHashModel);
170 
171         // Merge templates
172 
173         FreeMarkerEngineUtil.mergeTemplate(
174             source, freeMarkerContext, unsyncStringWriter);
175 
176         // Print output
177 
178         String output = unsyncStringWriter.toString();
179 
180         if (write) {
181             pageContext.getOut().print(output);
182 
183             return null;
184         }
185         else {
186             return output;
187         }
188     }
189 
190     public static void includeJSP(
191             ServletContext servletContext, HttpServletRequest request,
192             HttpServletResponse response, String path, Theme theme)
193         throws Exception {
194 
195         String tilesTitle = _getTilesVariables(request, "title");
196         String tilesContent = _getTilesVariables(request, "content");
197         boolean tilesSelectable = GetterUtil.getBoolean(
198             _getTilesVariables(request, "selectable"));
199 
200         ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
201             WebKeys.THEME_DISPLAY);
202 
203         themeDisplay.setTilesTitle(tilesTitle);
204         themeDisplay.setTilesContent(tilesContent);
205         themeDisplay.setTilesSelectable(tilesSelectable);
206 
207         if (theme.isWARFile()) {
208             ServletContext themeServletContext = servletContext.getContext(
209                 theme.getContextPath());
210 
211             if (themeServletContext == null) {
212                 _log.error(
213                     "Theme " + theme.getThemeId() + " cannot find its " +
214                         "servlet context at " + theme.getServletContextName());
215             }
216             else {
217                 RequestDispatcher requestDispatcher =
218                     themeServletContext.getRequestDispatcher(path);
219 
220                 if (requestDispatcher == null) {
221                     _log.error(
222                         "Theme " + theme.getThemeId() + " does not have " +
223                             path);
224                 }
225                 else {
226                     requestDispatcher.include(request, response);
227                 }
228             }
229         }
230         else {
231             RequestDispatcher requestDispatcher =
232                 servletContext.getRequestDispatcher(path);
233 
234             if (requestDispatcher == null) {
235                 _log.error(
236                     "Theme " + theme.getThemeId() + " does not have " + path);
237             }
238             else {
239                 requestDispatcher.include(request, response);
240             }
241         }
242     }
243 
244     public static String includeVM(
245             ServletContext servletContext, HttpServletRequest request,
246             PageContext pageContext, String page, Theme theme, boolean write)
247         throws Exception {
248 
249         // The servlet context name will be null when the theme is deployed to
250         // the root directory in Tomcat. See
251         // com.liferay.portal.servlet.MainServlet and
252         // com.liferay.portlet.PortletContextImpl for other cases where a null
253         // servlet context name is also converted to an empty string.
254 
255         String ctxName = GetterUtil.getString(theme.getServletContextName());
256 
257         if (VelocityContextPool.get(ctxName) == null) {
258 
259             // This should only happen if the Velocity template is the first
260             // page to be accessed in the system
261 
262             VelocityContextPool.put(ctxName, servletContext);
263         }
264 
265         int pos = page.lastIndexOf(StringPool.PERIOD);
266 
267         StringBundler sb = new StringBundler(7);
268 
269         sb.append(ctxName);
270         sb.append(theme.getVelocityResourceListener());
271         sb.append(theme.getTemplatesPath());
272         sb.append(StringPool.SLASH);
273         sb.append(page.substring(0, pos));
274         sb.append(StringPool.PERIOD);
275         sb.append(_TEMPLATE_EXTENSION_VM);
276 
277         String source = sb.toString();
278 
279         if (!VelocityEngineUtil.resourceExists(source)) {
280             _log.error(source + " does not exist");
281 
282             return null;
283         }
284 
285         UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter(true);
286 
287         VelocityContext velocityContext =
288             VelocityEngineUtil.getWrappedStandardToolsContext();
289 
290         // Velocity variables
291 
292         VelocityVariables.insertVariables(velocityContext, request);
293 
294         // Theme servlet context
295 
296         ServletContext themeServletContext = VelocityContextPool.get(ctxName);
297 
298         // liferay:include tag library
299 
300         StringServletResponse stringResponse = new StringServletResponse(
301             (HttpServletResponse)pageContext.getResponse());
302 
303         VelocityTaglib velocityTaglib = new VelocityTaglib(
304             servletContext, request, stringResponse, pageContext);
305 
306         request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
307 
308         velocityContext.put("themeServletContext", themeServletContext);
309         velocityContext.put("taglibLiferay", velocityTaglib);
310         velocityContext.put("theme", velocityTaglib);
311 
312         // Merge templates
313 
314         VelocityEngineUtil.mergeTemplate(
315             source, velocityContext, unsyncStringWriter);
316 
317         // Print output
318 
319         String output = unsyncStringWriter.toString();
320 
321         if (write) {
322             pageContext.getOut().print(output);
323 
324             return null;
325         }
326         else {
327             return output;
328         }
329     }
330 
331     private static String _getTilesVariables(
332         HttpServletRequest request, String attributeName) {
333 
334         ComponentContext componentContext =
335             (ComponentContext)request.getAttribute(
336                 ComponentConstants.COMPONENT_CONTEXT);
337 
338         String value = null;
339 
340         if (componentContext != null) {
341             value = (String)componentContext.getAttribute(attributeName);
342         }
343 
344         return value;
345     }
346 
347     private static final String _TEMPLATE_EXTENSION_FTL = "ftl";
348 
349     private static final String _TEMPLATE_EXTENSION_VM = "vm";
350 
351     private static Log _log = LogFactoryUtil.getLog(ThemeUtil.class);
352 
353 }