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