View Javadoc

    1   package org.apache.turbine.util.uri;
    2
    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
    22  import java.io.UnsupportedEncodingException;
    23  import java.net.URLEncoder;
    24  import java.util.ArrayList;
    25  import java.util.Collection;
    26  import java.util.Iterator;
    27  import java.util.List;
    28
    29  import org.apache.commons.lang.StringUtils;
    30  import org.apache.commons.logging.Log;
    31  import org.apache.commons.logging.LogFactory;
    32  import org.apache.fulcrum.parser.ParameterParser;
    33  import org.apache.fulcrum.parser.ParserService;
    34  import org.apache.turbine.services.TurbineServices;
    35  import org.apache.turbine.util.RunData;
    36  import org.apache.turbine.util.ServerData;
    37
    38  /**
    39   * This class allows you to keep all the information needed for a single
    40   * link at one place. It keeps your query data, path info, the server
    41   * scheme, name, port and the script path.
    42   *
    43   * If you must generate a Turbine Link, use this class.
    44   *
    45   * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
    46   * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
    47   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    48   * @version $Id: TurbineURI.java 1709648 2015-10-20 17:08:10Z tv $
    49   */
    50
    51  public class TurbineURI
    52          extends BaseURI
    53  {
    54      /** Logging */
    55      private static Log log = LogFactory.getLog(TurbineURI.class);
    56
    57      /** Contains the PathInfo and QueryData vectors */
    58      private List<URIParam> [] dataVectors = null;
    59
    60      /** Local reference to the parser service for URI parameter folding */
    61      private ParserService parserService;
    62
    63      /*
    64       * ========================================================================
    65       *
    66       * Constructors
    67       *
    68       * ========================================================================
    69       *
    70       */
    71
    72      /**
    73       * Empty C'tor. Uses Turbine.getDefaultServerData().
    74       */
    75      public TurbineURI()
    76      {
    77          super();
    78          init();
    79      }
    80
    81      /**
    82       * Constructor with a RunData object.
    83       *
    84       * @param runData A RunData object
    85       */
    86      public TurbineURI(RunData runData)
    87      {
    88          super(runData);
    89          init();
    90      }
    91
    92      /**
    93       * Constructor, set explicit redirection.
    94       *
    95       * @param runData A RunData object
    96       * @param redirect True if redirection allowed.
    97       */
    98      public TurbineURI(RunData runData, boolean redirect)
    99      {
    100         super(runData, redirect);
    101         init();
    102     }
    103
    104     /**
    105      * Constructor, set Screen.
    106      *
    107      * @param runData A RunData object
    108      * @param screen A Screen Name
    109      */
    110     public TurbineURI(RunData runData, String screen)
    111     {
    112         this(runData);
    113         setScreen(screen);
    114     }
    115
    116     /**
    117      * Constructor, set Screen, set explicit redirection.
    118      *
    119      * @param runData A RunData object
    120      * @param screen A Screen Name
    121      * @param redirect True if redirection allowed.
    122      */
    123     public TurbineURI(RunData runData, String screen, boolean redirect)
    124     {
    125         this(runData, redirect);
    126         setScreen(screen);
    127     }
    128
    129     /**
    130      * Constructor, set Screen and Action.
    131      *
    132      * @param runData A RunData object
    133      * @param screen A Screen Name
    134      * @param action An Action Name
    135      */
    136     public TurbineURI(RunData runData, String screen, String action)
    137     {
    138         this(runData, screen);
    139         setAction(action);
    140     }
    141
    142     /**
    143      * Constructor, set Screen and Action, set explicit redirection.
    144      *
    145      * @param runData A RunData object
    146      * @param screen A Screen Name
    147      * @param action An Action Name
    148      * @param redirect True if redirection allowed.
    149      */
    150     public TurbineURI(RunData runData, String screen, String action, boolean redirect)
    151     {
    152         this(runData, screen, redirect);
    153         setAction(action);
    154     }
    155
    156     /**
    157      * Constructor with a ServerData object.
    158      *
    159      * @param serverData A ServerData object
    160      */
    161     public TurbineURI(ServerData serverData)
    162     {
    163         super(serverData);
    164         init();
    165     }
    166
    167     /**
    168      * Constructor, set explicit redirection.
    169      *
    170      * @param serverData A ServerData object
    171      * @param redirect True if redirection allowed.
    172      */
    173     public TurbineURI(ServerData serverData, boolean redirect)
    174     {
    175         super(serverData, redirect);
    176         init();
    177     }
    178
    179     /**
    180      * Constructor, set Screen.
    181      *
    182      * @param serverData A ServerData object
    183      * @param screen A Screen Name
    184      */
    185     public TurbineURI(ServerData serverData, String screen)
    186     {
    187         this(serverData);
    188         setScreen(screen);
    189     }
    190
    191     /**
    192      * Constructor, set Screen, set explicit redirection.
    193      *
    194      * @param serverData A ServerData object
    195      * @param screen A Screen Name
    196      * @param redirect True if redirection allowed.
    197      */
    198     public TurbineURI(ServerData serverData, String screen, boolean redirect)
    199     {
    200         this(serverData, redirect);
    201         setScreen(screen);
    202     }
    203
    204     /**
    205      * Constructor, set Screen and Action.
    206      *
    207      * @param serverData A ServerData object
    208      * @param screen A Screen Name
    209      * @param action An Action Name
    210      */
    211     public TurbineURI(ServerData serverData, String screen, String action)
    212     {
    213         this(serverData, screen);
    214         setAction(action);
    215     }
    216
    217     /**
    218      * Constructor, set Screen and Action, set explicit redirection.
    219      *
    220      * @param serverData A ServerData object
    221      * @param screen A Screen Name
    222      * @param action An Action Name
    223      * @param redirect True if redirection allowed.
    224      */
    225     public TurbineURI(ServerData serverData, String screen, String action,
    226                       boolean redirect)
    227     {
    228         this(serverData, screen, redirect);
    229         setAction(action);
    230     }
    231
    232     /**
    233      * Constructor, user Turbine.getDefaultServerData(), set Screen and Action.
    234      *
    235      * @param screen A Screen Name
    236      * @param action An Action Name
    237      */
    238     public TurbineURI(String screen, String action)
    239     {
    240         this();
    241         setScreen(screen);
    242         setAction(action);
    243     }
    244
    245     /*
    246      * ========================================================================
    247      *
    248      * Init
    249      *
    250      * ========================================================================
    251      *
    252      */
    253
    254     /**
    255      * Init the TurbineURI.
    256      */
    257     @SuppressWarnings("unchecked")
    258     private void init()
    259     {
    260         dataVectors = new List[2];
    261         dataVectors[PATH_INFO]  = new ArrayList<URIParam>();
    262         dataVectors[QUERY_DATA] = new ArrayList<URIParam>();
    263         parserService = (ParserService)TurbineServices.getInstance().getService(ParserService.ROLE);
    264     }
    265
    266     /**
    267      * Sets the action= value for this URL.
    268      *
    269      * By default it adds the information to the path_info instead
    270      * of the query data. An empty value (null or "") cleans out
    271      * an existing value.
    272      *
    273      * @param action A String with the action value.
    274      */
    275     public void setAction(String action)
    276     {
    277         if(StringUtils.isNotEmpty(action))
    278         {
    279             add(PATH_INFO, CGI_ACTION_PARAM, action);
    280         }
    281         else
    282         {
    283             clearAction();
    284         }
    285     }
    286
    287     /**
    288      * Sets the fired eventSubmit= value for this URL.
    289      *
    290      * @param event The event to fire.
    291      *
    292      */
    293     public void setEvent(String event)
    294     {
    295         add(PATH_INFO, EVENT_PREFIX + event, event);
    296     }
    297
    298     /**
    299      * Sets the action= and eventSubmit= values for this URL.
    300      *
    301      * By default it adds the information to the path_info instead
    302      * of the query data. An empty value (null or "") for the action cleans out
    303      * an existing value.  An empty value (null or "") for the event has no
    304      * effect.
    305      *
    306      * @param action A String with the action value.
    307      * @param event A string with the event name.
    308      */
    309     public void setActionEvent(String action, String event)
    310     {
    311         setAction(action);
    312         if(StringUtils.isNotEmpty(event))
    313         {
    314             setEvent(event);
    315         }
    316     }
    317
    318     /**
    319      * Clears the action= value for this URL.
    320      */
    321     public void clearAction()
    322     {
    323         removePathInfo(CGI_ACTION_PARAM);
    324     }
    325
    326     /**
    327      * Sets the screen= value for this URL.
    328      *
    329      * By default it adds the information to the path_info instead
    330      * of the query data. An empty value (null or "") cleans out
    331      * an existing value.
    332      *
    333      * @param screen A String with the screen value.
    334      */
    335     public void setScreen(String screen)
    336     {
    337         if(StringUtils.isNotEmpty(screen))
    338         {
    339             add(PATH_INFO, CGI_SCREEN_PARAM, screen);
    340         }
    341         else
    342         {
    343             clearScreen();
    344         }
    345     }
    346
    347     /**
    348      * Clears the screen= value for this URL.
    349      */
    350     public void clearScreen()
    351     {
    352         removePathInfo(CGI_SCREEN_PARAM);
    353     }
    354
    355     /*
    356      * ========================================================================
    357      *
    358      * Adding and removing Data from the Path Info and Query Data
    359      *
    360      * ========================================================================
    361      */
    362
    363
    364     /**
    365      * Adds a name=value pair for every entry in a ParameterParser
    366      * object to the path_info string.
    367      *
    368      * @param pp A ParameterParser.
    369      */
    370     public void addPathInfo(ParameterParser pp)
    371     {
    372         add(PATH_INFO, pp);
    373     }
    374
    375     /**
    376      * Adds an existing List of URIParam objects to
    377      * the path_info string.
    378      *
    379      * @param list A list with URIParam objects.
    380      */
    381     public void addPathInfo(List<URIParam> list)
    382     {
    383         add(PATH_INFO, list);
    384     }
    385
    386     /**
    387      * Adds a name=value pair to the path_info string.
    388      *
    389      * @param name A String with the name to add.
    390      * @param value An Object with the value to add.
    391      */
    392     public void addPathInfo(String name, Object value)
    393     {
    394         add(PATH_INFO, name, null == value ? null : value.toString());
    395     }
    396
    397     /**
    398      * Adds a name=value pair to the path_info string.
    399      *
    400      * @param name A String with the name to add.
    401      * @param value A String with the value to add.
    402      */
    403     public void addPathInfo(String name, String value)
    404     {
    405         add(PATH_INFO, name, value);
    406     }
    407
    408     /**
    409      * Adds a name=value pair to the path_info string.
    410      *
    411      * @param name A String with the name to add.
    412      * @param value A double with the value to add.
    413      */
    414     public void addPathInfo(String name, double value)
    415     {
    416         add(PATH_INFO, name, Double.toString(value));
    417     }
    418
    419     /**
    420      * Adds a name=value pair to the path_info string.
    421      *
    422      * @param name A String with the name to add.
    423      * @param value An int with the value to add.
    424      */
    425     public void addPathInfo(String name, int value)
    426     {
    427         add(PATH_INFO, name, Integer.toString(value));
    428     }
    429
    430     /**
    431      * Adds a name=value pair to the path_info string.
    432      *
    433      * @param name A String with the name to add.
    434      * @param value A long with the value to add.
    435      */
    436     public void addPathInfo(String name, long value)
    437     {
    438         add(PATH_INFO, name, Long.toString(value));
    439     }
    440
    441     /**
    442      * Adds a name=value pair to the query string.
    443      *
    444      * @param name A String with the name to add.
    445      * @param value An Object with the value to add.
    446      */
    447     public void addQueryData(String name, Object value)
    448     {
    449         add(QUERY_DATA, name, null == value ? null : value.toString());
    450     }
    451
    452     /**
    453      * Adds a name=value pair to the query string.
    454      *
    455      * @param name A String with the name to add.
    456      * @param value A String with the value to add.
    457      */
    458     public void addQueryData(String name, String value)
    459     {
    460         add(QUERY_DATA, name, value);
    461     }
    462
    463     /**
    464      * Adds a name=value pair to the query string.
    465      *
    466      * @param name A String with the name to add.
    467      * @param value A double with the value to add.
    468      */
    469     public void addQueryData(String name, double value)
    470     {
    471         add(QUERY_DATA, name, Double.toString(value));
    472     }
    473
    474     /**
    475      * Adds a name=value pair to the query string.
    476      *
    477      * @param name A String with the name to add.
    478      * @param value An int with the value to add.
    479      */
    480     public void addQueryData(String name, int value)
    481     {
    482         add(QUERY_DATA, name, Integer.toString(value));
    483     }
    484
    485     /**
    486      * Adds a name=value pair to the query string.
    487      *
    488      * @param name A String with the name to add.
    489      * @param value A long with the value to add.
    490      */
    491     public void addQueryData(String name, long value)
    492     {
    493         add(QUERY_DATA, name, Long.toString(value));
    494     }
    495
    496     /**
    497      * Adds a name=value pair for every entry in a ParameterParser
    498      * object to the query string.
    499      *
    500      * @param pp A ParameterParser.
    501      */
    502     public void addQueryData(ParameterParser pp)
    503     {
    504         add(QUERY_DATA, pp);
    505     }
    506
    507     /**
    508      * Adds an existing List of URIParam objects to the query data.
    509      *
    510      * @param list A list with URIParam objects.
    511      */
    512     public void addQueryData(List<URIParam> list)
    513     {
    514         add(QUERY_DATA, list);
    515     }
    516
    517     /**
    518      * Is Path Info data set in this URI?
    519      *
    520      * @return true if Path Info has values
    521      */
    522     public boolean hasPathInfo()
    523     {
    524         return !dataVectors[PATH_INFO].isEmpty();
    525     }
    526
    527     /**
    528      * Removes all the path info elements.
    529      */
    530     public void removePathInfo()
    531     {
    532         dataVectors[PATH_INFO].clear();
    533     }
    534
    535     /**
    536      * Removes a name=value pair from the path info.
    537      *
    538      * @param name A String with the name to be removed.
    539      */
    540     public void removePathInfo(String name)
    541     {
    542         remove(PATH_INFO, name);
    543     }
    544
    545     /**
    546      * Is Query data set in this URI?
    547      *
    548      * @return true if Query data has values
    549      */
    550     public boolean hasQueryData()
    551     {
    552         return !dataVectors[QUERY_DATA].isEmpty();
    553     }
    554
    555     /**
    556      * Removes all the query string elements.
    557      */
    558     public void removeQueryData()
    559     {
    560         dataVectors[QUERY_DATA].clear();
    561     }
    562
    563     /**
    564      * Removes a name=value pair from the query string.
    565      *
    566      * @param name A String with the name to be removed.
    567      */
    568     public void removeQueryData(String name)
    569     {
    570         remove (QUERY_DATA, name);
    571     }
    572
    573     /**
    574      * Template Link and friends want to be able to turn the encoding
    575      * of the servlet container off. After calling this method,
    576      * the no encoding will happen any longer. If you think, that you
    577      * need this outside a template context, think again.
    578      */
    579     public void clearResponse()
    580     {
    581         setResponse(null);
    582     }
    583
    584
    585     /**
    586      * Builds the URL with all of the data URL-encoded as well as
    587      * encoded using HttpServletResponse.encodeUrl(). The resulting
    588      * URL is absolute; it starts with http/https...
    589      *
    590      * <p>
    591      * <code><pre>
    592      * TurbineURI tui = new TurbineURI (data, "UserScreen");
    593      * tui.addPathInfo("user","jon");
    594      * tui.getAbsoluteLink();
    595      * </pre></code>
    596      *
    597      *  The above call to absoluteLink() would return the String:
    598      *
    599      * <p>
    600      * http://www.server.com/servlets/Turbine/screen/UserScreen/user/jon
    601      *
    602      * @return A String with the built URL.
    603      */
    604     public String getAbsoluteLink()
    605     {
    606         StringBuilder output = new StringBuilder();
    607
    608         getSchemeAndPort(output);
    609
    610         buildRelativeLink(output);
    611
    612         //
    613         // Encode Response does all the fixup for the Servlet Container
    614         //
    615         return encodeResponse(output.toString());
    616     }
    617
    618     /**
    619      * Builds the URL with all of the data URL-encoded as well as
    620      * encoded using HttpServletResponse.encodeUrl(). The resulting
    621      * URL is relative to the webserver root.
    622      *
    623      * <p>
    624      * <code><pre>
    625      * TurbineURI tui = new TurbineURI (data, "UserScreen");
    626      * tui.addPathInfo("user","jon");
    627      * tui.getRelativeLink();
    628      * </pre></code>
    629      *
    630      *  The above call to relativeLink() would return the String:
    631      *
    632      * <p>
    633      * /servlets/Turbine/screen/UserScreen/user/jon
    634      *
    635      * @return A String with the built URL.
    636      */
    637     public String getRelativeLink()
    638     {
    639         StringBuilder output = new StringBuilder();
    640
    641         buildRelativeLink(output);
    642
    643         //
    644         // Encode Response does all the fixup for the Servlet Container
    645         //
    646         return encodeResponse(output.toString());
    647     }
    648
    649     /**
    650      * Add everything needed for a relative link to the passed StringBuilder.
    651      *
    652      * @param output A Stringbuffer
    653      */
    654     private void buildRelativeLink(StringBuilder output)
    655     {
    656         getContextAndScript(output);
    657
    658         if (hasPathInfo())
    659         {
    660             output.append('/');
    661             getPathInfoAsString(output);
    662         }
    663
    664         if (hasReference())
    665         {
    666             output.append('#');
    667             output.append(getReference());
    668         }
    669
    670         if (hasQueryData())
    671         {
    672             output.append('?');
    673             getQueryDataAsString(output);
    674         }
    675     }
    676
    677     /**
    678      * Gets the current Query Data List.
    679      *
    680      * @return A List which contains all query data keys. The keys
    681      * are URIParam objects.
    682      */
    683     public List<URIParam> getPathInfo()
    684     {
    685         return dataVectors[PATH_INFO];
    686     }
    687
    688     /**
    689      * Sets the Query Data List. Replaces the current query data list
    690      * with the one supplied. The list must contain only URIParam
    691      * objects!
    692      *
    693      * @param pathInfo A List with new param objects.
    694      */
    695
    696     public void setPathInfo(List<URIParam> pathInfo)
    697     {
    698         dataVectors[PATH_INFO] = pathInfo;
    699     }
    700
    701     /**
    702      * Gets the current Query Data List.
    703      *
    704      * @return A List which contains all query data keys. The keys
    705      * are URIParam objects.
    706      */
    707     public List<URIParam> getQueryData()
    708     {
    709         return dataVectors[QUERY_DATA];
    710     }
    711
    712     /**
    713      * Sets the Query Data List. Replaces the current query data list
    714      * with the one supplied. The list must contain only URIParam
    715      * objects!
    716      *
    717      * @param queryData A List with new param objects.
    718      */
    719
    720     public void setQueryData(List<URIParam> queryData)
    721     {
    722         dataVectors[QUERY_DATA] = queryData;
    723     }
    724
    725     /**
    726      * Simply calls getAbsoluteLink(). You should not use this in your
    727      * code unless you have to. Use getAbsoluteLink.
    728      *
    729      * @return This URI as a String
    730      *
    731      */
    732     @Override
    733     public String toString()
    734     {
    735         return getAbsoluteLink();
    736     }
    737
    738     /*
    739      * ========================================================================
    740      *
    741      * Protected / Private Methods
    742      *
    743      * ========================================================================
    744      *
    745      */
    746
    747     /**
    748      * Returns the Path Info data as a String.
    749      *
    750      * @param output The StringBuilder that should hold the path info.
    751      */
    752     private void getPathInfoAsString(StringBuilder output)
    753     {
    754         doEncode(output, dataVectors[PATH_INFO], '/', '/');
    755     }
    756
    757     /**
    758      * Returns the Query data as a String.
    759      *
    760      * @param output The StringBuilder that should hold the query data.
    761      */
    762     private void getQueryDataAsString(StringBuilder output)
    763     {
    764         doEncode(output, dataVectors[QUERY_DATA], '&', '=');
    765     }
    766
    767     /**
    768      * Does the actual encoding for pathInfoAsString and queryDataAsString.
    769      *
    770      * @param output The Stringbuffer that should contain the information.
    771      * @param list A Collection
    772      * @param fieldDelim A char which is used to separate key/value pairs
    773      * @param valueDelim A char which is used to separate key and value
    774      */
    775     private void doEncode(StringBuilder output, Collection<URIParam> list, char fieldDelim, char valueDelim)
    776     {
    777         if(!list.isEmpty())
    778         {
    779         	String encoding = parserService.getParameterEncoding();
    780
    781             for(Iterator<URIParam> it = list.iterator(); it.hasNext();)
    782             {
    783             	try
    784             	{
    785 					URIParam uriParam = it.next();
    786 					String key = URLEncoder.encode(uriParam.getKey(), encoding);
    787 					String val = null == uriParam.getValue()
    788 					        ? null : String.valueOf(uriParam.getValue());
    789
    790 					output.append(key);
    791 					output.append(valueDelim);
    792
    793 					if(StringUtils.isEmpty(val))
    794 					{
    795 					    if (val == null)
    796 					    {
    797 					        if (log.isWarnEnabled())
    798 					        {
    799 					            log.warn("Found a null value for " + key);
    800 					        }
    801 					        // For backwards compatibility:
    802 					        val = "null";
    803 					    }
    804 					    output.append(val);
    805 					}
    806 					else
    807 					{
    808 					    output.append(URLEncoder.encode(val, encoding));
    809 					}
    810
    811 					if (it.hasNext())
    812 					{
    813 					    output.append(fieldDelim);
    814 					}
    815 				}
    816             	catch (UnsupportedEncodingException e)
    817             	{
    818             		log.warn("Unsupported encoding " + encoding);
    819 				}
    820             }
    821         }
    822     }
    823
    824     /**
    825      * If the type is PATH_INFO, then add name/value to the pathInfo
    826      * hashtable.
    827      * <p>
    828      * If the type is QUERY_DATA, then add name/value to the queryData
    829      * hashtable.
    830      *
    831      * @param type Type (PATH_INFO or QUERY_DATA) of insertion.
    832      * @param name A String with the name to add.
    833      * @param value A String with the value to add.
    834      */
    835     protected void add(int type,
    836             String name,
    837             String value)
    838     {
    839         URIParam uriParam = new URIParam(parserService.convertAndTrim(name), value);
    840
    841         dataVectors[type].add(uriParam); // Code so clean you can eat from...
    842     }
    843
    844     /**
    845      * Method for a quick way to add all the parameters in a
    846      * ParameterParser.
    847      *
    848      * <p>If the type is P (0), then add name/value to the pathInfo
    849      * hashtable.
    850      *
    851      * <p>If the type is Q (1), then add name/value to the queryData
    852      * hashtable.
    853      *
    854      * @param type Type of insertion (@see #add(char type, String name, String value))
    855      * @param pp A ParameterParser.
    856      */
    857     protected void add(int type,
    858             ParameterParser pp)
    859     {
    860         for(Iterator<?> it = pp.keySet().iterator(); it.hasNext();)
    861         {
    862             String key = (String) it.next();
    863
    864             if (!key.equalsIgnoreCase(CGI_ACTION_PARAM) &&
    865                     !key.equalsIgnoreCase(CGI_SCREEN_PARAM))
    866             {
    867                 String[] values = pp.getStrings(key);
    868                 if(values != null)
    869                 {
    870                     for (int i = 0; i < values.length; i++)
    871                     {
    872                         add(type, key, values[i]);
    873                     }
    874                 }
    875                 else
    876                 {
    877                     add(type, key, "");
    878                 }
    879             }
    880         }
    881     }
    882
    883     /**
    884      * Method for a quick way to add all the parameters in a
    885      * List with URIParam objects.
    886      *
    887      * <p>If the type is P (0), then add name/value to the pathInfo
    888      * hashtable.
    889      *
    890      * <p>If the type is Q (1), then add name/value to the queryData
    891      * hashtable.
    892      *
    893      * @param type Type of insertion (@see #add(char type, String name, String value))
    894      * @param list A List of URIParam objects
    895      */
    896     protected void add(int type, List<URIParam> list)
    897     {
    898         for (URIParam uriParam : list)
    899         {
    900             dataVectors[type].add(uriParam);
    901         }
    902     }
    903
    904     /**
    905      * If the type is P (0), then remove name/value from the
    906      * pathInfo hashtable.
    907      *
    908      * <p>If the type is Q (1), then remove name/value from the
    909      * queryData hashtable.
    910      *
    911      * @param type Type (P or Q) of removal.
    912      * @param name A String with the name to be removed.
    913      */
    914     protected void remove (int type, String name)
    915     {
    916         Collection<URIParam> c = dataVectors[type];
    917         String key = parserService.convertAndTrim(name);
    918
    919         for (Iterator<URIParam> it = c.iterator(); it.hasNext();)
    920         {
    921             URIParam uriParam = it.next();
    922
    923             if (key.equals(uriParam.getKey()))
    924             {
    925                 it.remove();
    926             }
    927         }
    928     }
    929 }