1 // ======================================================================== 2 // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd. 3 // ------------------------------------------------------------------------ 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // ======================================================================== 14 15 package org.mortbay.util; 16 17 import java.util.Arrays; 18 import java.util.HashMap; 19 import java.util.Iterator; 20 import java.util.List; 21 import java.util.Map; 22 23 /* ------------------------------------------------------------ */ 24 /** A multi valued Map. 25 * This Map specializes HashMap and provides methods 26 * that operate on multi valued items. 27 * <P> 28 * Implemented as a map of LazyList values 29 * 30 * @see LazyList 31 * @author Greg Wilkins (gregw) 32 */ 33 public class MultiMap extends HashMap 34 implements Cloneable 35 { 36 /* ------------------------------------------------------------ */ 37 /** Constructor. 38 */ 39 public MultiMap() 40 {} 41 42 /* ------------------------------------------------------------ */ 43 /** Constructor. 44 * @param size Capacity of the map 45 */ 46 public MultiMap(int size) 47 { 48 super(size); 49 } 50 51 /* ------------------------------------------------------------ */ 52 /** Constructor. 53 * @param map 54 */ 55 public MultiMap(Map map) 56 { 57 super((map.size()*3)/2); 58 putAll(map); 59 } 60 61 /* ------------------------------------------------------------ */ 62 /** Get multiple values. 63 * Single valued entries are converted to singleton lists. 64 * @param name The entry key. 65 * @return Unmodifieable List of values. 66 */ 67 public List getValues(Object name) 68 { 69 return LazyList.getList(super.get(name),true); 70 } 71 72 /* ------------------------------------------------------------ */ 73 /** Get a value from a multiple value. 74 * If the value is not a multivalue, then index 0 retrieves the 75 * value or null. 76 * @param name The entry key. 77 * @param i Index of element to get. 78 * @return Unmodifieable List of values. 79 */ 80 public Object getValue(Object name,int i) 81 { 82 Object l=super.get(name); 83 if (i==0 && LazyList.size(l)==0) 84 return null; 85 return LazyList.get(l,i); 86 } 87 88 89 /* ------------------------------------------------------------ */ 90 /** Get value as String. 91 * Single valued items are converted to a String with the toString() 92 * Object method. Multi valued entries are converted to a comma separated 93 * List. No quoting of commas within values is performed. 94 * @param name The entry key. 95 * @return String value. 96 */ 97 public String getString(Object name) 98 { 99 Object l=super.get(name); 100 switch(LazyList.size(l)) 101 { 102 case 0: 103 return null; 104 case 1: 105 Object o=LazyList.get(l,0); 106 return o==null?null:o.toString(); 107 default: 108 StringBuffer values=new StringBuffer(128); 109 synchronized(values) 110 { 111 for (int i=0; i<LazyList.size(l); i++) 112 { 113 Object e=LazyList.get(l,i); 114 if (e!=null) 115 { 116 if (values.length()>0) 117 values.append(','); 118 values.append(e.toString()); 119 } 120 } 121 return values.toString(); 122 } 123 } 124 } 125 126 /* ------------------------------------------------------------ */ 127 public Object get(Object name) 128 { 129 Object l=super.get(name); 130 switch(LazyList.size(l)) 131 { 132 case 0: 133 return null; 134 case 1: 135 Object o=LazyList.get(l,0); 136 return o; 137 default: 138 return LazyList.getList(l,true); 139 } 140 } 141 142 /* ------------------------------------------------------------ */ 143 /** Put and entry into the map. 144 * @param name The entry key. 145 * @param value The entry value. 146 * @return The previous value or null. 147 */ 148 public Object put(Object name, Object value) 149 { 150 return super.put(name,LazyList.add(null,value)); 151 } 152 153 /* ------------------------------------------------------------ */ 154 /** Put multi valued entry. 155 * @param name The entry key. 156 * @param values The List of multiple values. 157 * @return The previous value or null. 158 */ 159 public Object putValues(Object name, List values) 160 { 161 return super.put(name,values); 162 } 163 164 /* ------------------------------------------------------------ */ 165 /** Put multi valued entry. 166 * @param name The entry key. 167 * @param values The String array of multiple values. 168 * @return The previous value or null. 169 */ 170 public Object putValues(Object name, String[] values) 171 { 172 Object list=null; 173 for (int i=0;i<values.length;i++) 174 list=LazyList.add(list,values[i]); 175 return put(name,list); 176 } 177 178 179 /* ------------------------------------------------------------ */ 180 /** Add value to multi valued entry. 181 * If the entry is single valued, it is converted to the first 182 * value of a multi valued entry. 183 * @param name The entry key. 184 * @param value The entry value. 185 */ 186 public void add(Object name, Object value) 187 { 188 Object lo = super.get(name); 189 Object ln = LazyList.add(lo,value); 190 if (lo!=ln) 191 super.put(name,ln); 192 } 193 194 /* ------------------------------------------------------------ */ 195 /** Add values to multi valued entry. 196 * If the entry is single valued, it is converted to the first 197 * value of a multi valued entry. 198 * @param name The entry key. 199 * @param values The List of multiple values. 200 */ 201 public void addValues(Object name, List values) 202 { 203 Object lo = super.get(name); 204 Object ln = LazyList.addCollection(lo,values); 205 if (lo!=ln) 206 super.put(name,ln); 207 } 208 209 /* ------------------------------------------------------------ */ 210 /** Add values to multi valued entry. 211 * If the entry is single valued, it is converted to the first 212 * value of a multi valued entry. 213 * @param name The entry key. 214 * @param values The String array of multiple values. 215 */ 216 public void addValues(Object name, String[] values) 217 { 218 Object lo = super.get(name); 219 Object ln = LazyList.addCollection(lo,Arrays.asList(values)); 220 if (lo!=ln) 221 super.put(name,ln); 222 } 223 224 /* ------------------------------------------------------------ */ 225 /** Remove value. 226 * @param name The entry key. 227 * @param value The entry value. 228 * @return true if it was removed. 229 */ 230 public boolean removeValue(Object name,Object value) 231 { 232 Object lo = super.get(name); 233 Object ln=lo; 234 int s=LazyList.size(lo); 235 if (s>0) 236 { 237 ln=LazyList.remove(lo,value); 238 if (ln==null) 239 super.remove(name); 240 else 241 super.put(name, ln); 242 } 243 return LazyList.size(ln)!=s; 244 } 245 246 /* ------------------------------------------------------------ */ 247 /** Put all contents of map. 248 * @param m Map 249 */ 250 public void putAll(Map m) 251 { 252 Iterator i = m.entrySet().iterator(); 253 boolean multi=m instanceof MultiMap; 254 while(i.hasNext()) 255 { 256 Map.Entry entry = 257 (Map.Entry)i.next(); 258 if (multi) 259 super.put(entry.getKey(),LazyList.clone(entry.getValue())); 260 else 261 put(entry.getKey(),entry.getValue()); 262 } 263 } 264 265 /* ------------------------------------------------------------ */ 266 /** 267 * @return Map of String arrays 268 */ 269 public Map toStringArrayMap() 270 { 271 HashMap map = new HashMap(size()*3/2); 272 273 Iterator i = super.entrySet().iterator(); 274 while(i.hasNext()) 275 { 276 Map.Entry entry = (Map.Entry)i.next(); 277 Object l = entry.getValue(); 278 String[] a = LazyList.toStringArray(l); 279 // for (int j=a.length;j-->0;) 280 // if (a[j]==null) 281 // a[j]=""; 282 map.put(entry.getKey(),a); 283 } 284 return map; 285 } 286 287 /* ------------------------------------------------------------ */ 288 public Object clone() 289 { 290 MultiMap mm = (MultiMap) super.clone(); 291 292 Iterator iter = mm.entrySet().iterator(); 293 while (iter.hasNext()) 294 { 295 Map.Entry entry = (Map.Entry)iter.next(); 296 entry.setValue(LazyList.clone(entry.getValue())); 297 } 298 299 return mm; 300 } 301 }