1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 * <result name="success" type="redirect">
66 * <param name="<b>location</b>">foo.jsp</param>
67 * </result></pre>
68 * <p/>
69 * or
70 * <p/>
71 * <pre>
72 * <result name="success" type="redirect" >
73 * <param name="<b>location</b>">foo.jsp?url=${myUrl}</param>
74 * <param name="<b>parse</b>">true</param>
75 * <param name="<b>encode</b>">true</param>
76 * </result></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 * <result name="success" type="redirect"><b>foo.jsp</b></result></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 * <result-types>
94 * ...
95 * <result-type name="myresult" class="com.foo.MyResult" />
96 * </result-types></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
205
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 }