001    /* 
002        Licensed to the Apache Software Foundation (ASF) under one
003        or more contributor license agreements.  See the NOTICE file
004        distributed with this work for additional information
005        regarding copyright ownership.  The ASF licenses this file
006        to you under the Apache License, Version 2.0 (the
007        "License"); you may not use this file except in compliance
008        with the License.  You may obtain a copy of the License at
009    
010           http://www.apache.org/licenses/LICENSE-2.0
011    
012        Unless required by applicable law or agreed to in writing,
013        software distributed under the License is distributed on an
014        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015        KIND, either express or implied.  See the License for the
016        specific language governing permissions and limitations
017        under the License.  
018     */
019    package org.apache.wiki.util;
020    
021    import java.util.ArrayList;
022    import java.util.Enumeration;
023    import java.util.HashMap;
024    import java.util.List;
025    import java.util.Map;
026    
027    import javax.servlet.http.HttpServletRequest;
028    
029    /**
030     * A collection of (static) utilities used by the WikiForms code.
031     * FormUtil is mainly concerned with mapping HTTP parameters to
032     * WikiPlugin parameters.
033     *
034     */
035    public final class FormUtil
036    {
037        /**
038         * Private constructor to prevent direct instantiation.
039         */
040        private FormUtil()
041        {
042        }
043        
044        /**
045         * <p>Looks for a named value in the Map. Returns either the
046         * value named by key, or values named by key.0, key.1, ...
047         * if the direct value is not found. The values are packed
048         * in an ArrayList.</p>
049         * <p>This is a utility method, mainly used when we don't know
050         * whether there was just one value, or several, in a mapping list
051         * (e.g. an HttpRequest / FORM checkbox).</p>
052         * @param params the Map container form parameters
053         * @param key the key to look up
054         * @return the List of keys
055         */
056        public static List getValues( Map params, String key )
057        {
058            if( params == null || key == null )
059                return new ArrayList(0);
060    
061            Object entry = params.get( key );
062            if( entry != null )
063            {
064                ArrayList<Object> rval = new ArrayList<Object>(1);
065                rval.add( entry );
066                return rval;
067            }
068    
069            return getNumberedValues( params, key );
070        }
071    
072    
073        /**
074         * Looks up all keys starting with a given prefix and returns
075         * the values in an ArrayList. The keys must be Strings.
076         *
077         * <p>For example, calling this method for a Map containing
078         * key-value pairs foo.1 = a, foo.2 = b, and foo.3 = c returns
079         * an ArrayList containing [a, b, c].
080         *
081         * <p>Handles both 0- and 1-indexed names. Parsing stops at the
082         * first gap in the numeric postfix.
083         *
084         * @param params a Map of string-object pairs, presumably containing
085         *               key.1, key.2,...
086         * @param keyPrefix a String prefix; values will be looked up by adding
087         *                  ".0", ".1", and so on, until the first gap.
088         * @return ArrayList, containing the values corresponding to the
089         *          keyPrefix, in order.
090         */
091        public static List getNumberedValues( Map params, String keyPrefix )
092        {
093            ArrayList<Object> rval = new ArrayList<Object>();
094            if( params == null || 
095                params.size() == 0 || 
096                keyPrefix == null || 
097                keyPrefix.length() == 0 )
098                return rval;
099    
100            String fullPrefix = null;
101            if( keyPrefix.charAt( keyPrefix.length() - 1 ) == '.' )
102                fullPrefix = keyPrefix;
103            else
104                fullPrefix = keyPrefix + ".";
105    
106            int ix = 0;
107            Object value = params.get( fullPrefix + (ix++) );
108            if( value == null )
109                value = params.get( fullPrefix + (ix++) );
110            if( value == null )
111                return rval;
112            while( true )
113            {
114                rval.add( value );
115                value = params.get( fullPrefix + (ix++) );
116                if( value == null )
117                    break;
118            }
119    
120            return rval;
121        }
122    
123    
124        /**
125         * <p>Converts the parameter contents of an HTTP request into a map,
126         * modifying the keys to preserve multiple values per key. This
127         * is done by adding an ordered suffix to the key:</p>
128         * <p><pre>foo=bar,baz,xyzzy</pre></p>
129         * <p>becomes</p>
130         * <p><pre>foo.0=bar foo.1=baz foo.2=xyzzy</pre></p>
131         * <p>If filterPrefix is specified, only keys starting with the prefix
132         * are included in the result map. If the prefix is null, all keys are
133         * checked.</p>
134         * <p>FIX: this is not necessarily encoding-safe: see
135         * WikiContext.getHttpParameter().</p>
136         * @param req the HTTP request
137         * @param filterPrefix the prefix
138         * @return the Map containing parsed key/value pairs
139         */
140        public static Map< String, String > requestToMap( HttpServletRequest req, 
141                                                          String filterPrefix )
142        {
143            HashMap<String,String> params = new HashMap<String,String>();
144            
145            if( filterPrefix == null ) filterPrefix = "";
146            
147            Enumeration en = req.getParameterNames();
148            while( en.hasMoreElements() )
149            {
150                String param = (String)en.nextElement();
151                
152                if( param.startsWith( filterPrefix ) )
153                {
154                    String realName = param.substring( filterPrefix.length() );
155                    String[] values = req.getParameterValues( param );
156                    if( values != null )
157                    {
158                        if( values.length == 1 )
159                        {
160                            params.put( realName, values[0] );
161                        }
162                        else
163                        {
164                            for( int i = 0; i < values.length; i++ )
165                            {
166                                if( values[i] != null && values[i].length() > 0 )
167                                {
168                                    params.put( realName + "." + i, values[i] );
169                                }
170                            }
171                        }
172                    }
173                }
174            }
175    
176            return params;
177        }
178    
179    }