View Javadoc

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