001: /*
002: * $Id: ActionRedirect.java 513602 2007-03-02 02:50:23Z pbenedict $
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.struts.action;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.apache.struts.config.ForwardConfig;
026: import org.apache.struts.util.ResponseUtils;
027:
028: import java.util.ArrayList;
029: import java.util.Arrays;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034:
035: /**
036: * <p> A subclass of {@link ActionForward} which is designed for use in
037: * redirecting requests, with support for adding parameters at runtime. <br/>
038: * An {@link ForwardConfig} (or subclass) can be passed to the constructor to
039: * copy its configuration: </p> <p>
040: * <pre>
041: * public ActionForward execute(ActionMapping mapping,
042: * ActionForm form,
043: * HttpServletRequest request,
044: * HttpServletResponse response)
045: * throws Exception {
046: * ActionRedirect redirect =
047: * new ActionRedirect(mapping.findForward("doRedirect"));
048: * redirect.addParameter("param1","value1");
049: * redirect.addParameter("param2","2");
050: * redirect.addParameter("param3","3.0");
051: * return redirect;
052: * }
053: * </pre>
054: * </p>
055: *
056: * @version $Rev: 513602 $ $Date: 2007-03-01 20:50:23 -0600 (Thu, 01 Mar 2007) $
057: */
058: public class ActionRedirect extends ActionForward {
059: // ----------------------------------------------------- Manifest constants
060:
061: /**
062: * <p>Default allocation size for string buffers.</p>
063: */
064: private static final int DEFAULT_BUFFER_SIZE = 256;
065:
066: // ----------------------------------------------------- Static variables
067:
068: /**
069: * <p>Commons logging instance.</p>
070: */
071: protected static final Log LOG = LogFactory
072: .getLog(ActionRedirect.class);
073:
074: // ----------------------------------------------------- Instance variables
075:
076: /**
077: * <p>Holds the redirect parameters. Each entry is either a String or a
078: * String[] depending on whether it has one or more entries.</p>
079: */
080: protected Map parameterValues = null;
081:
082: /**
083: * <p>Holds the anchor value.</p>
084: */
085: protected String anchorValue = null;
086:
087: // ----------------------------------------------------- Constructors
088:
089: /**
090: * <p>Construct a new instance with redirect set to true and initialize
091: * parameter lists.</p>
092: */
093: public ActionRedirect() {
094: setRedirect(true);
095: initializeParameters();
096: }
097:
098: /**
099: * <p>Construct a new instance with the specified path and initialize
100: * parameter lists.</p>
101: *
102: * @param path Path for this instance
103: */
104: public ActionRedirect(String path) {
105: super (path);
106: setRedirect(true);
107: initializeParameters();
108: }
109:
110: /**
111: * <p>Construct a new instance with the specified values and initialize
112: * parameter lists.</p>
113: *
114: * @param name Name of this instance
115: * @param path Path for this instance
116: * @param module Module prefix, if any
117: */
118: public ActionRedirect(String name, String path, String module) {
119: super (name, path, true);
120: setModule(module);
121: initializeParameters();
122: }
123:
124: /**
125: * <p>Construct a new instance with a {@link ForwardConfig} object to copy
126: * name, path, contextRelative, and arbitrary property values from.</p>
127: *
128: * @param baseConfig the {@link ForwardConfig} to copy configuration
129: * values from
130: */
131: public ActionRedirect(ForwardConfig baseConfig) {
132: setName(baseConfig.getName());
133: setPath(baseConfig.getPath());
134: setModule(baseConfig.getModule());
135: setRedirect(true);
136: inheritProperties(baseConfig);
137: initializeParameters();
138: }
139:
140: // ----------------------------------------------------- Private methods
141:
142: /**
143: * <p>Initializes the internal objects used to hold parameter values.</p>
144: */
145: private void initializeParameters() {
146: parameterValues = new HashMap();
147: }
148:
149: // ----------------------------------------------------- Public methods
150:
151: /**
152: * <p>Adds the object's toString() to the list of parameters if it's not
153: * null, or an empty string with the given fieldName if it is.</p>
154: *
155: * @param fieldName the name to use for the parameter
156: * @param valueObj the value for this parameter
157: * @return The ActionRedirect instance this method is called on
158: */
159: public ActionRedirect addParameter(String fieldName, Object valueObj) {
160: String value = (valueObj != null) ? valueObj.toString() : "";
161:
162: if (parameterValues == null) {
163: initializeParameters();
164: }
165:
166: //try {
167: value = ResponseUtils.encodeURL(value);
168:
169: //} catch (UnsupportedEncodingException uce) {
170: // this shouldn't happen since UTF-8 is the W3C Recommendation
171: // String errorMsg = "UTF-8 Character Encoding not supported";
172: // LOG.error(errorMsg, uce);
173: // throw new RuntimeException(errorMsg, uce);
174: // }
175: Object currentValue = parameterValues.get(fieldName);
176:
177: if (currentValue == null) {
178: // there's no value for this param yet; add it to the map
179: parameterValues.put(fieldName, value);
180: } else if (currentValue instanceof String) {
181: // there's already a value; let's use an array for these parameters
182: String[] newValue = new String[2];
183:
184: newValue[0] = (String) currentValue;
185: newValue[1] = value;
186: parameterValues.put(fieldName, newValue);
187: } else if (currentValue instanceof String[]) {
188: // add the value to the list of existing values
189: List newValues = new ArrayList(Arrays
190: .asList((Object[]) currentValue));
191:
192: newValues.add(value);
193: parameterValues.put(fieldName, newValues
194: .toArray(new String[newValues.size()]));
195: }
196: return this ;
197: }
198:
199: /**
200: * <p>Adds an anchor to the path. Technically, the anchor value is
201: * just stored for later and will be added to the path in getPath().
202: * Note that this is a considerably simpler method than the
203: * addParmaeter method because aside from encoding the value, there
204: * isn't really anything to do. Passing in null is fine because that
205: * is the value that will be checked for later to determine whether
206: * to append an anchor to the path or not.</p>
207: *
208: * @param anchorValue The anchor to append to the path
209: * @return The ActionRefirect instance this method is called on
210: */
211: public ActionRedirect setAnchor(String anchorValue) {
212: this .anchorValue = ResponseUtils.encodeURL(anchorValue);
213: return this ;
214: }
215:
216: /**
217: * <p>Get the original path without the parameters added at runtime.</p>
218: *
219: * @return the original path as configured.
220: */
221: public String getOriginalPath() {
222: return super .getPath();
223: }
224:
225: /**
226: * <p>Get the path for this object, including any parameters that may have
227: * been added at runtime.</p>
228: *
229: * @return The path for this object.
230: */
231: public String getPath() {
232: // get the original path and the parameter string that was formed
233: String originalPath = getOriginalPath();
234: String parameterString = getParameterString();
235: String anchorString = getAnchorString();
236:
237: StringBuffer result = new StringBuffer(originalPath);
238:
239: if ((parameterString != null) && (parameterString.length() > 0)) {
240: // the parameter separator we're going to use
241: String paramSeparator = "?";
242:
243: // true if we need to use a parameter separator after originalPath
244: boolean needsParamSeparator = true;
245:
246: // does the original path already have a "?"?
247: int paramStartIndex = originalPath.indexOf("?");
248:
249: if (paramStartIndex > 0) {
250: // did the path end with "?"?
251: needsParamSeparator = (paramStartIndex != (originalPath
252: .length() - 1));
253:
254: if (needsParamSeparator) {
255: paramSeparator = "&";
256: }
257: }
258:
259: if (needsParamSeparator) {
260: result.append(paramSeparator);
261: }
262:
263: result.append(parameterString);
264: }
265:
266: // append anchor string (or blank if none was set)
267: result.append(anchorString);
268:
269: return result.toString();
270: }
271:
272: /**
273: * <p>Forms the string containing the parameters
274: * passed onto this object thru calls to addParameter().</p>
275: *
276: * @return a string which can be appended to the URLs. The
277: * return string includes a leading hash
278: * mark (#).
279: */
280: public String getAnchorString() {
281: String retVal = "";
282: if (anchorValue != null) {
283: retVal = "#" + anchorValue;
284: }
285: return retVal;
286: }
287:
288: /**
289: * <p>Forms the string containing the parameters passed onto this object
290: * thru calls to addParameter().</p>
291: *
292: * @return a string which can be appended to the URLs. The return string
293: * does not include a leading question mark (?).
294: */
295: public String getParameterString() {
296: StringBuffer strParam = new StringBuffer(DEFAULT_BUFFER_SIZE);
297:
298: // loop through all parameters
299: Iterator iterator = parameterValues.keySet().iterator();
300:
301: while (iterator.hasNext()) {
302: // get the parameter name
303: String paramName = (String) iterator.next();
304:
305: // get the value for this parameter
306: Object value = parameterValues.get(paramName);
307:
308: if (value instanceof String) {
309: // just one value for this param
310: strParam.append(paramName).append("=").append(value);
311: } else if (value instanceof String[]) {
312: // loop through all values for this param
313: String[] values = (String[]) value;
314:
315: for (int i = 0; i < values.length; i++) {
316: strParam.append(paramName).append("=").append(
317: values[i]);
318:
319: if (i < (values.length - 1)) {
320: strParam.append("&");
321: }
322: }
323: }
324:
325: if (iterator.hasNext()) {
326: strParam.append("&");
327: }
328: }
329:
330: return strParam.toString();
331: }
332:
333: // ----------------------------------------------------- toString()
334:
335: /**
336: * <p>Return a string description of this object.</p>
337: *
338: * @return a string containing the original path for this object and the
339: * parameters it currently holds
340: */
341: public String toString() {
342: StringBuffer result = new StringBuffer(DEFAULT_BUFFER_SIZE);
343:
344: result.append("ActionRedirect [");
345: result.append("originalPath=").append(getOriginalPath())
346: .append(";");
347: result.append("parameterString=").append(getParameterString())
348: .append("]");
349: result.append("anchorString=").append(getAnchorString())
350: .append("]");
351:
352: return result.toString();
353: }
354: }
|