--- /dev/null
+/**\r
+ * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.\r
+ *\r
+ * This library is free software; you can redistribute it and/or modify it under\r
+ * the terms of the GNU Lesser General Public License as published by the Free\r
+ * Software Foundation; either version 2.1 of the License, or (at your option)\r
+ * any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful, but WITHOUT\r
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more\r
+ * details.\r
+ */\r
+\r
+package com.liferay.portal.struts;\r
+\r
+import com.liferay.portal.kernel.log.Log;\r
+import com.liferay.portal.kernel.log.LogFactoryUtil;\r
+import com.liferay.portal.kernel.portlet.LiferayPortletURL;\r
+import com.liferay.portal.kernel.util.CharPool;\r
+import com.liferay.portal.kernel.util.JavaConstants;\r
+import com.liferay.portal.kernel.util.StringPool;\r
+import com.liferay.portal.kernel.util.Validator;\r
+import com.liferay.portal.model.Layout;\r
+import com.liferay.portal.model.Portlet;\r
+import com.liferay.portal.security.auth.PrincipalException;\r
+import com.liferay.portal.security.permission.ActionKeys;\r
+import com.liferay.portal.security.permission.PermissionChecker;\r
+import com.liferay.portal.service.PortletLocalServiceUtil;\r
+import com.liferay.portal.service.permission.PortletPermissionUtil;\r
+import com.liferay.portal.theme.ThemeDisplay;\r
+import com.liferay.portal.util.PortalUtil;\r
+import com.liferay.portal.util.PropsValues;\r
+import com.liferay.portal.util.WebKeys;\r
+import com.liferay.portlet.ActionResponseImpl;\r
+import com.liferay.portlet.PortletConfigImpl;\r
+import com.liferay.portlet.PortletRequestDispatcherImpl;\r
+\r
+import java.io.IOException;\r
+\r
+import java.lang.reflect.Constructor;\r
+\r
+import javax.portlet.ActionRequest;\r
+import javax.portlet.ActionResponse;\r
+import javax.portlet.PortletContext;\r
+import javax.portlet.PortletException;\r
+import javax.portlet.PortletRequest;\r
+import javax.portlet.PortletResponse;\r
+import javax.portlet.RenderRequest;\r
+import javax.portlet.RenderResponse;\r
+import javax.portlet.ResourceRequest;\r
+import javax.portlet.ResourceResponse;\r
+\r
+import javax.servlet.ServletException;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import org.apache.struts.Globals;\r
+import org.apache.struts.action.Action;\r
+import org.apache.struts.action.ActionErrors;\r
+import org.apache.struts.action.ActionForm;\r
+import org.apache.struts.action.ActionForward;\r
+import org.apache.struts.action.ActionMapping;\r
+import org.apache.struts.action.ActionServlet;\r
+import org.apache.struts.config.ActionConfig;\r
+import org.apache.struts.config.ForwardConfig;\r
+import org.apache.struts.config.ModuleConfig;\r
+import org.apache.struts.tiles.TilesRequestProcessor;\r
+import org.apache.struts.util.MessageResources;\r
+\r
+/**\r
+ * @author Brian Wing Shun Chan\r
+ * @author Raymond Augé\r
+ */\r
+public class PortletRequestProcessor extends TilesRequestProcessor {\r
+\r
+ public static PortletRequestProcessor getInstance(\r
+ ActionServlet servlet, ModuleConfig moduleConfig)\r
+ throws ServletException {\r
+\r
+ try {\r
+ String className = PropsValues.STRUTS_PORTLET_REQUEST_PROCESSOR;\r
+\r
+ Class<?> clazz = Class.forName(className);\r
+\r
+ Constructor<?> constructor = clazz.getConstructor(\r
+ ActionServlet.class, ModuleConfig.class);\r
+\r
+ PortletRequestProcessor portletReqProcessor =\r
+ (PortletRequestProcessor)constructor.newInstance(\r
+ servlet, moduleConfig);\r
+\r
+ return portletReqProcessor;\r
+ }\r
+ catch (Exception e) {\r
+ _log.error(e);\r
+\r
+ return new PortletRequestProcessor(servlet, moduleConfig);\r
+ }\r
+ }\r
+\r
+ public PortletRequestProcessor(\r
+ ActionServlet actionServlet, ModuleConfig moduleConfig)\r
+ throws ServletException {\r
+\r
+ init(actionServlet, moduleConfig);\r
+ }\r
+\r
+ public void process(\r
+ ActionRequest actionRequest, ActionResponse actionResponse,\r
+ String path)\r
+ throws IOException, ServletException {\r
+\r
+ ActionResponseImpl actionResponseImpl =\r
+ (ActionResponseImpl)actionResponse;\r
+\r
+ HttpServletRequest request = PortalUtil.getHttpServletRequest(\r
+ actionRequest);\r
+ HttpServletResponse response = PortalUtil.getHttpServletResponse(\r
+ actionResponse);\r
+\r
+ ActionMapping actionMapping = processMapping(request, response, path);\r
+\r
+ if (actionMapping == null) {\r
+ return;\r
+ }\r
+\r
+ if (!processRoles(request, response, actionMapping, true)) {\r
+ return;\r
+ }\r
+\r
+ ActionForm actionForm = processActionForm(\r
+ request, response, actionMapping);\r
+\r
+ processPopulate(request, response, actionForm, actionMapping);\r
+\r
+ if (!processValidateAction(\r
+ request, response, actionForm, actionMapping)) {\r
+\r
+ return;\r
+ }\r
+\r
+ PortletAction portletAction = (PortletAction)processActionCreate(\r
+ request, response, actionMapping);\r
+\r
+ if (portletAction == null) {\r
+ return;\r
+ }\r
+\r
+ PortletConfigImpl portletConfigImpl =\r
+ (PortletConfigImpl)actionRequest.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_CONFIG);\r
+\r
+ try {\r
+ if (portletAction.isCheckMethodOnProcessAction()) {\r
+ if (!PortalUtil.isMethodPost(actionRequest)) {\r
+ String currentURL = PortalUtil.getCurrentURL(actionRequest);\r
+\r
+ if (_log.isWarnEnabled()) {\r
+ _log.warn(\r
+ "This URL can only be invoked using POST: " +\r
+ currentURL);\r
+ }\r
+\r
+ throw new PrincipalException(currentURL);\r
+ }\r
+ }\r
+\r
+ portletAction.processAction(\r
+ actionMapping, actionForm, portletConfigImpl, actionRequest,\r
+ actionResponse);\r
+ }\r
+ catch (Exception e) {\r
+ String exceptionId =\r
+ WebKeys.PORTLET_STRUTS_EXCEPTION + StringPool.PERIOD +\r
+ portletConfigImpl.getPortletId();\r
+\r
+ actionRequest.setAttribute(exceptionId, e);\r
+ }\r
+\r
+ String forward = (String)actionRequest.getAttribute(\r
+ PortletAction.getForwardKey(actionRequest));\r
+\r
+ if (forward != null) {\r
+ String queryString = StringPool.BLANK;\r
+\r
+ int pos = forward.indexOf(CharPool.QUESTION);\r
+\r
+ if (pos != -1) {\r
+ queryString = forward.substring(pos + 1);\r
+ forward = forward.substring(0, pos);\r
+ }\r
+\r
+ ActionForward actionForward = actionMapping.findForward(forward);\r
+\r
+ if ((actionForward != null) && actionForward.getRedirect()) {\r
+ String forwardPath = actionForward.getPath();\r
+\r
+ if (forwardPath.startsWith(StringPool.SLASH)) {\r
+ LiferayPortletURL forwardURL =\r
+ (LiferayPortletURL)actionResponseImpl.createRenderURL();\r
+\r
+ forwardURL.setParameter("struts_action", forwardPath);\r
+\r
+ StrutsURLEncoder.setParameters(forwardURL, queryString);\r
+\r
+ forwardPath = forwardURL.toString();\r
+ }\r
+\r
+ actionResponse.sendRedirect(forwardPath);\r
+ }\r
+ }\r
+ }\r
+\r
+ public void process(\r
+ RenderRequest renderRequest, RenderResponse renderResponse)\r
+ throws IOException, ServletException {\r
+\r
+ HttpServletRequest request = PortalUtil.getHttpServletRequest(\r
+ renderRequest);\r
+ HttpServletResponse response = PortalUtil.getHttpServletResponse(\r
+ renderResponse);\r
+\r
+ process(request, response);\r
+ }\r
+\r
+ public void process(\r
+ ResourceRequest resourceRequest, ResourceResponse resourceResponse)\r
+ throws IOException, ServletException {\r
+\r
+ HttpServletRequest request = PortalUtil.getHttpServletRequest(\r
+ resourceRequest);\r
+ HttpServletResponse response = PortalUtil.getHttpServletResponse(\r
+ resourceResponse);\r
+\r
+ process(request, response);\r
+ }\r
+\r
+ @Override\r
+ public ActionMapping processMapping(\r
+ HttpServletRequest request, HttpServletResponse response, String path) {\r
+\r
+ if (path == null) {\r
+ return null;\r
+ }\r
+\r
+ ActionMapping actionMapping = null;\r
+\r
+ long companyId = PortalUtil.getCompanyId(request);\r
+\r
+ PortletConfigImpl portletConfigImpl =\r
+ (PortletConfigImpl)request.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_CONFIG);\r
+\r
+ try {\r
+ Portlet portlet = PortletLocalServiceUtil.getPortletById(\r
+ companyId, portletConfigImpl.getPortletId());\r
+\r
+ if (StrutsActionRegistryUtil.getAction(path) != null) {\r
+ actionMapping = (ActionMapping)moduleConfig.findActionConfig(\r
+ path);\r
+\r
+ if (actionMapping == null) {\r
+ actionMapping = new ActionMapping();\r
+\r
+ actionMapping.setModuleConfig(moduleConfig);\r
+ actionMapping.setPath(path);\r
+\r
+ request.setAttribute(Globals.MAPPING_KEY, actionMapping);\r
+ }\r
+ }\r
+ else if (moduleConfig.findActionConfig(path) != null) {\r
+ actionMapping = super.processMapping(request, response, path);\r
+ }\r
+ else if (Validator.isNotNull(portlet.getParentStrutsPath())) {\r
+ int pos = path.indexOf(StringPool.SLASH, 1);\r
+\r
+ String parentPath =\r
+ StringPool.SLASH + portlet.getParentStrutsPath() +\r
+ path.substring(pos);\r
+\r
+ if (StrutsActionRegistryUtil.getAction(parentPath) != null) {\r
+ actionMapping =\r
+ (ActionMapping)moduleConfig.findActionConfig(path);\r
+\r
+ if (actionMapping == null) {\r
+ actionMapping = new ActionMapping();\r
+\r
+ actionMapping.setModuleConfig(moduleConfig);\r
+ actionMapping.setPath(parentPath);\r
+\r
+ request.setAttribute(\r
+ Globals.MAPPING_KEY, actionMapping);\r
+ }\r
+ }\r
+ else if (moduleConfig.findActionConfig(parentPath) != null) {\r
+ actionMapping = super.processMapping(\r
+ request, response, parentPath);\r
+ }\r
+ }\r
+ }\r
+ catch (Exception e) {\r
+ }\r
+\r
+ if (actionMapping == null) {\r
+ MessageResources messageResources = getInternal();\r
+\r
+ String msg = messageResources.getMessage("processInvalid");\r
+\r
+ //_log.error("User ID " + request.getRemoteUser());\r
+ //_log.error("Current URL " + PortalUtil.getCurrentURL(request));\r
+ //_log.error("Referer " + request.getHeader("Referer"));\r
+ //_log.error("Remote address " + request.getRemoteAddr());\r
+\r
+ //_log.error(msg + " " + path);\r
+ }\r
+\r
+ return actionMapping;\r
+ }\r
+\r
+ @Override\r
+ protected void doForward(\r
+ String uri, HttpServletRequest request,\r
+ HttpServletResponse response)\r
+ throws IOException, ServletException {\r
+\r
+ doInclude(uri, request, response);\r
+ }\r
+\r
+ @Override\r
+ protected void doInclude(\r
+ String uri, HttpServletRequest request,\r
+ HttpServletResponse response)\r
+ throws IOException, ServletException {\r
+\r
+ PortletConfigImpl portletConfigImpl =\r
+ (PortletConfigImpl)request.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_CONFIG);\r
+\r
+ PortletContext portletContext = portletConfigImpl.getPortletContext();\r
+\r
+ PortletRequest portletRequest = (PortletRequest)request.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_REQUEST);\r
+\r
+ PortletResponse portletResponse = (PortletResponse)request.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_RESPONSE);\r
+\r
+ PortletRequestDispatcherImpl portletRequestDispatcher =\r
+ (PortletRequestDispatcherImpl)portletContext.getRequestDispatcher(\r
+ StrutsUtil.TEXT_HTML_DIR + uri);\r
+\r
+ try {\r
+ if (portletRequestDispatcher == null) {\r
+ _log.error(uri + " is not a valid include");\r
+ }\r
+ else {\r
+ portletRequestDispatcher.include(\r
+ portletRequest, portletResponse, true);\r
+ }\r
+ }\r
+ catch (PortletException pe) {\r
+ Throwable cause = pe.getCause();\r
+\r
+ if (cause instanceof ServletException) {\r
+ throw (ServletException)cause;\r
+ }\r
+ else {\r
+ _log.error(cause, cause);\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected Action processActionCreate(\r
+ HttpServletRequest request, HttpServletResponse response,\r
+ ActionMapping actionMapping)\r
+ throws IOException {\r
+\r
+ PortletActionAdapter portletActionAdapter =\r
+ (PortletActionAdapter)StrutsActionRegistryUtil.getAction(\r
+ actionMapping.getPath());\r
+\r
+ if (portletActionAdapter != null) {\r
+ ActionConfig actionConfig = moduleConfig.findActionConfig(\r
+ actionMapping.getPath());\r
+\r
+ if (actionConfig != null) {\r
+ PortletAction originalPortletAction =\r
+ (PortletAction)super.processActionCreate(\r
+ request, response, actionMapping);\r
+\r
+ portletActionAdapter.setOriginalPortletAction(\r
+ originalPortletAction);\r
+ }\r
+\r
+ return portletActionAdapter;\r
+ }\r
+\r
+ return super.processActionCreate(request, response, actionMapping);\r
+ }\r
+\r
+ @Override\r
+ protected ActionForm processActionForm(\r
+ HttpServletRequest request, HttpServletResponse response,\r
+ ActionMapping actionMapping) {\r
+\r
+ ActionForm actionForm = super.processActionForm(\r
+ request, response, actionMapping);\r
+\r
+ if (actionForm instanceof InitializableActionForm) {\r
+ InitializableActionForm initializableActionForm =\r
+ (InitializableActionForm)actionForm;\r
+\r
+ initializableActionForm.init(request, response, actionMapping);\r
+ }\r
+\r
+ return actionForm;\r
+ }\r
+\r
+ @Override\r
+ protected ActionForward processActionPerform(\r
+ HttpServletRequest request, HttpServletResponse response,\r
+ Action action, ActionForm actionForm, ActionMapping actionMapping)\r
+ throws IOException, ServletException {\r
+\r
+ PortletConfigImpl portletConfigImpl =\r
+ (PortletConfigImpl)request.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_CONFIG);\r
+\r
+ String exceptionId =\r
+ WebKeys.PORTLET_STRUTS_EXCEPTION + StringPool.PERIOD +\r
+ portletConfigImpl.getPortletId();\r
+\r
+ Exception e = (Exception)request.getAttribute(exceptionId);\r
+\r
+ if (e != null) {\r
+ return processException(\r
+ request, response, e, actionForm, actionMapping);\r
+ }\r
+ else {\r
+ return super.processActionPerform(\r
+ request, response, action, actionForm, actionMapping);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected void processForwardConfig(\r
+ HttpServletRequest request, HttpServletResponse response,\r
+ ForwardConfig forward)\r
+ throws IOException, ServletException {\r
+\r
+ if (forward == null) {\r
+ _log.error("Forward does not exist");\r
+ }\r
+ else {\r
+\r
+ // Don't render a null path. This is useful if you're sending a file\r
+ // in an exclusive window state.\r
+\r
+ if (forward.getPath().equals(ActionConstants.COMMON_NULL)) {\r
+ return;\r
+ }\r
+ }\r
+\r
+ super.processForwardConfig(request, response, forward);\r
+ }\r
+\r
+ @Override\r
+ protected HttpServletRequest processMultipart(HttpServletRequest request) {\r
+\r
+ // Disable Struts from automatically wrapping a multipart request\r
+\r
+ return request;\r
+ }\r
+\r
+ @Override\r
+ protected String processPath(\r
+ HttpServletRequest request, HttpServletResponse response) {\r
+\r
+ String path = request.getParameter("struts_action");\r
+\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug("Getting request parameter path " + path);\r
+ }\r
+\r
+ if (Validator.isNull(path)) {\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug("Getting request attribute path " + path);\r
+ }\r
+\r
+ path = (String)request.getAttribute(WebKeys.PORTLET_STRUTS_ACTION);\r
+ }\r
+\r
+ if (path == null) {\r
+ PortletConfigImpl portletConfigImpl =\r
+ (PortletConfigImpl)request.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_CONFIG);\r
+\r
+ _log.error(\r
+ portletConfigImpl.getPortletName() +\r
+ " does not have any paths specified");\r
+ }\r
+ else {\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug("Processing path " + path);\r
+ }\r
+ }\r
+\r
+ return path;\r
+ }\r
+\r
+ @Override\r
+ protected boolean processRoles(\r
+ HttpServletRequest request, HttpServletResponse response,\r
+ ActionMapping actionMapping)\r
+ throws IOException, ServletException {\r
+\r
+ return processRoles(request, response, actionMapping, false);\r
+ }\r
+\r
+ protected boolean processRoles(\r
+ HttpServletRequest request, HttpServletResponse response,\r
+ ActionMapping actionMapping, boolean action)\r
+ throws IOException, ServletException {\r
+\r
+ long companyId = PortalUtil.getCompanyId(request);\r
+\r
+ String path = actionMapping.getPath();\r
+\r
+ try {\r
+ PortletConfigImpl portletConfigImpl =\r
+ (PortletConfigImpl)request.getAttribute(\r
+ JavaConstants.JAVAX_PORTLET_CONFIG);\r
+\r
+ Portlet portlet = PortletLocalServiceUtil.getPortletById(\r
+ companyId, portletConfigImpl.getPortletId());\r
+\r
+ if (portlet == null) {\r
+ return false;\r
+ }\r
+\r
+ String strutsPath = path.substring(\r
+ 1, path.lastIndexOf(CharPool.SLASH));\r
+\r
+ if (!strutsPath.equals(portlet.getStrutsPath()) &&\r
+ !strutsPath.equals(portlet.getParentStrutsPath())) {\r
+ if (_log.isWarnEnabled()) {\r
+ _log.warn(\r
+ "The struts path " + strutsPath + " does not belong " +\r
+ "to portlet " + portlet.getPortletId() + ". " +\r
+ "Check the definition in liferay-portlet.xml");\r
+ }\r
+\r
+ throw new PrincipalException();\r
+ }\r
+ else if (portlet.isActive()) {\r
+ if (PortalUtil.isAllowAddPortletDefaultResource(\r
+ request, portlet)) {\r
+\r
+ PortalUtil.addPortletDefaultResource(request, portlet);\r
+ }\r
+\r
+ ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(\r
+ WebKeys.THEME_DISPLAY);\r
+\r
+ Layout layout = themeDisplay.getLayout();\r
+ PermissionChecker permissionChecker =\r
+ themeDisplay.getPermissionChecker();\r
+\r
+ if (!PortletPermissionUtil.contains(\r
+ permissionChecker, layout, portlet, ActionKeys.VIEW)) {\r
+\r
+ throw new PrincipalException();\r
+ }\r
+ }\r
+ else if (!portlet.isActive()) {\r
+ ForwardConfig forwardConfig = actionMapping.findForward(\r
+ _PATH_PORTAL_PORTLET_INACTIVE);\r
+\r
+ if (!action) {\r
+ processForwardConfig(request, response, forwardConfig);\r
+ }\r
+\r
+ return false;\r
+ }\r
+ }\r
+ catch (Exception e) {\r
+ if (_log.isWarnEnabled()) {\r
+ _log.warn(e.getMessage());\r
+ }\r
+\r
+ ForwardConfig forwardConfig = actionMapping.findForward(\r
+ _PATH_PORTAL_PORTLET_ACCESS_DENIED);\r
+\r
+ if (!action) {\r
+ processForwardConfig(request, response, forwardConfig);\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ protected boolean processValidateAction(\r
+ HttpServletRequest request, HttpServletResponse response,\r
+ ActionForm actionForm, ActionMapping actionMapping) {\r
+\r
+ if (actionForm == null) {\r
+ return true;\r
+ }\r
+\r
+ if (request.getAttribute(Globals.CANCEL_KEY) != null) {\r
+ return true;\r
+ }\r
+\r
+ if (!actionMapping.getValidate()) {\r
+ return true;\r
+ }\r
+\r
+ ActionErrors errors = actionForm.validate(actionMapping, request);\r
+\r
+ if ((errors == null) || errors.isEmpty()) {\r
+ return true;\r
+ }\r
+\r
+ if (actionForm.getMultipartRequestHandler() != null) {\r
+ actionForm.getMultipartRequestHandler().rollback();\r
+ }\r
+\r
+ String input = actionMapping.getInput();\r
+\r
+ if (input == null) {\r
+ _log.error("Validation failed but no input form is available");\r
+\r
+ return false;\r
+ }\r
+\r
+ request.setAttribute(Globals.ERROR_KEY, errors);\r
+\r
+ // Struts normally calls internalModuleRelativeForward which breaks\r
+ // if called inside processAction\r
+\r
+ request.setAttribute(PortletAction.getForwardKey(request), input);\r
+\r
+ return false;\r
+ }\r
+\r
+ private static final String _PATH_PORTAL_PORTLET_ACCESS_DENIED =\r
+ "/portal/portlet_access_denied";\r
+\r
+ private static final String _PATH_PORTAL_PORTLET_INACTIVE =\r
+ "/portal/portlet_inactive";\r
+\r
+ private static Log _log = LogFactoryUtil.getLog(\r
+ PortletRequestProcessor.class);\r
+\r
+}
\ No newline at end of file