001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.taglib.util;
016    
017    import com.liferay.portal.freemarker.FreeMarkerVariables;
018    import com.liferay.portal.kernel.freemarker.FreeMarkerContext;
019    import com.liferay.portal.kernel.freemarker.FreeMarkerEngineUtil;
020    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.servlet.PipingServletResponse;
024    import com.liferay.portal.kernel.servlet.ServletContextPool;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.StringBundler;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.util.WebKeys;
029    import com.liferay.portal.kernel.velocity.VelocityContext;
030    import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
031    import com.liferay.portal.model.Theme;
032    import com.liferay.portal.theme.ThemeDisplay;
033    import com.liferay.portal.velocity.VelocityVariables;
034    
035    import freemarker.ext.jsp.TaglibFactory;
036    import freemarker.ext.servlet.HttpRequestHashModel;
037    
038    import freemarker.template.ObjectWrapper;
039    
040    import java.io.Writer;
041    
042    import javax.servlet.RequestDispatcher;
043    import javax.servlet.ServletContext;
044    import javax.servlet.http.HttpServletRequest;
045    import javax.servlet.http.HttpServletResponse;
046    import javax.servlet.jsp.PageContext;
047    
048    import org.apache.struts.taglib.tiles.ComponentConstants;
049    import org.apache.struts.tiles.ComponentContext;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     * @author Brian Myunghun Kim
054     * @author Raymond Augé
055     * @author Mika Koivisto
056     * @author Shuyang Zhou
057     */
058    public class ThemeUtil {
059    
060            public static void include(
061                            ServletContext servletContext, HttpServletRequest request,
062                            HttpServletResponse response, PageContext pageContext, String page,
063                            Theme theme)
064                    throws Exception {
065    
066                    String extension = theme.getTemplateExtension();
067    
068                    if (extension.equals(_TEMPLATE_EXTENSION_FTL)) {
069                            includeFTL(servletContext, request, pageContext, page, theme, true);
070                    }
071                    else if (extension.equals(_TEMPLATE_EXTENSION_VM)) {
072                            includeVM(servletContext, request, pageContext, page, theme, true);
073                    }
074                    else {
075                            String path =
076                                    theme.getTemplatesPath() + StringPool.SLASH + page;
077    
078                            includeJSP(servletContext, request, response, path, theme);
079                    }
080            }
081    
082            public static String includeFTL(
083                            ServletContext servletContext, HttpServletRequest request,
084                            PageContext pageContext, String page, Theme theme, boolean write)
085                    throws Exception {
086    
087                    // The servlet context name will be null when the theme is deployed to
088                    // the root directory in Tomcat. See
089                    // com.liferay.portal.servlet.MainServlet and
090                    // com.liferay.portlet.PortletContextImpl for other cases where a null
091                    // servlet context name is also converted to an empty string.
092    
093                    String servletContextName = GetterUtil.getString(
094                            theme.getServletContextName());
095    
096                    if (ServletContextPool.get(servletContextName) == null) {
097    
098                            // This should only happen if the FreeMarker template is the first
099                            // page to be accessed in the system
100    
101                            ServletContextPool.put(servletContextName, servletContext);
102                    }
103    
104                    int pos = page.lastIndexOf(StringPool.PERIOD);
105    
106                    StringBundler sb = new StringBundler(7);
107    
108                    sb.append(servletContextName);
109                    sb.append(theme.getFreeMarkerTemplateLoader());
110                    sb.append(theme.getTemplatesPath());
111                    sb.append(StringPool.SLASH);
112                    sb.append(page.substring(0, pos));
113                    sb.append(StringPool.PERIOD);
114                    sb.append(_TEMPLATE_EXTENSION_FTL);
115    
116                    String source = sb.toString();
117    
118                    if (!FreeMarkerEngineUtil.resourceExists(source)) {
119                            _log.error(source + " does not exist");
120    
121                            return null;
122                    }
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 = ServletContextPool.get(
134                            servletContextName);
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                    if (theme.isWARFile()) {
198                            ServletContext themeServletContext = servletContext.getContext(
199                                    theme.getContextPath());
200    
201                            if (themeServletContext == null) {
202                                    _log.error(
203                                            "Theme " + theme.getThemeId() + " cannot find its " +
204                                                    "servlet context at " + theme.getServletContextName());
205                            }
206                            else {
207                                    RequestDispatcher requestDispatcher =
208                                            themeServletContext.getRequestDispatcher(path);
209    
210                                    if (requestDispatcher == null) {
211                                            _log.error(
212                                                    "Theme " + theme.getThemeId() + " does not have " +
213                                                            path);
214                                    }
215                                    else {
216                                            requestDispatcher.include(request, response);
217                                    }
218                            }
219                    }
220                    else {
221                            RequestDispatcher requestDispatcher =
222                                    servletContext.getRequestDispatcher(path);
223    
224                            if (requestDispatcher == null) {
225                                    _log.error(
226                                            "Theme " + theme.getThemeId() + " does not have " + path);
227                            }
228                            else {
229                                    requestDispatcher.include(request, response);
230                            }
231                    }
232            }
233    
234            public static String includeVM(
235                            ServletContext servletContext, HttpServletRequest request,
236                            PageContext pageContext, String page, Theme theme, boolean write)
237                    throws Exception {
238    
239                    // The servlet context name will be null when the theme is deployed to
240                    // the root directory in Tomcat. See
241                    // com.liferay.portal.servlet.MainServlet and
242                    // com.liferay.portlet.PortletContextImpl for other cases where a null
243                    // servlet context name is also converted to an empty string.
244    
245                    String servletContextName = GetterUtil.getString(
246                            theme.getServletContextName());
247    
248                    if (ServletContextPool.get(servletContextName) == null) {
249    
250                            // This should only happen if the Velocity template is the first
251                            // page to be accessed in the system
252    
253                            ServletContextPool.put(servletContextName, servletContext);
254                    }
255    
256                    int pos = page.lastIndexOf(StringPool.PERIOD);
257    
258                    StringBundler sb = new StringBundler(7);
259    
260                    sb.append(servletContextName);
261                    sb.append(theme.getVelocityResourceListener());
262                    sb.append(theme.getTemplatesPath());
263                    sb.append(StringPool.SLASH);
264                    sb.append(page.substring(0, pos));
265                    sb.append(StringPool.PERIOD);
266                    sb.append(_TEMPLATE_EXTENSION_VM);
267    
268                    String source = sb.toString();
269    
270                    if (!VelocityEngineUtil.resourceExists(source)) {
271                            _log.error(source + " does not exist");
272    
273                            return null;
274                    }
275    
276                    VelocityContext velocityContext =
277                            VelocityEngineUtil.getWrappedStandardToolsContext();
278    
279                    // Velocity variables
280    
281                    VelocityVariables.insertVariables(velocityContext, request);
282    
283                    // Theme servlet context
284    
285                    ServletContext themeServletContext = ServletContextPool.get(
286                            servletContextName);
287    
288                    velocityContext.put("themeServletContext", themeServletContext);
289    
290                    // Tag libraries
291    
292                    HttpServletResponse response =
293                            (HttpServletResponse)pageContext.getResponse();
294    
295                    Writer writer = null;
296    
297                    if (write) {
298                            writer = pageContext.getOut();
299                    }
300                    else {
301                            writer = new UnsyncStringWriter();
302                    }
303    
304                    VelocityTaglib velocityTaglib = new VelocityTaglib(
305                            servletContext, request,
306                            new PipingServletResponse(response, writer), pageContext);
307    
308                    request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
309    
310                    velocityContext.put("taglibLiferay", velocityTaglib);
311                    velocityContext.put("theme", velocityTaglib);
312                    velocityContext.put("writer", writer);
313    
314                    // Merge templates
315    
316                    VelocityEngineUtil.mergeTemplate(source, velocityContext, writer);
317    
318                    if (write) {
319    
320                            return null;
321                    }
322                    else {
323                            return ((UnsyncStringWriter)writer).toString();
324                    }
325            }
326    
327            public static void insertTilesVariables(HttpServletRequest request) {
328                    ComponentContext componentContext =
329                            (ComponentContext)request.getAttribute(
330                                    ComponentConstants.COMPONENT_CONTEXT);
331    
332                    if (componentContext == null) {
333                            return;
334                    }
335    
336                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
337                            WebKeys.THEME_DISPLAY);
338    
339                    String tilesTitle = (String)componentContext.getAttribute("title");
340                    String tilesContent = (String)componentContext.getAttribute("content");
341                    boolean tilesSelectable = GetterUtil.getBoolean(
342                            (String)componentContext.getAttribute("selectable"));
343    
344                    themeDisplay.setTilesTitle(tilesTitle);
345                    themeDisplay.setTilesContent(tilesContent);
346                    themeDisplay.setTilesSelectable(tilesSelectable);
347            }
348    
349            private static final String _TEMPLATE_EXTENSION_FTL = "ftl";
350    
351            private static final String _TEMPLATE_EXTENSION_VM = "vm";
352    
353            private static Log _log = LogFactoryUtil.getLog(ThemeUtil.class);
354    
355    }