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 }