001: /*
002: * $Id: StrutsResultSupport.java 557291 2007-07-18 15:17:41Z jholmes $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.dispatcher;
022:
023: import java.io.UnsupportedEncodingException;
024: import java.net.URLEncoder;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.apache.struts2.StrutsStatics;
029:
030: import com.opensymphony.xwork2.ActionInvocation;
031: import com.opensymphony.xwork2.Result;
032: import com.opensymphony.xwork2.util.TextParseUtil;
033:
034: /**
035: * <!-- START SNIPPET: javadoc -->
036: *
037: * A base class for all Struts action execution results.
038: * The "location" param is the default parameter, meaning the most common usage of this result would be:
039: * <p/>
040: * This class provides two common parameters for any subclass:
041: * <ul>
042: * <li>location - the location to go to after execution (could be a jsp page or another action).
043: * It can be parsed as per the rules definied in the
044: * {@link TextParseUtil#translateVariables(java.lang.String, com.opensymphony.xwork2.util.ValueStack) translateVariables}
045: * method</li>
046: * <li>parse - true by default. If set to false, the location param will not be parsed for expressions</li>
047: * <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>
048: * </ul>
049: *
050: * <b>NOTE:</b>
051: * The encode param will only have effect when parse is true
052: *
053: * <!-- END SNIPPET: javadoc -->
054: *
055: * <p/>
056: *
057: * <!-- START SNIPPET: example -->
058: *
059: * <p/>
060: * In the struts.xml configuration file, these would be included as:
061: * <p/>
062: * <pre>
063: * <result name="success" type="redirect">
064: * <param name="<b>location</b>">foo.jsp</param>
065: * </result></pre>
066: * <p/>
067: * or
068: * <p/>
069: * <pre>
070: * <result name="success" type="redirect" >
071: * <param name="<b>location</b>">foo.jsp?url=${myUrl}</param>
072: * <param name="<b>parse</b>">true</param>
073: * <param name="<b>encode</b>">true</param>
074: * </result></pre>
075: * <p/>
076: * In the above case, myUrl will be parsed against Ognl Value Stack and then
077: * URL encoded.
078: * <p/>
079: * or when using the default parameter feature
080: * <p/>
081: * <pre>
082: * <result name="success" type="redirect"><b>foo.jsp</b></result></pre>
083: * <p/>
084: * You should subclass this class if you're interested in adding more parameters or functionality
085: * to your Result. If you do subclass this class you will need to
086: * override {@link #doExecute(String, ActionInvocation)}.<p>
087: * <p/>
088: * Any custom result can be defined in struts.xml as:
089: * <p/>
090: * <pre>
091: * <result-types>
092: * ...
093: * <result-type name="myresult" class="com.foo.MyResult" />
094: * </result-types></pre>
095: * <p/>
096: * Please see the {@link com.opensymphony.xwork2.Result} class for more info on Results in general.
097: *
098: * <!-- END SNIPPET: example -->
099: *
100: * @see com.opensymphony.xwork2.Result
101: */
102: public abstract class StrutsResultSupport implements Result,
103: StrutsStatics {
104:
105: private static final Log _log = LogFactory
106: .getLog(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,
125: boolean encode) {
126: this .location = location;
127: this .parse = parse;
128: this .encode = encode;
129: }
130:
131: /**
132: * The location to go to after action execution. This could be a JSP page or another action.
133: * The location can contain OGNL expressions which will be evaulated if the <tt>parse</tt>
134: * parameter is set to <tt>true</tt>.
135: *
136: * @param location the location to go to after action execution.
137: * @see #setParse(boolean)
138: */
139: public void setLocation(String location) {
140: this .location = location;
141: }
142:
143: /**
144: * Returns the last parsed and encoded location value
145: */
146: public String getLastFinalLocation() {
147: return lastFinalLocation;
148: }
149:
150: /**
151: * Set parse to <tt>true</tt> to indicate that the location should be parsed as an OGNL expression. This
152: * is set to <tt>true</tt> by default.
153: *
154: * @param parse <tt>true</tt> if the location parameter is an OGNL expression, <tt>false</tt> otherwise.
155: */
156: public void setParse(boolean parse) {
157: this .parse = parse;
158: }
159:
160: /**
161: * Set encode to <tt>true</tt> to indicate that the location should be url encoded. This is set to
162: * <tt>true</tt> by default
163: *
164: * @param encode <tt>true</tt> if the location parameter should be url encode, <tt>false</tt> otherwise.
165: */
166: public void setEncode(boolean encode) {
167: this .encode = encode;
168: }
169:
170: /**
171: * Implementation of the <tt>execute</tt> method from the <tt>Result</tt> interface. This will call
172: * the abstract method {@link #doExecute(String, ActionInvocation)} after optionally evaluating the
173: * location as an OGNL evaluation.
174: *
175: * @param invocation the execution state of the action.
176: * @throws Exception if an error occurs while executing the result.
177: */
178: public void execute(ActionInvocation invocation) throws Exception {
179: lastFinalLocation = conditionalParse(location, invocation);
180: doExecute(lastFinalLocation, invocation);
181: }
182:
183: /**
184: * Parses the parameter for OGNL expressions against the valuestack
185: *
186: * @param param The parameter value
187: * @param invocation The action invocation instance
188: * @return The resulting string
189: */
190: protected String conditionalParse(String param,
191: ActionInvocation invocation) {
192: if (parse && param != null && invocation != null) {
193: return TextParseUtil.translateVariables(param, invocation
194: .getStack(),
195: new TextParseUtil.ParsedValueEvaluator() {
196: public Object evaluate(Object parsedValue) {
197: if (encode) {
198: if (parsedValue != null) {
199: try {
200: // use UTF-8 as this is the recommended encoding by W3C to
201: // avoid incompatibilities.
202: return URLEncoder.encode(
203: parsedValue.toString(),
204: "UTF-8");
205: } catch (UnsupportedEncodingException e) {
206: _log.warn(
207: "error while trying to encode ["
208: + parsedValue
209: + "]", 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,
231: ActionInvocation invocation) throws Exception;
232: }
|