View Javadoc

    1   /*
    2    * $Id: StrutsResultSupport.java 471756 2006-11-06 15:01:43Z husted $
    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.dispatcher;
    22
    23  import java.io.UnsupportedEncodingException;
    24  import java.net.URLEncoder;
    25
    26  import org.apache.commons.logging.Log;
    27  import org.apache.commons.logging.LogFactory;
    28  import org.apache.struts2.StrutsStatics;
    29
    30  import com.opensymphony.xwork2.ActionInvocation;
    31  import com.opensymphony.xwork2.Result;
    32  import com.opensymphony.xwork2.util.TextParseUtil;
    33
    34
    35  /***
    36   * <!-- START SNIPPET: javadoc -->
    37   *
    38   * A base class for all Struts action execution results.
    39   * The "location" param is the default parameter, meaning the most common usage of this result would be:
    40   * <p/>
    41   * This class provides two common parameters for any subclass:
    42   * <ul>
    43   * <li>location - the location to go to after execution (could be a jsp page or another action).
    44   * It can be parsed as per the rules definied in the
    45   * {@link TextParseUtil#translateVariables(java.lang.String, com.opensymphony.xwork2.util.ValueStack) translateVariables}
    46   * method</li>
    47   * <li>parse - true by default. If set to false, the location param will not be parsed for expressions</li>
    48   * <li>encode - false by default. If set to false, the location param will not be url encoded. This only have effect when parse is true</li>
    49   * </ul>
    50   *
    51   * <b>NOTE:</b>
    52   * The encode param will only have effect when parse is true
    53   *
    54   * <!-- END SNIPPET: javadoc -->
    55   *
    56   * <p/>
    57   *
    58   * <!-- START SNIPPET: example -->
    59   *
    60   * <p/>
    61   * In the struts.xml configuration file, these would be included as:
    62   * <p/>
    63   * <pre>
    64   *  &lt;result name="success" type="redirect"&gt;
    65   *      &lt;param name="<b>location</b>"&gt;foo.jsp&lt;/param&gt;
    66   *  &lt;/result&gt;</pre>
    67   * <p/>
    68   * or
    69   * <p/>
    70   * <pre>
    71   *  &lt;result name="success" type="redirect" &gt;
    72   *      &lt;param name="<b>location</b>"&gt;foo.jsp?url=${myUrl}&lt;/param&gt;
    73   *      &lt;param name="<b>parse</b>"&gt;true&lt;/param&gt;
    74   *      &lt;param name="<b>encode</b>"&gt;true&lt;/param&gt;
    75   *  &lt;/result&gt;</pre>
    76   * <p/>
    77   * In the above case, myUrl will be parsed against Ognl Value Stack and then
    78   * URL encoded.
    79   * <p/>
    80   * or when using the default parameter feature
    81   * <p/>
    82   * <pre>
    83   *  &lt;result name="success" type="redirect"&gt;<b>foo.jsp</b>&lt;/result&gt;</pre>
    84   * <p/>
    85   * You should subclass this class if you're interested in adding more parameters or functionality
    86   * to your Result. If you do subclass this class you will need to
    87   * override {@link #doExecute(String, ActionInvocation)}.<p>
    88   * <p/>
    89   * Any custom result can be defined in struts.xml as:
    90   * <p/>
    91   * <pre>
    92   *  &lt;result-types&gt;
    93   *      ...
    94   *      &lt;result-type name="myresult" class="com.foo.MyResult" /&gt;
    95   *  &lt;/result-types&gt;</pre>
    96   * <p/>
    97   * Please see the {@link com.opensymphony.xwork2.Result} class for more info on Results in general.
    98   *
    99   * <!-- END SNIPPET: example -->
    100  *
    101  * @see com.opensymphony.xwork2.Result
    102  */
    103 public abstract class StrutsResultSupport implements Result, StrutsStatics {
    104
    105     private static final Log _log = LogFactory.getLog(StrutsResultSupport.class);
    106
    107     /*** The default parameter */
    108     public static final String DEFAULT_PARAM = "location";
    109
    110     private boolean parse;
    111     private boolean encode;
    112     private String location;
    113     private String lastFinalLocation;
    114
    115     public StrutsResultSupport() {
    116         this(null, true, false);
    117     }
    118
    119     public StrutsResultSupport(String location) {
    120         this(location, false, false);
    121     }
    122
    123     public StrutsResultSupport(String location, boolean parse, boolean encode) {
    124         this.location = location;
    125         this.parse = parse;
    126         this.encode = encode;
    127     }
    128
    129     /***
    130      * The location to go to after action execution. This could be a JSP page or another action.
    131      * The location can contain OGNL expressions which will be evaulated if the <tt>parse</tt>
    132      * parameter is set to <tt>true</tt>.
    133      *
    134      * @param location the location to go to after action execution.
    135      * @see #setParse(boolean)
    136      */
    137     public void setLocation(String location) {
    138         this.location = location;
    139     }
    140
    141     /***
    142      * Returns the last parsed and encoded location value
    143      */
    144     public String getLastFinalLocation() {
    145         return lastFinalLocation;
    146     }
    147
    148     /***
    149      * Set parse to <tt>true</tt> to indicate that the location should be parsed as an OGNL expression. This
    150      * is set to <tt>true</tt> by default.
    151      *
    152      * @param parse <tt>true</tt> if the location parameter is an OGNL expression, <tt>false</tt> otherwise.
    153      */
    154     public void setParse(boolean parse) {
    155         this.parse = parse;
    156     }
    157
    158     /***
    159      * Set encode to <tt>true</tt> to indicate that the location should be url encoded. This is set to
    160      * <tt>true</tt> by default
    161      *
    162      * @param encode <tt>true</tt> if the location parameter should be url encode, <tt>false</tt> otherwise.
    163      */
    164     public void setEncode(boolean encode) {
    165         this.encode = encode;
    166     }
    167
    168     /***
    169      * Implementation of the <tt>execute</tt> method from the <tt>Result</tt> interface. This will call
    170      * the abstract method {@link #doExecute(String, ActionInvocation)} after optionally evaluating the
    171      * location as an OGNL evaluation.
    172      *
    173      * @param invocation the execution state of the action.
    174      * @throws Exception if an error occurs while executing the result.
    175      */
    176     public void execute(ActionInvocation invocation) throws Exception {
    177         lastFinalLocation = conditionalParse(location, invocation);
    178         doExecute(lastFinalLocation, invocation);
    179     }
    180
    181     /***
    182      * Parses the parameter for OGNL expressions against the valuestack
    183      *
    184      * @param param The parameter value
    185      * @param invocation The action invocation instance
    186      * @return The resulting string
    187      */
    188     protected String conditionalParse(String param, ActionInvocation invocation) {
    189         if (parse && param != null && invocation != null) {
    190             return TextParseUtil.translateVariables(param, invocation.getStack(),
    191                     new TextParseUtil.ParsedValueEvaluator() {
    192                         public Object evaluate(Object parsedValue) {
    193                             if (encode) {
    194                                 if (parsedValue != null) {
    195                                     try {
    196                                         // use UTF-8 as this is the recommended encoding by W3C to
    197                                         // avoid incompatibilities.
    198                                         return URLEncoder.encode(parsedValue.toString(), "UTF-8");
    199                                     }
    200                                     catch(UnsupportedEncodingException e) {
    201                                         _log.warn("error while trying to encode ["+parsedValue+"]", e);
    202                                     }
    203                                 }
    204                             }
    205                             return parsedValue;
    206                         }
    207             });
    208         } else {
    209             return param;
    210         }
    211     }
    212
    213     /***
    214      * Executes the result given a final location (jsp page, action, etc) and the action invocation
    215      * (the state in which the action was executed). Subclasses must implement this class to handle
    216      * custom logic for result handling.
    217      *
    218      * @param finalLocation the location (jsp page, action, etc) to go to.
    219      * @param invocation    the execution state of the action.
    220      * @throws Exception if an error occurs while executing the result.
    221      */
    222     protected abstract void doExecute(String finalLocation, ActionInvocation invocation) throws Exception;
    223 }