Save This Page
Home » struts-2.1.8.1-src » org.apache » struts2 » components » [javadoc | source]
    1   /*
    2    * $Id: ActionComponent.java 817333 2009-09-21 17:29:44Z wesw $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
   10    * with the License.  You may obtain a copy of the License at
   11    *
   12    *  http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing,
   15    * software distributed under the License is distributed on an
   16    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   17    * KIND, either express or implied.  See the License for the
   18    * specific language governing permissions and limitations
   19    * under the License.
   20    */
   21   
   22   package org.apache.struts2.components;
   23   
   24   import java.io.IOException;
   25   import java.io.Writer;
   26   import java.util.HashMap;
   27   import java.util.Iterator;
   28   import java.util.Map;
   29   
   30   import javax.servlet.ServletContext;
   31   import javax.servlet.http.HttpServletRequest;
   32   import javax.servlet.http.HttpServletResponse;
   33   import javax.servlet.jsp.PageContext;
   34   
   35   import org.apache.struts2.ServletActionContext;
   36   import org.apache.struts2.StrutsException;
   37   import org.apache.struts2.dispatcher.Dispatcher;
   38   import org.apache.struts2.dispatcher.RequestMap;
   39   import org.apache.struts2.dispatcher.mapper.ActionMapper;
   40   import org.apache.struts2.dispatcher.mapper.ActionMapping;
   41   import org.apache.struts2.views.annotations.StrutsTag;
   42   import org.apache.struts2.views.annotations.StrutsTagAttribute;
   43   import org.apache.struts2.views.jsp.TagUtils;
   44   
   45   import com.opensymphony.xwork2.ActionContext;
   46   import com.opensymphony.xwork2.ActionProxy;
   47   import com.opensymphony.xwork2.ActionProxyFactory;
   48   import com.opensymphony.xwork2.ActionInvocation;
   49   import com.opensymphony.xwork2.inject.Inject;
   50   import com.opensymphony.xwork2.util.ValueStack;
   51   import com.opensymphony.xwork2.util.ValueStackFactory;
   52   import com.opensymphony.xwork2.util.logging.Logger;
   53   import com.opensymphony.xwork2.util.logging.LoggerFactory;
   54   
   55   /**
   56    * <!-- START SNIPPET: javadoc -->
   57    * <p>This tag enables developers to call actions directly from a JSP page by specifying the action name and an optional
   58    * namespace.  The body content of the tag is used to render the results from the Action.  Any result processor defined
   59    * for this action in struts.xml will be ignored, <i>unless</i> the executeResult parameter is specified.</p>
   60    * <!-- END SNIPPET: javadoc -->
   61    *
   62    * <!-- START SNIPPET: params -->
   63    * <ul>
   64    *      <li>id (String) - the id (if specified) to put the action under stack's context.
   65    *      <li>name* (String) - name of the action to be executed (without the extension suffix eg. .action)</li>
   66    *      <li>namespace (String) - default to the namespace where this action tag is invoked</li>
   67    *      <li>executeResult (Boolean) -  default is false. Decides whether the result of this action is to be executed or not</li>
   68    *      <li>ignoreContextParams (Boolean) - default to false. Decides whether the request parameters are to be included when the action is invoked</li>
   69    * </ul>
   70    * <!-- END SNIPPET: params -->
   71    *
   72    * <pre>
   73    * <!-- START SNIPPET: javacode -->
   74    * public class ActionTagAction extends ActionSupport {
   75    *
   76    *  public String execute() throws Exception {
   77    *      return "done";
   78    *  }
   79    *
   80    *  public String doDefault() throws Exception {
   81    *      ServletActionContext.getRequest().setAttribute("stringByAction", "This is a String put in by the action's doDefault()");
   82    *      return "done";
   83    *  }
   84    * }
   85    * <!-- END SNIPPET: javacode -->
   86    * </pre>
   87    *
   88    * <pre>
   89    * <!-- START SNIPPET: strutsxml -->
   90    *   <xwork>
   91    *      ....
   92    *     <action name="actionTagAction1" class="tmjee.testing.ActionTagAction">
   93    *         <result name="done">success.jsp</result>
   94    *     </action>
   95    *      <action name="actionTagAction2" class="tmjee.testing.ActionTagAction" method="default">
   96    *         <result name="done">success.jsp</result>
   97    *     </action>
   98    *      ....
   99    *   </xwork>
  100    * <!-- END SNIPPET: strutsxml -->
  101    * </pre>
  102    *
  103    * <pre>
  104    * <!-- START SNIPPET: example -->
  105    *  <div>The following action tag will execute result and include it in this page</div>
  106    *  <br />
  107    *  <s:action name="actionTagAction" executeResult="true" />
  108    *  <br />
  109    *  <div>The following action tag will do the same as above, but invokes method specialMethod in action</div>
  110    *  <br />
  111    *  <s:action name="actionTagAction!specialMethod" executeResult="true" />
  112    *  <br />
  113    *  <div>The following action tag will not execute result, but put a String in request scope
  114    *       under an id "stringByAction" which will be retrieved using property tag</div>
  115    *  <s:action name="actionTagAction!default" executeResult="false" />
  116    *  <s:property value="#attr.stringByAction" />
  117    * <!-- END SNIPPET: example -->
  118    * </pre>
  119    *
  120    */
  121   @StrutsTag(name="action", tldTagClass="org.apache.struts2.views.jsp.ActionTag", description="Execute an action from within a view")
  122   public class ActionComponent extends ContextBean {
  123       private static final Logger LOG = LoggerFactory.getLogger(ActionComponent.class);
  124   
  125       protected HttpServletResponse res;
  126       protected HttpServletRequest req;
  127   
  128       protected ValueStackFactory valueStackFactory;
  129       protected ActionProxyFactory actionProxyFactory;
  130       protected ActionProxy proxy;
  131       protected String name;
  132       protected String namespace;
  133       protected boolean executeResult;
  134       protected boolean ignoreContextParams;
  135       protected boolean flush = true;
  136       protected boolean rethrowException;
  137   
  138       public ActionComponent(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
  139           super(stack);
  140           this.req = req;
  141           this.res = res;
  142       }
  143   
  144       /**
  145        * @param actionProxyFactory the actionProxyFactory to set
  146        */
  147       @Inject
  148       public void setActionProxyFactory(ActionProxyFactory actionProxyFactory) {
  149           this.actionProxyFactory = actionProxyFactory;
  150       }
  151       
  152       @Inject
  153       public void setValueStackFactory(ValueStackFactory valueStackFactory) {
  154           this.valueStackFactory = valueStackFactory;
  155       }
  156   
  157       @Inject
  158       public void setActionMapper(ActionMapper mapper) {
  159           this.actionMapper = mapper;
  160       }
  161   
  162       public boolean end(Writer writer, String body) {
  163           boolean end = super.end(writer, "", false);
  164           try {
  165               if (flush) {
  166                   try {
  167                       writer.flush();
  168                   } catch (IOException e) {
  169                       LOG.warn("error while trying to flush writer ", e);
  170                   }
  171               }
  172               executeAction();
  173   
  174               if ((getVar() != null) && (proxy != null)) {
  175                   getStack().setValue("#attr['" + getVar() + "']",
  176                           proxy.getAction());
  177               }
  178           } finally {
  179               popComponentStack();
  180           }
  181           return end;
  182       }
  183   
  184       protected Map createExtraContext() {
  185           Map newParams = createParametersForContext();
  186   
  187           ActionContext ctx = new ActionContext(stack.getContext());
  188           ServletContext servletContext = (ServletContext) ctx.get(ServletActionContext.SERVLET_CONTEXT);
  189           PageContext pageContext = (PageContext) ctx.get(ServletActionContext.PAGE_CONTEXT);
  190           Map session = ctx.getSession();
  191           Map application = ctx.getApplication();
  192   
  193           Dispatcher du = Dispatcher.getInstance();
  194           Map<String, Object> extraContext = du.createContextMap(new RequestMap(req),
  195                   newParams,
  196                   session,
  197                   application,
  198                   req,
  199                   res,
  200                   servletContext);
  201   
  202           ValueStack newStack = valueStackFactory.createValueStack(stack);
  203           extraContext.put(ActionContext.VALUE_STACK, newStack);
  204   
  205           // add page context, such that ServletDispatcherResult will do an include
  206           extraContext.put(ServletActionContext.PAGE_CONTEXT, pageContext);
  207   
  208           return extraContext;
  209       }
  210   
  211       /**
  212        * Creates parameters map using parameters from the value stack and component parameters.  Any non-String array
  213        * values will be converted into a single-value String array.
  214        * 
  215        * @return A map of String[] parameters
  216        */
  217       protected Map<String,String[]> createParametersForContext() {
  218           Map parentParams = null;
  219   
  220           if (!ignoreContextParams) {
  221               parentParams = new ActionContext(getStack().getContext()).getParameters();
  222           }
  223   
  224           Map<String,String[]> newParams = (parentParams != null) 
  225               ? new HashMap<String,String[]>(parentParams) 
  226               : new HashMap<String,String[]>();
  227   
  228           if (parameters != null) {
  229               Map<String,String[]> params = new HashMap<String,String[]>();
  230               for (Iterator i = parameters.entrySet().iterator(); i.hasNext(); ) {
  231                   Map.Entry entry = (Map.Entry) i.next();
  232                   String key = (String) entry.getKey();
  233                   Object val = entry.getValue();
  234                   if (val.getClass().isArray() && String.class == val.getClass().getComponentType()) {
  235                       params.put(key, (String[])val);
  236                   } else {
  237                       params.put(key, new String[]{val.toString()});
  238                   }
  239               }
  240               newParams.putAll(params);
  241           }
  242           return newParams;
  243       }
  244   
  245       public ActionProxy getProxy() {
  246           return proxy;
  247       }
  248   
  249       /**
  250        * Execute the requested action.  If no namespace is provided, we'll
  251        * attempt to derive a namespace using buildNamespace().  The ActionProxy
  252        * and the namespace will be saved into the instance variables proxy and
  253        * namespace respectively.
  254        *
  255        * @see org.apache.struts2.views.jsp.TagUtils#buildNamespace
  256        */
  257       protected void executeAction() {
  258           String actualName = findString(name, "name", "Action name is required. Example: updatePerson");
  259   
  260           if (actualName == null) {
  261               throw new StrutsException("Unable to find value for name " + name);
  262           }
  263   
  264           // handle "name!method" convention.
  265           final String actionName;
  266           final String methodName;
  267   
  268           ActionMapping mapping = actionMapper.getMappingFromActionName(actualName);
  269           actionName = mapping.getName();
  270           methodName = mapping.getMethod();
  271   
  272           String namespace;
  273   
  274           if (this.namespace == null) {
  275               namespace = TagUtils.buildNamespace(actionMapper, getStack(), req);
  276           } else {
  277               namespace = findString(this.namespace);
  278           }
  279   
  280           // get the old value stack from the request
  281           ValueStack stack = getStack();
  282           // execute at this point, after params have been set
  283           ActionInvocation inv = ActionContext.getContext().getActionInvocation();
  284           try {
  285   
  286               proxy = actionProxyFactory.createActionProxy(namespace, actionName, methodName, createExtraContext(), executeResult, true);
  287               // set the new stack into the request for the taglib to use
  288               req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
  289               proxy.execute();
  290   
  291           } catch (Exception e) {
  292               String message = "Could not execute action: " + namespace + "/" + actualName;
  293               LOG.error(message, e);
  294               if (rethrowException) {
  295                   throw new StrutsException(message, e);
  296               }
  297           } finally {
  298               // set the old stack back on the request
  299               req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
  300               if (inv != null) {
  301                   ActionContext.getContext().setActionInvocation(inv);
  302               }
  303           }
  304   
  305           if ((getVar() != null) && (proxy != null)) {
  306               putInContext(proxy.getAction());
  307           }
  308       }
  309   
  310       @StrutsTagAttribute(required=true,description="Name of the action to be executed (without the extension suffix eg. .action)")
  311       public void setName(String name) {
  312           this.name = name;
  313       }
  314   
  315       @StrutsTagAttribute(description="Namespace for action to call", defaultValue="namespace from where tag is used")
  316       public void setNamespace(String namespace) {
  317           this.namespace = namespace;
  318       }
  319   
  320       @StrutsTagAttribute(description="Whether the result of this action (probably a view) should be executed/rendered", type="Boolean", defaultValue="false")
  321       public void setExecuteResult(boolean executeResult) {
  322           this.executeResult = executeResult;
  323       }
  324   
  325       @StrutsTagAttribute(description="Whether the request parameters are to be included when the action is invoked", type="Boolean", defaultValue="false")
  326       public void setIgnoreContextParams(boolean ignoreContextParams) {
  327           this.ignoreContextParams = ignoreContextParams;
  328       }
  329   
  330       @StrutsTagAttribute(description="Whether the writer should be flush upon end of action component tag, default to true", type="Boolean", defaultValue="true")
  331       public void setFlush(boolean flush) {
  332           this.flush = flush;
  333       }
  334   
  335       @StrutsTagAttribute(description="Whether an exception should be rethrown, if the target action throws an exception", type="Boolean", defaultValue="false")
  336       public void setRethrowException(boolean rethrowException) {
  337           this.rethrowException = rethrowException;
  338       }
  339   }

Save This Page
Home » struts-2.1.8.1-src » org.apache » struts2 » components » [javadoc | source]