View Javadoc

1   /*
2    * $Id: ActionRedirect.java 513602 2007-03-02 02:50:23Z pbenedict $
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.struts.action;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.struts.config.ForwardConfig;
26  import org.apache.struts.util.ResponseUtils;
27  
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Map;
34  
35  /**
36   * <p> A subclass of {@link ActionForward} which is designed for use in
37   * redirecting requests, with support for adding parameters at runtime. <br/>
38   * An {@link ForwardConfig} (or subclass) can be passed to the constructor to
39   * copy its configuration: </p> <p>
40   * <pre>
41   * public ActionForward execute(ActionMapping mapping,
42   *                              ActionForm form,
43   *                              HttpServletRequest request,
44   *                              HttpServletResponse response)
45   *         throws Exception {
46   *     ActionRedirect redirect =
47   *             new ActionRedirect(mapping.findForward("doRedirect"));
48   *     redirect.addParameter("param1","value1");
49   *     redirect.addParameter("param2","2");
50   *     redirect.addParameter("param3","3.0");
51   *     return redirect;
52   * }
53   * </pre>
54   * </p>
55   *
56   * @version $Rev: 513602 $ $Date: 2007-03-01 20:50:23 -0600 (Thu, 01 Mar 2007) $
57   */
58  public class ActionRedirect extends ActionForward {
59      // ----------------------------------------------------- Manifest constants
60  
61      /**
62       * <p>Default allocation size for string buffers.</p>
63       */
64      private static final int DEFAULT_BUFFER_SIZE = 256;
65  
66      // ----------------------------------------------------- Static variables
67  
68      /**
69       * <p>Commons logging instance.</p>
70       */
71      protected static final Log LOG = LogFactory.getLog(ActionRedirect.class);
72  
73      // ----------------------------------------------------- Instance variables
74  
75      /**
76       * <p>Holds the redirect parameters. Each entry is either a String or a
77       * String[] depending on whether it has one or more entries.</p>
78       */
79      protected Map parameterValues = null;
80  
81      /**
82       * <p>Holds the anchor value.</p>
83       */
84      protected String anchorValue = null;
85  
86      // ----------------------------------------------------- Constructors
87  
88      /**
89       * <p>Construct a new instance with redirect set to true and initialize
90       * parameter lists.</p>
91       */
92      public ActionRedirect() {
93          setRedirect(true);
94          initializeParameters();
95      }
96  
97      /**
98       * <p>Construct a new instance with the specified path and initialize
99       * parameter lists.</p>
100      *
101      * @param path Path for this instance
102      */
103     public ActionRedirect(String path) {
104         super(path);
105         setRedirect(true);
106         initializeParameters();
107     }
108 
109     /**
110      * <p>Construct a new instance with the specified values and initialize
111      * parameter lists.</p>
112      *
113      * @param name   Name of this instance
114      * @param path   Path for this instance
115      * @param module Module prefix, if any
116      */
117     public ActionRedirect(String name, String path, String module) {
118         super(name, path, true);
119         setModule(module);
120         initializeParameters();
121     }
122 
123     /**
124      * <p>Construct a new instance with a {@link ForwardConfig} object to copy
125      * name, path, contextRelative, and arbitrary property values from.</p>
126      *
127      * @param baseConfig the {@link ForwardConfig} to copy configuration
128      *                   values from
129      */
130     public ActionRedirect(ForwardConfig baseConfig) {
131         setName(baseConfig.getName());
132         setPath(baseConfig.getPath());
133         setModule(baseConfig.getModule());
134         setRedirect(true);
135         inheritProperties(baseConfig);
136         initializeParameters();
137     }
138 
139     // ----------------------------------------------------- Private methods
140 
141     /**
142      * <p>Initializes the internal objects used to hold parameter values.</p>
143      */
144     private void initializeParameters() {
145         parameterValues = new HashMap();
146     }
147 
148     // ----------------------------------------------------- Public methods
149 
150     /**
151      * <p>Adds the object's toString() to the list of parameters if it's not
152      * null, or an empty string with the given fieldName if it is.</p>
153      *
154      * @param fieldName the name to use for the parameter
155      * @param valueObj  the value for this parameter
156      * @return The ActionRedirect instance this method is called on
157      */
158     public ActionRedirect addParameter(String fieldName, Object valueObj) {
159         String value = (valueObj != null) ? valueObj.toString() : "";
160 
161         if (parameterValues == null) {
162             initializeParameters();
163         }
164 
165         //try {
166         value = ResponseUtils.encodeURL(value);
167 
168         //} catch (UnsupportedEncodingException uce) {
169         // this shouldn't happen since UTF-8 is the W3C Recommendation
170         //     String errorMsg = "UTF-8 Character Encoding not supported";
171         //     LOG.error(errorMsg, uce);
172         //     throw new RuntimeException(errorMsg, uce);
173         // }
174         Object currentValue = parameterValues.get(fieldName);
175 
176         if (currentValue == null) {
177             // there's no value for this param yet; add it to the map
178             parameterValues.put(fieldName, value);
179         } else if (currentValue instanceof String) {
180             // there's already a value; let's use an array for these parameters
181             String[] newValue = new String[2];
182 
183             newValue[0] = (String) currentValue;
184             newValue[1] = value;
185             parameterValues.put(fieldName, newValue);
186         } else if (currentValue instanceof String[]) {
187             // add the value to the list of existing values
188             List newValues =
189                 new ArrayList(Arrays.asList((Object[]) currentValue));
190 
191             newValues.add(value);
192             parameterValues.put(fieldName,
193                 newValues.toArray(new String[newValues.size()]));
194         }
195         return this;
196     }
197 
198     /**
199      * <p>Adds an anchor to the path.  Technically, the anchor value is
200      * just stored for later and will be added to the path in getPath().
201      * Note that this is a considerably simpler method than the
202      * addParmaeter method because aside from encoding the value, there
203      * isn't really anything to do.  Passing in null is fine because that
204      * is the value that will be checked for later to determine whether
205      * to append an anchor to the path or not.</p>
206      *
207      * @param anchorValue The anchor to append to the path
208      * @return The ActionRefirect instance this method is called on
209      */
210     public ActionRedirect setAnchor(String anchorValue) {
211         this.anchorValue = ResponseUtils.encodeURL(anchorValue);
212         return this;
213     }
214 
215     /**
216      * <p>Get the original path without the parameters added at runtime.</p>
217      *
218      * @return the original path as configured.
219      */
220     public String getOriginalPath() {
221         return super.getPath();
222     }
223 
224     /**
225      * <p>Get the path for this object, including any parameters that may have
226      * been added at runtime.</p>
227      *
228      * @return The path for this object.
229      */
230     public String getPath() {
231         // get the original path and the parameter string that was formed
232         String originalPath = getOriginalPath();
233         String parameterString = getParameterString();
234         String anchorString = getAnchorString();
235 
236         StringBuffer result = new StringBuffer(originalPath);
237 
238         if ((parameterString != null) && (parameterString.length() > 0)) {
239             // the parameter separator we're going to use
240             String paramSeparator = "?";
241 
242             // true if we need to use a parameter separator after originalPath
243             boolean needsParamSeparator = true;
244 
245             // does the original path already have a "?"?
246             int paramStartIndex = originalPath.indexOf("?");
247 
248             if (paramStartIndex > 0) {
249                 // did the path end with "?"?
250                 needsParamSeparator = (paramStartIndex != (originalPath.length()
251                     - 1));
252 
253                 if (needsParamSeparator) {
254                     paramSeparator = "&";
255                 }
256             }
257 
258             if (needsParamSeparator) {
259                 result.append(paramSeparator);
260             }
261 
262             result.append(parameterString);
263         }
264 
265         // append anchor string (or blank if none was set)
266         result.append(anchorString);
267 
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(values[i]);
317 
318                     if (i < (values.length - 1)) {
319                         strParam.append("&");
320                     }
321                 }
322             }
323 
324             if (iterator.hasNext()) {
325                 strParam.append("&");
326             }
327         }
328 
329         return strParam.toString();
330     }
331 
332     // ----------------------------------------------------- toString()
333 
334     /**
335      * <p>Return a string description of this object.</p>
336      *
337      * @return a string containing the original path for this object and the
338      *         parameters it currently holds
339      */
340     public String toString() {
341         StringBuffer result = new StringBuffer(DEFAULT_BUFFER_SIZE);
342 
343         result.append("ActionRedirect [");
344         result.append("originalPath=").append(getOriginalPath()).append(";");
345         result.append("parameterString=").append(getParameterString()).append("]");
346         result.append("anchorString=").append(getAnchorString()).append("]");
347 
348         return result.toString();
349     }
350 }