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.servlet.ServletContextPool;
25  import com.liferay.portal.kernel.util.GetterUtil;
26  import com.liferay.portal.kernel.util.StringBundler;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.WebKeys;
29  import com.liferay.portal.kernel.velocity.VelocityContext;
30  import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
31  import com.liferay.portal.model.Theme;
32  import com.liferay.portal.theme.ThemeDisplay;
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 servletContextName = GetterUtil.getString(
96              theme.getServletContextName());
97  
98          if (ServletContextPool.get(servletContextName) == null) {
99  
100             // This should only happen if the FreeMarker template is the first
101             // page to be accessed in the system
102 
103             ServletContextPool.put(servletContextName, servletContext);
104         }
105 
106         int pos = page.lastIndexOf(StringPool.PERIOD);
107 
108         StringBundler sb = new StringBundler(7);
109 
110         sb.append(servletContextName);
111         sb.append(theme.getFreeMarkerTemplateLoader());
112         sb.append(theme.getTemplatesPath());
113         sb.append(StringPool.SLASH);
114         sb.append(page.substring(0, pos));
115         sb.append(StringPool.PERIOD);
116         sb.append(_TEMPLATE_EXTENSION_FTL);
117 
118         String source = sb.toString();
119 
120         if (!FreeMarkerEngineUtil.resourceExists(source)) {
121             _log.error(source + " does not exist");
122 
123             return null;
124         }
125 
126         FreeMarkerContext freeMarkerContext =
127             FreeMarkerEngineUtil.getWrappedStandardToolsContext();
128 
129         // FreeMarker variables
130 
131         FreeMarkerVariables.insertVariables(freeMarkerContext, request);
132 
133         // Theme servlet context
134 
135         ServletContext themeServletContext = ServletContextPool.get(
136             servletContextName);
137 
138         freeMarkerContext.put("themeServletContext", themeServletContext);
139 
140         // Tag libraries
141 
142         HttpServletResponse response =
143             (HttpServletResponse)pageContext.getResponse();
144 
145         Writer writer = null;
146 
147         if (write) {
148             writer = pageContext.getOut();
149         }
150         else {
151             writer = new UnsyncStringWriter();
152         }
153 
154         VelocityTaglib velocityTaglib = new VelocityTaglib(
155             servletContext, request,
156             new PipingServletResponse(response, writer), pageContext);
157 
158         request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
159 
160         freeMarkerContext.put("taglibLiferay", velocityTaglib);
161         freeMarkerContext.put("theme", velocityTaglib);
162 
163         // Portal JSP tag library factory
164 
165         TaglibFactory portalTaglib = new TaglibFactory(servletContext);
166 
167         freeMarkerContext.put("PortalJspTagLibs", portalTaglib);
168 
169         // Theme JSP tag library factory
170 
171         TaglibFactory themeTaglib = new TaglibFactory(themeServletContext);
172 
173         freeMarkerContext.put("ThemeJspTaglibs", themeTaglib);
174 
175         // FreeMarker JSP tag library support
176 
177         HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
178             request, response, ObjectWrapper.DEFAULT_WRAPPER);
179 
180         freeMarkerContext.put("Request", httpRequestHashModel);
181 
182         // Merge templates
183 
184         FreeMarkerEngineUtil.mergeTemplate(source, freeMarkerContext, writer);
185 
186         if (write) {
187             return null;
188         }
189         else {
190             return ((UnsyncStringWriter)writer).toString();
191         }
192     }
193 
194     public static void includeJSP(
195             ServletContext servletContext, HttpServletRequest request,
196             HttpServletResponse response, String path, Theme theme)
197         throws Exception {
198 
199         if (theme.isWARFile()) {
200             ServletContext themeServletContext = servletContext.getContext(
201                 theme.getContextPath());
202 
203             if (themeServletContext == null) {
204                 _log.error(
205                     "Theme " + theme.getThemeId() + " cannot find its " +
206                         "servlet context at " + theme.getServletContextName());
207             }
208             else {
209                 RequestDispatcher requestDispatcher =
210                     themeServletContext.getRequestDispatcher(path);
211 
212                 if (requestDispatcher == null) {
213                     _log.error(
214                         "Theme " + theme.getThemeId() + " does not have " +
215                             path);
216                 }
217                 else {
218                     requestDispatcher.include(request, response);
219                 }
220             }
221         }
222         else {
223             RequestDispatcher requestDispatcher =
224                 servletContext.getRequestDispatcher(path);
225 
226             if (requestDispatcher == null) {
227                 _log.error(
228                     "Theme " + theme.getThemeId() + " does not have " + path);
229             }
230             else {
231                 requestDispatcher.include(request, response);
232             }
233         }
234     }
235 
236     public static String includeVM(
237             ServletContext servletContext, HttpServletRequest request,
238             PageContext pageContext, String page, Theme theme, boolean write)
239         throws Exception {
240 
241         // The servlet context name will be null when the theme is deployed to
242         // the root directory in Tomcat. See
243         // com.liferay.portal.servlet.MainServlet and
244         // com.liferay.portlet.PortletContextImpl for other cases where a null
245         // servlet context name is also converted to an empty string.
246 
247         String servletContextName = GetterUtil.getString(
248             theme.getServletContextName());
249 
250         if (ServletContextPool.get(servletContextName) == null) {
251 
252             // This should only happen if the Velocity template is the first
253             // page to be accessed in the system
254 
255             ServletContextPool.put(servletContextName, servletContext);
256         }
257 
258         int pos = page.lastIndexOf(StringPool.PERIOD);
259 
260         StringBundler sb = new StringBundler(7);
261 
262         sb.append(servletContextName);
263         sb.append(theme.getVelocityResourceListener());
264         sb.append(theme.getTemplatesPath());
265         sb.append(StringPool.SLASH);
266         sb.append(page.substring(0, pos));
267         sb.append(StringPool.PERIOD);
268         sb.append(_TEMPLATE_EXTENSION_VM);
269 
270         String source = sb.toString();
271 
272         if (!VelocityEngineUtil.resourceExists(source)) {
273             _log.error(source + " does not exist");
274 
275             return null;
276         }
277 
278         VelocityContext velocityContext =
279             VelocityEngineUtil.getWrappedStandardToolsContext();
280 
281         // Velocity variables
282 
283         VelocityVariables.insertVariables(velocityContext, request);
284 
285         // Theme servlet context
286 
287         ServletContext themeServletContext = ServletContextPool.get(
288             servletContextName);
289 
290         velocityContext.put("themeServletContext", themeServletContext);
291 
292         // Tag libraries
293 
294         HttpServletResponse response =
295             (HttpServletResponse)pageContext.getResponse();
296 
297         Writer writer = null;
298 
299         if (write) {
300             writer = pageContext.getOut();
301         }
302         else {
303             writer = new UnsyncStringWriter();
304         }
305 
306         VelocityTaglib velocityTaglib = new VelocityTaglib(
307             servletContext, request,
308             new PipingServletResponse(response, writer), pageContext);
309 
310         request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
311 
312         velocityContext.put("taglibLiferay", velocityTaglib);
313         velocityContext.put("theme", velocityTaglib);
314 
315         // Merge templates
316 
317         VelocityEngineUtil.mergeTemplate(source, velocityContext, writer);
318 
319         if (write) {
320 
321             return null;
322         }
323         else {
324             return ((UnsyncStringWriter)writer).toString();
325         }
326     }
327 
328     public static void insertTilesVariables(HttpServletRequest request) {
329         ComponentContext componentContext =
330             (ComponentContext)request.getAttribute(
331                 ComponentConstants.COMPONENT_CONTEXT);
332 
333         if (componentContext == null) {
334             return;
335         }
336 
337         ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
338             WebKeys.THEME_DISPLAY);
339 
340         String tilesTitle = (String)componentContext.getAttribute("title");
341         String tilesContent = (String)componentContext.getAttribute("content");
342         boolean tilesSelectable = GetterUtil.getBoolean(
343             (String)componentContext.getAttribute("selectable"));
344 
345         themeDisplay.setTilesTitle(tilesTitle);
346         themeDisplay.setTilesContent(tilesContent);
347         themeDisplay.setTilesSelectable(tilesSelectable);
348     }
349 
350     private static final String _TEMPLATE_EXTENSION_FTL = "ftl";
351 
352     private static final String _TEMPLATE_EXTENSION_VM = "vm";
353 
354     private static Log _log = LogFactoryUtil.getLog(ThemeUtil.class);
355 
356 }