001: package com.ibatis.struts;
002:
003: import java.lang.reflect.Method;
004:
005: import javax.servlet.http.HttpServletRequest;
006: import javax.servlet.http.HttpServletResponse;
007:
008: import org.apache.struts.action.Action;
009: import org.apache.struts.action.ActionForm;
010: import org.apache.struts.action.ActionForward;
011: import org.apache.struts.action.ActionMapping;
012: import org.huihoo.jfox.soaf.container.ServiceFactory;
013: import org.huihoo.jfox.soaf.services.logging.LoggingService;
014:
015: /**
016: * BeanAction is an extension to the typical Struts Action class that enables
017: * mappings to bean methods. This allows for a more typical Object Oriented
018: * design where each object has behaviour as part of its definition. Instead of
019: * writing separate Actions and Forms, BeanAction allows you to simply have a
020: * Bean, which models both the state and the methods that operate on that state.
021: * <p/>In addition to the simpler packaging, BeanAction also simplifies the
022: * Struts progamming paradigm and reduces dependency on Struts. Using this
023: * pattern could allow easier migration to newer frameworks like JSF. <p/>The
024: * method signatures are greatly simplified to the following
025: *
026: * <pre>
027: * public String myActionMethod() {
028: * //..work
029: * return "success";
030: * }
031: * </pre>
032: *
033: * The return parameter becomes simply the name of the forward (as defined in
034: * the config file as usual). Form parameters, request, response, session,
035: * attributes, and cookies are all accessed via the ActionContext class (see the
036: * ActionContext javadocs for more). <p/>The forms that you map to a BaseAction
037: * mapping must be a subclass of the BaseBean class. BaseBean continues to
038: * simplify the validation and reset methods by removing the parameters from the
039: * signature as was done with the above action method example. <p/>There are 3
040: * ways to map a BeanAction in the struts configuration file. They are as
041: * follows. <p/><B>URL Pattern </B> <p/>This approach uses the end of the
042: * action definition to determine which method to call on the Bean. For example
043: * if you request the URL: <p/>http://localhost/jpetstore4/shop/viewOrder.do
044: * <p/>Then the method called would be "viewOrder" (of the mapped bean as
045: * specified by the name="" parameter in the mapping below). The mapping used
046: * for this approach is as follows.
047: *
048: * <pre>
049: *
050: *
051: * <action path="/shop/<b>viewOrder</b>" type="com.ibatis.struts.BeanAction"
052: * name="orderBean" scope="session"
053: * validate="false">
054: * <forward name="success" path="/order/ViewOrder.jsp"/>
055: * </action>
056: *
057: *
058: * </pre>
059: *
060: * <B>Method Parameter </B> <p/>This approach uses the Struts action parameter
061: * within the mapping to determine the method to call on the Bean. For example
062: * the following action mapping would cause the "viewOrder" method to be called
063: * on the bean ("orderBean"). The mapping used for this approach is as follows.
064: *
065: * <pre>
066: *
067: *
068: * <action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
069: * <b>name="orderBean" parameter="viewOrder"</b> scope="session"
070: * validate="false">
071: * <forward name="success" path="/order/ViewOrder.jsp"/>
072: * </action>
073: *
074: *
075: * </pre>
076: *
077: * <B>No Method call </B> <p/>BeanAction will ignore any Struts action mappings
078: * without beans associated to them (i.e. no name="" attribute in the mapping).
079: * If you do want to associate a bean to the action mapping, but do not want a
080: * method to be called, simply set the parameter to an asterisk ("*"). The
081: * mapping used for this approach is as follows (no method will be called).
082: *
083: * <pre>
084: *
085: *
086: * <action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
087: * <b>name="orderBean" parameter="*"</b> scope="session"
088: * validate="false">
089: * <forward name="success" path="/order/ViewOrder.jsp"/>
090: * </action>
091: *
092: *
093: * </pre>
094: *
095: * <p/><B>A WORK IN PROGRESS </B> <p/><i>The BeanAction Struts extension is a
096: * work in progress. While it demonstrates good patterns for application
097: * development, the framework itself is very new and should not be considered
098: * stable. Your comments and suggestions are welcome. Please visit <a
099: * href="http://www.ibatis.com">http://www.ibatis.com </a> for contact
100: * information. </i> <p/>Date: Mar 11, 2004 10:03:56 PM
101: *
102: * @author Clinton Begin
103: * @see BaseBean
104: * @see ActionContext
105: */
106: public class BeanAction extends Action {
107:
108: private LoggingService log = (LoggingService) ServiceFactory
109: .getInstance().getService(LoggingService.class);
110:
111: public ActionForward execute(ActionMapping mapping,
112: ActionForm form, HttpServletRequest request,
113: HttpServletResponse response) throws Exception {
114:
115: String forward = "success";
116:
117: try {
118:
119: ActionContext.initialize(request, response);
120:
121: if (form != null) {
122:
123: // Explicit Method Mapping
124: Method method = null;
125: String methodName = mapping.getParameter();
126: log.info("Invoke Method Name : " + methodName);
127: if (methodName != null && !"*".equals(methodName)) {
128: try {
129: method = form.getClass().getMethod(methodName,
130: null);
131: forward = (String) method.invoke(form, null);
132: } catch (Exception e) {
133: throw new BeanActionException(
134: "Error dispatching bean action via method parameter ('"
135: + methodName + "'). Cause: "
136: + e, e);
137: }
138: }
139:
140: // Path Based Method Mapping
141: if (method == null && !"*".equals(methodName)) {
142: methodName = mapping.getPath();
143: if (methodName.length() > 1) {
144: int slash = methodName.lastIndexOf("/") + 1;
145: methodName = methodName.substring(slash);
146: log.info("Invoke Method Name : " + methodName);
147: if (methodName.length() > 0) {
148: try {
149: method = form.getClass().getMethod(
150: methodName, null);
151: forward = (String) method.invoke(form,
152: null);
153: } catch (Exception e) {
154: throw new BeanActionException(
155: "Error dispatching bean action via URL pattern ('"
156: + methodName
157: + "'). Cause: " + e, e);
158: }
159: }
160: }
161: }
162: }
163:
164: } catch (Exception e) {
165: request.setAttribute("BeanActionException", e);
166: throw e;
167: }
168:
169: return mapping.findForward(forward);
170: }
171:
172: }
|