Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » components » [javadoc | source]
    1   /*
    2    * $Id: ActionComponent.java 497654 2007-01-19 00:21:57Z rgielen $
    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   package org.apache.struts2.components;
   22   
   23   import java.io.IOException;
   24   import java.io.Writer;
   25   import java.util.HashMap;
   26   import java.util.Map;
   27   
   28   import javax.servlet.ServletContext;
   29   import javax.servlet.http.HttpServletRequest;
   30   import javax.servlet.http.HttpServletResponse;
   31   import javax.servlet.jsp.PageContext;
   32   
   33   import org.apache.commons.logging.Log;
   34   import org.apache.commons.logging.LogFactory;
   35   import org.apache.struts2.views.annotations.StrutsTag;
   36   import org.apache.struts2.views.annotations.StrutsTagAttribute;
   37   import org.apache.struts2.ServletActionContext;
   38   import org.apache.struts2.StrutsException;
   39   import org.apache.struts2.dispatcher.Dispatcher;
   40   import org.apache.struts2.dispatcher.RequestMap;
   41   import org.apache.struts2.views.jsp.TagUtils;
   42   
   43   import com.opensymphony.xwork2.ActionContext;
   44   import com.opensymphony.xwork2.ActionProxy;
   45   import com.opensymphony.xwork2.ActionProxyFactory;
   46   import com.opensymphony.xwork2.inject.Inject;
   47   import com.opensymphony.xwork2.util.ValueStack;
   48   import com.opensymphony.xwork2.util.ValueStackFactory;
   49   
   50   /**
   51    * <!-- START SNIPPET: javadoc -->
   52    * <p>This tag enables developers to call actions directly from a JSP page by specifying the action name and an optional
   53    * namespace.  The body content of the tag is used to render the results from the Action.  Any result processor defined
   54    * for this action in struts.xml will be ignored, <i>unless</i> the executeResult parameter is specified.</p>
   55    * <!-- END SNIPPET: javadoc -->
   56    *
   57    * <!-- START SNIPPET: params -->
   58    * <ul>
   59    *      <li>id (String) - the id (if specified) to put the action under stack's context.
   60    *      <li>name* (String) - name of the action to be executed (without the extension suffix eg. .action)</li>
   61    *      <li>namespace (String) - default to the namespace where this action tag is invoked</li>
   62    *      <li>executeResult (Boolean) -  default is false. Decides wheather the result of this action is to be executed or not</li>
   63    *      <li>ignoreContextParams (Boolean) - default to false. Decides wheather the request parameters are to be included when the action is invoked</li>
   64    * </ul>
   65    * <!-- END SNIPPET: params -->
   66    *
   67    * <pre>
   68    * <!-- START SNIPPET: javacode -->
   69    * public class ActionTagAction extends ActionSupport {
   70    *
   71    *  public String execute() throws Exception {
   72    *      return "done";
   73    *  }
   74    *
   75    *  public String doDefault() throws Exception {
   76    *      ServletActionContext.getRequest().setAttribute("stringByAction", "This is a String put in by the action's doDefault()");
   77    *      return "done";
   78    *  }
   79    * }
   80    * <!-- END SNIPPET: javacode -->
   81    * </pre>
   82    *
   83    * <pre>
   84    * <!-- START SNIPPET: strutsxml -->
   85    *   <xwork>
   86    *      ....
   87    *     <action name="actionTagAction1" class="tmjee.testing.ActionTagAction">
   88    *         <result name="done">success.jsp</result>
   89    *     </action>
   90    *      <action name="actionTagAction2" class="tmjee.testing.ActionTagAction" method="default">
   91    *         <result name="done">success.jsp</result>
   92    *     </action>
   93    *      ....
   94    *   </xwork>
   95    * <!-- END SNIPPET: strutsxml -->
   96    * </pre>
   97    *
   98    * <pre>
   99    * <!-- START SNIPPET: example -->
  100    *  <div>The following action tag will execute result and include it in this page</div>
  101    *  <br />
  102    *  <s:action name="actionTagAction" executeResult="true" />
  103    *  <br />
  104    *  <div>The following action tag will do the same as above, but invokes method specialMethod in action</div>
  105    *  <br />
  106    *  <s:action name="actionTagAction!specialMethod" executeResult="true" />
  107    *  <br />
  108    *  <div>The following action tag will not execute result, but put a String in request scope
  109    *       under an id "stringByAction" which will be retrieved using property tag</div>
  110    *  <s:action name="actionTagAction!default" executeResult="false" />
  111    *  <s:property value="#attr.stringByAction" />
  112    * <!-- END SNIPPET: example -->
  113    * </pre>
  114    *
  115    */
  116   @StrutsTag(name="action", tldTagClass="org.apache.struts2.views.jsp.ActionTag", description="Execute an action from within a view")
  117   public class ActionComponent extends Component {
  118       private static final Log LOG = LogFactory.getLog(ActionComponent.class);
  119   
  120       protected HttpServletResponse res;
  121       protected HttpServletRequest req;
  122   
  123       protected ActionProxyFactory actionProxyFactory;
  124       protected ActionProxy proxy;
  125       protected String name;
  126       protected String namespace;
  127       protected boolean executeResult;
  128       protected boolean ignoreContextParams;
  129       protected boolean flush = true;
  130   
  131       public ActionComponent(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
  132           super(stack);
  133           this.req = req;
  134           this.res = res;
  135       }
  136   
  137       /**
  138        * @param actionProxyFactory the actionProxyFactory to set
  139        */
  140       @Inject
  141       public void setActionProxyFactory(ActionProxyFactory actionProxyFactory) {
  142           this.actionProxyFactory = actionProxyFactory;
  143       }
  144   
  145       public boolean end(Writer writer, String body) {
  146           boolean end = super.end(writer, "", false);
  147           try {
  148               if (flush) {
  149                   try {
  150                       writer.flush();
  151                   } catch (IOException e) {
  152                       LOG.warn("error while trying to flush writer ", e);
  153                   }
  154               }
  155               executeAction();
  156   
  157               if ((getId() != null) && (proxy != null)) {
  158                   getStack().setValue("#attr['" + getId() + "']",
  159                           proxy.getAction());
  160               }
  161           } finally {
  162               popComponentStack();
  163           }
  164           return end;
  165       }
  166   
  167       private Map createExtraContext() {
  168           Map parentParams = null;
  169   
  170           if (!ignoreContextParams) {
  171               parentParams = new ActionContext(getStack().getContext()).getParameters();
  172           }
  173   
  174           Map newParams = (parentParams != null) ? new HashMap(parentParams) : new HashMap();
  175   
  176           if (parameters != null) {
  177               newParams.putAll(parameters);
  178           }
  179   
  180           ActionContext ctx = new ActionContext(stack.getContext());
  181           ServletContext servletContext = (ServletContext) ctx.get(ServletActionContext.SERVLET_CONTEXT);
  182           PageContext pageContext = (PageContext) ctx.get(ServletActionContext.PAGE_CONTEXT);
  183           Map session = ctx.getSession();
  184           Map application = ctx.getApplication();
  185   
  186           Dispatcher du = Dispatcher.getInstance();
  187           Map extraContext = du.createContextMap(new RequestMap(req),
  188                   newParams,
  189                   session,
  190                   application,
  191                   req,
  192                   res,
  193                   servletContext);
  194   
  195           ValueStack newStack = ValueStackFactory.getFactory().createValueStack(stack);
  196           extraContext.put(ActionContext.VALUE_STACK, newStack);
  197   
  198           // add page context, such that ServletDispatcherResult will do an include
  199           extraContext.put(ServletActionContext.PAGE_CONTEXT, pageContext);
  200   
  201           return extraContext;
  202       }
  203   
  204       public ActionProxy getProxy() {
  205           return proxy;
  206       }
  207   
  208       /**
  209        * Execute the requested action.  If no namespace is provided, we'll
  210        * attempt to derive a namespace using buildNamespace().  The ActionProxy
  211        * and the namespace will be saved into the instance variables proxy and
  212        * namespace respectively.
  213        *
  214        * @see org.apache.struts2.views.jsp.TagUtils#buildNamespace
  215        */
  216       private void executeAction() {
  217           String actualName = findString(name, "name", "Action name is required. Example: updatePerson");
  218   
  219           if (actualName == null) {
  220               throw new StrutsException("Unable to find value for name " + name);
  221           }
  222   
  223           // handle "name!method" convention.
  224           final String actionName;
  225           final String methodName;
  226   
  227           int exclamation = actualName.lastIndexOf("!");
  228           if (exclamation != -1) {
  229               actionName = actualName.substring(0, exclamation);
  230               methodName = actualName.substring(exclamation + 1);
  231           } else {
  232               actionName = actualName;
  233               methodName = null;
  234           }
  235   
  236           String namespace;
  237   
  238           if (this.namespace == null) {
  239               namespace = TagUtils.buildNamespace(actionMapper, getStack(), req);
  240           } else {
  241               namespace = findString(this.namespace);
  242           }
  243   
  244           // get the old value stack from the request
  245           ValueStack stack = getStack();
  246           // execute at this point, after params have been set
  247           try {
  248   
  249               proxy = actionProxyFactory.createActionProxy(namespace, actionName, createExtraContext(), executeResult, true);
  250               if (null != methodName) {
  251                   proxy.setMethod(methodName);
  252               }
  253               // set the new stack into the request for the taglib to use
  254               req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
  255               proxy.execute();
  256   
  257           } catch (Exception e) {
  258               String message = "Could not execute action: " + namespace + "/" + actualName;
  259               LOG.error(message, e);
  260           } finally {
  261               // set the old stack back on the request
  262               req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
  263           }
  264   
  265           if ((getId() != null) && (proxy != null)) {
  266               final Map context = stack.getContext();
  267               context.put(getId(), proxy.getAction());
  268           }
  269       }
  270   
  271       @StrutsTagAttribute(required=true,description="Name of the action to be executed (without the extension suffix eg. .action)")
  272       public void setName(String name) {
  273           this.name = name;
  274       }
  275   
  276       @StrutsTagAttribute(description="Namespace for action to call", defaultValue="namespace from where tag is used")
  277       public void setNamespace(String namespace) {
  278           this.namespace = namespace;
  279       }
  280   
  281       @StrutsTagAttribute(description="Whether the result of this action (probably a view) should be executed/rendered", type="Boolean", defaultValue="false")
  282       public void setExecuteResult(boolean executeResult) {
  283           this.executeResult = executeResult;
  284       }
  285   
  286       @StrutsTagAttribute(description="Whether the request parameters are to be included when the action is invoked", type="Boolean", defaultValue="false")
  287       public void setIgnoreContextParams(boolean ignoreContextParams) {
  288           this.ignoreContextParams = ignoreContextParams;
  289       }
  290   
  291       @StrutsTagAttribute(description="Whether the writer should be flush upon end of action component tag, default to true", type="Boolean", defaultValue="true")
  292       public void setFlush(boolean flush) {
  293           this.flush = flush;
  294       }
  295   }

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