    001package org.apache.turbine.util.uri;
    002
    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
    022import java.io.UnsupportedEncodingException;
    023import java.net.URLEncoder;
    024import java.util.ArrayList;
    025import java.util.Collection;
    026import java.util.Iterator;
    027import java.util.List;
    028
    029import org.apache.commons.lang.StringUtils;
    030import org.apache.commons.logging.Log;
    031import org.apache.commons.logging.LogFactory;
    032import org.apache.fulcrum.parser.ParameterParser;
    033import org.apache.fulcrum.parser.ParserService;
    034import org.apache.turbine.services.TurbineServices;
    035import org.apache.turbine.util.RunData;
    036import org.apache.turbine.util.ServerData;
    037
    038/**
    039 * This class allows you to keep all the information needed for a single
    040 * link at one place. It keeps your query data, path info, the server
    041 * scheme, name, port and the script path.
    042 *
    043 * If you must generate a Turbine Link, use this class.
    044 *
    045 * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
    046 * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
    047 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    048 * @version $Id: TurbineURI.java 1709648 2015-10-20 17:08:10Z tv $
    049 */
    050
    051public class TurbineURI
    052        extends BaseURI
    053{
    054    /** Logging */
    055    private static Log log = LogFactory.getLog(TurbineURI.class);
    056
    057    /** Contains the PathInfo and QueryData vectors */
    058    private List<URIParam> [] dataVectors = null;
    059
    060    /** Local reference to the parser service for URI parameter folding */
    061    private ParserService parserService;
    062
    063    /*
    064     * ========================================================================
    065     *
    066     * Constructors
    067     *
    068     * ========================================================================
    069     *
    070     */
    071
    072    /**
    073     * Empty C'tor. Uses Turbine.getDefaultServerData().
    074     */
    075    public TurbineURI()
    076    {
    077        super();
    078        init();
    079    }
    080
    081    /**
    082     * Constructor with a RunData object.
    083     *
    084     * @param runData A RunData object
    085     */
    086    public TurbineURI(RunData runData)
    087    {
    088        super(runData);
    089        init();
    090    }
    091
    092    /**
    093     * Constructor, set explicit redirection.
    094     *
    095     * @param runData A RunData object
    096     * @param redirect True if redirection allowed.
    097     */
    098    public TurbineURI(RunData runData, boolean redirect)
    099    {
    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}