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 */ 019package org.apache.wiki.util; 020 021import java.util.ArrayList; 022import java.util.Enumeration; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import 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 */ 035public 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(final Map< ? , ? > params, final String key ) 057 { 058 if( params == null || key == null ) 059 return new ArrayList<>(0); 060 061 final Object entry = params.get( key ); 062 if( entry != null ) 063 { 064 final ArrayList<Object> rval = new ArrayList<>(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(final Map< ?, ? > params, final String keyPrefix ) 092 { 093 final ArrayList<Object> rval = new ArrayList<>(); 094 if( params == null || 095 params.size() == 0 || 096 keyPrefix == null || 097 keyPrefix.isEmpty() ) 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(final HttpServletRequest req, String filterPrefix ) 141 { 142 final HashMap<String,String> params = new HashMap<>(); 143 144 if( filterPrefix == null ) filterPrefix = ""; 145 146 final Enumeration< String > en = req.getParameterNames(); 147 while( en.hasMoreElements() ) 148 { 149 final String param = en.nextElement(); 150 151 if( param.startsWith( filterPrefix ) ) 152 { 153 final String realName = param.substring( filterPrefix.length() ); 154 final String[] values = req.getParameterValues( param ); 155 if( values != null ) 156 { 157 if( values.length == 1 ) 158 { 159 params.put( realName, values[0] ); 160 } 161 else 162 { 163 for( int i = 0; i < values.length; i++ ) 164 { 165 if( values[i] != null && !values[i].isEmpty() ) 166 { 167 params.put( realName + "." + i, values[i] ); 168 } 169 } 170 } 171 } 172 } 173 } 174 175 return params; 176 } 177 178}