Save This Page
Home » xwork-2.1.5 » com.opensymphony » xwork2 » [javadoc | source]
    1   /*
    2    * Copyright (c) 2002-2006 by OpenSymphony
    3    * All rights reserved.
    4    */
    5   package com.opensymphony.xwork2;
    6   
    7   import com.opensymphony.xwork2.config.Configuration;
    8   import com.opensymphony.xwork2.config.ConfigurationException;
    9   import com.opensymphony.xwork2.config.entities.ActionConfig;
   10   import com.opensymphony.xwork2.config.entities.InterceptorMapping;
   11   import com.opensymphony.xwork2.config.entities.ResultConfig;
   12   import com.opensymphony.xwork2.inject.Container;
   13   import com.opensymphony.xwork2.inject.Inject;
   14   import com.opensymphony.xwork2.interceptor.PreResultListener;
   15   import com.opensymphony.xwork2.util.ValueStack;
   16   import com.opensymphony.xwork2.util.ValueStackFactory;
   17   import com.opensymphony.xwork2.util.logging.Logger;
   18   import com.opensymphony.xwork2.util.logging.LoggerFactory;
   19   import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
   20   
   21   import java.lang.reflect.InvocationTargetException;
   22   import java.lang.reflect.Method;
   23   import java.util.ArrayList;
   24   import java.util.Iterator;
   25   import java.util.List;
   26   import java.util.Map;
   27   
   28   
   29   /**
   30    * The Default ActionInvocation implementation
   31    *
   32    * @author Rainer Hermanns
   33    * @author tmjee
   34    * @version $Date: 2009-07-22 19:18:39 +0200 (Mi, 22 Jul 2009) $ $Id: DefaultActionInvocation.java 2024 2009-07-22 17:18:39Z musachy $
   35    * @see com.opensymphony.xwork2.DefaultActionProxy
   36    */
   37   public class DefaultActionInvocation implements ActionInvocation {
   38   
   39       private static final long serialVersionUID = -585293628862447329L;
   40   
   41       //static {
   42       //    if (ObjectFactory.getContinuationPackage() != null) {
   43       //        continuationHandler = new ContinuationHandler();
   44       //    }
   45       //}
   46       private static final Logger LOG = LoggerFactory.getLogger(DefaultActionInvocation.class);
   47   
   48       protected Object action;
   49       protected ActionProxy proxy;
   50       protected List<PreResultListener> preResultListeners;
   51       protected Map<String, Object> extraContext;
   52       protected ActionContext invocationContext;
   53       protected Iterator<InterceptorMapping> interceptors;
   54       protected ValueStack stack;
   55       protected Result result;
   56       protected Result explicitResult;
   57       protected String resultCode;
   58       protected boolean executed = false;
   59       protected boolean pushAction = true;
   60       protected ObjectFactory objectFactory;
   61       protected ActionEventListener actionEventListener;
   62       protected ValueStackFactory valueStackFactory;
   63       protected Container container;
   64       private Configuration configuration;
   65       protected UnknownHandlerManager unknownHandlerManager;
   66   
   67       public DefaultActionInvocation(final Map<String, Object> extraContext, final boolean pushAction) {
   68           DefaultActionInvocation.this.extraContext = extraContext;
   69           DefaultActionInvocation.this.pushAction = pushAction;
   70       }
   71   
   72       @Inject
   73       public void setUnknownHandlerManager(UnknownHandlerManager unknownHandlerManager) {
   74           this.unknownHandlerManager = unknownHandlerManager;
   75       }
   76   
   77       @Inject
   78       public void setValueStackFactory(ValueStackFactory fac) {
   79           this.valueStackFactory = fac;
   80       }
   81   
   82       @Inject
   83       public void setConfiguration(Configuration configuration) {
   84           this.configuration = configuration;
   85       }
   86   
   87       @Inject
   88       public void setObjectFactory(ObjectFactory fac) {
   89           this.objectFactory = fac;
   90       }
   91   
   92       @Inject
   93       public void setContainer(Container cont) {
   94           this.container = cont;
   95       }
   96   
   97       @Inject(required=false)
   98       public void setActionEventListener(ActionEventListener listener) {
   99           this.actionEventListener = listener;
  100       }
  101   
  102       public Object getAction() {
  103           return action;
  104       }
  105   
  106       public boolean isExecuted() {
  107           return executed;
  108       }
  109   
  110       public ActionContext getInvocationContext() {
  111           return invocationContext;
  112       }
  113   
  114       public ActionProxy getProxy() {
  115           return proxy;
  116       }
  117   
  118       /**
  119        * If the DefaultActionInvocation has been executed before and the Result is an instance of ActionChainResult, this method
  120        * will walk down the chain of ActionChainResults until it finds a non-chain result, which will be returned. If the
  121        * DefaultActionInvocation's result has not been executed before, the Result instance will be created and populated with
  122        * the result params.
  123        *
  124        * @return a Result instance
  125        * @throws Exception
  126        */
  127       public Result getResult() throws Exception {
  128           Result returnResult = result;
  129   
  130           // If we've chained to other Actions, we need to find the last result
  131           while (returnResult instanceof ActionChainResult) {
  132               ActionProxy aProxy = ((ActionChainResult) returnResult).getProxy();
  133   
  134               if (aProxy != null) {
  135                   Result proxyResult = aProxy.getInvocation().getResult();
  136   
  137                   if ((proxyResult != null) && (aProxy.getExecuteResult())) {
  138                       returnResult = proxyResult;
  139                   } else {
  140                       break;
  141                   }
  142               } else {
  143                   break;
  144               }
  145           }
  146   
  147           return returnResult;
  148       }
  149   
  150       public String getResultCode() {
  151           return resultCode;
  152       }
  153   
  154       public void setResultCode(String resultCode) {
  155           if (isExecuted())
  156               throw new IllegalStateException("Result has already been executed.");
  157   
  158           this.resultCode = resultCode;
  159       }
  160   
  161   
  162       public ValueStack getStack() {
  163           return stack;
  164       }
  165   
  166       /**
  167        * Register a com.opensymphony.xwork2.interceptor.PreResultListener to be notified after the Action is executed and before the
  168        * Result is executed. The ActionInvocation implementation must guarantee that listeners will be called in the order
  169        * in which they are registered. Listener registration and execution does not need to be thread-safe.
  170        *
  171        * @param listener
  172        */
  173       public void addPreResultListener(PreResultListener listener) {
  174           if (preResultListeners == null) {
  175               preResultListeners = new ArrayList<PreResultListener>(1);
  176           }
  177   
  178           preResultListeners.add(listener);
  179       }
  180   
  181       public Result createResult() throws Exception {
  182   
  183           if (explicitResult != null) {
  184               Result ret = explicitResult;
  185               explicitResult = null;
  186   
  187               return ret;
  188           }
  189           ActionConfig config = proxy.getConfig();
  190           Map<String, ResultConfig> results = config.getResults();
  191   
  192           ResultConfig resultConfig = null;
  193   
  194           try {
  195               resultConfig = results.get(resultCode);
  196           } catch (NullPointerException e) {
  197               // swallow
  198           }
  199           
  200           if (resultConfig == null) {
  201               // If no result is found for the given resultCode, try to get a wildcard '*' match.
  202               resultConfig = results.get("*");
  203           }
  204   
  205           if (resultConfig != null) {
  206               try {
  207                   return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
  208               } catch (Exception e) {
  209                   LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);
  210                   throw new XWorkException(e, resultConfig);
  211               }
  212           } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {
  213               return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
  214           }
  215           return null;
  216       }
  217   
  218       /**
  219        * @throws ConfigurationException If no result can be found with the returned code
  220        */
  221       public String invoke() throws Exception {
  222           String profileKey = "invoke: ";
  223           try {
  224               UtilTimerStack.push(profileKey);
  225   
  226               if (executed) {
  227                   throw new IllegalStateException("Action has already executed");
  228               }
  229   
  230               if (interceptors.hasNext()) {
  231                   final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
  232                   String interceptorMsg = "interceptor: " + interceptor.getName();
  233                   UtilTimerStack.push(interceptorMsg);
  234                   try {
  235                                   resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
  236                               }
  237                   finally {
  238                       UtilTimerStack.pop(interceptorMsg);
  239                   }
  240               } else {
  241                   resultCode = invokeActionOnly();
  242               }
  243   
  244               // this is needed because the result will be executed, then control will return to the Interceptor, which will
  245               // return above and flow through again
  246               if (!executed) {
  247                   if (preResultListeners != null) {
  248                       for (Object preResultListener : preResultListeners) {
  249                           PreResultListener listener = (PreResultListener) preResultListener;
  250   
  251                           String _profileKey = "preResultListener: ";
  252                           try {
  253                               UtilTimerStack.push(_profileKey);
  254                               listener.beforeResult(this, resultCode);
  255                           }
  256                           finally {
  257                               UtilTimerStack.pop(_profileKey);
  258                           }
  259                       }
  260                   }
  261   
  262                   // now execute the result, if we're supposed to
  263                   if (proxy.getExecuteResult()) {
  264                       executeResult();
  265                   }
  266   
  267                   executed = true;
  268               }
  269   
  270               return resultCode;
  271           }
  272           finally {
  273               UtilTimerStack.pop(profileKey);
  274           }
  275       }
  276   
  277       public String invokeActionOnly() throws Exception {
  278           return invokeAction(getAction(), proxy.getConfig());
  279       }
  280   
  281       protected void createAction(Map<String, Object> contextMap) {
  282           // load action
  283           String timerKey = "actionCreate: " + proxy.getActionName();
  284           try {
  285               UtilTimerStack.push(timerKey);
  286               action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
  287           } catch (InstantiationException e) {
  288               throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());
  289           } catch (IllegalAccessException e) {
  290               throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());
  291           } catch (Exception e) {
  292               String gripe = "";
  293   
  294               if (proxy == null) {
  295                   gripe = "Whoa!  No ActionProxy instance found in current ActionInvocation.  This is bad ... very bad";
  296               } else if (proxy.getConfig() == null) {
  297                   gripe = "Sheesh.  Where'd that ActionProxy get to?  I can't find it in the current ActionInvocation!?";
  298               } else if (proxy.getConfig().getClassName() == null) {
  299                   gripe = "No Action defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";
  300               } else {
  301                   gripe = "Unable to instantiate Action, " + proxy.getConfig().getClassName() + ",  defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";
  302               }
  303   
  304               gripe += (((" -- " + e.getMessage()) != null) ? e.getMessage() : " [no message in exception]");
  305               throw new XWorkException(gripe, e, proxy.getConfig());
  306           } finally {
  307               UtilTimerStack.pop(timerKey);
  308           }
  309   
  310           if (actionEventListener != null) {
  311               action = actionEventListener.prepare(action, stack);
  312           }
  313       }
  314   
  315       protected Map<String, Object> createContextMap() {
  316           Map<String, Object> contextMap;
  317   
  318           if ((extraContext != null) && (extraContext.containsKey(ActionContext.VALUE_STACK))) {
  319               // In case the ValueStack was passed in
  320               stack = (ValueStack) extraContext.get(ActionContext.VALUE_STACK);
  321   
  322               if (stack == null) {
  323                   throw new IllegalStateException("There was a null Stack set into the extra params.");
  324               }
  325   
  326               contextMap = stack.getContext();
  327           } else {
  328               // create the value stack
  329               // this also adds the ValueStack to its context
  330               stack = valueStackFactory.createValueStack();
  331   
  332               // create the action context
  333               contextMap = stack.getContext();
  334           }
  335   
  336           // put extraContext in
  337           if (extraContext != null) {
  338               contextMap.putAll(extraContext);
  339           }
  340   
  341           //put this DefaultActionInvocation into the context map
  342           contextMap.put(ActionContext.ACTION_INVOCATION, this);
  343           contextMap.put(ActionContext.CONTAINER, container);
  344   
  345           return contextMap;
  346       }
  347   
  348       /**
  349        * Uses getResult to get the final Result and executes it
  350        *
  351        * @throws ConfigurationException If not result can be found with the returned code
  352        */
  353       private void executeResult() throws Exception {
  354           result = createResult();
  355   
  356           String timerKey = "executeResult: " + getResultCode();
  357           try {
  358               UtilTimerStack.push(timerKey);
  359               if (result != null) {
  360                   result.execute(this);
  361               } else if (resultCode != null && !Action.NONE.equals(resultCode)) {
  362                   throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()
  363                           + " and result " + getResultCode(), proxy.getConfig());
  364               } else {
  365                   if (LOG.isDebugEnabled()) {
  366                       LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());
  367                   }
  368               }
  369           } finally {
  370               UtilTimerStack.pop(timerKey);
  371           }
  372       }
  373   
  374       public void init(ActionProxy proxy) {
  375           this.proxy = proxy;
  376           Map<String, Object> contextMap = createContextMap();
  377   
  378           // Setting this so that other classes, like object factories, can use the ActionProxy and other
  379           // contextual information to operate
  380           ActionContext actionContext = ActionContext.getContext();
  381   
  382           if (actionContext != null) {
  383               actionContext.setActionInvocation(this);
  384           }
  385   
  386           createAction(contextMap);
  387   
  388           if (pushAction) {
  389               stack.push(action);
  390               contextMap.put("action", action);
  391           }
  392   
  393           invocationContext = new ActionContext(contextMap);
  394           invocationContext.setName(proxy.getActionName());
  395   
  396           // get a new List so we don't get problems with the iterator if someone changes the list
  397           List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
  398           interceptors = interceptorList.iterator();
  399       }
  400   
  401       protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
  402           String methodName = proxy.getMethod();
  403   
  404           if (LOG.isDebugEnabled()) {
  405               LOG.debug("Executing action method = " + actionConfig.getMethodName());
  406           }
  407   
  408           String timerKey = "invokeAction: " + proxy.getActionName();
  409           try {
  410               UtilTimerStack.push(timerKey);
  411   
  412               boolean methodCalled = false;
  413               Object methodResult = null;
  414               Method method = null;
  415               try {
  416                   method = getAction().getClass().getMethod(methodName, new Class[0]);
  417               } catch (NoSuchMethodException e) {
  418                   // hmm -- OK, try doXxx instead
  419                   try {
  420                       String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
  421                       method = getAction().getClass().getMethod(altMethodName, new Class[0]);
  422                   } catch (NoSuchMethodException e1) {
  423                       // well, give the unknown handler a shot
  424                       if (unknownHandlerManager.hasUnknownHandlers()) {
  425                           try {
  426                               methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
  427                               methodCalled = true;
  428                           } catch (NoSuchMethodException e2) {
  429                               // throw the original one
  430                               throw e;
  431                           }
  432                       } else {
  433                           throw e;
  434                       }
  435                   }
  436               }
  437   
  438               if (!methodCalled) {
  439                   methodResult = method.invoke(action, new Object[0]);
  440               }
  441   
  442               if (methodResult instanceof Result) {
  443                   this.explicitResult = (Result) methodResult;
  444   
  445                   // Wire the result automatically
  446                   container.inject(explicitResult);
  447                   return null;
  448               } else {
  449                   return (String) methodResult;
  450               }
  451           } catch (NoSuchMethodException e) {
  452               throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
  453           } catch (InvocationTargetException e) {
  454               // We try to return the source exception.
  455               Throwable t = e.getTargetException();
  456   
  457               if (actionEventListener != null) {
  458                   String result = actionEventListener.handleException(t, getStack());
  459                   if (result != null) {
  460                       return result;
  461                   }
  462               }
  463               if (t instanceof Exception) {
  464                   throw (Exception) t;
  465               } else {
  466                   throw e;
  467               }
  468           } finally {
  469               UtilTimerStack.pop(timerKey);
  470           }
  471       }
  472   
  473   
  474   }

Save This Page
Home » xwork-2.1.5 » com.opensymphony » xwork2 » [javadoc | source]