Home » Struts-1.3.10 » org.apache.struts » actions » [javadoc | source]

    1   /*
    2    * $Id: DispatchAction.java 384089 2006-03-08 01:50:52Z niallp $ 
    3    *
    4    * Copyright 2001-2006 The Apache Software Foundation.
    5    * 
    6    * Licensed under the Apache License, Version 2.0 (the "License");
    7    * you may not use this file except in compliance with the License.
    8    * You may obtain a copy of the License at
    9    * 
   10    *      http://www.apache.org/licenses/LICENSE-2.0
   11    * 
   12    * Unless required by applicable law or agreed to in writing, software
   13    * distributed under the License is distributed on an "AS IS" BASIS,
   14    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    * See the License for the specific language governing permissions and
   16    * limitations under the License.
   17    */
   18   
   19   package org.apache.struts.actions;
   20   
   21   import java.lang.reflect.InvocationTargetException;
   22   import java.lang.reflect.Method;
   23   import java.util.HashMap;
   24   
   25   import javax.servlet.ServletException;
   26   import javax.servlet.http.HttpServletRequest;
   27   import javax.servlet.http.HttpServletResponse;
   28   
   29   import org.apache.commons.logging.Log;
   30   import org.apache.commons.logging.LogFactory;
   31   import org.apache.struts.action.Action;
   32   import org.apache.struts.action.ActionForm;
   33   import org.apache.struts.action.ActionForward;
   34   import org.apache.struts.action.ActionMapping;
   35   import org.apache.struts.util.MessageResources;
   36   
   37   /**
   38    * <p>An abstract <strong>Action</strong> that dispatches to a public
   39    * method that is named by the request parameter whose name is specified
   40    * by the <code>parameter</code> property of the corresponding
   41    * ActionMapping.  This Action is useful for developers who prefer to
   42    * combine many similar actions into a single Action class, in order to
   43    * simplify their application design.</p>
   44    *
   45    * <p>To configure the use of this action in your
   46    * <code>struts-config.xml</code> file, create an entry like this:</p>
   47    *
   48    * <code>
   49    *   &lt;action path="/saveSubscription"
   50    *           type="org.apache.struts.actions.DispatchAction"
   51    *           name="subscriptionForm"
   52    *          scope="request"
   53    *          input="/subscription.jsp"
   54    *      parameter="method"/&gt;
   55    * </code>
   56    *
   57    * <p>which will use the value of the request parameter named "method"
   58    * to pick the appropriate "execute" method, which must have the same
   59    * signature (other than method name) of the standard Action.execute
   60    * method.  For example, you might have the following three methods in the
   61    * same action:</p>
   62    * <ul>
   63    * <li>public ActionForward delete(ActionMapping mapping, ActionForm form,
   64    *     HttpServletRequest request, HttpServletResponse response)
   65    *     throws Exception</li>
   66    * <li>public ActionForward insert(ActionMapping mapping, ActionForm form,
   67    *     HttpServletRequest request, HttpServletResponse response)
   68    *     throws Exception</li>
   69    * <li>public ActionForward update(ActionMapping mapping, ActionForm form,
   70    *     HttpServletRequest request, HttpServletResponse response)
   71    *     throws Exception</li>
   72    * </ul>
   73    * <p>and call one of the methods with a URL like this:</p>
   74    * <code>
   75    *   http://localhost:8080/myapp/saveSubscription.do?method=update
   76    * </code>
   77    *
   78    * <p><strong>NOTE</strong> - All of the other mapping characteristics of
   79    * this action must be shared by the various handlers.  This places some
   80    * constraints over what types of handlers may reasonably be packaged into
   81    * the same <code>DispatchAction</code> subclass.</p>
   82    *
   83    * <p><strong>NOTE</strong> - If the value of the request parameter is empty,
   84    * a method named <code>unspecified</code> is called. The default action is
   85    * to throw an exception. If the request was cancelled (a <code>html:cancel</code>
   86    * button was pressed), the custom handler <code>cancelled</code> will be used instead.
   87    * You can also override the <code>getMethodName</code> method to override the action's
   88    * default handler selection.</p>
   89    *
   90    * @version $Rev: 384089 $ $Date: 2006-03-08 01:50:52 +0000 (Wed, 08 Mar 2006) $
   91    */
   92   public abstract class DispatchAction extends Action {
   93   
   94   
   95       // ----------------------------------------------------- Instance Variables
   96   
   97   
   98       /**
   99        * The Class instance of this <code>DispatchAction</code> class.
  100        */
  101       protected Class clazz = this.getClass();
  102   
  103   
  104       /**
  105        * Commons Logging instance.
  106        */
  107       protected static Log log = LogFactory.getLog(DispatchAction.class);
  108   
  109   
  110       /**
  111        * The message resources for this package.
  112        */
  113       protected static MessageResources messages =
  114               MessageResources.getMessageResources
  115               ("org.apache.struts.actions.LocalStrings");
  116   
  117   
  118       /**
  119        * The set of Method objects we have introspected for this class,
  120        * keyed by method name.  This collection is populated as different
  121        * methods are called, so that introspection needs to occur only
  122        * once per method name.
  123        */
  124       protected HashMap methods = new HashMap();
  125   
  126   
  127       /**
  128        * The set of argument type classes for the reflected method call.  These
  129        * are the same for all calls, so calculate them only once.
  130        */
  131       protected Class[] types =
  132               {
  133                   ActionMapping.class,
  134                   ActionForm.class,
  135                   HttpServletRequest.class,
  136                   HttpServletResponse.class};
  137   
  138   
  139   
  140       // --------------------------------------------------------- Public Methods
  141   
  142   
  143       /**
  144        * Process the specified HTTP request, and create the corresponding HTTP
  145        * response (or forward to another web component that will create it).
  146        * Return an <code>ActionForward</code> instance describing where and how
  147        * control should be forwarded, or <code>null</code> if the response has
  148        * already been completed.
  149        *
  150        * @param mapping The ActionMapping used to select this instance
  151        * @param form The optional ActionForm bean for this request (if any)
  152        * @param request The HTTP request we are processing
  153        * @param response The HTTP response we are creating
  154        *
  155        * @exception Exception if an exception occurs
  156        */
  157       public ActionForward execute(ActionMapping mapping,
  158                                    ActionForm form,
  159                                    HttpServletRequest request,
  160                                    HttpServletResponse response)
  161               throws Exception {
  162           if (isCancelled(request)) {
  163               ActionForward af = cancelled(mapping, form, request, response);
  164               if (af != null) {
  165                   return af;
  166               }
  167           }
  168   
  169           // Get the parameter. This could be overridden in subclasses.
  170           String parameter = getParameter(mapping, form, request, response);
  171   
  172           // Get the method's name. This could be overridden in subclasses.
  173           String name = getMethodName(mapping, form, request, response, parameter);
  174   
  175   
  176   	// Prevent recursive calls
  177   	if ("execute".equals(name) || "perform".equals(name)){
  178   		String message =
  179   			messages.getMessage("dispatch.recursive", mapping.getPath());
  180   
  181   		log.error(message);
  182   		throw new ServletException(message);
  183   	}
  184   
  185   
  186           // Invoke the named method, and return the result
  187           return dispatchMethod(mapping, form, request, response, name);
  188   
  189       }
  190   
  191   
  192   
  193       
  194       /**
  195        * Method which is dispatched to when there is no value for specified
  196        * request parameter included in the request.  Subclasses of
  197        * <code>DispatchAction</code> should override this method if they wish
  198        * to provide default behavior different than throwing a ServletException.
  199        */
  200       protected ActionForward unspecified(
  201               ActionMapping mapping,
  202               ActionForm form,
  203               HttpServletRequest request,
  204               HttpServletResponse response)
  205               throws Exception {
  206   
  207           String message =
  208                   messages.getMessage(
  209                           "dispatch.parameter",
  210                           mapping.getPath(),
  211                           mapping.getParameter());
  212   
  213           log.error(message);
  214   
  215           throw new ServletException(message);
  216       }
  217   
  218       /**
  219        * Method which is dispatched to when the request is a cancel button submit.
  220        * Subclasses of <code>DispatchAction</code> should override this method if
  221        * they wish to provide default behavior different than returning null.
  222        * @since Struts 1.2.0
  223        */
  224       protected ActionForward cancelled(ActionMapping mapping,
  225                                         ActionForm form,
  226                                         HttpServletRequest request,
  227                                         HttpServletResponse response)
  228               throws Exception {
  229   
  230           return null;
  231       }
  232   
  233       // ----------------------------------------------------- Protected Methods
  234   
  235   
  236       /**
  237        * Dispatch to the specified method.
  238        * @since Struts 1.1
  239        */
  240       protected ActionForward dispatchMethod(ActionMapping mapping,
  241                                              ActionForm form,
  242                                              HttpServletRequest request,
  243                                              HttpServletResponse response,
  244                                              String name) throws Exception {
  245   
  246           // Make sure we have a valid method name to call.
  247           // This may be null if the user hacks the query string.
  248           if (name == null) {
  249               return this.unspecified(mapping, form, request, response);
  250           }
  251   
  252           // Identify the method object to be dispatched to
  253           Method method = null;
  254           try {
  255               method = getMethod(name);
  256   
  257           } catch(NoSuchMethodException e) {
  258               String message =
  259                       messages.getMessage("dispatch.method", mapping.getPath(), name);
  260               log.error(message, e);
  261   
  262               String userMsg =
  263                   messages.getMessage("dispatch.method.user", mapping.getPath());
  264               throw new NoSuchMethodException(userMsg);
  265           }
  266   
  267           ActionForward forward = null;
  268           try {
  269               Object args[] = {mapping, form, request, response};
  270               forward = (ActionForward) method.invoke(this, args);
  271   
  272           } catch(ClassCastException e) {
  273               String message =
  274                       messages.getMessage("dispatch.return", mapping.getPath(), name);
  275               log.error(message, e);
  276               throw e;
  277   
  278           } catch(IllegalAccessException e) {
  279               String message =
  280                       messages.getMessage("dispatch.error", mapping.getPath(), name);
  281               log.error(message, e);
  282               throw e;
  283   
  284           } catch(InvocationTargetException e) {
  285               // Rethrow the target exception if possible so that the
  286               // exception handling machinery can deal with it
  287               Throwable t = e.getTargetException();
  288               if (t instanceof Exception) {
  289                   throw ((Exception) t);
  290               } else {
  291                   String message =
  292                           messages.getMessage("dispatch.error", mapping.getPath(), name);
  293                   log.error(message, e);
  294                   throw new ServletException(t);
  295               }
  296           }
  297   
  298           // Return the returned ActionForward instance
  299           return (forward);
  300       }
  301   
  302       /**
  303        * <p>Returns the parameter value.</p>
  304        *
  305        * @param mapping  The ActionMapping used to select this instance
  306        * @param form     The optional ActionForm bean for this request (if any)
  307        * @param request  The HTTP request we are processing
  308        * @param response The HTTP response we are creating
  309        * @return The <code>ActionMapping</code> parameter's value
  310        * @throws Exception if the parameter is missing.
  311        */
  312       protected String getParameter(ActionMapping mapping, ActionForm form,
  313           HttpServletRequest request, HttpServletResponse response)
  314           throws Exception {
  315   
  316           // Identify the request parameter containing the method name
  317           String parameter = mapping.getParameter();
  318   
  319           if (parameter == null) {
  320               String message =
  321                   messages.getMessage("dispatch.handler", mapping.getPath());
  322   
  323               log.error(message);
  324   
  325               throw new ServletException(message);
  326           }
  327   
  328   
  329           return parameter;
  330       }
  331   
  332       /**
  333        * Introspect the current class to identify a method of the specified
  334        * name that accepts the same parameter types as the <code>execute</code>
  335        * method does.
  336        *
  337        * @param name Name of the method to be introspected
  338        *
  339        * @exception NoSuchMethodException if no such method can be found
  340        */
  341       protected Method getMethod(String name)
  342               throws NoSuchMethodException {
  343   
  344           synchronized(methods) {
  345               Method method = (Method) methods.get(name);
  346               if (method == null) {
  347                   method = clazz.getMethod(name, types);
  348                   methods.put(name, method);
  349               }
  350               return (method);
  351           }
  352   
  353       }
  354   
  355       /**
  356        * Returns the method name, given a parameter's value.
  357        *
  358        * @param mapping The ActionMapping used to select this instance
  359        * @param form The optional ActionForm bean for this request (if any)
  360        * @param request The HTTP request we are processing
  361        * @param response The HTTP response we are creating
  362        * @param parameter The <code>ActionMapping</code> parameter's name
  363        *
  364        * @return The method's name.
  365        * @since Struts 1.2.0
  366        */
  367       protected String getMethodName(ActionMapping mapping,
  368                                      ActionForm form,
  369                                      HttpServletRequest request,
  370                                      HttpServletResponse response,
  371                                      String parameter)
  372               throws Exception {
  373   
  374           // Identify the method name to be dispatched to.
  375           // dispatchMethod() will call unspecified() if name is null
  376           return request.getParameter(parameter);
  377       }
  378   
  379   }

Home » Struts-1.3.10 » org.apache.struts » actions » [javadoc | source]