View Javadoc

1   /*
2    * $Id: ActionRedirect.java 421119 2006-07-12 04:49:11Z wsmoak $
3    *
4    * Copyright 2000-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts.action;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.apache.struts.config.ForwardConfig;
23  import org.apache.struts.util.ResponseUtils;
24  
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  
32  /***
33   * <p> A subclass of {@link ActionForward} which is designed for use in
34   * redirecting requests, with support for adding parameters at runtime. <br/>
35   * An {@link ForwardConfig} (or subclass) can be passed to the constructor to
36   * copy its configuration: </p> <p>
37   * <pre>
38   * public ActionForward execute(ActionMapping mapping,
39   *                              ActionForm form,
40   *                              HttpServletRequest request,
41   *                              HttpServletResponse response)
42   *         throws Exception {
43   *     ActionRedirect redirect =
44   *             new ActionRedirect(mapping.findForward("doRedirect"));
45   *     redirect.addParameter("param1","value1");
46   *     redirect.addParameter("param2","2");
47   *     redirect.addParameter("param3","3.0");
48   *     return redirect;
49   * }
50   * </pre>
51   * </p>
52   *
53   * @version $Rev: 421119 $ $Date: 2006-07-11 21:49:11 -0700 (Tue, 11 Jul 2006) $
54   */
55  public class ActionRedirect extends ActionForward {
56      // ----------------------------------------------------- Manifest constants
57  
58      /***
59       * <p>Default allocation size for string buffers.</p>
60       */
61      private static final int DEFAULT_BUFFER_SIZE = 256;
62  
63      // ----------------------------------------------------- Static variables
64  
65      /***
66       * <p>Commons logging instance.</p>
67       */
68      protected static final Log LOG = LogFactory.getLog(ActionRedirect.class);
69  
70      // ----------------------------------------------------- Instance variables
71  
72      /***
73       * <p>Holds the redirect parameters. Each entry is either a String or a
74       * String[] depending on whether it has one or more entries.</p>
75       */
76      protected Map parameterValues = null;
77  
78      /***
79       * <p>Holds the anchor value.</p>
80       */
81      protected String anchorValue = null;
82  
83      // ----------------------------------------------------- Constructors
84  
85      /***
86       * <p>Construct a new instance with redirect set to true and initialize
87       * parameter lists.</p>
88       */
89      public ActionRedirect() {
90          setRedirect(true);
91          initializeParameters();
92      }
93  
94      /***
95       * <p>Construct a new instance with the specified path and initialize
96       * parameter lists.</p>
97       *
98       * @param path Path for this instance
99       */
100     public ActionRedirect(String path) {
101         super(path);
102         setRedirect(true);
103         initializeParameters();
104     }
105 
106     /***
107      * <p>Construct a new instance with the specified values and initialize
108      * parameter lists.</p>
109      *
110      * @param name   Name of this instance
111      * @param path   Path for this instance
112      * @param module Module prefix, if any
113      */
114     public ActionRedirect(String name, String path, String module) {
115         super(name, path, true);
116         setModule(module);
117         initializeParameters();
118     }
119 
120     /***
121      * <p>Construct a new instance with a {@link ForwardConfig} object to copy
122      * name, path, and contextRelative values from.</p>
123      *
124      * @param baseConfig the {@link ForwardConfig} to copy configuration
125      *                   values from
126      */
127     public ActionRedirect(ForwardConfig baseConfig) {
128         setName(baseConfig.getName());
129         setPath(baseConfig.getPath());
130         setModule(baseConfig.getModule());
131         setRedirect(baseConfig.getRedirect());
132         initializeParameters();
133     }
134 
135     // ----------------------------------------------------- Private methods
136 
137     /***
138      * <p>Initializes the internal objects used to hold parameter values.</p>
139      */
140     private void initializeParameters() {
141         parameterValues = new HashMap();
142     }
143 
144     // ----------------------------------------------------- Public methods
145 
146     /***
147      * <p>Adds the object's toString() to the list of parameters if it's not
148      * null, or an empty string with the given fieldName if it is.</p>
149      *
150      * @param fieldName the name to use for the parameter
151      * @param valueObj  the value for this parameter
152      * @return The ActionRedirect instance this method is called on
153      */
154     public ActionRedirect addParameter(String fieldName, Object valueObj) {
155         String value = (valueObj != null) ? valueObj.toString() : "";
156 
157         if (parameterValues == null) {
158             initializeParameters();
159         }
160 
161         //try {
162         value = ResponseUtils.encodeURL(value);
163 
164         //} catch (UnsupportedEncodingException uce) {
165         // this shouldn't happen since UTF-8 is the W3C Recommendation
166         //     String errorMsg = "UTF-8 Character Encoding not supported";
167         //     LOG.error(errorMsg, uce);
168         //     throw new RuntimeException(errorMsg, uce);
169         // }
170         Object currentValue = parameterValues.get(fieldName);
171 
172         if (currentValue == null) {
173             // there's no value for this param yet; add it to the map
174             parameterValues.put(fieldName, value);
175         } else if (currentValue instanceof String) {
176             // there's already a value; let's use an array for these parameters
177             String[] newValue = new String[2];
178 
179             newValue[0] = (String) currentValue;
180             newValue[1] = value;
181             parameterValues.put(fieldName, newValue);
182         } else if (currentValue instanceof String[]) {
183             // add the value to the list of existing values
184             List newValues =
185                 new ArrayList(Arrays.asList((Object[]) currentValue));
186 
187             newValues.add(value);
188             parameterValues.put(fieldName,
189                 newValues.toArray(new String[newValues.size()]));
190         }
191         return this;
192     }
193 
194     /***
195      * <p>Adds an anchor to the path.  Technically, the anchor value is
196      * just stored for later and will be added to the path in getPath().
197      * Note that this is a considerably simpler method than the
198      * addParmaeter method because aside from encoding the value, there
199      * isn't really anything to do.  Passing in null is fine because that
200      * is the value that will be checked for later to determine whether
201      * to append an anchor to the path or not.</p>
202      *
203      * @param anchorValue The anchor to append to the path
204      * @return The ActionRefirect instance this method is called on
205      */
206     public ActionRedirect setAnchor(String anchorValue) {
207         this.anchorValue = ResponseUtils.encodeURL(anchorValue);
208         return this;
209     }
210 
211     /***
212      * <p>Get the original path without the parameters added at runtime.</p>
213      *
214      * @return the original path as configured.
215      */
216     public String getOriginalPath() {
217         return super.getPath();
218     }
219 
220     /***
221      * <p>Get the path for this object, including any parameters that may have
222      * been added at runtime.</p>
223      *
224      * @return The path for this object.
225      */
226     public String getPath() {
227         // get the original path and the parameter string that was formed
228         String originalPath = getOriginalPath();
229         String parameterString = getParameterString();
230         String anchorString = getAnchorString();
231 
232         StringBuffer result = new StringBuffer(originalPath);
233 
234         if ((parameterString != null) && (parameterString.length() > 0)) {
235             // the parameter separator we're going to use
236             String paramSeparator = "?";
237 
238             // true if we need to use a parameter separator after originalPath
239             boolean needsParamSeparator = true;
240 
241             // does the original path already have a "?"?
242             int paramStartIndex = originalPath.indexOf("?");
243 
244             if (paramStartIndex > 0) {
245                 // did the path end with "?"?
246                 needsParamSeparator = (paramStartIndex != (originalPath.length()
247                     - 1));
248 
249                 if (needsParamSeparator) {
250                     paramSeparator = "&";
251                 }
252             }
253 
254             if (needsParamSeparator) {
255                 result.append(paramSeparator);
256             }
257 
258             result.append(parameterString);
259         }
260 
261         // append anchor string (or blank if none was set)
262         result.append(anchorString);
263 
264 
265         return result.toString();
266     }
267 
268     /***
269      * <p>Forms the string containing the parameters
270      *  passed onto this object thru calls to addParameter().</p>
271      *
272      * @return a string which can be appended to the URLs.  The
273      *    return string includes a leading hash
274      *    mark (#).
275      */
276     public String getAnchorString() {
277         String retVal = "";
278         if (anchorValue != null) {
279             retVal = "#" + anchorValue;
280         }
281         return retVal;
282     }
283 
284     /***
285      * <p>Forms the string containing the parameters passed onto this object
286      * thru calls to addParameter().</p>
287      *
288      * @return a string which can be appended to the URLs.  The return string
289      *         does not include a leading question mark (?).
290      */
291     public String getParameterString() {
292         StringBuffer strParam = new StringBuffer(DEFAULT_BUFFER_SIZE);
293 
294         // loop through all parameters
295         Iterator iterator = parameterValues.keySet().iterator();
296 
297         while (iterator.hasNext()) {
298             // get the parameter name
299             String paramName = (String) iterator.next();
300 
301             // get the value for this parameter
302             Object value = parameterValues.get(paramName);
303 
304             if (value instanceof String) {
305                 // just one value for this param
306                 strParam.append(paramName).append("=").append(value);
307             } else if (value instanceof String[]) {
308                 // loop through all values for this param
309                 String[] values = (String[]) value;
310 
311                 for (int i = 0; i < values.length; i++) {
312                     strParam.append(paramName).append("=").append(values[i]);
313 
314                     if (i < (values.length - 1)) {
315                         strParam.append("&");
316                     }
317                 }
318             }
319 
320             if (iterator.hasNext()) {
321                 strParam.append("&");
322             }
323         }
324 
325         return strParam.toString();
326     }
327 
328     // ----------------------------------------------------- toString()
329 
330     /***
331      * <p>Return a string description of this object.</p>
332      *
333      * @return a string containing the original path for this object and the
334      *         parameters it currently holds
335      */
336     public String toString() {
337         StringBuffer result = new StringBuffer(DEFAULT_BUFFER_SIZE);
338 
339         result.append("ActionRedirect [");
340         result.append("originalPath=").append(getOriginalPath()).append(";");
341         result.append("parameterString=").append(getParameterString()).append("]");
342         result.append("anchorString=").append(getAnchorString()).append("]");
343 
344         return result.toString();
345     }
346 }