415 lines
16 KiB
Java
415 lines
16 KiB
Java
package org.apache.struts.action;
|
|
|
|
import java.io.IOException;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.Locale;
|
|
import javax.servlet.RequestDispatcher;
|
|
import javax.servlet.ServletContext;
|
|
import javax.servlet.ServletException;
|
|
import javax.servlet.ServletRequest;
|
|
import javax.servlet.ServletResponse;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import javax.servlet.http.HttpSession;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.apache.struts.config.ActionConfig;
|
|
import org.apache.struts.config.ExceptionConfig;
|
|
import org.apache.struts.config.ForwardConfig;
|
|
import org.apache.struts.config.ModuleConfig;
|
|
import org.apache.struts.upload.MultipartRequestWrapper;
|
|
import org.apache.struts.util.MessageResources;
|
|
import org.apache.struts.util.RequestUtils;
|
|
|
|
public class RequestProcessor {
|
|
public static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
|
|
|
|
public static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
|
|
|
|
protected HashMap actions = new HashMap();
|
|
|
|
protected ModuleConfig appConfig = null;
|
|
|
|
protected ModuleConfig moduleConfig = null;
|
|
|
|
protected static Log log = LogFactory.getLog(RequestProcessor.class);
|
|
|
|
protected ActionServlet servlet = null;
|
|
|
|
public void destroy() {
|
|
synchronized (this.actions) {
|
|
Iterator actions = this.actions.values().iterator();
|
|
while (actions.hasNext()) {
|
|
Action action = actions.next();
|
|
action.setServlet(null);
|
|
}
|
|
this.actions.clear();
|
|
}
|
|
this.servlet = null;
|
|
}
|
|
|
|
public void init(ActionServlet servlet, ModuleConfig moduleConfig) throws ServletException {
|
|
synchronized (this.actions) {
|
|
this.actions.clear();
|
|
}
|
|
this.servlet = servlet;
|
|
this.appConfig = moduleConfig;
|
|
this.moduleConfig = moduleConfig;
|
|
}
|
|
|
|
public void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
request = processMultipart(request);
|
|
String path = processPath(request, response);
|
|
if (path == null)
|
|
return;
|
|
if (log.isDebugEnabled())
|
|
log.debug("Processing a '" + request.getMethod() + "' for path '" + path + "'");
|
|
processLocale(request, response);
|
|
processContent(request, response);
|
|
processNoCache(request, response);
|
|
if (!processPreprocess(request, response))
|
|
return;
|
|
ActionMapping mapping = processMapping(request, response, path);
|
|
if (mapping == null)
|
|
return;
|
|
if (!processRoles(request, response, mapping))
|
|
return;
|
|
ActionForm form = processActionForm(request, response, mapping);
|
|
processPopulate(request, response, form, mapping);
|
|
if (!processValidate(request, response, form, mapping))
|
|
return;
|
|
if (!processForward(request, response, mapping))
|
|
return;
|
|
if (!processInclude(request, response, mapping))
|
|
return;
|
|
Action action = processActionCreate(request, response, mapping);
|
|
if (action == null)
|
|
return;
|
|
ActionForward forward = processActionPerform(request, response, action, form, mapping);
|
|
processForwardConfig(request, response, forward);
|
|
}
|
|
|
|
protected Action processActionCreate(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException {
|
|
String className = mapping.getType();
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Looking for Action instance for class " + className);
|
|
Action instance = null;
|
|
synchronized (this.actions) {
|
|
instance = (Action)this.actions.get(className);
|
|
if (instance != null) {
|
|
if (log.isTraceEnabled())
|
|
log.trace(" Returning existing Action instance");
|
|
return instance;
|
|
}
|
|
if (log.isTraceEnabled())
|
|
log.trace(" Creating new Action instance");
|
|
try {
|
|
instance = (Action)RequestUtils.applicationInstance(className);
|
|
} catch (Exception e) {
|
|
log.error(getInternal().getMessage("actionCreate", mapping.getPath()), e);
|
|
response.sendError(500, getInternal().getMessage("actionCreate", mapping.getPath()));
|
|
return null;
|
|
}
|
|
instance.setServlet(this.servlet);
|
|
this.actions.put(className, instance);
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
protected ActionForm processActionForm(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) {
|
|
ActionForm instance = RequestUtils.createActionForm(request, mapping, this.moduleConfig, this.servlet);
|
|
if (instance == null)
|
|
return null;
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Storing ActionForm bean instance in scope '" + mapping.getScope() + "' under attribute key '" + mapping.getAttribute() + "'");
|
|
if ("request".equals(mapping.getScope())) {
|
|
request.setAttribute(mapping.getAttribute(), instance);
|
|
} else {
|
|
HttpSession session = request.getSession();
|
|
session.setAttribute(mapping.getAttribute(), instance);
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
protected void processActionForward(HttpServletRequest request, HttpServletResponse response, ActionForward forward) throws IOException, ServletException {
|
|
processForwardConfig(request, response, forward);
|
|
}
|
|
|
|
protected void processForwardConfig(HttpServletRequest request, HttpServletResponse response, ForwardConfig forward) throws IOException, ServletException {
|
|
if (forward == null)
|
|
return;
|
|
if (log.isDebugEnabled())
|
|
log.debug("processForwardConfig(" + forward + ")");
|
|
String forwardPath = forward.getPath();
|
|
String uri = null;
|
|
if (forwardPath.startsWith("/")) {
|
|
uri = RequestUtils.forwardURL(request, forward);
|
|
} else {
|
|
uri = forwardPath;
|
|
}
|
|
if (forward.getRedirect()) {
|
|
if (uri.startsWith("/"))
|
|
uri = request.getContextPath() + uri;
|
|
response.sendRedirect(response.encodeRedirectURL(uri));
|
|
} else {
|
|
doForward(uri, request, response);
|
|
}
|
|
}
|
|
|
|
protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException {
|
|
try {
|
|
return action.execute(mapping, form, request, response);
|
|
} catch (Exception e) {
|
|
return processException(request, response, e, form, mapping);
|
|
}
|
|
}
|
|
|
|
protected void processContent(HttpServletRequest request, HttpServletResponse response) {
|
|
String contentType = this.moduleConfig.getControllerConfig().getContentType();
|
|
if (contentType != null)
|
|
response.setContentType(contentType);
|
|
}
|
|
|
|
protected ActionForward processException(HttpServletRequest request, HttpServletResponse response, Exception exception, ActionForm form, ActionMapping mapping) throws IOException, ServletException {
|
|
ExceptionConfig config = mapping.findException(exception.getClass());
|
|
if (config == null) {
|
|
log.warn(getInternal().getMessage("unhandledException", exception.getClass()));
|
|
if (exception instanceof IOException)
|
|
throw (IOException)exception;
|
|
if (exception instanceof ServletException)
|
|
throw (ServletException)exception;
|
|
throw new ServletException(exception);
|
|
}
|
|
try {
|
|
ExceptionHandler handler = (ExceptionHandler)RequestUtils.applicationInstance(config.getHandler());
|
|
return handler.execute(exception, config, mapping, form, request, response);
|
|
} catch (Exception e) {
|
|
throw new ServletException(e);
|
|
}
|
|
}
|
|
|
|
protected boolean processForward(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException, ServletException {
|
|
String forward = mapping.getForward();
|
|
if (forward == null)
|
|
return true;
|
|
internalModuleRelativeForward(forward, request, response);
|
|
return false;
|
|
}
|
|
|
|
protected boolean processInclude(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException, ServletException {
|
|
String include = mapping.getInclude();
|
|
if (include == null)
|
|
return true;
|
|
internalModuleRelativeInclude(include, request, response);
|
|
return false;
|
|
}
|
|
|
|
protected void processLocale(HttpServletRequest request, HttpServletResponse response) {
|
|
if (!this.moduleConfig.getControllerConfig().getLocale())
|
|
return;
|
|
HttpSession session = request.getSession();
|
|
if (session.getAttribute("org.apache.struts.action.LOCALE") != null)
|
|
return;
|
|
Locale locale = request.getLocale();
|
|
if (locale != null) {
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Setting user locale '" + locale + "'");
|
|
session.setAttribute("org.apache.struts.action.LOCALE", locale);
|
|
}
|
|
}
|
|
|
|
protected ActionMapping processMapping(HttpServletRequest request, HttpServletResponse response, String path) throws IOException {
|
|
ActionMapping mapping = (ActionMapping)this.moduleConfig.findActionConfig(path);
|
|
if (mapping != null) {
|
|
request.setAttribute("org.apache.struts.action.mapping.instance", mapping);
|
|
return mapping;
|
|
}
|
|
ActionConfig[] configs = this.moduleConfig.findActionConfigs();
|
|
for (int i = 0; i < configs.length; i++) {
|
|
if (configs[i].getUnknown()) {
|
|
mapping = (ActionMapping)configs[i];
|
|
request.setAttribute("org.apache.struts.action.mapping.instance", mapping);
|
|
return mapping;
|
|
}
|
|
}
|
|
log.error(getInternal().getMessage("processInvalid", path));
|
|
response.sendError(400, getInternal().getMessage("processInvalid", path));
|
|
return null;
|
|
}
|
|
|
|
protected HttpServletRequest processMultipart(HttpServletRequest request) {
|
|
if (!"POST".equalsIgnoreCase(request.getMethod()))
|
|
return request;
|
|
String contentType = request.getContentType();
|
|
if (contentType != null && contentType.startsWith("multipart/form-data"))
|
|
return (HttpServletRequest)new MultipartRequestWrapper(request);
|
|
return request;
|
|
}
|
|
|
|
protected void processNoCache(HttpServletRequest request, HttpServletResponse response) {
|
|
if (this.moduleConfig.getControllerConfig().getNocache()) {
|
|
response.setHeader("Pragma", "No-cache");
|
|
response.setHeader("Cache-Control", "no-cache");
|
|
response.setDateHeader("Expires", 1L);
|
|
}
|
|
}
|
|
|
|
protected String processPath(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
|
String path = null;
|
|
path = (String)request.getAttribute("javax.servlet.include.path_info");
|
|
if (path == null)
|
|
path = request.getPathInfo();
|
|
if (path != null && path.length() > 0)
|
|
return path;
|
|
path = (String)request.getAttribute("javax.servlet.include.servlet_path");
|
|
if (path == null)
|
|
path = request.getServletPath();
|
|
String prefix = this.moduleConfig.getPrefix();
|
|
if (!path.startsWith(prefix)) {
|
|
log.error(getInternal().getMessage("processPath", request.getRequestURI()));
|
|
response.sendError(400, getInternal().getMessage("processPath", request.getRequestURI()));
|
|
return null;
|
|
}
|
|
path = path.substring(prefix.length());
|
|
int slash = path.lastIndexOf("/");
|
|
int period = path.lastIndexOf(".");
|
|
if (period >= 0 && period > slash)
|
|
path = path.substring(0, period);
|
|
return path;
|
|
}
|
|
|
|
protected void processPopulate(HttpServletRequest request, HttpServletResponse response, ActionForm form, ActionMapping mapping) throws ServletException {
|
|
if (form == null)
|
|
return;
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Populating bean properties from this request");
|
|
form.setServlet(this.servlet);
|
|
form.reset(mapping, request);
|
|
if (mapping.getMultipartClass() != null)
|
|
request.setAttribute("org.apache.struts.action.mapping.multipartclass", mapping.getMultipartClass());
|
|
RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix(), request);
|
|
if (request.getParameter("org.apache.struts.taglib.html.CANCEL") != null || request.getParameter("org.apache.struts.taglib.html.CANCEL.x") != null)
|
|
request.setAttribute("org.apache.struts.action.CANCEL", Boolean.TRUE);
|
|
}
|
|
|
|
protected boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) {
|
|
return true;
|
|
}
|
|
|
|
protected boolean processRoles(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException, ServletException {
|
|
String[] roles = mapping.getRoleNames();
|
|
if (roles == null || roles.length < 1)
|
|
return true;
|
|
for (int i = 0; i < roles.length; i++) {
|
|
if (request.isUserInRole(roles[i])) {
|
|
if (log.isDebugEnabled())
|
|
log.debug(" User '" + request.getRemoteUser() + "' has role '" + roles[i] + "', granting access");
|
|
return true;
|
|
}
|
|
}
|
|
if (log.isDebugEnabled())
|
|
log.debug(" User '" + request.getRemoteUser() + "' does not have any required role, denying access");
|
|
response.sendError(400, getInternal().getMessage("notAuthorized", mapping.getPath()));
|
|
return false;
|
|
}
|
|
|
|
protected boolean processValidate(HttpServletRequest request, HttpServletResponse response, ActionForm form, ActionMapping mapping) throws IOException, ServletException {
|
|
if (form == null)
|
|
return true;
|
|
if (request.getAttribute("org.apache.struts.action.CANCEL") != null) {
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Cancelled transaction, skipping validation");
|
|
return true;
|
|
}
|
|
if (!mapping.getValidate())
|
|
return true;
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Validating input form properties");
|
|
ActionErrors errors = form.validate(mapping, request);
|
|
if (errors == null || errors.isEmpty()) {
|
|
if (log.isTraceEnabled())
|
|
log.trace(" No errors detected, accepting input");
|
|
return true;
|
|
}
|
|
if (form.getMultipartRequestHandler() != null) {
|
|
if (log.isTraceEnabled())
|
|
log.trace(" Rolling back multipart request");
|
|
form.getMultipartRequestHandler().rollback();
|
|
}
|
|
String input = mapping.getInput();
|
|
if (input == null) {
|
|
if (log.isTraceEnabled())
|
|
log.trace(" Validation failed but no input form available");
|
|
response.sendError(500, getInternal().getMessage("noInput", mapping.getPath()));
|
|
return false;
|
|
}
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Validation failed, returning to '" + input + "'");
|
|
request.setAttribute("org.apache.struts.action.ERROR", errors);
|
|
if (this.moduleConfig.getControllerConfig().getInputForward()) {
|
|
ForwardConfig forward = mapping.findForward(input);
|
|
processForwardConfig(request, response, forward);
|
|
} else {
|
|
internalModuleRelativeForward(input, request, response);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected void internalModuleRelativeForward(String uri, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
uri = this.moduleConfig.getPrefix() + uri;
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Delegating via forward to '" + uri + "'");
|
|
doForward(uri, request, response);
|
|
}
|
|
|
|
protected void internalModuleRelativeInclude(String uri, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
uri = this.moduleConfig.getPrefix() + uri;
|
|
if (log.isDebugEnabled())
|
|
log.debug(" Delegating via include to '" + uri + "'");
|
|
doInclude(uri, request, response);
|
|
}
|
|
|
|
protected void doForward(String uri, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
if (request instanceof MultipartRequestWrapper)
|
|
request = ((MultipartRequestWrapper)request).getRequest();
|
|
RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
|
|
if (rd == null) {
|
|
response.sendError(500, getInternal().getMessage("requestDispatcher", uri));
|
|
return;
|
|
}
|
|
rd.forward((ServletRequest)request, (ServletResponse)response);
|
|
}
|
|
|
|
protected void doInclude(String uri, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
if (request instanceof MultipartRequestWrapper)
|
|
request = ((MultipartRequestWrapper)request).getRequest();
|
|
RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
|
|
if (rd == null) {
|
|
response.sendError(500, getInternal().getMessage("requestDispatcher", uri));
|
|
return;
|
|
}
|
|
rd.include((ServletRequest)request, (ServletResponse)response);
|
|
}
|
|
|
|
public int getDebug() {
|
|
return this.servlet.getDebug();
|
|
}
|
|
|
|
protected MessageResources getInternal() {
|
|
return this.servlet.getInternal();
|
|
}
|
|
|
|
protected ServletContext getServletContext() {
|
|
return this.servlet.getServletContext();
|
|
}
|
|
|
|
protected void log(String message) {
|
|
this.servlet.log(message);
|
|
}
|
|
|
|
protected void log(String message, Throwable exception) {
|
|
this.servlet.log(message, exception);
|
|
}
|
|
}
|