/** * 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.portal.kernel.portlet.bridges.mvc; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.portlet.LiferayPortlet; import com.liferay.portal.kernel.portlet.LiferayPortletConfig; import com.liferay.portal.kernel.servlet.SessionMessages; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.HtmlUtil; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import java.io.IOException; import java.util.List; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.EventRequest; import javax.portlet.EventResponse; import javax.portlet.PortletConfig; import javax.portlet.PortletContext; import javax.portlet.PortletException; import javax.portlet.PortletPreferences; import javax.portlet.PortletRequest; import javax.portlet.PortletRequestDispatcher; import javax.portlet.PortletResponse; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import javax.portlet.WindowState; import javax.servlet.http.HttpServletRequest; /** * @author Brian Wing Shun Chan * @author Raymond Augé */ public class MVCPortlet extends LiferayPortlet { @Override public void destroy() { super.destroy(); _actionMVCCommandCache.close(); _renderMVCCommandCache.close(); _resourceMVCCommandCache.close(); } @Override public void doAbout( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(aboutTemplate, renderRequest, renderResponse); } @Override public void doConfig( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(configTemplate, renderRequest, renderResponse); } @Override public void doEdit( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { PortletPreferences portletPreferences = renderRequest.getPreferences(); if (portletPreferences == null) { super.doEdit(renderRequest, renderResponse); } else { include(editTemplate, renderRequest, renderResponse); } } @Override public void doEditDefaults( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { PortletPreferences portletPreferences = renderRequest.getPreferences(); if (portletPreferences == null) { super.doEdit(renderRequest, renderResponse); } else { include(editDefaultsTemplate, renderRequest, renderResponse); } } @Override public void doEditGuest( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { PortletPreferences portletPreferences = renderRequest.getPreferences(); if (portletPreferences == null) { super.doEdit(renderRequest, renderResponse); } else { include(editGuestTemplate, renderRequest, renderResponse); } } @Override public void doHelp( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(helpTemplate, renderRequest, renderResponse); } @Override public void doPreview( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(previewTemplate, renderRequest, renderResponse); } @Override public void doPrint( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(printTemplate, renderRequest, renderResponse); } @Override public void doView( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include(viewTemplate, renderRequest, renderResponse); } @Override public void init() throws PortletException { super.init(); templatePath = _getInitParameter("template-path"); if (Validator.isNull(templatePath)) { templatePath = StringPool.SLASH; } else if (templatePath.contains(StringPool.BACK_SLASH) || templatePath.contains(StringPool.DOUBLE_SLASH) || templatePath.contains(StringPool.PERIOD) || templatePath.contains(StringPool.SPACE)) { throw new PortletException( "template-path " + templatePath + " has invalid characters"); } else if (!templatePath.startsWith(StringPool.SLASH) || !templatePath.endsWith(StringPool.SLASH)) { throw new PortletException( "template-path " + templatePath + " must start and end with a /"); } aboutTemplate = _getInitParameter("about-template"); configTemplate = _getInitParameter("config-template"); editTemplate = _getInitParameter("edit-template"); editDefaultsTemplate = _getInitParameter("edit-defaults-template"); editGuestTemplate = _getInitParameter("edit-guest-template"); helpTemplate = _getInitParameter("help-template"); previewTemplate = _getInitParameter("preview-template"); printTemplate = _getInitParameter("print-template"); viewTemplate = _getInitParameter("view-template"); clearRequestParameters = GetterUtil.getBoolean( getInitParameter("clear-request-parameters")); copyRequestParameters = GetterUtil.getBoolean( getInitParameter("copy-request-parameters"), true); LiferayPortletConfig liferayPortletConfig = (LiferayPortletConfig)getPortletConfig(); String portletId = liferayPortletConfig.getPortletId(); _actionMVCCommandCache = new MVCCommandCache( MVCActionCommand.EMPTY, getInitParameter("mvc-action-command-package-prefix"), getPortletName(), portletId, MVCActionCommand.class, "ActionCommand"); _renderMVCCommandCache = new MVCCommandCache( MVCRenderCommand.EMPTY, getInitParameter("mvc-render-command-package-prefix"), getPortletName(), portletId, MVCRenderCommand.class, "RenderCommand"); _resourceMVCCommandCache = new MVCCommandCache( MVCResourceCommand.EMPTY, getInitParameter("mvc-resource-command-package-prefix"), getPortletName(), portletId, MVCResourceCommand.class, "ResourceCommand"); initValidPaths(templatePath, ".jsp"); } /** * @deprecated As of 7.0.0, with no direct replacement */ @Deprecated public void invokeTaglibDiscussion( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { PortletConfig portletConfig = getPortletConfig(); PortalUtil.invokeTaglibDiscussion( portletConfig, actionRequest, actionResponse); } /** * @deprecated As of 7.0.0, with no direct replacement */ @Deprecated public void invokeTaglibDiscussionPagination( ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { PortletConfig portletConfig = getPortletConfig(); PortalUtil.invokeTaglibDiscussionPagination( portletConfig, resourceRequest, resourceResponse); } @Override public void processAction( ActionRequest actionRequest, ActionResponse actionResponse) throws IOException, PortletException { super.processAction(actionRequest, actionResponse); if (copyRequestParameters) { PortalUtil.copyRequestParameters(actionRequest, actionResponse); } } @Override public void render( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { invokeHideDefaultSuccessMessage(renderRequest); String mvcRenderCommandName = ParamUtil.getString( renderRequest, "mvcRenderCommandName", "/"); String mvcPath = ParamUtil.getString(renderRequest, "mvcPath"); if (!mvcRenderCommandName.equals("/") || Validator.isNull(mvcPath)) { MVCRenderCommand mvcRenderCommand = (MVCRenderCommand)_renderMVCCommandCache.getMVCCommand( mvcRenderCommandName); mvcPath = null; if (mvcRenderCommand != MVCRenderCommand.EMPTY) { mvcPath = mvcRenderCommand.render( renderRequest, renderResponse); } if (MVCRenderConstants.MVC_PATH_VALUE_SKIP_DISPATCH.equals( mvcPath)) { return; } if (Validator.isNotNull(mvcPath)) { renderRequest.setAttribute( getMVCPathAttributeName(renderResponse.getNamespace()), mvcPath); } else if (!mvcRenderCommandName.equals("/")) { if (_log.isWarnEnabled()) { StringBundler sb = new StringBundler(5); sb.append("No render mappings found for MVC render "); sb.append("command name \""); sb.append(HtmlUtil.escape(mvcRenderCommandName)); sb.append("\" for portlet "); sb.append(renderRequest.getAttribute(WebKeys.PORTLET_ID)); _log.warn(sb.toString()); } } } super.render(renderRequest, renderResponse); } @Override public void serveResource( ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { invokeHideDefaultSuccessMessage(resourceRequest); String path = getPath(resourceRequest, resourceResponse); if (path != null) { include( path, resourceRequest, resourceResponse, PortletRequest.RESOURCE_PHASE); } boolean invokeTaglibDiscussion = GetterUtil.getBoolean( resourceRequest.getParameter("invokeTaglibDiscussion")); if (invokeTaglibDiscussion) { invokeTaglibDiscussionPagination(resourceRequest, resourceResponse); } else { super.serveResource(resourceRequest, resourceResponse); } } @Override protected boolean callActionMethod( ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException { try { checkPermissions(actionRequest); } catch (Exception e) { throw new PortletException(e); } String[] actionNames = ParamUtil.getParameterValues( actionRequest, ActionRequest.ACTION_NAME); String actionName = StringUtil.merge(actionNames); if (!actionName.contains(StringPool.COMMA)) { MVCActionCommand mvcActionCommand = (MVCActionCommand)_actionMVCCommandCache.getMVCCommand( actionName); if (mvcActionCommand != MVCActionCommand.EMPTY) { if (mvcActionCommand instanceof FormMVCActionCommand) { FormMVCActionCommand formMVCActionCommand = (FormMVCActionCommand)mvcActionCommand; if (!formMVCActionCommand.validateForm( actionRequest, actionResponse)) { return false; } } return mvcActionCommand.processAction( actionRequest, actionResponse); } } else { List<MVCActionCommand> mvcActionCommands = (List<MVCActionCommand>)_actionMVCCommandCache.getMVCCommands( actionName); if (!mvcActionCommands.isEmpty()) { boolean valid = true; for (MVCActionCommand mvcActionCommand : mvcActionCommands) { if (mvcActionCommand instanceof FormMVCActionCommand) { FormMVCActionCommand formMVCActionCommand = (FormMVCActionCommand)mvcActionCommand; valid &= formMVCActionCommand.validateForm( actionRequest, actionResponse); } } if (!valid) { return false; } for (MVCActionCommand mvcActionCommand : mvcActionCommands) { if (!mvcActionCommand.processAction( actionRequest, actionResponse)) { return false; } } return true; } } return super.callActionMethod(actionRequest, actionResponse); } @Override protected boolean callResourceMethod( ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws PortletException { try { checkPermissions(resourceRequest); } catch (Exception e) { throw new PortletException(e); } String resourceID = GetterUtil.getString( resourceRequest.getResourceID()); if (!resourceID.contains(StringPool.COMMA)) { MVCResourceCommand mvcResourceCommand = (MVCResourceCommand)_resourceMVCCommandCache.getMVCCommand( resourceID); if (mvcResourceCommand != MVCResourceCommand.EMPTY) { return mvcResourceCommand.serveResource( resourceRequest, resourceResponse); } } else { List<MVCResourceCommand> mvcResourceCommands = (List<MVCResourceCommand>) _resourceMVCCommandCache.getMVCCommands(resourceID); if (!mvcResourceCommands.isEmpty()) { for (MVCResourceCommand mvcResourceCommand : mvcResourceCommands) { if (!mvcResourceCommand.serveResource( resourceRequest, resourceResponse)) { return false; } } return true; } } return super.callResourceMethod(resourceRequest, resourceResponse); } protected void checkPermissions(PortletRequest portletRequest) throws Exception { } @Override protected void doDispatch( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { String path = getPath(renderRequest, renderResponse); if (path != null) { if (!isProcessRenderRequest(renderRequest)) { renderRequest.setAttribute( WebKeys.PORTLET_DECORATE, Boolean.FALSE); return; } WindowState windowState = renderRequest.getWindowState(); if (windowState.equals(WindowState.MINIMIZED)) { return; } include(path, renderRequest, renderResponse); } else { super.doDispatch(renderRequest, renderResponse); } } protected MVCCommandCache getActionMVCCommandCache() { return _actionMVCCommandCache; } protected String getMVCPathAttributeName(String namespace) { return namespace.concat(StringPool.PERIOD).concat( MVCRenderConstants.MVC_PATH_REQUEST_ATTRIBUTE_NAME); } protected String getPath( PortletRequest portletRequest, PortletResponse portletResponse) { String mvcPath = portletRequest.getParameter("mvcPath"); if (mvcPath == null) { mvcPath = (String)portletRequest.getAttribute( getMVCPathAttributeName(portletResponse.getNamespace())); } // Check deprecated parameter if (mvcPath == null) { mvcPath = portletRequest.getParameter("jspPage"); } return mvcPath; } protected MVCCommandCache getRenderMVCCommandCache() { return _renderMVCCommandCache; } protected MVCCommandCache getResourceMVCCommandCache() { return _resourceMVCCommandCache; } protected void hideDefaultErrorMessage(PortletRequest portletRequest) { SessionMessages.add( portletRequest, PortalUtil.getPortletId(portletRequest) + SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE); } protected void hideDefaultSuccessMessage(PortletRequest portletRequest) { SessionMessages.add( portletRequest, PortalUtil.getPortletId(portletRequest) + SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_SUCCESS_MESSAGE); } protected void include( String path, ActionRequest actionRequest, ActionResponse actionResponse) throws IOException, PortletException { include( path, actionRequest, actionResponse, PortletRequest.ACTION_PHASE); } protected void include( String path, EventRequest eventRequest, EventResponse eventResponse) throws IOException, PortletException { include(path, eventRequest, eventResponse, PortletRequest.EVENT_PHASE); } protected void include( String path, PortletRequest portletRequest, PortletResponse portletResponse, String lifecycle) throws IOException, PortletException { HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest(portletRequest); PortletContext portletContext = (PortletContext)httpServletRequest.getAttribute( MVCRenderConstants. PORTLET_CONTEXT_OVERRIDE_REQUEST_ATTIBUTE_NAME_PREFIX + path); if (portletContext == null) { portletContext = getPortletContext(); } PortletRequestDispatcher portletRequestDispatcher = portletContext.getRequestDispatcher(path); if (portletRequestDispatcher == null) { _log.error(path + " is not a valid include"); } else { checkPath(path); portletRequestDispatcher.include(portletRequest, portletResponse); } if (clearRequestParameters) { if (lifecycle.equals(PortletRequest.RENDER_PHASE)) { portletResponse.setProperty( "clear-request-parameters", Boolean.TRUE.toString()); } } } protected void include( String path, RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { include( path, renderRequest, renderResponse, PortletRequest.RENDER_PHASE); } protected void include( String path, ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { include( path, resourceRequest, resourceResponse, PortletRequest.RESOURCE_PHASE); } protected void invokeHideDefaultSuccessMessage( PortletRequest portletRequest) { boolean hideDefaultSuccessMessage = ParamUtil.getBoolean( portletRequest, "hideDefaultSuccessMessage"); if (hideDefaultSuccessMessage) { hideDefaultSuccessMessage(portletRequest); } } protected String aboutTemplate; protected boolean clearRequestParameters; protected String configTemplate; protected boolean copyRequestParameters; protected String editDefaultsTemplate; protected String editGuestTemplate; protected String editTemplate; protected String helpTemplate; protected String previewTemplate; protected String printTemplate; protected String templatePath; protected String viewTemplate; private String _getInitParameter(String name) { String value = getInitParameter(name); if (value != null) { return value; } // Check deprecated parameter if (name.equals("template-path")) { return getInitParameter("jsp-path"); } else if (name.endsWith("-template")) { name = name.substring(0, name.length() - 9) + "-jsp"; return getInitParameter(name); } return null; } private static final Log _log = LogFactoryUtil.getLog(MVCPortlet.class); private MVCCommandCache _actionMVCCommandCache; private MVCCommandCache _renderMVCCommandCache; private MVCCommandCache _resourceMVCCommandCache; }