STR-3168: Extract out argument construction
git-svn-id: https://svn.apache.org/repos/asf/struts/struts1/trunk@721261 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/main/java/org/apache/struts/dispatcher/AbstractDispatcher.java b/core/src/main/java/org/apache/struts/dispatcher/AbstractDispatcher.java
index 782c0bf..27a2957 100644
--- a/core/src/main/java/org/apache/struts/dispatcher/AbstractDispatcher.java
+++ b/core/src/main/java/org/apache/struts/dispatcher/AbstractDispatcher.java
@@ -20,8 +20,6 @@
*/
package org.apache.struts.dispatcher;
-import org.apache.struts.action.ActionForm;
-import org.apache.struts.action.ActionMapping;
import org.apache.struts.chain.contexts.ActionContext;
import org.apache.struts.config.ActionConfig;
import org.apache.struts.util.MessageResources;
@@ -31,9 +29,6 @@
import java.lang.reflect.Method;
import java.util.HashMap;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -56,7 +51,6 @@
/**
* The name of the <code>cancelled</code> method.
*
- * @see #cancelled(ActionContext)
* @see ActionContext#getCancelled()
*/
public static final String CANCELLED_METHOD_NAME = "cancelled";
@@ -132,18 +126,11 @@
/**
* Dispatch to the specified method.
*
+ * @param context the current action context
* @param method The method to invoke
* @param name The name of the method to invoke
- * @param mapping The ActionMapping used to select this instance
- * @param form The optional ActionForm bean for this request (if any)
- * @param request The non-HTTP request we are processing
- * @param response The non-HTTP response we are creating
- *
- * @return The forward to which control should be transferred, or
- * <code>null</code> if the response has been completed.
+ * @return the return value of the method
* @throws Exception if the dispatch fails with an exception
- * @see #dispatchMethod(ActionMapping, ActionForm, HttpServletRequest,
- * HttpServletResponse, String)
*/
protected abstract Object dispatchMethod(ActionContext context, Method method, String name) throws Exception;
@@ -180,7 +167,7 @@
* @param methodName the name of the method to be introspected
* @return the method of the specified name
* @throws NoSuchMethodException if no such method can be found
- * @see #resolveMethod(String, ActionContext)
+ * @see #resolveMethod(ActionContext, String)
* @see #flushMethodCache()
*/
protected final Method getMethod(ActionContext context, String methodName) throws NoSuchMethodException {
@@ -255,15 +242,15 @@
/**
* Decides the appropriate method instance for the specified method name.
* Implementations may introspect for any desired method signature. This
- * resolution is only invoked if {@link #getMethod(String)} does not find a
+ * resolution is only invoked if {@link #getMethod(ActionContext, String)} does not find a
* match in its method cache.
*
* @param context the current action context
* @param methodName the method name to use for introspection
* @return the method to invoke
* @throws NoSuchMethodException if an appropriate method cannot be found
- * @see #getMethod(String)
- * @see #invoke(Object, Method, Object[], String, String)
+ * @see #getMethod(ActionContext, String)
+ * @see #invoke(Object, Method, Object[], String)
*/
protected abstract Method resolveMethod(ActionContext context, String methodName) throws NoSuchMethodException;
diff --git a/core/src/main/java/org/apache/struts/dispatcher/AbstractMappingDispatcher.java b/core/src/main/java/org/apache/struts/dispatcher/AbstractMappingDispatcher.java
index fb77b5c..d7e5c14 100644
--- a/core/src/main/java/org/apache/struts/dispatcher/AbstractMappingDispatcher.java
+++ b/core/src/main/java/org/apache/struts/dispatcher/AbstractMappingDispatcher.java
@@ -24,16 +24,22 @@
import org.apache.struts.chain.contexts.ActionContext;
/**
- * <p>
* This abstract class is a template for choosing the target method based on the
* <code>parameter</code> attribute of the {@link ActionMapping}.
- * </p>
*
* @version $Rev$
* @since Struts 1.4
*/
public abstract class AbstractMappingDispatcher extends AbstractDispatcher {
+ /**
+ * Resolves the method name by obtaining the <code>parameter</code>
+ * attribute from the {@link ActionMapping}.
+ *
+ * @param context {@inheritDoc}
+ * @throws IllegalStateException if the parameter is absent
+ * @return the parameter attribute value
+ */
protected String resolveMethodName(ActionContext context) {
// Null out an empty string parameter
ActionMapping mapping = (ActionMapping) context.getActionConfig();
@@ -42,6 +48,7 @@
parameter = null;
}
+ // Parameter is required
if ((parameter == null)) {
String message = messages.getMessage(MSG_KEY_MISSING_MAPPING_PARAMETER, mapping.getPath());
log.error(message);
diff --git a/core/src/main/java/org/apache/struts/dispatcher/AbstractParameterDispatcher.java b/core/src/main/java/org/apache/struts/dispatcher/AbstractParameterDispatcher.java
index 10f461d..f08ab10 100644
--- a/core/src/main/java/org/apache/struts/dispatcher/AbstractParameterDispatcher.java
+++ b/core/src/main/java/org/apache/struts/dispatcher/AbstractParameterDispatcher.java
@@ -23,27 +23,8 @@
import org.apache.struts.chain.contexts.ActionContext;
/**
- * <p>
* This abstract class is a template for choosing the target method based on a
- * servlet request parameter. It is based upon the functionality of
- * <code>org.apache.struts.actions.DispatchAction</code>.
- * </p>
- * <p>
- * To configure the use of this dispatcher in your configuration, create an
- * entry like below. The dispatcher will use the value of the request parameter
- * named "method" (or whatever specified) to pick the appropriate method on the
- * action.
- * </p>
- *
- * <code>
- * <action path="/saveSubscription"
- * dispatcher="org.apache.struts.dispatcher.servlet.ServletParameterDispatcher"
- * name="subscriptionForm"
- * scope="request"
- * input="/subscription.jsp"
- * parameter="method"/>
- * </code>
- * <p>
+ * servlet request parameter.
*
* @version $Rev$
* @since Struts 1.4
@@ -77,7 +58,7 @@
* <code>parameter</code> attribute; otherwise fallback to the default
* parameter name.
*
- * @param context the action context
+ * @param context the current action context
* @return the mapping's parameter name
* @see #getDefaultParameterName()
*/
@@ -102,6 +83,13 @@
return null;
}
+ /**
+ * Extracts the value that is keyed by the specified parameter.
+ *
+ * @param context the current action context
+ * @param parameter the parameter name
+ * @return the parameter value
+ */
protected abstract String resolveParameterValue(ActionContext context, String parameter);
}
diff --git a/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletMappingDispatcher.java b/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletMappingDispatcher.java
index a8661aa..b288173 100644
--- a/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletMappingDispatcher.java
+++ b/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletMappingDispatcher.java
@@ -29,11 +29,95 @@
import javax.servlet.http.HttpServletResponse;
+/**
+ * This servlet-based dispatcher uses the configuration value of the
+ * <code>parameter</code> attribute from the corresponding
+ * {@link org.apache.struts.action.ActionMapping} to pick the appropriate method
+ * on the action. Because mapping characteristics may differ between the various
+ * handlers, actions can be combined in the same class that, differ in their use
+ * of method signatures, forms, and/or validation.
+ * <p>
+ * For example, a single action may manage a subscription process by defining
+ * the following methods:
+ * <ul>
+ * <li><code>public ActionForward create(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * <li><code>public ActionForward delete(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * <li><code>public ActionForward edit(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * <li><code>public ActionForward list(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * <li><code>public ActionForward save(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * </ul>
+ * for which a corresponding configuration would exist:
+ *
+ * <pre><code>
+ * <action path="/createSubscription"
+ * type="org.example.SubscriptionAction"
+ * dispatcher="org.apache.struts.dispatcher.servlet.ServletMappingDispatcher"
+ * parameter="create">
+ * <forward path="/editSubscription.jsp"/>
+ * </action>
+ *
+ * <action path="/deleteSubscription"
+ * type="org.example.SubscriptionAction"
+ * dispatcher="org.apache.struts.dispatcher.servlet.ServletMappingDispatcher"
+ * parameter="delete"
+ * name="subscriptionForm"
+ * scope="request"
+ * input="/subscription.jsp">
+ * <forward path="/deletedSubscription.jsp"/>
+ * </action>
+ *
+ * <action path="/editSubscription"
+ * type="org.example.SubscriptionAction"
+ * dispatcher="org.apache.struts.dispatcher.servlet.ServletMappingDispatcher"
+ * parameter="edit">
+ * <forward path="/editSubscription.jsp"/>
+ * </action>
+ *
+ * <action path="/listSubscriptions"
+ * type="org.example.SubscriptionAction"
+ * dispatcher="org.apache.struts.dispatcher.servlet.ServletMappingDispatcher"
+ * parameter="list">
+ * <forward path="/subscriptionList.jsp"/>
+ * </action>
+ *
+ * <action path="/saveSubscription"
+ * type="org.example.SubscriptionAction"
+ * dispatcher="org.apache.struts.dispatcher.servlet.ServletMappingDispatcher"
+ * parameter="save"
+ * name="subscriptionForm"
+ * scope="request"
+ * validate="true"
+ * input="/editSubscription.jsp">
+ * <forward path="/savedSubscription.jsp"/>
+ * </action>
+ * </code></pre>
+ *
+ * @version $Rev$
+ * @since Struts 1.4
+ */
public class ServletMappingDispatcher extends AbstractMappingDispatcher {
- protected Object dispatchMethod(ActionContext context, Method method, String name) throws Exception {
+ /**
+ * Constructs the arguments that will be passed to the dispatched method.
+ *
+ * @param context the current action context
+ * @param method the target method of this dispatch
+ *
+ * @return the arguments array
+ * @see #dispatchMethod(ActionContext, Method, String)
+ */
+ protected Object[] buildMethodArguments(ServletActionContext context, Method method) {
+ return ServletDispatchUtils.buildClassicExecuteArguments(context);
+ }
+
+ protected final Object dispatchMethod(ActionContext context, Method method, String name) throws Exception {
Action target = context.getAction();
- Object[] args = ServletDispatchUtils.buildClassicExecuteArguments((ServletActionContext) context);
+ Object[] args = buildMethodArguments((ServletActionContext) context, method);
String path = context.getActionConfig().getPath();
return invoke(target, method, args, path);
}
@@ -42,6 +126,11 @@
return ServletDispatchUtils.resolveClassicExecuteMethod(context, methodName);
}
+ /**
+ * Sends the 404 HTTP error response.
+ *
+ * @return always <code>null</code> since the response is handled directly
+ */
protected Object unspecified(ActionContext context) throws Exception {
HttpServletResponse response = ((ServletActionContext) context).getResponse();
response.sendError(HttpServletResponse.SC_NOT_FOUND);
diff --git a/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletParameterDispatcher.java b/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletParameterDispatcher.java
index 5400557..c771983 100644
--- a/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletParameterDispatcher.java
+++ b/core/src/main/java/org/apache/struts/dispatcher/servlet/ServletParameterDispatcher.java
@@ -29,12 +29,70 @@
import javax.servlet.http.HttpServletResponse;
+/**
+ * This servlet-based dispatcher uses the value of the request parameter to pick
+ * the appropriate method on the action.
+ * <p>
+ * To configure the use of this dispatcher in your configuration, create an
+ * entry like below:
+ * <p>
+ * <code>
+ * <pre>
+ * <action path="/saveSubscription"
+ * type="org.example.SubscriptionAction"
+ * dispatcher="org.apache.struts.dispatcher.servlet.ServletParameterDispatcher"
+ * parameter="method"/>
+ * name="subscriptionForm"
+ * scope="request"
+ * input="/subscription.jsp"
+ * </pre>
+ * </code>
+ * <p>
+ * This example will use the value of the request parameter named "method" to
+ * pick the appropriate method, which must have the same signature (other than
+ * method name) of the standard
+ * {@link Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm,
+ * javax.servlet.ServletRequest, javax.servlet.ServletResponse) Action.execute}
+ * method. For example, you might have the following three methods in the same
+ * action:
+ *
+ * <ul>
+ * <li><code>public ActionForward delete(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * <li><code>public ActionForward insert(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * <li><code>public ActionForward update(ActionMapping mapping, ActionForm form,
+ * HttpServletRequest request, HttpServletResponse response) throws Exception</code></li>
+ * </ul>
+ * and call one of the methods with a URL like this:
+ * <p>
+ * <code>http://localhost:8080/myapp/saveSubscription.do?method=update</code>
+ *
+ * @version $Rev$
+ * @since Struts 1.4
+ */
public class ServletParameterDispatcher extends AbstractParameterDispatcher {
- protected Object dispatchMethod(ActionContext context, Method method, String name) throws Exception {
+ /**
+ * Constructs the arguments that will be passed to the dispatched method.
+ *
+ * @param context the current action context
+ * @param method the target method of this dispatch
+ *
+ * @return the arguments array
+ * @see #dispatchMethod(ActionContext, Method, String)
+ */
+ protected Object[] buildMethodArguments(ServletActionContext context, Method method) {
+ return ServletDispatchUtils.buildClassicExecuteArguments(context);
+ }
+
+ /**
+ * @see #buildMethodArguments(ServletActionContext, Method)
+ */
+ protected final Object dispatchMethod(ActionContext context, Method method, String name) throws Exception {
Action target = context.getAction();
- Object[] args = ServletDispatchUtils.buildClassicExecuteArguments((ServletActionContext) context);
String path = context.getActionConfig().getPath();
+ Object[] args = buildMethodArguments((ServletActionContext) context, method);
return invoke(target, method, args, path);
}
@@ -42,11 +100,25 @@
return ServletDispatchUtils.resolveClassicExecuteMethod(context, methodName);
}
+ /**
+ * Extracts the value from the specified servlet parameter.
+ *
+ * @param context {@inheritDoc}
+ * @param parameter the servlet parameter name
+ * @return the servlet parameter value
+ */
protected String resolveParameterValue(ActionContext context, String parameter) {
ServletActionContext servletContext = (ServletActionContext) context;
return (String) servletContext.getParam().get(parameter);
}
+ /**
+ * Sends the 404 HTTP error response.
+ *
+ * @param context {@inheritDoc}
+ * @return always <code>null</code> since the response is handled directly
+ * @throws Exception if the error code fails to set
+ */
protected Object unspecified(ActionContext context) throws Exception {
HttpServletResponse response = ((ServletActionContext) context).getResponse();
response.sendError(HttpServletResponse.SC_NOT_FOUND);