KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > actions > DispatchAction


1 /*
2  * $Id: DispatchAction.java 54929 2004-10-16 16:38:42Z germuska $
3  *
4  * Copyright 2001-2004 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
19 package org.apache.struts.actions;
20
21 import java.lang.reflect.InvocationTargetException JavaDoc;
22 import java.lang.reflect.Method JavaDoc;
23 import java.util.HashMap JavaDoc;
24
25 import javax.servlet.ServletException JavaDoc;
26 import javax.servlet.http.HttpServletRequest JavaDoc;
27 import javax.servlet.http.HttpServletResponse JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.struts.action.Action;
32 import org.apache.struts.action.ActionForm;
33 import org.apache.struts.action.ActionForward;
34 import org.apache.struts.action.ActionMapping;
35 import org.apache.struts.util.MessageResources;
36
37 /**
38  * <p>An abstract <strong>Action</strong> that dispatches to a public
39  * method that is named by the request parameter whose name is specified
40  * by the <code>parameter</code> property of the corresponding
41  * ActionMapping. This Action is useful for developers who prefer to
42  * combine many similar actions into a single Action class, in order to
43  * simplify their application design.</p>
44  *
45  * <p>To configure the use of this action in your
46  * <code>struts-config.xml</code> file, create an entry like this:</p>
47  *
48  * <code>
49  * &lt;action path="/saveSubscription"
50  * type="org.apache.struts.actions.DispatchAction"
51  * name="subscriptionForm"
52  * scope="request"
53  * input="/subscription.jsp"
54  * parameter="method"/&gt;
55  * </code>
56  *
57  * <p>which will use the value of the request parameter named "method"
58  * to pick the appropriate "execute" method, which must have the same
59  * signature (other than method name) of the standard Action.execute
60  * method. For example, you might have the following three methods in the
61  * same action:</p>
62  * <ul>
63  * <li>public ActionForward delete(ActionMapping mapping, ActionForm form,
64  * HttpServletRequest request, HttpServletResponse response)
65  * throws Exception</li>
66  * <li>public ActionForward insert(ActionMapping mapping, ActionForm form,
67  * HttpServletRequest request, HttpServletResponse response)
68  * throws Exception</li>
69  * <li>public ActionForward update(ActionMapping mapping, ActionForm form,
70  * HttpServletRequest request, HttpServletResponse response)
71  * throws Exception</li>
72  * </ul>
73  * <p>and call one of the methods with a URL like this:</p>
74  * <code>
75  * http://localhost:8080/myapp/saveSubscription.do?method=update
76  * </code>
77  *
78  * <p><strong>NOTE</strong> - All of the other mapping characteristics of
79  * this action must be shared by the various handlers. This places some
80  * constraints over what types of handlers may reasonably be packaged into
81  * the same <code>DispatchAction</code> subclass.</p>
82  *
83  * <p><strong>NOTE</strong> - If the value of the request parameter is empty,
84  * a method named <code>unspecified</code> is called. The default action is
85  * to throw an exception. If the request was cancelled (a <code>html:cancel</code>
86  * button was pressed), the custom handler <code>cancelled</code> will be used instead.
87  * You can also override the <code>getMethodName</code> method to override the action's
88  * default handler selection.</p>
89  *
90  * @version $Rev: 54929 $ $Date: 2004-10-16 17:38:42 +0100 (Sat, 16 Oct 2004) $
91  */

92 public abstract class DispatchAction extends Action {
93
94
95     // ----------------------------------------------------- Instance Variables
96

97
98     /**
99      * The Class instance of this <code>DispatchAction</code> class.
100      */

101     protected Class JavaDoc clazz = this.getClass();
102
103
104     /**
105      * Commons Logging instance.
106      */

107     protected static Log log = LogFactory.getLog(DispatchAction.class);
108
109
110     /**
111      * The message resources for this package.
112      */

113     protected static MessageResources messages =
114             MessageResources.getMessageResources
115             ("org.apache.struts.actions.LocalStrings");
116
117
118     /**
119      * The set of Method objects we have introspected for this class,
120      * keyed by method name. This collection is populated as different
121      * methods are called, so that introspection needs to occur only
122      * once per method name.
123      */

124     protected HashMap JavaDoc methods = new HashMap JavaDoc();
125
126
127     /**
128      * The set of argument type classes for the reflected method call. These
129      * are the same for all calls, so calculate them only once.
130      */

131     protected Class JavaDoc[] types =
132             {
133                 ActionMapping.class,
134                 ActionForm.class,
135                 HttpServletRequest JavaDoc.class,
136                 HttpServletResponse JavaDoc.class};
137
138
139
140     // --------------------------------------------------------- Public Methods
141

142
143     /**
144      * Process the specified HTTP request, and create the corresponding HTTP
145      * response (or forward to another web component that will create it).
146      * Return an <code>ActionForward</code> instance describing where and how
147      * control should be forwarded, or <code>null</code> if the response has
148      * already been completed.
149      *
150      * @param mapping The ActionMapping used to select this instance
151      * @param form The optional ActionForm bean for this request (if any)
152      * @param request The HTTP request we are processing
153      * @param response The HTTP response we are creating
154      *
155      * @exception Exception if an exception occurs
156      */

157     public ActionForward execute(ActionMapping mapping,
158                                  ActionForm form,
159                                  HttpServletRequest JavaDoc request,
160                                  HttpServletResponse JavaDoc response)
161             throws Exception JavaDoc {
162         if (isCancelled(request)) {
163             ActionForward af = cancelled(mapping, form, request, response);
164             if (af != null) {
165                 return af;
166             }
167         }
168         // Identify the request parameter containing the method name
169
String JavaDoc parameter = mapping.getParameter();
170         if (parameter == null) {
171             String JavaDoc message =
172                     messages.getMessage("dispatch.handler", mapping.getPath());
173
174             log.error(message);
175
176             throw new ServletException JavaDoc(message);
177         }
178
179         // Get the method's name. This could be overridden in subclasses.
180
String JavaDoc name = getMethodName(mapping, form, request, response, parameter);
181
182
183     // Prevent recursive calls
184
if ("execute".equals(name) || "perform".equals(name)){
185         String JavaDoc message =
186             messages.getMessage("dispatch.recursive", mapping.getPath());
187
188         log.error(message);
189         throw new ServletException JavaDoc(message);
190     }
191
192
193         // Invoke the named method, and return the result
194
return dispatchMethod(mapping, form, request, response, name);
195
196     }
197
198
199
200     
201     /**
202      * Method which is dispatched to when there is no value for specified
203      * request parameter included in the request. Subclasses of
204      * <code>DispatchAction</code> should override this method if they wish
205      * to provide default behavior different than throwing a ServletException.
206      */

207     protected ActionForward unspecified(
208             ActionMapping mapping,
209             ActionForm form,
210             HttpServletRequest JavaDoc request,
211             HttpServletResponse JavaDoc response)
212             throws Exception JavaDoc {
213
214         String JavaDoc message =
215                 messages.getMessage(
216                         "dispatch.parameter",
217                         mapping.getPath(),
218                         mapping.getParameter());
219
220         log.error(message);
221
222         throw new ServletException JavaDoc(message);
223     }
224
225     /**
226      * Method which is dispatched to when the request is a cancel button submit.
227      * Subclasses of <code>DispatchAction</code> should override this method if
228      * they wish to provide default behavior different than returning null.
229      * @since Struts 1.2.0
230      */

231     protected ActionForward cancelled(ActionMapping mapping,
232                                       ActionForm form,
233                                       HttpServletRequest JavaDoc request,
234                                       HttpServletResponse JavaDoc response)
235             throws Exception JavaDoc {
236
237         return null;
238     }
239
240     // ----------------------------------------------------- Protected Methods
241

242
243     /**
244      * Dispatch to the specified method.
245      * @since Struts 1.1
246      */

247     protected ActionForward dispatchMethod(ActionMapping mapping,
248                                            ActionForm form,
249                                            HttpServletRequest JavaDoc request,
250                                            HttpServletResponse JavaDoc response,
251                                            String JavaDoc name) throws Exception JavaDoc {
252
253         // Make sure we have a valid method name to call.
254
// This may be null if the user hacks the query string.
255
if (name == null) {
256             return this.unspecified(mapping, form, request, response);
257         }
258
259         // Identify the method object to be dispatched to
260
Method JavaDoc method = null;
261         try {
262             method = getMethod(name);
263
264         } catch(NoSuchMethodException JavaDoc e) {
265             String JavaDoc message =
266                     messages.getMessage("dispatch.method", mapping.getPath(), name);
267             log.error(message, e);
268             throw e;
269         }
270
271         ActionForward forward = null;
272         try {
273             Object JavaDoc args[] = {mapping, form, request, response};
274             forward = (ActionForward) method.invoke(this, args);
275
276         } catch(ClassCastException JavaDoc e) {
277             String JavaDoc message =
278                     messages.getMessage("dispatch.return", mapping.getPath(), name);
279             log.error(message, e);
280             throw e;
281
282         } catch(IllegalAccessException JavaDoc e) {
283             String JavaDoc message =
284                     messages.getMessage("dispatch.error", mapping.getPath(), name);
285             log.error(message, e);
286             throw e;
287
288         } catch(InvocationTargetException JavaDoc e) {
289             // Rethrow the target exception if possible so that the
290
// exception handling machinery can deal with it
291
Throwable JavaDoc t = e.getTargetException();
292             if (t instanceof Exception JavaDoc) {
293                 throw ((Exception JavaDoc) t);
294             } else {
295                 String JavaDoc message =
296                         messages.getMessage("dispatch.error", mapping.getPath(), name);
297                 log.error(message, e);
298                 throw new ServletException JavaDoc(t);
299             }
300         }
301
302         // Return the returned ActionForward instance
303
return (forward);
304     }
305
306
307     /**
308      * Introspect the current class to identify a method of the specified
309      * name that accepts the same parameter types as the <code>execute</code>
310      * method does.
311      *
312      * @param name Name of the method to be introspected
313      *
314      * @exception NoSuchMethodException if no such method can be found
315      */

316     protected Method JavaDoc getMethod(String JavaDoc name)
317             throws NoSuchMethodException JavaDoc {
318
319         synchronized(methods) {
320             Method JavaDoc method = (Method JavaDoc) methods.get(name);
321             if (method == null) {
322                 method = clazz.getMethod(name, types);
323                 methods.put(name, method);
324             }
325             return (method);
326         }
327
328     }
329
330     /**
331      * Returns the method name, given a parameter's value.
332      *
333      * @param mapping The ActionMapping used to select this instance
334      * @param form The optional ActionForm bean for this request (if any)
335      * @param request The HTTP request we are processing
336      * @param response The HTTP response we are creating
337      * @param parameter The <code>ActionMapping</code> parameter's name
338      *
339      * @return The method's name.
340      * @since Struts 1.2.0
341      */

342     protected String JavaDoc getMethodName(ActionMapping mapping,
343                                    ActionForm form,
344                                    HttpServletRequest JavaDoc request,
345                                    HttpServletResponse JavaDoc response,
346                                    String JavaDoc parameter)
347             throws Exception JavaDoc {
348
349         // Identify the method name to be dispatched to.
350
// dispatchMethod() will call unspecified() if name is null
351
return request.getParameter(parameter);
352     }
353
354 }
355
Popular Tags