1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 * <result name="success" type="redirect">
62 * <param name="<b>location</b>">foo.jsp</param>
63 * </result></pre>
64 * <p/>
65 * or
66 * <p/>
67 * <pre>
68 * <result name="success" type="redirect" >
69 * <param name="<b>location</b>">foo.jsp?url=${myUrl}</param>
70 * <param name="<b>parse</b>">true</param>
71 * <param name="<b>encode</b>">true</param>
72 * </result></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 * <result name="success" type="redirect"><b>foo.jsp</b></result></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 * <result-types>
90 * ...
91 * <result-type name="myresult" class="com.foo.MyResult" />
92 * </result-types></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
194
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 }