/** * 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.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.log.LogUtil; import com.liferay.portal.kernel.model.Group; import com.liferay.portal.kernel.model.PortletConstants; import com.liferay.portal.kernel.model.Theme; import com.liferay.portal.kernel.portlet.PortletBag; import com.liferay.portal.kernel.portlet.PortletBagPool; import com.liferay.portal.kernel.servlet.DirectRequestDispatcherFactoryUtil; import com.liferay.portal.kernel.servlet.TrackedServletRequest; import com.liferay.portal.kernel.servlet.taglib.TagDynamicIdFactory; import com.liferay.portal.kernel.servlet.taglib.TagDynamicIdFactoryRegistry; import com.liferay.portal.kernel.servlet.taglib.TagDynamicIncludeUtil; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.CustomJspRegistryUtil; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.ServerDetector; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.UnicodeProperties; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.taglib.FileAvailabilityUtil; import com.liferay.taglib.servlet.PipingServletResponse; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyContent; /** * @author Brian Wing Shun Chan * @author Shuyang Zhou * @author Eduardo Lundgren * @author Raymond Augé */ public class IncludeTag extends AttributesTagSupport { @Override public int doEndTag() throws JspException { try { String page = getPage(); if (Validator.isNull(page)) { page = getEndPage(); } callSetAttributes(); if (themeResourceExists(page)) { doIncludeTheme(page); return EVAL_PAGE; } if (!FileAvailabilityUtil.isAvailable(servletContext, page)) { logUnavailablePage(page); return processEndTag(); } doInclude(page, false); return EVAL_PAGE; } catch (Exception e) { throw new JspException(e); } finally { doClearTag(); } } @Override public int doStartTag() throws JspException { try { String page = getStartPage(); callSetAttributes(); if (themeResourceExists(page)) { doIncludeTheme(page); return EVAL_BODY_INCLUDE; } if (!FileAvailabilityUtil.isAvailable(servletContext, page)) { logUnavailablePage(page); return processStartTag(); } doInclude(page, true); return EVAL_BODY_INCLUDE; } catch (Exception e) { throw new JspException(e); } } public void runTag() throws JspException { doStartTag(); doEndTag(); } public void setPage(String page) { _page = page; } public void setPortletId(String portletId) { if (Validator.isNotNull(portletId)) { String rootPortletId = PortletConstants.getRootPortletId(portletId); PortletBag portletBag = PortletBagPool.get(rootPortletId); servletContext = portletBag.getServletContext(); } } public void setStrict(boolean strict) { _strict = strict; } public void setUseCustomPage(boolean useCustomPage) { _useCustomPage = useCustomPage; } protected void callSetAttributes() { HttpServletRequest request = getOriginalServletRequest(); if (isCleanUpSetAttributes()) { _trackedRequest = new TrackedServletRequest(request); request = _trackedRequest; } setNamespacedAttribute(request, "bodyContent", getBodyContentWrapper()); setNamespacedAttribute( request, "dynamicAttributes", getDynamicAttributes()); setAttributes(request); } protected void cleanUp() { } protected void cleanUpSetAttributes() { if (isCleanUpSetAttributes() && (_trackedRequest != null)) { for (String name : _trackedRequest.getSetAttributes()) { _trackedRequest.removeAttribute(name); } _trackedRequest = null; } } protected void doClearTag() { clearDynamicAttributes(); clearParams(); clearProperties(); cleanUpSetAttributes(); if (!ServerDetector.isResin()) { setPage(null); setUseCustomPage(true); cleanUp(); } } protected void doInclude( String page, boolean dynamicIncludeAscendingPriority) throws JspException { try { include(page, dynamicIncludeAscendingPriority); } catch (Exception e) { String currentURL = (String)request.getAttribute( WebKeys.CURRENT_URL); String message = "Current URL " + currentURL + " generates exception: " + e.getMessage(); LogUtil.log(_log, e, message); if (e instanceof JspException) { throw (JspException)e; } } } protected void doIncludeTheme(String page) throws Exception { HttpServletResponse response = (HttpServletResponse)pageContext.getResponse(); Theme theme = (Theme)request.getAttribute(WebKeys.THEME); ThemeUtil.include(servletContext, request, response, page, theme); } protected Object getBodyContentWrapper() { final BodyContent bodyContent = getBodyContent(); if (bodyContent == null) { return null; } return new Object() { @Override public String toString() { return bodyContent.getString(); } }; } protected String getCustomPage( ServletContext servletContext, HttpServletRequest request, String page) { if (Validator.isNull(page)) { return null; } ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute( WebKeys.THEME_DISPLAY); if (themeDisplay == null) { return null; } Group group = themeDisplay.getScopeGroup(); if (group.isStagingGroup() && !group.isStagedRemotely()) { group = group.getLiveGroup(); } UnicodeProperties typeSettingsProperties = group.getTypeSettingsProperties(); String customJspServletContextName = typeSettingsProperties.getProperty( "customJspServletContextName"); if (Validator.isNull(customJspServletContextName)) { return null; } String customPage = CustomJspRegistryUtil.getCustomJspFileName( customJspServletContextName, page); if (FileAvailabilityUtil.isAvailable(servletContext, customPage)) { return customPage; } return null; } protected String getEndPage() { return null; } protected HttpServletRequest getOriginalServletRequest() { return (HttpServletRequest)pageContext.getRequest(); } protected String getPage() { return _page; } protected String getStartPage() { return null; } protected void include(String page, boolean doStartTag) throws Exception { HttpServletResponse httpServletResponse = null; Class<?> clazz = getClass(); String tagClassName = clazz.getName(); String tagDynamicId = null; String tagPointPrefix = null; if (doStartTag) { tagPointPrefix = "doStartTag#"; } else { tagPointPrefix = "doEndTag#"; } TagDynamicIdFactory tagDynamicIdFactory = TagDynamicIdFactoryRegistry.getTagDynamicIdFactory(tagClassName); if (tagDynamicIdFactory != null) { httpServletResponse = PipingServletResponse.createPipingServletResponse(pageContext); tagDynamicId = tagDynamicIdFactory.getTagDynamicId( request, httpServletResponse, this); TagDynamicIncludeUtil.include( request, httpServletResponse, tagClassName, tagDynamicId, tagPointPrefix + "before", doStartTag); } if (_useCustomPage) { String customPage = getCustomPage(servletContext, request, page); if (Validator.isNotNull(customPage)) { page = customPage; } } if (_THEME_JSP_OVERRIDE_ENABLED) { request.setAttribute( WebKeys.SERVLET_CONTEXT_INCLUDE_FILTER_STRICT, _strict); } includePage( page, PipingServletResponse.createPipingServletResponse(pageContext)); if (_THEME_JSP_OVERRIDE_ENABLED) { request.removeAttribute( WebKeys.SERVLET_CONTEXT_INCLUDE_FILTER_STRICT); } if (tagDynamicIdFactory != null) { TagDynamicIncludeUtil.include( request, httpServletResponse, tagClassName, tagDynamicId, tagPointPrefix + "after", doStartTag); } } protected void includePage(String page, HttpServletResponse response) throws IOException, ServletException { RequestDispatcher requestDispatcher = DirectRequestDispatcherFactoryUtil.getRequestDispatcher( servletContext, page); requestDispatcher.include(request, response); } protected boolean isCleanUpSetAttributes() { return _CLEAN_UP_SET_ATTRIBUTES; } protected boolean isPortalPage(String page) { if (page.startsWith("/html/taglib/") && (page.endsWith("/end.jsp") || page.endsWith("/page.jsp") || page.endsWith("/start.jsp"))) { return true; } return false; } protected boolean isUseCustomPage() { return _useCustomPage; } protected void logUnavailablePage(String page) { if ((page == null) || !_log.isDebugEnabled()) { return; } StringBundler sb = new StringBundler(8); sb.append("Unable to find "); sb.append(page); sb.append(" in the context "); String contextPath = PortalUtil.getPathContext( servletContext.getContextPath()); if (contextPath.equals(StringPool.BLANK)) { contextPath = StringPool.SLASH; } sb.append(contextPath); sb.append("."); boolean portalContext = false; String portalContextPath = PortalUtil.getPathContext(); if (portalContextPath.equals(StringPool.BLANK)) { portalContextPath = StringPool.SLASH; } if (contextPath.equals(portalContextPath)) { portalContext = true; } if (isPortalPage(page)) { if (portalContext) { return; } else { sb.append(" You must not use a taglib from a module and set "); sb.append("the attribute \"servletContext\". Inline the "); sb.append("content directly where the taglib is invoked."); } } else if (portalContext) { Class<?> clazz = getClass(); if (clazz.equals(IncludeTag.class)) { sb.append(" You must set the attribute \"servletContext\" "); sb.append("with the value \"<%= application %>\" when "); sb.append("invoking a taglib from a module."); } else { sb.append(" You must not use a taglib from a module and set "); sb.append("the attribute \"file\". Inline the content "); sb.append("directly where the taglib is invoked."); } } _log.debug(sb.toString()); } protected int processEndTag() throws Exception { return EVAL_PAGE; } protected int processStartTag() throws Exception { return EVAL_BODY_INCLUDE; } protected void setAttributes(HttpServletRequest request) { } protected boolean themeResourceExists(String page) throws Exception { if ((page == null) || !_THEME_JSP_OVERRIDE_ENABLED || _strict) { return false; } Theme theme = (Theme)request.getAttribute(WebKeys.THEME); if (theme == null) { ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute( WebKeys.THEME_DISPLAY); if (themeDisplay != null) { theme = themeDisplay.getTheme(); } } if (theme == null) { return false; } String portletId = ThemeUtil.getPortletId(request); boolean exists = theme.resourceExists(servletContext, portletId, page); if (_log.isDebugEnabled() && exists) { String resourcePath = theme.getResourcePath( servletContext, null, page); _log.debug(resourcePath); } return exists; } private static final boolean _CLEAN_UP_SET_ATTRIBUTES = false; private static final boolean _THEME_JSP_OVERRIDE_ENABLED = GetterUtil.getBoolean( PropsUtil.get(PropsKeys.THEME_JSP_OVERRIDE_ENABLED)); private static final Log _log = LogFactoryUtil.getLog(IncludeTag.class); private String _page; private boolean _strict; private TrackedServletRequest _trackedRequest; private boolean _useCustomPage = true; }