1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.actions;
19
20 import java.util.StringTokenizer;
21
22 import javax.servlet.ServletException;
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.struts.action.ActionForm;
29 import org.apache.struts.action.ActionMapping;
30 import org.apache.struts.action.ActionForward;
31
32 /***
33 * <p>An <strong>Action</strong> that dispatches to to one of the public methods
34 * that are named in the <code>parameter</code> attribute of the corresponding
35 * ActionMapping and matches a submission parameter. This is useful for
36 * developers who prefer to use many submit buttons, images, or submit links
37 * on a single form and whose related actions exist in a single Action class.</p>
38 *
39 * <p>The method(s) must have the same signature (other than method name) of the
40 * standard Action.execute method.</p>
41 *
42 * <p>To configure the use of this action in your
43 * <code>struts-config.xml</code> file, create an entry like this:</p>
44 *
45 * <pre><code>
46 * <action path="/saveSubscription"
47 * type="org.example.SubscriptionAction"
48 * name="subscriptionForm"
49 * scope="request"
50 * input="/subscription.jsp"
51 * parameter="save,back,recalc=recalculate,default=save"/>
52 * </code></pre>
53 *
54 * <p>where <code>parameter</code> contains three possible methods and one
55 * default method if nothing matches (such as the user pressing the enter key).</p>
56 *
57 * <p>For utility purposes, you can use the <code>key=value</code> notation to
58 * alias methods so that they are exposed as different form element names, in the
59 * event of a naming conflict or otherwise. In this example, the <em>recalc</em>
60 * button (via a request parameter) will invoke the <code>recalculate</code>
61 * method. The security-minded person may find this feature valuable to
62 * obfuscate and not expose the methods.</p>
63 *
64 * <p>The <em>default</em> key is purely optional. If this is not specified
65 * and no parameters match the list of method keys, <code>null</code> is
66 * returned which means the <code>unspecified</code> method will be invoked.</p>
67 *
68 * <p>The order of the parameters are guaranteed to be iterated in the order
69 * specified. If multiple buttons were accidently submitted, the first match in
70 * the list will be dispatched.</p>
71 *
72 * @since Struts 1.2.9
73 */
74 public class EventDispatchAction extends DispatchAction {
75
76 /***
77 * Commons Logging instance.
78 */
79 private static final Log LOG = LogFactory.getLog(EventDispatchAction.class);
80
81 /***
82 * The method key, if present, to use if other specified method keys
83 * do not match a request parameter.
84 */
85 private static final String DEFAULT_METHOD_KEY = "default";
86
87
88
89 /***
90 * Method which is dispatched to when there is no value for specified
91 * request parameter included in the request. Subclasses of
92 * <code>DispatchAction</code> should override this method if they wish to
93 * provide default behavior different than throwing a ServletException.
94 *
95 * @param mapping The ActionMapping used to select this instance
96 * @param form The optional ActionForm bean for this request (if any)
97 * @param request The non-HTTP request we are processing
98 * @param response The non-HTTP response we are creating
99 * @return The forward to which control should be transferred, or
100 * <code>null</code> if the response has been completed.
101 * @throws Exception if the application business logic throws an
102 * exception.
103 */
104 protected ActionForward unspecified(ActionMapping mapping, ActionForm form,
105 HttpServletRequest request, HttpServletResponse response)
106 throws Exception {
107 String message =
108 messages.getMessage("event.parameter", mapping.getPath(),
109 mapping.getParameter());
110
111 LOG.error(message + " " + mapping.getParameter());
112
113 throw new ServletException(message);
114 }
115
116 /***
117 * Returns the method name, given a parameter's value.
118 *
119 * @param mapping The ActionMapping used to select this instance
120 * @param form The optional ActionForm bean for this request (if
121 * any)
122 * @param request The HTTP request we are processing
123 * @param response The HTTP response we are creating
124 * @param parameter The <code>ActionMapping</code> parameter's name
125 * @return The method's name.
126 * @throws Exception if an error occurs.
127 */
128 protected String getMethodName(ActionMapping mapping, ActionForm form,
129 HttpServletRequest request, HttpServletResponse response,
130 String parameter) throws Exception {
131
132 StringTokenizer st = new StringTokenizer(parameter, ",");
133 String defaultMethodName = null;
134
135 while (st.hasMoreTokens()) {
136 String methodKey = st.nextToken().trim();
137 String methodName = methodKey;
138
139
140
141 int equals = methodKey.indexOf('=');
142 if (equals > -1) {
143 methodName = methodKey.substring(equals + 1).trim();
144 methodKey = methodKey.substring(0, equals).trim();
145 }
146
147
148 if (methodKey.equals(DEFAULT_METHOD_KEY)) {
149 defaultMethodName = methodName;
150 }
151
152
153
154 if ((request.getParameter(methodKey) != null)
155 || (request.getParameter(methodKey + ".x") != null)) {
156 return methodName;
157 }
158 }
159
160 return defaultMethodName;
161 }
162 }