1 16 package org.apache.commons.collections.map; 17 18 import java.util.AbstractCollection ; 19 import java.util.ArrayList ; 20 import java.util.Collection ; 21 import java.util.HashMap ; 22 import java.util.Iterator ; 23 import java.util.Map ; 24 import java.util.Set ; 25 26 import org.apache.commons.collections.Factory; 27 import org.apache.commons.collections.FunctorException; 28 import org.apache.commons.collections.MultiMap; 29 import org.apache.commons.collections.iterators.EmptyIterator; 30 import org.apache.commons.collections.iterators.IteratorChain; 31 32 63 public class MultiValueMap extends AbstractMapDecorator implements MultiMap { 64 65 66 private final Factory collectionFactory; 67 68 private transient Collection values; 69 70 76 public static MultiValueMap decorate(Map map) { 77 return new MultiValueMap(map, new ReflectionFactory(ArrayList .class)); 78 } 79 80 87 public static MultiValueMap decorate(Map map, Class collectionClass) { 88 return new MultiValueMap(map, new ReflectionFactory(collectionClass)); 89 } 90 91 98 public static MultiValueMap decorate(Map map, Factory collectionFactory) { 99 return new MultiValueMap(map, collectionFactory); 100 } 101 102 107 public MultiValueMap() { 108 this(new HashMap (), new ReflectionFactory(ArrayList .class)); 109 } 110 111 118 protected MultiValueMap(Map map, Factory collectionFactory) { 119 super(map); 120 if (collectionFactory == null) { 121 throw new IllegalArgumentException ("The factory must not be null"); 122 } 123 this.collectionFactory = collectionFactory; 124 } 125 126 130 public void clear() { 131 getMap().clear(); 140 } 141 142 155 public Object remove(Object key, Object value) { 156 Collection valuesForKey = getCollection(key); 157 if (valuesForKey == null) { 158 return null; 159 } 160 boolean removed = valuesForKey.remove(value); 161 if (removed == false) { 162 return null; 163 } 164 if (valuesForKey.isEmpty()) { 165 remove(key); 166 } 167 return value; 168 } 169 170 178 public boolean containsValue(Object value) { 179 Set pairs = getMap().entrySet(); 180 if (pairs == null) { 181 return false; 182 } 183 Iterator pairsIterator = pairs.iterator(); 184 while (pairsIterator.hasNext()) { 185 Map.Entry keyValuePair = (Map.Entry ) pairsIterator.next(); 186 Collection coll = (Collection ) keyValuePair.getValue(); 187 if (coll.contains(value)) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 204 public Object put(Object key, Object value) { 205 boolean result = false; 206 Collection coll = getCollection(key); 207 if (coll == null) { 208 coll = createCollection(1); 209 result = coll.add(value); 210 if (coll.size() > 0) { 211 getMap().put(key, coll); 213 result = false; 214 } 215 } else { 216 result = coll.add(value); 217 } 218 return (result ? value : null); 219 } 220 221 232 public void putAll(Map map) { 233 if (map instanceof MultiMap) { 234 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 235 Map.Entry entry = (Map.Entry ) it.next(); 236 Collection coll = (Collection ) entry.getValue(); 237 putAll(entry.getKey(), coll); 238 } 239 } else { 240 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 241 Map.Entry entry = (Map.Entry ) it.next(); 242 put(entry.getKey(), entry.getValue()); 243 } 244 } 245 } 246 247 254 public Collection values() { 255 Collection vs = values; 256 return (vs != null ? vs : (values = new Values())); 257 } 258 259 265 public boolean containsValue(Object key, Object value) { 266 Collection coll = getCollection(key); 267 if (coll == null) { 268 return false; 269 } 270 return coll.contains(value); 271 } 272 273 280 public Collection getCollection(Object key) { 281 return (Collection ) getMap().get(key); 282 } 283 284 290 public int size(Object key) { 291 Collection coll = getCollection(key); 292 if (coll == null) { 293 return 0; 294 } 295 return coll.size(); 296 } 297 298 306 public boolean putAll(Object key, Collection values) { 307 if (values == null || values.size() == 0) { 308 return false; 309 } 310 Collection coll = getCollection(key); 311 if (coll == null) { 312 coll = createCollection(values.size()); 313 boolean result = coll.addAll(values); 314 if (coll.size() > 0) { 315 getMap().put(key, coll); 317 result = false; 318 } 319 return result; 320 } else { 321 return coll.addAll(values); 322 } 323 } 324 325 331 public Iterator iterator(Object key) { 332 if (!containsKey(key)) { 333 return EmptyIterator.INSTANCE; 334 } else { 335 return new ValuesIterator(key); 336 } 337 } 338 339 344 public int totalSize() { 345 int total = 0; 346 Collection values = getMap().values(); 347 for (Iterator it = values.iterator(); it.hasNext();) { 348 Collection coll = (Collection ) it.next(); 349 total += coll.size(); 350 } 351 return total; 352 } 353 354 364 protected Collection createCollection(int size) { 365 return (Collection ) collectionFactory.create(); 366 } 367 368 372 private class Values extends AbstractCollection { 373 public Iterator iterator() { 374 final IteratorChain chain = new IteratorChain(); 375 for (Iterator it = keySet().iterator(); it.hasNext();) { 376 chain.addIterator(new ValuesIterator(it.next())); 377 } 378 return chain; 379 } 380 381 public int size() { 382 return totalSize(); 383 } 384 385 public void clear() { 386 MultiValueMap.this.clear(); 387 } 388 } 389 390 393 private class ValuesIterator implements Iterator { 394 private final Object key; 395 private final Collection values; 396 private final Iterator iterator; 397 398 public ValuesIterator(Object key) { 399 this.key = key; 400 this.values = getCollection(key); 401 this.iterator = values.iterator(); 402 } 403 404 public void remove() { 405 iterator.remove(); 406 if (values.isEmpty()) { 407 MultiValueMap.this.remove(key); 408 } 409 } 410 411 public boolean hasNext() { 412 return iterator.hasNext(); 413 } 414 415 public Object next() { 416 return iterator.next(); 417 } 418 } 419 420 423 private static class ReflectionFactory implements Factory { 424 private final Class clazz; 425 426 public ReflectionFactory(Class clazz) { 427 this.clazz = clazz; 428 } 429 430 public Object create() { 431 try { 432 return clazz.newInstance(); 433 } catch (Exception ex) { 434 throw new FunctorException("Cannot instantiate class: " + clazz, ex); 435 } 436 } 437 } 438 439 } 440 | Popular Tags |