001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.UnsyncPrintWriter;
021    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.servlet.PipingServletResponse;
025    import com.liferay.portal.kernel.servlet.ServletContextPool;
026    import com.liferay.portal.kernel.util.CharPool;
027    import com.liferay.portal.kernel.util.GetterUtil;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.WebKeys;
031    import com.liferay.portal.kernel.velocity.VelocityContext;
032    import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
033    import com.liferay.portal.model.Theme;
034    import com.liferay.portal.theme.ThemeDisplay;
035    import com.liferay.portal.velocity.VelocityVariables;
036    
037    import freemarker.ext.jsp.TaglibFactory;
038    import freemarker.ext.servlet.HttpRequestHashModel;
039    import freemarker.ext.servlet.ServletContextHashModel;
040    
041    import freemarker.template.ObjectWrapper;
042    
043    import java.io.Writer;
044    
045    import javax.servlet.GenericServlet;
046    import javax.servlet.RequestDispatcher;
047    import javax.servlet.ServletContext;
048    import javax.servlet.http.HttpServletRequest;
049    import javax.servlet.http.HttpServletResponse;
050    import javax.servlet.jsp.PageContext;
051    
052    import org.apache.struts.taglib.tiles.ComponentConstants;
053    import org.apache.struts.tiles.ComponentContext;
054    
055    /**
056     * @author Brian Wing Shun Chan
057     * @author Brian Myunghun Kim
058     * @author Raymond Augé
059     * @author Mika Koivisto
060     * @author Shuyang Zhou
061     */
062    public class ThemeUtil {
063    
064            public static void include(
065                            ServletContext servletContext, HttpServletRequest request,
066                            HttpServletResponse response, PageContext pageContext, String page,
067                            Theme theme)
068                    throws Exception {
069    
070                    String extension = theme.getTemplateExtension();
071    
072                    if (extension.equals(_TEMPLATE_EXTENSION_FTL)) {
073                            includeFTL(servletContext, request, pageContext, page, theme, true);
074                    }
075                    else if (extension.equals(_TEMPLATE_EXTENSION_VM)) {
076                            includeVM(servletContext, request, pageContext, page, theme, true);
077                    }
078                    else {
079                            String path =
080                                    theme.getTemplatesPath() + StringPool.SLASH + page;
081    
082                            includeJSP(servletContext, request, response, path, theme);
083                    }
084            }
085    
086            public static String includeFTL(
087                            ServletContext servletContext, HttpServletRequest request,
088                            PageContext pageContext, String page, Theme theme, boolean write)
089                    throws Exception {
090    
091                    // The servlet context name will be null when the theme is deployed to
092                    // the root directory in Tomcat. See
093                    // com.liferay.portal.servlet.MainServlet and
094                    // com.liferay.portlet.PortletContextImpl for other cases where a null
095                    // servlet context name is also converted to an empty string.
096    
097                    String servletContextName = GetterUtil.getString(
098                            theme.getServletContextName());
099    
100                    if (ServletContextPool.get(servletContextName) == null) {
101    
102                            // This should only happen if the FreeMarker template is the first
103                            // page to be accessed in the system
104    
105                            ServletContextPool.put(servletContextName, servletContext);
106                    }
107    
108                    int pos = page.lastIndexOf(CharPool.PERIOD);
109    
110                    StringBundler sb = new StringBundler(7);
111    
112                    sb.append(servletContextName);
113                    sb.append(theme.getFreeMarkerTemplateLoader());
114                    sb.append(theme.getTemplatesPath());
115                    sb.append(StringPool.SLASH);
116                    sb.append(page.substring(0, pos));
117                    sb.append(StringPool.PERIOD);
118                    sb.append(_TEMPLATE_EXTENSION_FTL);
119    
120                    String source = sb.toString();
121    
122                    if (!FreeMarkerEngineUtil.resourceExists(source)) {
123                            _log.error(source + " does not exist");
124    
125                            return null;
126                    }
127    
128                    FreeMarkerContext freeMarkerContext =
129                            FreeMarkerEngineUtil.getWrappedStandardToolsContext();
130    
131                    // FreeMarker variables
132    
133                    FreeMarkerVariables.insertVariables(freeMarkerContext, request);
134    
135                    // Theme servlet context
136    
137                    ServletContext themeServletContext = ServletContextPool.get(
138                            servletContextName);
139    
140                    freeMarkerContext.put("themeServletContext", themeServletContext);
141    
142                    // Tag libraries
143    
144                    HttpServletResponse response =
145                            (HttpServletResponse)pageContext.getResponse();
146    
147                    Writer writer = null;
148    
149                    if (write) {
150    
151                            // Wrapping is needed because of a bug in FreeMarker
152    
153                            writer = new UnsyncPrintWriter(pageContext.getOut());
154                    }
155                    else {
156                            writer = new UnsyncStringWriter();
157                    }
158    
159                    VelocityTaglib velocityTaglib = new VelocityTaglib(
160                            servletContext, request,
161                            new PipingServletResponse(response, writer), pageContext);
162    
163                    request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
164    
165                    freeMarkerContext.put("taglibLiferay", velocityTaglib);
166                    freeMarkerContext.put("theme", velocityTaglib);
167    
168                    // Portal JSP tag library factory
169    
170                    TaglibFactory portalTaglib = new TaglibFactory(servletContext);
171    
172                    freeMarkerContext.put("PortalJspTagLibs", portalTaglib);
173    
174                    // Theme JSP tag library factory
175    
176                    TaglibFactory themeTaglib = new TaglibFactory(themeServletContext);
177    
178                    freeMarkerContext.put("ThemeJspTaglibs", themeTaglib);
179    
180                    // FreeMarker JSP tag library support
181    
182                    ServletContextHashModel servletContextHashModel =
183                            new ServletContextHashModel(
184                                    (GenericServlet)pageContext.getPage(),
185                                    ObjectWrapper.DEFAULT_WRAPPER);
186    
187                    freeMarkerContext.put("Application", servletContextHashModel);
188    
189                    HttpRequestHashModel httpRequestHashModel = new HttpRequestHashModel(
190                            request, response, ObjectWrapper.DEFAULT_WRAPPER);
191    
192                    freeMarkerContext.put("Request", httpRequestHashModel);
193    
194                    // Merge templates
195    
196                    FreeMarkerEngineUtil.mergeTemplate(source, freeMarkerContext, writer);
197    
198                    if (write) {
199                            return null;
200                    }
201                    else {
202                            return ((UnsyncStringWriter)writer).toString();
203                    }
204            }
205    
206            public static void includeJSP(
207                            ServletContext servletContext, HttpServletRequest request,
208                            HttpServletResponse response, String path, Theme theme)
209                    throws Exception {
210    
211                    if (theme.isWARFile()) {
212                            ServletContext themeServletContext = servletContext.getContext(
213                                    theme.getContextPath());
214    
215                            if (themeServletContext == null) {
216                                    _log.error(
217                                            "Theme " + theme.getThemeId() + " cannot find its " +
218                                                    "servlet context at " + theme.getServletContextName());
219                            }
220                            else {
221                                    RequestDispatcher requestDispatcher =
222                                            themeServletContext.getRequestDispatcher(path);
223    
224                                    if (requestDispatcher == null) {
225                                            _log.error(
226                                                    "Theme " + theme.getThemeId() + " does not have " +
227                                                            path);
228                                    }
229                                    else {
230                                            requestDispatcher.include(request, response);
231                                    }
232                            }
233                    }
234                    else {
235                            RequestDispatcher requestDispatcher =
236                                    servletContext.getRequestDispatcher(path);
237    
238                            if (requestDispatcher == null) {
239                                    _log.error(
240                                            "Theme " + theme.getThemeId() + " does not have " + path);
241                            }
242                            else {
243                                    requestDispatcher.include(request, response);
244                            }
245                    }
246            }
247    
248            public static String includeVM(
249                            ServletContext servletContext, HttpServletRequest request,
250                            PageContext pageContext, String page, Theme theme, boolean write)
251                    throws Exception {
252    
253                    // The servlet context name will be null when the theme is deployed to
254                    // the root directory in Tomcat. See
255                    // com.liferay.portal.servlet.MainServlet and
256                    // com.liferay.portlet.PortletContextImpl for other cases where a null
257                    // servlet context name is also converted to an empty string.
258    
259                    String servletContextName = GetterUtil.getString(
260                            theme.getServletContextName());
261    
262                    if (ServletContextPool.get(servletContextName) == null) {
263    
264                            // This should only happen if the Velocity template is the first
265                            // page to be accessed in the system
266    
267                            ServletContextPool.put(servletContextName, servletContext);
268                    }
269    
270                    int pos = page.lastIndexOf(CharPool.PERIOD);
271    
272                    StringBundler sb = new StringBundler(7);
273    
274                    sb.append(servletContextName);
275                    sb.append(theme.getVelocityResourceListener());
276                    sb.append(theme.getTemplatesPath());
277                    sb.append(StringPool.SLASH);
278                    sb.append(page.substring(0, pos));
279                    sb.append(StringPool.PERIOD);
280                    sb.append(_TEMPLATE_EXTENSION_VM);
281    
282                    String source = sb.toString();
283    
284                    if (!VelocityEngineUtil.resourceExists(source)) {
285                            _log.error(source + " does not exist");
286    
287                            return null;
288                    }
289    
290                    VelocityContext velocityContext =
291                            VelocityEngineUtil.getWrappedStandardToolsContext();
292    
293                    // Velocity variables
294    
295                    VelocityVariables.insertVariables(velocityContext, request);
296    
297                    // Theme servlet context
298    
299                    ServletContext themeServletContext = ServletContextPool.get(
300                            servletContextName);
301    
302                    velocityContext.put("themeServletContext", themeServletContext);
303    
304                    // Tag libraries
305    
306                    HttpServletResponse response =
307                            (HttpServletResponse)pageContext.getResponse();
308    
309                    Writer writer = null;
310    
311                    if (write) {
312                            writer = pageContext.getOut();
313                    }
314                    else {
315                            writer = new UnsyncStringWriter();
316                    }
317    
318                    VelocityTaglib velocityTaglib = new VelocityTaglib(
319                            servletContext, request,
320                            new PipingServletResponse(response, writer), pageContext);
321    
322                    request.setAttribute(WebKeys.VELOCITY_TAGLIB, velocityTaglib);
323    
324                    velocityContext.put("taglibLiferay", velocityTaglib);
325                    velocityContext.put("theme", velocityTaglib);
326                    velocityContext.put("writer", writer);
327    
328                    // Merge templates
329    
330                    VelocityEngineUtil.mergeTemplate(source, velocityContext, writer);
331    
332                    if (write) {
333    
334                            return null;
335                    }
336                    else {
337                            return ((UnsyncStringWriter)writer).toString();
338                    }
339            }
340    
341            public static void insertTilesVariables(HttpServletRequest request) {
342                    ComponentContext componentContext =
343                            (ComponentContext)request.getAttribute(
344                                    ComponentConstants.COMPONENT_CONTEXT);
345    
346                    if (componentContext == null) {
347                            return;
348                    }
349    
350                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
351                            WebKeys.THEME_DISPLAY);
352    
353                    String tilesTitle = (String)componentContext.getAttribute("title");
354                    String tilesContent = (String)componentContext.getAttribute("content");
355                    boolean tilesSelectable = GetterUtil.getBoolean(
356                            (String)componentContext.getAttribute("selectable"));
357    
358                    themeDisplay.setTilesTitle(tilesTitle);
359                    themeDisplay.setTilesContent(tilesContent);
360                    themeDisplay.setTilesSelectable(tilesSelectable);
361            }
362    
363            private static final String _TEMPLATE_EXTENSION_FTL = "ftl";
364    
365            private static final String _TEMPLATE_EXTENSION_VM = "vm";
366    
367            private static Log _log = LogFactoryUtil.getLog(ThemeUtil.class);
368    
369    }