View Javadoc

1   /*
2    * Copyright 2000-2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.ibatis.struts;
17  
18  import org.apache.struts.action.Action;
19  import org.apache.struts.action.ActionForm;
20  import org.apache.struts.action.ActionForward;
21  import org.apache.struts.action.ActionMapping;
22  
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  import java.lang.reflect.Method;
26  
27  /***
28   * BeanAction is an extension to the typical Struts Action class that
29   * enables mappings to bean methods.  This allows for a more typical
30   * Object Oriented design where each object has behaviour as part of
31   * its definition.  Instead of writing separate Actions and Forms,
32   * BeanAction allows you to simply have a Bean, which models both
33   * the state and the methods that operate on that state.
34   * <p/>
35   * In addition to the simpler packaging, BeanAction also simplifies the
36   * Struts progamming paradigm and reduces dependency on Struts.  Using
37   * this pattern could allow easier migration to newer frameworks like JSF.
38   * <p/>
39   * The method signatures are greatly simplified to the following
40   * <pre>
41   * public String myActionMethod() {
42   *   //..work
43   *   return "success";
44   * }
45   * </pre>
46   * The return parameter becomes simply the name of the forward (as defined
47   * in the config file as usual).  Form parameters, request, response, session,
48   * attributes, and cookies are all accessed via the ActionContext class (see the
49   * ActionContext javadocs for more).
50   * <p/>
51   * The forms that you map to a BaseAction mapping must be a subclass of the
52   * BaseBean class.  BaseBean continues to simplify the validation and
53   * reset methods by removing the parameters from the signature as was done with
54   * the above action method example.
55   * <p/>
56   * There are 3 ways to map a BeanAction in the struts configuration file.
57   * They are as follows.
58   * <p/>
59   * <B>URL Pattern</B>
60   * <p/>
61   * This approach uses the end of the action definition to determine which
62   * method to call on the Bean.  For example if you request the URL:
63   * <p/>
64   * http://localhost/jpetstore4/shop/viewOrder.do
65   * <p/>
66   * Then the method called would be "viewOrder" (of the mapped bean as specified
67   * by the name="" parameter in the mapping below).  The mapping used for this
68   * approach is as follows.
69   * <pre>
70   *  &lt;action path="/shop/<b>viewOrder</b>" type="com.ibatis.struts.BeanAction"
71   *    name="orderBean" scope="session"
72   *    validate="false"&gt;
73   *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
74   *  &lt;/action&gt;
75   * </pre>
76   *
77   * <B>Method Parameter</B>
78   * <p/>
79   * This approach uses the Struts action parameter within the mapping
80   * to determine the method to call on the Bean.  For example the
81   * following action mapping would cause the "viewOrder" method to
82   * be called on the bean ("orderBean").  The mapping used for this
83   * approach is as follows.
84   * <pre>
85   *  &lt;action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
86   *    <b>name="orderBean" parameter="viewOrder"</b> scope="session"
87   *    validate="false"&gt;
88   *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
89   *  &lt;/action&gt;
90   * </pre>
91   * <B>No Method call</B>
92   * <p/>
93   * BeanAction will ignore any Struts action mappings without beans associated
94   * to them (i.e. no name="" attribute in the mapping).  If you do want to associate
95   * a bean to the action mapping, but do not want a method to be called, simply
96   * set the parameter to an asterisk ("*").  The mapping used for this approach
97   * is as follows (no method will be called).
98   * <pre>
99   *  &lt;action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
100  *    <b>name="orderBean" parameter="*"</b> scope="session"
101  *    validate="false"&gt;
102  *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
103  *  &lt;/action&gt;
104  * </pre>
105  * <p/>
106  * <B>A WORK IN PROGRESS</B>
107  * <p/>
108  * <i>The BeanAction Struts extension is a work in progress.  While it demonstrates
109  * good patterns for application development, the framework itself is very new and
110  * should not be considered stable.  Your comments and suggestions are welcome.
111  * Please visit <a href="http://www.ibatis.com">http://www.ibatis.com</a> for contact information.</i>
112  * <p/>
113  * Date: Mar 11, 2004 10:03:56 PM
114  *
115  * @author Clinton Begin
116  * @see BaseBean
117  * @see ActionContext
118  */
119 public class BeanAction extends Action {
120 
121   public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
122       throws Exception {
123 
124     String forward = "success";
125 
126     try {
127 
128       ActionContext.initialize(request, response);
129 
130       if (form != null) {
131 
132         // Explicit Method Mapping
133         Method method = null;
134         String methodName = mapping.getParameter();
135         if (methodName != null && !"*".equals(methodName)) {
136           try {
137             method = form.getClass().getMethod(methodName, null);
138             forward = (String) method.invoke(form, null);
139           } catch (Exception e) {
140             throw new BeanActionException("Error dispatching bean action via method parameter ('" + methodName + "').  Cause: " + e, e);
141           }
142         }
143 
144         // Path Based Method Mapping
145         if (method == null && !"*".equals(methodName)) {
146           methodName = mapping.getPath();
147           if (methodName.length() > 1) {
148             int slash = methodName.lastIndexOf("/") + 1;
149             methodName = methodName.substring(slash);
150             if (methodName.length() > 0) {
151               try {
152                 method = form.getClass().getMethod(methodName, null);
153                 forward = (String) method.invoke(form, null);
154               } catch (Exception e) {
155                 throw new BeanActionException("Error dispatching bean action via URL pattern ('" + methodName + "').  Cause: " + e, e);
156               }
157             }
158           }
159         }
160       }
161 
162     } catch (Exception e) {
163       request.setAttribute("BeanActionException", e);
164       throw e;
165     }
166 
167     return mapping.findForward(forward);
168   }
169 
170 }