View Javadoc

1   /*
2    * $Id: EventDispatchAction.java 384133 2006-03-08 06:42:48Z niallp $
3    *
4    * Copyright 2006 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
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   *   &lt;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"/&gt;
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      // --------------------------------------------------------- Protected Methods
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             // The key can either be a direct method name or an alias
140             // to a method as indicated by a "key=value" signature
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             // Set the default if it passes by
148             if (methodKey.equals(DEFAULT_METHOD_KEY)) {
149                 defaultMethodName = methodName;
150             }
151 
152             // If the method key exists as a standalone parameter or with
153             // the image suffixes (.x/.y), the method name has been found.
154             if ((request.getParameter(methodKey) != null)
155                   || (request.getParameter(methodKey + ".x") != null)) {
156                 return methodName;
157             }
158         }
159 
160         return defaultMethodName;
161     }
162 }