    001    package 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
    022    import java.io.UnsupportedEncodingException;
    023    import java.net.URLEncoder;
    024    import java.util.ArrayList;
    025    import java.util.Collection;
    026    import java.util.Iterator;
    027    import java.util.List;
    028
    029    import org.apache.commons.lang.StringUtils;
    030    import org.apache.commons.logging.Log;
    031    import org.apache.commons.logging.LogFactory;
    032    import org.apache.fulcrum.parser.ParameterParser;
    033    import org.apache.fulcrum.parser.ParserService;
    034    import org.apache.turbine.services.TurbineServices;
    035    import org.apache.turbine.util.RunData;
    036    import 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 1078552 2011-03-06 19:58:46Z tv $
    049     */
    050
    051    public 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            StringBuffer output = new StringBuffer();
    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            StringBuffer output = new StringBuffer();
    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 StringBuffer.
    651         *
    652         * @param output A Stringbuffer
    653         */
    654        private void buildRelativeLink(StringBuffer 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 StringBuffer that should hold the path info.
    751         */
    752        private void getPathInfoAsString(StringBuffer output)
    753        {
    754            doEncode(output, dataVectors[PATH_INFO], '/', '/');
    755        }
    756
    757        /**
    758         * Returns the Query data as a String.
    759         *
    760         * @param output The StringBuffer that should hold the query data.
    761         */
    762        private void getQueryDataAsString(StringBuffer 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(StringBuffer 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    }