1 /*
2 * $Id: StrutsResultSupport.java 557291 2007-07-18 15:17:41Z jholmes $
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 * <result name="success" type="redirect">
65 * <param name="<b>location</b>">foo.jsp</param>
66 * </result></pre>
67 * <p/>
68 * or
69 * <p/>
70 * <pre>
71 * <result name="success" type="redirect" >
72 * <param name="<b>location</b>">foo.jsp?url=${myUrl}</param>
73 * <param name="<b>parse</b>">true</param>
74 * <param name="<b>encode</b>">true</param>
75 * </result></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 * <result name="success" type="redirect"><b>foo.jsp</b></result></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 * <result-types>
93 * ...
94 * <result-type name="myresult" class="com.foo.MyResult" />
95 * </result-types></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, true, 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 }