View Javadoc

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