1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 * <action path="/shop/<b>viewOrder</b>" type="com.ibatis.struts.BeanAction"
71 * name="orderBean" scope="session"
72 * validate="false">
73 * <forward name="success" path="/order/ViewOrder.jsp"/>
74 * </action>
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 * <action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
86 * <b>name="orderBean" parameter="viewOrder"</b> scope="session"
87 * validate="false">
88 * <forward name="success" path="/order/ViewOrder.jsp"/>
89 * </action>
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 * <action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
100 * <b>name="orderBean" parameter="*"</b> scope="session"
101 * validate="false">
102 * <forward name="success" path="/order/ViewOrder.jsp"/>
103 * </action>
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
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
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 }