View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    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   *  &lt;action path="/shop/<b>viewOrder</b>" type="com.ibatis.struts.BeanAction"
    72   *    name="orderBean" scope="session"
    73   *    validate="false"&gt;
    74   *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
    75   *  &lt;/action&gt;
    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   *  &lt;action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
    87   *    <b>name="orderBean" parameter="viewOrder"</b> scope="session"
    88   *    validate="false"&gt;
    89   *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
    90   *  &lt;/action&gt;
    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  *  &lt;action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction"
    101  *    <b>name="orderBean" parameter="*"</b> scope="session"
    102  *    validate="false"&gt;
    103  *    &lt;forward name="success" path="/order/ViewOrder.jsp"/&gt;
    104  *  &lt;/action&gt;
    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         // Explicit Method Mapping
    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         // Path Based Method Mapping
    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 }