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.PipingServletResponse;
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 java.io.Writer;
41  
42  import javax.servlet.RequestDispatcher;
43  import javax.servlet.ServletContext;
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpServletResponse;
46  import javax.servlet.jsp.PageContext;
47  
48  import org.apache.struts.taglib.tiles.ComponentConstants;
49  import org.apache.struts.tiles.ComponentContext;
50  
51  /**
52   * <a href="ThemeUtil.java.html"><b><i>View Source</i></b></a>
53   *
54   * @author Brian Wing Shun Chan
55   * @author Brian Myunghun Kim
56   * @author Raymond Augé
57   * @author Mika Koivisto
58   * @author Shuyang Zhou
59   */
60  public class ThemeUtil {
61  
62      public static void include(
63              ServletContext servletContext, HttpServletRequest request,
64              HttpServletResponse response, PageContext pageContext, String page,
65              Theme theme)
66          throws Exception {
67  
68          String extension = theme.getTemplateExtension();
69  
70          if (extension.equals(_TEMPLATE_EXTENSION_FTL)) {
71              includeFTL(servletContext, request, pageContext, page, theme, true);
72          }
73          else if (extension.equals(_TEMPLATE_EXTENSION_VM)) {
74              includeVM(servletContext, request, pageContext, page, theme, true);
75          }
76          else {
77              String path =
78                  theme.getTemplatesPath() + StringPool.SLASH + page;
79  
80              includeJSP(servletContext, request, response, path, theme);
81          }
82      }
83  
84      public static String includeFTL(
85              ServletContext servletContext, HttpServletRequest request,
86              PageContext pageContext, String page, Theme theme, boolean write)
87          throws Exception {
88  
89          // The servlet context name will be null when the theme is deployed to
90          // the root directory in Tomcat. See
91          // com.liferay.portal.servlet.MainServlet and
92          // com.liferay.portlet.PortletContextImpl for other cases where a null
93          // servlet context name is also converted to an empty string.
94  
95          String ctxName = GetterUtil.getString(theme.getServletContextName());
96  
97          if (VelocityContextPool.get(ctxName) == null) {
98  
99              // This should only happen if the FreeMarker template is the first
100             // page to be accessed in the system
101 
102             VelocityContextPool.put(ctxName, servletContext);
103         }
104 
105         int pos = page.lastIndexOf(StringPool.PERIOD);
106 
107         StringBundler sb = new StringBundler(7);
108 
109         sb.append(ctxName);
110         sb.append(theme.getFreeMarkerTemplateLoader());
111         sb.append(theme.getTemplatesPath());
112         sb.append(StringPool.SLASH);
113         sb.append(page.substring(0, pos));
114         sb.append(StringPool.PERIOD);
115         sb.append(_TEMPLATE_EXTENSION_FTL);
116 
117         String source = sb.toString();
118 
119         if (!FreeMarkerEngineUtil.resourceExists(source)) {
120             _log.error(source + " does not exist");
121 
122             return null;
123         }
124 
125         FreeMarkerContext freeMarkerContext =
126             FreeMarkerEngineUtil.getWrappedStandardToolsContext();
127 
128         // FreeMarker variables
129 
130         FreeMarkerVariables.insertVariables(freeMarkerContext, request);
131 
132         // Theme servlet context
133 
134         ServletContext themeServletContext = VelocityContextPool.get(ctxName);
135 
136         freeMarkerContext.put("themeServletContext", themeServletContext);
137 
138         // Tag libraries
139 
140         HttpServletResponse response =
141             (HttpServletResponse)pageContext.getResponse();
142 
143         Writer writer = null;
144 
145         if (write) {
146             writer = pageContext.getOut();
147         }
148         else {
149             writer = new UnsyncStringWriter();
150         }
151 
152         VelocityTaglib velocityTaglib = new VelocityTaglib(
153             servletContext, request,
154             new PipingServletResponse(response, writer), pageContext);
155 
156         request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
157 
158         freeMarkerContext.put("taglibLiferay", velocityTaglib);
159         freeMarkerContext.put("theme", velocityTaglib);
160 
161         // Portal JSP tag library factory
162 
163         TaglibFactory portalTaglib = new TaglibFactory(servletContext);
164 
165         freeMarkerContext.put("PortalJspTagLibs", portalTaglib);
166 
167         // Theme JSP tag library factory
168 
169         TaglibFactory themeTaglib = new TaglibFactory(themeServletContext);
170 
171         freeMarkerContext.put("ThemeJspTaglibs", themeTaglib);
172 
173         // FreeMarker JSP tag library support
174 
175         HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
176             request, response, ObjectWrapper.DEFAULT_WRAPPER);
177 
178         freeMarkerContext.put("Request", httpRequestHashModel);
179 
180         // Merge templates
181 
182         FreeMarkerEngineUtil.mergeTemplate(source, freeMarkerContext, writer);
183 
184         if (write) {
185             return null;
186         }
187         else {
188             return ((UnsyncStringWriter)writer).toString();
189         }
190     }
191 
192     public static void includeJSP(
193             ServletContext servletContext, HttpServletRequest request,
194             HttpServletResponse response, String path, Theme theme)
195         throws Exception {
196 
197         String tilesTitle = _getTilesVariables(request, "title");
198         String tilesContent = _getTilesVariables(request, "content");
199         boolean tilesSelectable = GetterUtil.getBoolean(
200             _getTilesVariables(request, "selectable"));
201 
202         ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
203             WebKeys.THEME_DISPLAY);
204 
205         themeDisplay.setTilesTitle(tilesTitle);
206         themeDisplay.setTilesContent(tilesContent);
207         themeDisplay.setTilesSelectable(tilesSelectable);
208 
209         if (theme.isWARFile()) {
210             ServletContext themeServletContext = servletContext.getContext(
211                 theme.getContextPath());
212 
213             if (themeServletContext == null) {
214                 _log.error(
215                     "Theme " + theme.getThemeId() + " cannot find its " +
216                         "servlet context at " + theme.getServletContextName());
217             }
218             else {
219                 RequestDispatcher requestDispatcher =
220                     themeServletContext.getRequestDispatcher(path);
221 
222                 if (requestDispatcher == null) {
223                     _log.error(
224                         "Theme " + theme.getThemeId() + " does not have " +
225                             path);
226                 }
227                 else {
228                     requestDispatcher.include(request, response);
229                 }
230             }
231         }
232         else {
233             RequestDispatcher requestDispatcher =
234                 servletContext.getRequestDispatcher(path);
235 
236             if (requestDispatcher == null) {
237                 _log.error(
238                     "Theme " + theme.getThemeId() + " does not have " + path);
239             }
240             else {
241                 requestDispatcher.include(request, response);
242             }
243         }
244     }
245 
246     public static String includeVM(
247             ServletContext servletContext, HttpServletRequest request,
248             PageContext pageContext, String page, Theme theme, boolean write)
249         throws Exception {
250 
251         // The servlet context name will be null when the theme is deployed to
252         // the root directory in Tomcat. See
253         // com.liferay.portal.servlet.MainServlet and
254         // com.liferay.portlet.PortletContextImpl for other cases where a null
255         // servlet context name is also converted to an empty string.
256 
257         String ctxName = GetterUtil.getString(theme.getServletContextName());
258 
259         if (VelocityContextPool.get(ctxName) == null) {
260 
261             // This should only happen if the Velocity template is the first
262             // page to be accessed in the system
263 
264             VelocityContextPool.put(ctxName, servletContext);
265         }
266 
267         int pos = page.lastIndexOf(StringPool.PERIOD);
268 
269         StringBundler sb = new StringBundler(7);
270 
271         sb.append(ctxName);
272         sb.append(theme.getVelocityResourceListener());
273         sb.append(theme.getTemplatesPath());
274         sb.append(StringPool.SLASH);
275         sb.append(page.substring(0, pos));
276         sb.append(StringPool.PERIOD);
277         sb.append(_TEMPLATE_EXTENSION_VM);
278 
279         String source = sb.toString();
280 
281         if (!VelocityEngineUtil.resourceExists(source)) {
282             _log.error(source + " does not exist");
283 
284             return null;
285         }
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         velocityContext.put("themeServletContext", themeServletContext);
299 
300         // Tag libraries
301 
302         HttpServletResponse response =
303             (HttpServletResponse)pageContext.getResponse();
304 
305         Writer writer = null;
306 
307         if (write) {
308             writer = pageContext.getOut();
309         }
310         else {
311             writer = new UnsyncStringWriter();
312         }
313 
314         VelocityTaglib velocityTaglib = new VelocityTaglib(
315             servletContext, request,
316             new PipingServletResponse(response, writer), pageContext);
317 
318         request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
319 
320         velocityContext.put("taglibLiferay", velocityTaglib);
321         velocityContext.put("theme", velocityTaglib);
322 
323         // Merge templates
324 
325         VelocityEngineUtil.mergeTemplate(source, velocityContext, writer);
326 
327         if (write) {
328 
329             return null;
330         }
331         else {
332             return ((UnsyncStringWriter)writer).toString();
333         }
334     }
335 
336     private static String _getTilesVariables(
337         HttpServletRequest request, String attributeName) {
338 
339         ComponentContext componentContext =
340             (ComponentContext)request.getAttribute(
341                 ComponentConstants.COMPONENT_CONTEXT);
342 
343         String value = null;
344 
345         if (componentContext != null) {
346             value = (String)componentContext.getAttribute(attributeName);
347         }
348 
349         return value;
350     }
351 
352     private static final String _TEMPLATE_EXTENSION_FTL = "ftl";
353 
354     private static final String _TEMPLATE_EXTENSION_VM = "vm";
355 
356     private static Log _log = LogFactoryUtil.getLog(ThemeUtil.class);
357 
358 }