/**
* 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.struts;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Portlet;
import com.liferay.portal.kernel.portlet.LiferayPortletConfig;
import com.liferay.portal.kernel.portlet.LiferayPortletRequestDispatcher;
import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
import com.liferay.portal.kernel.portlet.LiferayPortletURL;
import com.liferay.portal.kernel.security.auth.PrincipalException;
import com.liferay.portal.kernel.service.PortletLocalServiceUtil;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.JavaConstants;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.util.PropsValues;
import java.io.IOException;
import java.lang.reflect.Constructor;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.Globals;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.ActionConfig;
import org.apache.struts.config.ForwardConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.tiles.TilesRequestProcessor;
import org.apache.struts.util.MessageResources;
/**
* @author Brian Wing Shun Chan
* @author Raymond Augé
*/
public class PortletRequestProcessor extends TilesRequestProcessor {
public static PortletRequestProcessor getInstance(
ActionServlet servlet, ModuleConfig moduleConfig)
throws ServletException {
try {
String className = PropsValues.STRUTS_PORTLET_REQUEST_PROCESSOR;
Class<?> clazz = Class.forName(className);
Constructor<?> constructor = clazz.getConstructor(
ActionServlet.class, ModuleConfig.class);
PortletRequestProcessor portletReqProcessor =
(PortletRequestProcessor)constructor.newInstance(
servlet, moduleConfig);
return portletReqProcessor;
}
catch (Exception e) {
_log.error(e);
return new PortletRequestProcessor(servlet, moduleConfig);
}
}
public PortletRequestProcessor(
ActionServlet actionServlet, ModuleConfig moduleConfig)
throws ServletException {
init(actionServlet, moduleConfig);
}
public void process(
ActionRequest actionRequest, ActionResponse actionResponse,
String path)
throws IOException, ServletException {
HttpServletRequest request = PortalUtil.getHttpServletRequest(
actionRequest);
HttpServletResponse response = PortalUtil.getHttpServletResponse(
actionResponse);
ActionMapping actionMapping = processMapping(request, response, path);
if (actionMapping == null) {
return;
}
if (!processRoles(request, response, actionMapping, true)) {
return;
}
ActionForm actionForm = processActionForm(
request, response, actionMapping);
processPopulate(request, response, actionForm, actionMapping);
if (!processValidateAction(
request, response, actionForm, actionMapping)) {
return;
}
PortletAction portletAction = (PortletAction)processActionCreate(
request, response, actionMapping);
if (portletAction == null) {
return;
}
LiferayPortletConfig liferayPortletConfig =
(LiferayPortletConfig)actionRequest.getAttribute(
JavaConstants.JAVAX_PORTLET_CONFIG);
try {
if (portletAction.isCheckMethodOnProcessAction()) {
if (!PortalUtil.isMethodPost(actionRequest)) {
String currentURL = PortalUtil.getCurrentURL(actionRequest);
if (_log.isWarnEnabled()) {
_log.warn(
"This URL can only be invoked using POST: " +
currentURL);
}
throw new PrincipalException.MustBeInvokedUsingPost(
currentURL);
}
}
portletAction.processAction(
actionMapping, actionForm, liferayPortletConfig, actionRequest,
actionResponse);
}
catch (Exception e) {
String exceptionId =
WebKeys.PORTLET_STRUTS_EXCEPTION + StringPool.PERIOD +
liferayPortletConfig.getPortletId();
actionRequest.setAttribute(exceptionId, e);
}
String forward = (String)actionRequest.getAttribute(
PortletAction.getForwardKey(actionRequest));
if (forward == null) {
return;
}
String queryString = StringPool.BLANK;
int pos = forward.indexOf(CharPool.QUESTION);
if (pos != -1) {
queryString = forward.substring(pos + 1);
forward = forward.substring(0, pos);
}
ActionForward actionForward = actionMapping.findForward(forward);
if ((actionForward != null) && actionForward.getRedirect()) {
String forwardPath = actionForward.getPath();
if (forwardPath.startsWith(StringPool.SLASH)) {
LiferayPortletResponse liferayPortletResponse =
PortalUtil.getLiferayPortletResponse(actionResponse);
LiferayPortletURL forwardURL =
(LiferayPortletURL)liferayPortletResponse.createRenderURL();
forwardURL.setParameter("struts_action", forwardPath);
StrutsURLEncoder.setParameters(forwardURL, queryString);
forwardPath = forwardURL.toString();
}
actionResponse.sendRedirect(forwardPath);
}
}
public void process(EventRequest eventRequest, EventResponse eventResponse)
throws IOException, ServletException {
HttpServletRequest request = PortalUtil.getHttpServletRequest(
eventRequest);
HttpServletResponse response = PortalUtil.getHttpServletResponse(
eventResponse);
process(request, response);
}
public void process(
RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException, ServletException {
HttpServletRequest request = PortalUtil.getHttpServletRequest(
renderRequest);
HttpServletResponse response = PortalUtil.getHttpServletResponse(
renderResponse);
process(request, response);
}
public void process(
ResourceRequest resourceRequest, ResourceResponse resourceResponse)
throws IOException, ServletException {
HttpServletRequest request = PortalUtil.getHttpServletRequest(
resourceRequest);
HttpServletResponse response = PortalUtil.getHttpServletResponse(
resourceResponse);
process(request, response);
}
@Override
public ActionMapping processMapping(
HttpServletRequest request, HttpServletResponse response, String path) {
if (path == null) {
return null;
}
ActionMapping actionMapping = null;
long companyId = PortalUtil.getCompanyId(request);
LiferayPortletConfig liferayPortletConfig =
(LiferayPortletConfig)request.getAttribute(
JavaConstants.JAVAX_PORTLET_CONFIG);
try {
Portlet portlet = PortletLocalServiceUtil.getPortletById(
companyId, liferayPortletConfig.getPortletId());
if (StrutsActionRegistryUtil.getAction(path) != null) {
actionMapping = (ActionMapping)moduleConfig.findActionConfig(
path);
if (actionMapping == null) {
actionMapping = new ActionMapping();
actionMapping.setModuleConfig(moduleConfig);
actionMapping.setPath(path);
request.setAttribute(Globals.MAPPING_KEY, actionMapping);
}
}
else if (moduleConfig.findActionConfig(path) != null) {
actionMapping = super.processMapping(request, response, path);
}
else if (Validator.isNotNull(portlet.getParentStrutsPath())) {
int pos = path.indexOf(StringPool.SLASH, 1);
String parentPath =
StringPool.SLASH + portlet.getParentStrutsPath() +
path.substring(pos);
if (StrutsActionRegistryUtil.getAction(parentPath) != null) {
actionMapping =
(ActionMapping)moduleConfig.findActionConfig(
parentPath);
if (actionMapping == null) {
actionMapping = new ActionMapping();
actionMapping.setModuleConfig(moduleConfig);
actionMapping.setPath(parentPath);
request.setAttribute(
Globals.MAPPING_KEY, actionMapping);
}
}
else if (moduleConfig.findActionConfig(parentPath) != null) {
actionMapping = super.processMapping(
request, response, parentPath);
}
}
}
catch (Exception e) {
}
if (actionMapping == null) {
MessageResources messageResources = getInternal();
String msg = messageResources.getMessage("processInvalid");
_log.error("User ID " + request.getRemoteUser());
_log.error("Current URL " + PortalUtil.getCurrentURL(request));
_log.error("Referer " + request.getHeader("Referer"));
_log.error("Remote address " + request.getRemoteAddr());
_log.error(msg + " " + path);
}
return actionMapping;
}
@Override
protected void doForward(
String uri, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
doInclude(uri, request, response);
}
@Override
protected void doInclude(
String uri, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
LiferayPortletConfig liferayPortletConfig =
(LiferayPortletConfig)request.getAttribute(
JavaConstants.JAVAX_PORTLET_CONFIG);
PortletContext portletContext =
liferayPortletConfig.getPortletContext();
PortletRequest portletRequest = (PortletRequest)request.getAttribute(
JavaConstants.JAVAX_PORTLET_REQUEST);
PortletResponse portletResponse = (PortletResponse)request.getAttribute(
JavaConstants.JAVAX_PORTLET_RESPONSE);
LiferayPortletRequestDispatcher liferayPortletRequestDispatcher =
(LiferayPortletRequestDispatcher)
portletContext.getRequestDispatcher(
StrutsUtil.TEXT_HTML_DIR + uri);
try {
if (liferayPortletRequestDispatcher == null) {
_log.error(uri + " is not a valid include");
}
else {
liferayPortletRequestDispatcher.include(
portletRequest, portletResponse, true);
}
}
catch (PortletException pe) {
Throwable cause = pe.getCause();
if (cause instanceof ServletException) {
throw (ServletException)cause;
}
else {
_log.error(cause, cause);
}
}
}
@Override
protected Action processActionCreate(
HttpServletRequest request, HttpServletResponse response,
ActionMapping actionMapping)
throws IOException {
PortletActionAdapter portletActionAdapter =
(PortletActionAdapter)StrutsActionRegistryUtil.getAction(
actionMapping.getPath());
if (portletActionAdapter != null) {
ActionConfig actionConfig = moduleConfig.findActionConfig(
actionMapping.getPath());
if (actionConfig != null) {
PortletAction originalPortletAction =
(PortletAction)super.processActionCreate(
request, response, actionMapping);
portletActionAdapter.setOriginalPortletAction(
originalPortletAction);
}
return portletActionAdapter;
}
return super.processActionCreate(request, response, actionMapping);
}
@Override
protected ActionForm processActionForm(
HttpServletRequest request, HttpServletResponse response,
ActionMapping actionMapping) {
ActionForm actionForm = super.processActionForm(
request, response, actionMapping);
if (actionForm instanceof InitializableActionForm) {
InitializableActionForm initializableActionForm =
(InitializableActionForm)actionForm;
initializableActionForm.init(request, response, actionMapping);
}
return actionForm;
}
@Override
protected ActionForward processActionPerform(
HttpServletRequest request, HttpServletResponse response,
Action action, ActionForm actionForm, ActionMapping actionMapping)
throws IOException, ServletException {
LiferayPortletConfig liferayPortletConfig =
(LiferayPortletConfig)request.getAttribute(
JavaConstants.JAVAX_PORTLET_CONFIG);
String exceptionId =
WebKeys.PORTLET_STRUTS_EXCEPTION + StringPool.PERIOD +
liferayPortletConfig.getPortletId();
Exception e = (Exception)request.getAttribute(exceptionId);
if (e != null) {
return processException(
request, response, e, actionForm, actionMapping);
}
else {
return super.processActionPerform(
request, response, action, actionForm, actionMapping);
}
}
@Override
protected void processForwardConfig(
HttpServletRequest request, HttpServletResponse response,
ForwardConfig forward)
throws IOException, ServletException {
if (forward == null) {
_log.error("Forward does not exist");
}
else {
// Don't render a null path. This is useful if you're sending a file
// in an exclusive window state.
if (forward.getPath().equals(ActionConstants.COMMON_NULL)) {
return;
}
}
super.processForwardConfig(request, response, forward);
}
@Override
protected HttpServletRequest processMultipart(HttpServletRequest request) {
// Disable Struts from automatically wrapping a multipart request
return request;
}
@Override
protected String processPath(
HttpServletRequest request, HttpServletResponse response) {
String path = request.getParameter("struts_action");
if (_log.isDebugEnabled()) {
_log.debug("Getting request parameter path " + path);
}
if (Validator.isNull(path)) {
if (_log.isDebugEnabled()) {
_log.debug("Getting request attribute path " + path);
}
path = (String)request.getAttribute(WebKeys.PORTLET_STRUTS_ACTION);
}
if (path == null) {
LiferayPortletConfig liferayPortletConfig =
(LiferayPortletConfig)request.getAttribute(
JavaConstants.JAVAX_PORTLET_CONFIG);
_log.error(
liferayPortletConfig.getPortletName() +
" does not have any paths specified");
}
else {
if (_log.isDebugEnabled()) {
_log.debug("Processing path " + path);
}
request.removeAttribute(WebKeys.PORTLET_STRUTS_ACTION);
}
return path;
}
@Override
protected boolean processRoles(
HttpServletRequest request, HttpServletResponse response,
ActionMapping actionMapping)
throws IOException, ServletException {
return processRoles(request, response, actionMapping, false);
}
protected boolean processRoles(
HttpServletRequest request, HttpServletResponse response,
ActionMapping actionMapping, boolean action)
throws IOException, ServletException {
long companyId = PortalUtil.getCompanyId(request);
String path = actionMapping.getPath();
try {
LiferayPortletConfig liferayPortletConfig =
(LiferayPortletConfig)request.getAttribute(
JavaConstants.JAVAX_PORTLET_CONFIG);
Portlet portlet = PortletLocalServiceUtil.getPortletById(
companyId, liferayPortletConfig.getPortletId());
if (portlet == null) {
return false;
}
String strutsPath = path.substring(
1, path.lastIndexOf(CharPool.SLASH));
if (!strutsPath.equals(portlet.getStrutsPath()) &&
!strutsPath.equals(portlet.getParentStrutsPath())) {
throw new PrincipalException.MustBePortletStrutsPath(
strutsPath, portlet.getPortletId());
}
else if (!portlet.isActive()) {
ForwardConfig forwardConfig = actionMapping.findForward(
_PATH_PORTAL_PORTLET_INACTIVE);
if (!action) {
processForwardConfig(request, response, forwardConfig);
}
return false;
}
}
catch (Exception e) {
if (_log.isWarnEnabled()) {
_log.warn(e.getMessage());
}
ForwardConfig forwardConfig = actionMapping.findForward(
_PATH_PORTAL_PORTLET_ACCESS_DENIED);
if (!action) {
processForwardConfig(request, response, forwardConfig);
}
return false;
}
return true;
}
protected boolean processValidateAction(
HttpServletRequest request, HttpServletResponse response,
ActionForm actionForm, ActionMapping actionMapping) {
if (actionForm == null) {
return true;
}
if (request.getAttribute(Globals.CANCEL_KEY) != null) {
return true;
}
if (!actionMapping.getValidate()) {
return true;
}
ActionErrors errors = actionForm.validate(actionMapping, request);
if ((errors == null) || errors.isEmpty()) {
return true;
}
if (actionForm.getMultipartRequestHandler() != null) {
actionForm.getMultipartRequestHandler().rollback();
}
String input = actionMapping.getInput();
if (input == null) {
_log.error("Validation failed but no input form is available");
return false;
}
request.setAttribute(Globals.ERROR_KEY, errors);
// Struts normally calls internalModuleRelativeForward which breaks if
// called inside processAction
request.setAttribute(PortletAction.getForwardKey(request), input);
return false;
}
private static final String _PATH_PORTAL_PORTLET_ACCESS_DENIED =
"/portal/portlet_access_denied";
private static final String _PATH_PORTAL_PORTLET_INACTIVE =
"/portal/portlet_inactive";
private static final Log _log = LogFactoryUtil.getLog(
PortletRequestProcessor.class);
}