/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.taglib.util;
import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.PortletConstants;
import com.liferay.portal.kernel.model.Theme;
import com.liferay.portal.kernel.servlet.PluginContextListener;
import com.liferay.portal.kernel.servlet.ServletContextPool;
import com.liferay.portal.kernel.servlet.taglib.DynamicIncludeUtil;
import com.liferay.portal.kernel.template.Template;
import com.liferay.portal.kernel.template.TemplateConstants;
import com.liferay.portal.kernel.template.TemplateContextContributor;
import com.liferay.portal.kernel.template.TemplateManager;
import com.liferay.portal.kernel.template.TemplateManagerUtil;
import com.liferay.portal.kernel.template.TemplateResource;
import com.liferay.portal.kernel.template.TemplateResourceLoaderUtil;
import com.liferay.portal.kernel.theme.PortletDisplay;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.ThemeHelper;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.registry.collections.ServiceTrackerCollections;
import com.liferay.registry.collections.ServiceTrackerList;
import com.liferay.taglib.servlet.PipingServletResponse;
import java.io.Writer;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Brian Wing Shun Chan
* @author Brian Myunghun Kim
* @author Raymond Augé
* @author Mika Koivisto
* @author Shuyang Zhou
*/
public class ThemeUtil {
public static String getPortletId(HttpServletRequest request) {
String portletId = null;
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
if (themeDisplay != null) {
PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
portletId = portletDisplay.getId();
}
return portletId;
}
public static void include(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String path, Theme theme)
throws Exception {
String extension = theme.getTemplateExtension();
if (extension.equals(ThemeHelper.TEMPLATE_EXTENSION_FTL)) {
includeFTL(servletContext, request, response, path, theme, true);
}
else if (extension.equals(ThemeHelper.TEMPLATE_EXTENSION_VM)) {
includeVM(servletContext, request, response, path, theme, true);
}
else {
path = theme.getTemplatesPath() + StringPool.SLASH + path;
includeJSP(servletContext, request, response, path, theme);
}
}
public static String includeFTL(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String path, Theme theme,
boolean write)
throws Exception {
return doDispatch(
servletContext, request, response, path, theme, write,
ThemeHelper.TEMPLATE_EXTENSION_FTL);
}
public static void includeJSP(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String path, Theme theme)
throws Exception {
doDispatch(
servletContext, request, response, path, theme, true,
ThemeHelper.TEMPLATE_EXTENSION_JSP);
}
public static String includeVM(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String path, Theme theme,
boolean write)
throws Exception {
return doDispatch(
servletContext, request, response, path, theme, write,
ThemeHelper.TEMPLATE_EXTENSION_VM);
}
protected static String doDispatch(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String path, Theme theme,
boolean write, String extension)
throws Exception {
String pluginServletContextName = GetterUtil.getString(
theme.getServletContextName());
ServletContext pluginServletContext = ServletContextPool.get(
pluginServletContextName);
ClassLoader pluginClassLoader = null;
if (pluginServletContext != null) {
pluginClassLoader = (ClassLoader)pluginServletContext.getAttribute(
PluginContextListener.PLUGIN_CLASS_LOADER);
}
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
if ((pluginClassLoader != null) &&
(pluginClassLoader != contextClassLoader)) {
currentThread.setContextClassLoader(pluginClassLoader);
}
try {
if (extension.equals(ThemeHelper.TEMPLATE_EXTENSION_FTL)) {
return doIncludeFTL(
servletContext, request, response, path, theme, false,
write);
}
else if (extension.equals(ThemeHelper.TEMPLATE_EXTENSION_JSP)) {
doIncludeJSP(servletContext, request, response, path, theme);
}
else if (extension.equals(ThemeHelper.TEMPLATE_EXTENSION_VM)) {
return doIncludeVM(
servletContext, request, response, path, theme, false,
write);
}
return null;
}
finally {
if ((pluginClassLoader != null) &&
(pluginClassLoader != contextClassLoader)) {
currentThread.setContextClassLoader(contextClassLoader);
}
}
}
protected static String doIncludeFTL(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String path, Theme theme,
boolean restricted, boolean write)
throws Exception {
// The servlet context name will be null when the theme is deployed to
// the root directory in Tomcat. See
// com.liferay.portal.servlet.MainServlet and
// com.liferay.portlet.PortletContextImpl for other cases where a null
// servlet context name is also converted to an empty string.
String servletContextName = GetterUtil.getString(
theme.getServletContextName());
if (ServletContextPool.get(servletContextName) == null) {
// This should only happen if the FreeMarker template is the first
// page to be accessed in the system
ServletContextPool.put(servletContextName, servletContext);
}
String portletId = getPortletId(request);
String resourcePath = theme.getResourcePath(
servletContext, portletId, path);
if (Validator.isNotNull(portletId) &&
PortletConstants.hasInstanceId(portletId) &&
!TemplateResourceLoaderUtil.hasTemplateResource(
TemplateConstants.LANG_TYPE_FTL, resourcePath)) {
String rootPortletId = PortletConstants.getRootPortletId(portletId);
resourcePath = theme.getResourcePath(
servletContext, rootPortletId, path);
}
if (Validator.isNotNull(portletId) &&
!TemplateResourceLoaderUtil.hasTemplateResource(
TemplateConstants.LANG_TYPE_FTL, resourcePath)) {
resourcePath = theme.getResourcePath(servletContext, null, path);
}
if (!TemplateResourceLoaderUtil.hasTemplateResource(
TemplateConstants.LANG_TYPE_FTL, resourcePath)) {
_log.error(resourcePath + " does not exist");
return null;
}
TemplateResource templateResource =
TemplateResourceLoaderUtil.getTemplateResource(
TemplateConstants.LANG_TYPE_FTL, resourcePath);
Template template = TemplateManagerUtil.getTemplate(
TemplateConstants.LANG_TYPE_FTL, templateResource, restricted);
// FreeMarker variables
template.prepare(request);
// Custom theme variables
for (TemplateContextContributor templateContextContributor :
_templateContextContributors) {
templateContextContributor.prepare(template, request);
}
// Theme servlet context
ServletContext themeServletContext = ServletContextPool.get(
servletContextName);
template.put("themeServletContext", themeServletContext);
Writer writer = null;
if (write) {
writer = response.getWriter();
}
else {
writer = new UnsyncStringWriter();
response = new PipingServletResponse(response, writer);
}
TemplateManager templateManager =
TemplateManagerUtil.getTemplateManager(
TemplateConstants.LANG_TYPE_FTL);
templateManager.addTaglibSupport(template, request, response);
templateManager.addTaglibTheme(
template, "taglibLiferay", request, response);
template.put(TemplateConstants.WRITER, writer);
// Merge templates
template.processTemplate(writer);
if (write) {
return null;
}
else {
return writer.toString();
}
}
protected static void doIncludeJSP(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String path, Theme theme)
throws Exception {
DynamicIncludeUtil.include(
request, response, ThemeUtil.class.getName() + "#doIncludeJSP",
true);
if (theme.isWARFile()) {
ServletContext themeServletContext = servletContext.getContext(
theme.getContextPath());
if (themeServletContext == null) {
_log.error(
"Theme " + theme.getThemeId() + " cannot find its " +
"servlet context at " + theme.getServletContextName());
}
else {
RequestDispatcher requestDispatcher =
themeServletContext.getRequestDispatcher(path);
if (requestDispatcher == null) {
_log.error(
"Theme " + theme.getThemeId() + " does not have " +
path);
}
else {
requestDispatcher.include(request, response);
}
}
}
else {
RequestDispatcher requestDispatcher =
servletContext.getRequestDispatcher(path);
if (requestDispatcher == null) {
_log.error(
"Theme " + theme.getThemeId() + " does not have " + path);
}
else {
requestDispatcher.include(request, response);
}
}
}
protected static String doIncludeVM(
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, String page, Theme theme,
boolean restricted, boolean write)
throws Exception {
// The servlet context name will be null when the theme is deployed to
// the root directory in Tomcat. See
// com.liferay.portal.servlet.MainServlet and
// com.liferay.portlet.PortletContextImpl for other cases where a null
// servlet context name is also converted to an empty string.
String servletContextName = GetterUtil.getString(
theme.getServletContextName());
if (ServletContextPool.get(servletContextName) == null) {
// This should only happen if the Velocity template is the first
// page to be accessed in the system
ServletContextPool.put(servletContextName, servletContext);
}
String portletId = getPortletId(request);
String resourcePath = theme.getResourcePath(
servletContext, portletId, page);
boolean checkResourceExists = true;
if (Validator.isNotNull(portletId)) {
if (PortletConstants.hasInstanceId(portletId) &&
(checkResourceExists !=
TemplateResourceLoaderUtil.hasTemplateResource(
TemplateConstants.LANG_TYPE_VM, resourcePath))) {
String rootPortletId = PortletConstants.getRootPortletId(
portletId);
resourcePath = theme.getResourcePath(
servletContext, rootPortletId, page);
}
if (checkResourceExists &&
(checkResourceExists !=
TemplateResourceLoaderUtil.hasTemplateResource(
TemplateConstants.LANG_TYPE_VM, resourcePath))) {
resourcePath = theme.getResourcePath(
servletContext, null, page);
}
}
if (checkResourceExists &&
!TemplateResourceLoaderUtil.hasTemplateResource(
TemplateConstants.LANG_TYPE_VM, resourcePath)) {
_log.error(resourcePath + " does not exist");
return null;
}
TemplateResource templateResource =
TemplateResourceLoaderUtil.getTemplateResource(
TemplateConstants.LANG_TYPE_VM, resourcePath);
if (templateResource == null) {
throw new Exception(
"Unable to load template resource " + resourcePath);
}
TemplateManager templateManager =
TemplateManagerUtil.getTemplateManager(
TemplateConstants.LANG_TYPE_VM);
Template template = TemplateManagerUtil.getTemplate(
TemplateConstants.LANG_TYPE_VM, templateResource, restricted);
// Velocity variables
template.prepare(request);
// Custom theme variables
for (TemplateContextContributor templateContextContributor :
_templateContextContributors) {
templateContextContributor.prepare(template, request);
}
// Theme servlet context
ServletContext themeServletContext = ServletContextPool.get(
servletContextName);
template.put("themeServletContext", themeServletContext);
// Tag libraries
Writer writer = null;
if (write) {
writer = response.getWriter();
}
else {
writer = new UnsyncStringWriter();
response = new PipingServletResponse(response, writer);
}
templateManager.addTaglibTheme(
template, "taglibLiferay", request, response);
template.put(TemplateConstants.WRITER, writer);
// Merge templates
template.processTemplate(writer);
if (write) {
return null;
}
else {
return writer.toString();
}
}
private static final Log _log = LogFactoryUtil.getLog(ThemeUtil.class);
private static final ServiceTrackerList<TemplateContextContributor>
_templateContextContributors = ServiceTrackerCollections.openList(
TemplateContextContributor.class,
"(type=" + TemplateContextContributor.TYPE_THEME + ")");
}