Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » components » [javadoc | source]
    1   /*
    2    * $Id: Form.java 569304 2007-08-24 09:12:20Z nilsga $
    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 com.opensymphony.xwork2.ActionContext;
   24   import com.opensymphony.xwork2.ActionInvocation;
   25   import com.opensymphony.xwork2.ObjectFactory;
   26   import com.opensymphony.xwork2.config.Configuration;
   27   import com.opensymphony.xwork2.config.RuntimeConfiguration;
   28   import com.opensymphony.xwork2.config.entities.ActionConfig;
   29   import com.opensymphony.xwork2.config.entities.InterceptorMapping;
   30   import com.opensymphony.xwork2.inject.Inject;
   31   import com.opensymphony.xwork2.interceptor.MethodFilterInterceptorUtil;
   32   import com.opensymphony.xwork2.util.TextUtils;
   33   import com.opensymphony.xwork2.util.ValueStack;
   34   import com.opensymphony.xwork2.validator.ActionValidatorManagerFactory;
   35   import com.opensymphony.xwork2.validator.FieldValidator;
   36   import com.opensymphony.xwork2.validator.ValidationInterceptor;
   37   import com.opensymphony.xwork2.validator.Validator;
   38   import org.apache.commons.logging.Log;
   39   import org.apache.commons.logging.LogFactory;
   40   import org.apache.struts2.StrutsConstants;
   41   import org.apache.struts2.dispatcher.Dispatcher;
   42   import org.apache.struts2.dispatcher.mapper.ActionMapping;
   43   import org.apache.struts2.portlet.context.PortletActionContext;
   44   import org.apache.struts2.portlet.util.PortletUrlHelper;
   45   import org.apache.struts2.views.annotations.StrutsTag;
   46   import org.apache.struts2.views.annotations.StrutsTagAttribute;
   47   import org.apache.struts2.views.util.UrlHelper;
   48   
   49   import javax.servlet.http.HttpServletRequest;
   50   import javax.servlet.http.HttpServletResponse;
   51   import java.util.ArrayList;
   52   import java.util.Collections;
   53   import java.util.List;
   54   import java.util.Set;
   55   
   56   /**
   57    * <!-- START SNIPPET: javadoc -->
   58    * <p/>
   59    * Renders HTML an input form.<p/>
   60    * <p/>
   61    * The remote form allows the form to be submitted without the page being refreshed. The results from the form
   62    * can be inserted into any HTML element on the page.<p/>
   63    * <p/>
   64    * NOTE:<p/>
   65    * The order / logic in determining the posting url of the generated HTML form is as follows:-
   66    * <ol>
   67    * <li>
   68    * If the action attribute is not specified, then the current request will be used to
   69    * determine the posting url
   70    * </li>
   71    * <li>
   72    * If the action is given, Struts will try to obtain an ActionConfig. This will be
   73    * successfull if the action attribute is a valid action alias defined struts.xml.
   74    * </li>
   75    * <li>
   76    * If the action is given and is not an action alias defined in struts.xml, Struts
   77    * will used the action attribute as if it is the posting url, separting the namespace
   78    * from it and using UrlHelper to generate the final url.
   79    * </li>
   80    * </ol>
   81    * <p/>
   82    * <!-- END SNIPPET: javadoc -->
   83    * <p/>
   84    * <p/> <b>Examples</b>
   85    * <p/>
   86    * <pre>
   87    * <!-- START SNIPPET: example -->
   88    * <p/>
   89    * &lt;s:form ... /&gt;
   90    * <p/>
   91    * <!-- END SNIPPET: example -->
   92    * </pre>
   93    *
   94    */
   95   @StrutsTag(name="form", tldTagClass="org.apache.struts2.views.jsp.ui.FormTag", description="Renders an input form")
   96   public class Form extends ClosingUIBean {
   97       /**
   98        * Provide a logging instance.
   99        */
  100       private static final Log LOG = LogFactory.getLog(Form.class);
  101   
  102       public static final String OPEN_TEMPLATE = "form";
  103       public static final String TEMPLATE = "form-close";
  104   
  105       private int sequence = 0;
  106   
  107       protected String onsubmit;
  108       protected String action;
  109       protected String target;
  110       protected String enctype;
  111       protected String method;
  112       protected String namespace;
  113       protected String validate;
  114       protected String portletMode;
  115       protected String windowState;
  116       protected String acceptcharset;
  117   
  118       protected boolean enableDynamicMethodInvocation = true;
  119       protected Configuration configuration;
  120       protected ObjectFactory objectFactory;
  121   
  122       public Form(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
  123           super(stack, request, response);
  124       }
  125   
  126       protected boolean evaluateNameValue() {
  127           return false;
  128       }
  129   
  130       public String getDefaultOpenTemplate() {
  131           return OPEN_TEMPLATE;
  132       }
  133   
  134       protected String getDefaultTemplate() {
  135           return TEMPLATE;
  136       }
  137   
  138       @Inject(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION)
  139       public void setEnableDynamicMethodInvocation(String enable) {
  140           enableDynamicMethodInvocation = "true".equals(enable);
  141       }
  142   
  143       @Inject
  144       public void setConfiguration(Configuration configuration) {
  145           this.configuration = configuration;
  146       }
  147   
  148       @Inject
  149       public void setObjectFactory(ObjectFactory objectFactory) {
  150           this.objectFactory = objectFactory;
  151       }
  152   
  153   
  154       /*
  155       * Revised for Portlet actionURL as form action, and add wwAction as hidden
  156       * field. Refer to template.simple/form.vm
  157       */
  158       protected void evaluateExtraParams() {
  159           super.evaluateExtraParams();
  160   
  161           //boolean isAjax = "ajax".equalsIgnoreCase(this.theme);
  162   
  163           if (validate != null) {
  164               addParameter("validate", findValue(validate, Boolean.class));
  165           }
  166   
  167           // calculate the action and namespace
  168           /*String action = null;
  169           if (this.action != null) {
  170               // if it isn't specified, we'll make somethig up
  171               action = findString(this.action);
  172           }
  173   
  174           if (Dispatcher.getInstance().isPortletSupportActive() && PortletActionContext.isPortletRequest()) {
  175               evaluateExtraParamsPortletRequest(namespace, action);
  176           } else {
  177               String namespace = determineNamespace(this.namespace, getStack(),
  178                       request);
  179               evaluateExtraParamsServletRequest(action, namespace, isAjax);
  180           }*/
  181   
  182           if (onsubmit != null) {
  183               addParameter("onsubmit", findString(onsubmit));
  184           }
  185   
  186           if (target != null) {
  187               addParameter("target", findString(target));
  188           }
  189   
  190           if (enctype != null) {
  191               addParameter("enctype", findString(enctype));
  192           }
  193   
  194           if (method != null) {
  195               addParameter("method", findString(method));
  196           }
  197   
  198           if (acceptcharset != null) {
  199               addParameter("acceptcharset", findString(acceptcharset));
  200           }
  201   
  202           // keep a collection of the tag names for anything special the templates might want to do (such as pure client
  203           // side validation)
  204           if (!parameters.containsKey("tagNames")) {
  205               // we have this if check so we don't do this twice (on open and close of the template)
  206               addParameter("tagNames", new ArrayList());
  207           }
  208       }
  209   
  210       /**
  211        * The Form component determines its HTML element id as follows:-
  212        * <ol>
  213        *    <li>if an 'id' attribute is specified.</li>
  214        *    <li>if an 'action' attribute is specified, it will be used as the id.</li>
  215        * </ol>
  216        */
  217       protected void populateComponentHtmlId(Form form) {
  218           boolean isAjax = "ajax".equalsIgnoreCase(this.theme);
  219   
  220           String action = null;
  221           if (this.action != null) {
  222               // if it isn't specified, we'll make somethig up
  223               action = findString(this.action);
  224           }
  225   
  226           if (id != null) {
  227               addParameter("id", escape(id));
  228           }
  229   
  230           // if no id given, it will be tried to generate it from the action attribute in the
  231           // corresponding evaluateExtraParams method
  232           if (Dispatcher.getInstance().isPortletSupportActive() && PortletActionContext.isPortletRequest()) {
  233               evaluateExtraParamsPortletRequest(namespace, action);
  234           } else {
  235               String namespace = determineNamespace(this.namespace, getStack(),
  236                       request);
  237               evaluateExtraParamsServletRequest(action, namespace, isAjax);
  238           }
  239       }
  240   
  241       /**
  242        * @param isAjax
  243        * @param namespace
  244        * @param action
  245        */
  246       private void evaluateExtraParamsServletRequest(String action, String namespace, boolean isAjax) {
  247           if (action == null) {
  248               // no action supplied? ok, then default to the current request (action or general URL)
  249               ActionInvocation ai = (ActionInvocation) getStack().getContext().get(ActionContext.ACTION_INVOCATION);
  250               if (ai != null) {
  251                   action = ai.getProxy().getActionName();
  252                   namespace = ai.getProxy().getNamespace();
  253               } else {
  254                   // hmm, ok, we need to just assume the current URL cut down
  255                   String uri = request.getRequestURI();
  256                   action = uri.substring(uri.lastIndexOf('/'));
  257               }
  258           }
  259   
  260           String actionMethod = "";
  261           // FIXME: our implementation is flawed - the only concept of ! should be in DefaultActionMapper
  262           // handle "name!method" convention.
  263           if (enableDynamicMethodInvocation) {
  264               if (action.indexOf("!") != -1) {
  265                   int endIdx = action.lastIndexOf("!");
  266                   actionMethod = action.substring(endIdx + 1, action.length());
  267                   action = action.substring(0, endIdx);
  268               }
  269           }
  270   
  271           final ActionConfig actionConfig = configuration.getRuntimeConfiguration().getActionConfig(namespace, action);
  272           String actionName = action;
  273           if (actionConfig != null) {
  274   
  275               ActionMapping mapping = new ActionMapping(action, namespace, actionMethod, parameters);
  276               String result = UrlHelper.buildUrl(actionMapper.getUriFromActionMapping(mapping), request, response, null);
  277               addParameter("action", result);
  278   
  279               // let's try to get the actual action class and name
  280               // this can be used for getting the list of validators
  281               addParameter("actionName", actionName);
  282               try {
  283                   Class clazz = objectFactory.getClassInstance(actionConfig.getClassName());
  284                   addParameter("actionClass", clazz);
  285               } catch (ClassNotFoundException e) {
  286                   // this is OK, we'll just move on
  287               }
  288   
  289               addParameter("namespace", namespace);
  290   
  291               // if the name isn't specified, use the action name
  292               if (name == null) {
  293                   addParameter("name", action);
  294               }
  295   
  296               // if the id isn't specified, use the action name
  297               if (id == null && action!=null) {
  298                   addParameter("id", escape(action));
  299               }
  300           } else if (action != null) {
  301               // Since we can't find an action alias in the configuration, we just assume
  302               // the action attribute supplied is the path to be used as the URI this
  303               // form is submitting to.
  304   
  305               // Warn user that the specified namespace/action combo
  306               // was not found in the configuration.
  307               if (namespace != null) {
  308                   LOG.warn("No configuration found for the specified action: '" + action + "' in namespace: '" + namespace + "'. Form action defaulting to 'action' attribute's literal value.");
  309               }
  310   
  311               String result = UrlHelper.buildUrl(action, request, response, null);
  312               addParameter("action", result);
  313   
  314               // namespace: cut out anything between the start and the last /
  315               int slash = result.lastIndexOf('/');
  316               if (slash != -1) {
  317                   addParameter("namespace", result.substring(0, slash));
  318               } else {
  319                   addParameter("namespace", "");
  320               }
  321   
  322               // name/id: cut out anything between / and . should be the id and name
  323               if (id == null) {
  324                   slash = result.lastIndexOf('/');
  325                   int dot = result.indexOf('.', slash);
  326                   if (dot != -1) {
  327                       id = result.substring(slash + 1, dot);
  328                   } else {
  329                       id = result.substring(slash + 1);
  330                   }
  331                   addParameter("id", escape(id));
  332               }
  333           }
  334   
  335           // WW-1284
  336           // evaluate if client-side js is to be enabled. (if validation interceptor
  337           // does allow validation eg. method is not filtered out)
  338           evaluateClientSideJsEnablement(actionName, namespace, actionMethod);
  339       }
  340   
  341       private void evaluateClientSideJsEnablement(String actionName, String namespace, String actionMethod) {
  342   
  343           // Only evaluate if Client-Side js is to be enable when validate=true
  344           Boolean validate = (Boolean) getParameters().get("validate");
  345           if (validate != null && validate) {
  346   
  347               addParameter("performValidation", Boolean.FALSE);
  348   
  349               RuntimeConfiguration runtimeConfiguration = configuration.getRuntimeConfiguration();
  350               ActionConfig actionConfig = runtimeConfiguration.getActionConfig(namespace, actionName);
  351   
  352               if (actionConfig != null) {
  353                   List<InterceptorMapping> interceptors = actionConfig.getInterceptors();
  354                   for (InterceptorMapping interceptorMapping : interceptors) {
  355                       if (ValidationInterceptor.class.isInstance(interceptorMapping.getInterceptor())) {
  356                           ValidationInterceptor validationInterceptor = (ValidationInterceptor) interceptorMapping.getInterceptor();
  357   
  358                           Set excludeMethods = validationInterceptor.getExcludeMethodsSet();
  359                           Set includeMethods = validationInterceptor.getIncludeMethodsSet();
  360   
  361                           if (MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, actionMethod)) {
  362                               addParameter("performValidation", Boolean.TRUE);
  363                           }
  364                           return;
  365                       }
  366                   }
  367               }
  368           }
  369       }
  370   
  371       /**
  372        * Constructs the action url adapted to a portal environment.
  373        *
  374        * @param action The action to create the URL for.
  375        */
  376       private void evaluateExtraParamsPortletRequest(String namespace, String action) {
  377   
  378           String type = "action";
  379           if (TextUtils.stringSet(method)) {
  380               if ("GET".equalsIgnoreCase(method.trim())) {
  381                   type = "render";
  382               }
  383           }
  384           if (action != null) {
  385               String result = PortletUrlHelper.buildUrl(action, namespace, null,
  386                       getParameters(), type, portletMode, windowState);
  387               addParameter("action", result);
  388   
  389               // namespace: cut out anything between the start and the last /
  390               int slash = result.lastIndexOf('/');
  391               if (slash != -1) {
  392                   addParameter("namespace", result.substring(0, slash));
  393               } else {
  394                   addParameter("namespace", "");
  395               }
  396   
  397               // name/id: cut out anything between / and . should be the id and
  398               // name
  399               if (id == null) {
  400                   slash = action.lastIndexOf('/');
  401                   int dot = action.indexOf('.', slash);
  402                   if (dot != -1) {
  403                       id = action.substring(slash + 1, dot);
  404                   } else {
  405                       id = action.substring(slash + 1);
  406                   }
  407                   addParameter("id", escape(id));
  408               }
  409           }
  410   
  411       }
  412   
  413       public List getValidators(String name) {
  414           Class actionClass = (Class) getParameters().get("actionClass");
  415           if (actionClass == null) {
  416               return Collections.EMPTY_LIST;
  417           }
  418   
  419           List<Validator> all = ActionValidatorManagerFactory.getInstance().getValidators(actionClass, (String) getParameters().get("actionName"));
  420           List<Validator> validators = new ArrayList<Validator>();
  421           for (Validator validator : all) {
  422               if (validator instanceof FieldValidator) {
  423                   FieldValidator fieldValidator = (FieldValidator) validator;
  424                   if (fieldValidator.getFieldName().equals(name)) {
  425                       validators.add(fieldValidator);
  426                   }
  427               }
  428           }
  429   
  430           return validators;
  431       }
  432   
  433       /**
  434        * Get a incrementing sequence unique to this <code>Form</code> component.
  435        * It is used by <code>Form</code> component's child that might need a
  436        * sequence to make them unique.
  437        *
  438        * @return int
  439        */
  440       protected int getSequence() {
  441           return sequence++;
  442       }
  443   
  444       @StrutsTagAttribute(description="HTML onsubmit attribute")
  445       public void setOnsubmit(String onsubmit) {
  446           this.onsubmit = onsubmit;
  447       }
  448   
  449       @StrutsTagAttribute(description="Set action name to submit to, without .action suffix", defaultValue="current action")
  450       public void setAction(String action) {
  451           this.action = action;
  452       }
  453   
  454       @StrutsTagAttribute(description="HTML form target attribute")
  455       public void setTarget(String target) {
  456           this.target = target;
  457       }
  458   
  459       @StrutsTagAttribute(description="HTML form enctype attribute")
  460       public void setEnctype(String enctype) {
  461           this.enctype = enctype;
  462       }
  463   
  464       @StrutsTagAttribute(description="HTML form method attribute")
  465       public void setMethod(String method) {
  466           this.method = method;
  467       }
  468   
  469       @StrutsTagAttribute(description="Namespace for action to submit to", defaultValue="current namespace")
  470       public void setNamespace(String namespace) {
  471           this.namespace = namespace;
  472       }
  473   
  474       @StrutsTagAttribute(description="Whether client side/remote validation should be performed. Only" +
  475                   " useful with theme xhtml/ajax", type="Boolean", defaultValue="false")
  476       public void setValidate(String validate) {
  477           this.validate = validate;
  478       }
  479   
  480       @StrutsTagAttribute(description="The portlet mode to display after the form submit")
  481       public void setPortletMode(String portletMode) {
  482           this.portletMode = portletMode;
  483       }
  484   
  485       @StrutsTagAttribute(description="The window state to display after the form submit")
  486       public void setWindowState(String windowState) {
  487           this.windowState = windowState;
  488       }
  489   
  490       @StrutsTagAttribute(description="The accepted charsets for this form. The values may be comma or blank delimited.")
  491       public void setAcceptcharset(String acceptcharset) {
  492           this.acceptcharset = acceptcharset;
  493       }
  494   }

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