1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.multimap;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.util.AbstractCollection;
23 import java.util.AbstractMap;
24 import java.util.AbstractSet;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.Map;
29 import java.util.Map.Entry;
30 import java.util.Objects;
31 import java.util.Set;
32
33 import org.apache.commons.collections4.CollectionUtils;
34 import org.apache.commons.collections4.IteratorUtils;
35 import org.apache.commons.collections4.MapIterator;
36 import org.apache.commons.collections4.MultiSet;
37 import org.apache.commons.collections4.MultiValuedMap;
38 import org.apache.commons.collections4.Transformer;
39 import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
40 import org.apache.commons.collections4.iterators.EmptyMapIterator;
41 import org.apache.commons.collections4.iterators.IteratorChain;
42 import org.apache.commons.collections4.iterators.LazyIteratorChain;
43 import org.apache.commons.collections4.iterators.TransformIterator;
44 import org.apache.commons.collections4.keyvalue.AbstractMapEntry;
45 import org.apache.commons.collections4.keyvalue.UnmodifiableMapEntry;
46 import org.apache.commons.collections4.multiset.AbstractMultiSet;
47 import org.apache.commons.collections4.multiset.UnmodifiableMultiSet;
48
49
50
51
52
53
54
55
56
57
58
59
60 public abstract class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V> {
61
62
63
64
65 private final class AsMap extends AbstractMap<K, Collection<V>> {
66 final class AsMapEntrySet extends AbstractSet<Map.Entry<K, Collection<V>>> {
67
68 @Override
69 public void clear() {
70 AsMap.this.clear();
71 }
72
73 @Override
74 public boolean contains(final Object o) {
75 return map.entrySet().contains(o);
76 }
77
78 @Override
79 public Iterator<Map.Entry<K, Collection<V>>> iterator() {
80 return new AsMapEntrySetIterator(map.entrySet().iterator());
81 }
82
83 @Override
84 public boolean remove(final Object o) {
85 if (!contains(o)) {
86 return false;
87 }
88 final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
89 AbstractMultiValuedMap.this.remove(entry.getKey());
90 return true;
91 }
92
93 @Override
94 public int size() {
95 return AsMap.this.size();
96 }
97 }
98
99
100
101
102 final class AsMapEntrySetIterator extends AbstractIteratorDecorator<Map.Entry<K, Collection<V>>> {
103
104 AsMapEntrySetIterator(final Iterator<Map.Entry<K, Collection<V>>> iterator) {
105 super(iterator);
106 }
107
108 @Override
109 public Map.Entry<K, Collection<V>> next() {
110 final Map.Entry<K, Collection<V>> entry = super.next();
111 final K key = entry.getKey();
112 return new UnmodifiableMapEntry<>(key, wrappedCollection(key));
113 }
114 }
115
116 final transient Map<K, Collection<V>> map;
117
118 AsMap(final Map<K, Collection<V>> map) {
119 this.map = map;
120 }
121
122 @Override
123 public void clear() {
124 AbstractMultiValuedMap.this.clear();
125 }
126
127 @Override
128 public boolean containsKey(final Object key) {
129 return map.containsKey(key);
130 }
131
132 @Override
133 public Set<Map.Entry<K, Collection<V>>> entrySet() {
134 return new AsMapEntrySet();
135 }
136
137 @Override
138 public boolean equals(final Object object) {
139 return this == object || map.equals(object);
140 }
141
142 @Override
143 public Collection<V> get(final Object key) {
144 final Collection<V> collection = map.get(key);
145 if (collection == null) {
146 return null;
147 }
148 @SuppressWarnings("unchecked")
149 final K k = (K) key;
150 return wrappedCollection(k);
151 }
152
153 @Override
154 public int hashCode() {
155 return map.hashCode();
156 }
157
158 @Override
159 public Set<K> keySet() {
160 return AbstractMultiValuedMap.this.keySet();
161 }
162
163 @Override
164 public Collection<V> remove(final Object key) {
165 final Collection<V> collection = map.remove(key);
166 if (collection == null) {
167 return null;
168 }
169
170 final Collection<V> output = createCollection();
171 output.addAll(collection);
172 collection.clear();
173 return output;
174 }
175
176 @Override
177 public int size() {
178 return map.size();
179 }
180
181 @Override
182 public String toString() {
183 return map.toString();
184 }
185 }
186
187
188
189
190 private final class EntryValues extends AbstractCollection<Entry<K, V>> {
191
192 @Override
193 public Iterator<Entry<K, V>> iterator() {
194 return new LazyIteratorChain<Entry<K, V>>() {
195
196 final Collection<K> keysCol = new ArrayList<>(getMap().keySet());
197 final Iterator<K> keyIterator = keysCol.iterator();
198
199 @Override
200 protected Iterator<? extends Entry<K, V>> nextIterator(final int count) {
201 if (!keyIterator.hasNext()) {
202 return null;
203 }
204 final K key = keyIterator.next();
205 final Transformer<V, Entry<K, V>> entryTransformer = input -> new MultiValuedMapEntry(key, input);
206 return new TransformIterator<>(new ValuesIterator(key), entryTransformer);
207 }
208 };
209 }
210
211 @Override
212 public int size() {
213 return AbstractMultiValuedMap.this.size();
214 }
215
216 }
217
218
219
220
221 private final class KeysMultiSet extends AbstractMultiSet<K> {
222
223 private final class MapEntryTransformer implements Transformer<Map.Entry<K, Collection<V>>, MultiSet.Entry<K>> {
224
225 @Override
226 public MultiSet.Entry<K> transform(final Map.Entry<K, Collection<V>> mapEntry) {
227 return new AbstractMultiSet.AbstractEntry<K>() {
228
229 @Override
230 public int getCount() {
231 return mapEntry.getValue().size();
232 }
233
234 @Override
235 public K getElement() {
236 return mapEntry.getKey();
237 }
238 };
239 }
240 }
241
242 @Override
243 public boolean contains(final Object o) {
244 return getMap().containsKey(o);
245 }
246
247 @Override
248 protected Iterator<MultiSet.Entry<K>> createEntrySetIterator() {
249 final MapEntryTransformer transformer = new MapEntryTransformer();
250 return IteratorUtils.transformedIterator(map.entrySet().iterator(), transformer);
251 }
252
253 @Override
254 public int getCount(final Object object) {
255 int count = 0;
256 final Collection<V> col = AbstractMultiValuedMap.this.getMap().get(object);
257 if (col != null) {
258 count = col.size();
259 }
260 return count;
261 }
262
263 @Override
264 public boolean isEmpty() {
265 return getMap().isEmpty();
266 }
267
268 @Override
269 public int size() {
270 return AbstractMultiValuedMap.this.size();
271 }
272
273 @Override
274 protected int uniqueElements() {
275 return getMap().size();
276 }
277 }
278
279
280
281
282 private final class MultiValuedMapEntry extends AbstractMapEntry<K, V> {
283
284 MultiValuedMapEntry(final K key, final V value) {
285 super(key, value);
286 }
287
288 @Override
289 public V setValue(final V value) {
290 throw new UnsupportedOperationException();
291 }
292
293 }
294
295
296
297
298 private final class MultiValuedMapIterator implements MapIterator<K, V> {
299
300 private final Iterator<Entry<K, V>> it;
301
302 private Entry<K, V> current;
303
304 MultiValuedMapIterator() {
305 this.it = AbstractMultiValuedMap.this.entries().iterator();
306 }
307
308 @Override
309 public K getKey() {
310 if (current == null) {
311 throw new IllegalStateException();
312 }
313 return current.getKey();
314 }
315
316 @Override
317 public V getValue() {
318 if (current == null) {
319 throw new IllegalStateException();
320 }
321 return current.getValue();
322 }
323
324 @Override
325 public boolean hasNext() {
326 return it.hasNext();
327 }
328
329 @Override
330 public K next() {
331 current = it.next();
332 return current.getKey();
333 }
334
335 @Override
336 public void remove() {
337 it.remove();
338 }
339
340 @Override
341 public V setValue(final V value) {
342 if (current == null) {
343 throw new IllegalStateException();
344 }
345 return current.setValue(value);
346 }
347
348 }
349
350
351
352
353 private final class Values extends AbstractCollection<V> {
354 @Override
355 public void clear() {
356 AbstractMultiValuedMap.this.clear();
357 }
358
359 @Override
360 public Iterator<V> iterator() {
361 final IteratorChain<V> chain = new IteratorChain<>();
362 for (final K k : keySet()) {
363 chain.addIterator(new ValuesIterator(k));
364 }
365 return chain;
366 }
367
368 @Override
369 public int size() {
370 return AbstractMultiValuedMap.this.size();
371 }
372 }
373
374
375
376
377 private final class ValuesIterator implements Iterator<V> {
378 private final Object key;
379 private final Collection<V> values;
380 private final Iterator<V> iterator;
381
382 ValuesIterator(final Object key) {
383 this.key = key;
384 this.values = getMap().get(key);
385 this.iterator = values.iterator();
386 }
387
388 @Override
389 public boolean hasNext() {
390 return iterator.hasNext();
391 }
392
393 @Override
394 public V next() {
395 return iterator.next();
396 }
397
398 @Override
399 public void remove() {
400 iterator.remove();
401 if (values.isEmpty()) {
402 AbstractMultiValuedMap.this.remove(key);
403 }
404 }
405 }
406
407
408
409
410
411
412
413
414
415
416
417 class WrappedCollection implements Collection<V> {
418
419 protected final K key;
420
421 WrappedCollection(final K key) {
422 this.key = key;
423 }
424
425 @Override
426 public boolean add(final V value) {
427 Collection<V> coll = getMapping();
428 if (coll == null) {
429 coll = createCollection();
430 AbstractMultiValuedMap.this.map.put(key, coll);
431 }
432 return coll.add(value);
433 }
434
435 @Override
436 public boolean addAll(final Collection<? extends V> other) {
437 Collection<V> coll = getMapping();
438 if (coll == null) {
439 coll = createCollection();
440 AbstractMultiValuedMap.this.map.put(key, coll);
441 }
442 return coll.addAll(other);
443 }
444
445 @Override
446 public void clear() {
447 final Collection<V> coll = getMapping();
448 if (coll != null) {
449 coll.clear();
450 AbstractMultiValuedMap.this.remove(key);
451 }
452 }
453
454 @Override
455 public boolean contains(final Object obj) {
456 final Collection<V> coll = getMapping();
457 return coll != null && coll.contains(obj);
458 }
459
460 @Override
461 public boolean containsAll(final Collection<?> other) {
462 final Collection<V> coll = getMapping();
463 return coll != null && coll.containsAll(other);
464 }
465
466 protected Collection<V> getMapping() {
467 return getMap().get(key);
468 }
469
470 @Override
471 public boolean isEmpty() {
472 final Collection<V> coll = getMapping();
473 return coll == null || coll.isEmpty();
474 }
475
476 @Override
477 public Iterator<V> iterator() {
478 final Collection<V> coll = getMapping();
479 if (coll == null) {
480 return IteratorUtils.EMPTY_ITERATOR;
481 }
482 return new ValuesIterator(key);
483 }
484
485 @Override
486 public boolean remove(final Object item) {
487 final Collection<V> coll = getMapping();
488 if (coll == null) {
489 return false;
490 }
491
492 final boolean result = coll.remove(item);
493 if (coll.isEmpty()) {
494 AbstractMultiValuedMap.this.remove(key);
495 }
496 return result;
497 }
498
499 @Override
500 public boolean removeAll(final Collection<?> c) {
501 final Collection<V> coll = getMapping();
502 if (coll == null) {
503 return false;
504 }
505
506 final boolean result = coll.removeAll(c);
507 if (coll.isEmpty()) {
508 AbstractMultiValuedMap.this.remove(key);
509 }
510 return result;
511 }
512
513 @Override
514 public boolean retainAll(final Collection<?> c) {
515 final Collection<V> coll = getMapping();
516 if (coll == null) {
517 return false;
518 }
519
520 final boolean result = coll.retainAll(c);
521 if (coll.isEmpty()) {
522 AbstractMultiValuedMap.this.remove(key);
523 }
524 return result;
525 }
526
527 @Override
528 public int size() {
529 final Collection<V> coll = getMapping();
530 return coll == null ? 0 : coll.size();
531 }
532
533 @Override
534 public Object[] toArray() {
535 final Collection<V> coll = getMapping();
536 if (coll == null) {
537 return CollectionUtils.EMPTY_COLLECTION.toArray();
538 }
539 return coll.toArray();
540 }
541
542 @Override
543 @SuppressWarnings("unchecked")
544 public <T> T[] toArray(final T[] a) {
545 final Collection<V> coll = getMapping();
546 if (coll == null) {
547 return (T[]) CollectionUtils.EMPTY_COLLECTION.toArray(a);
548 }
549 return coll.toArray(a);
550 }
551
552 @Override
553 public String toString() {
554 final Collection<V> coll = getMapping();
555 if (coll == null) {
556 return CollectionUtils.EMPTY_COLLECTION.toString();
557 }
558 return coll.toString();
559 }
560
561 }
562
563
564 private transient Collection<V> valuesView;
565
566
567 private transient EntryValues entryValuesView;
568
569
570 private transient MultiSet<K> keysMultiSetView;
571
572
573 private transient AsMap asMapView;
574
575
576 private transient Map<K, Collection<V>> map;
577
578
579
580
581 protected AbstractMultiValuedMap() {
582 }
583
584
585
586
587
588
589
590 @SuppressWarnings("unchecked")
591 protected AbstractMultiValuedMap(final Map<K, ? extends Collection<V>> map) {
592 this.map = (Map<K, Collection<V>>) Objects.requireNonNull(map, "map");
593 }
594
595 @Override
596 public Map<K, Collection<V>> asMap() {
597 return asMapView != null ? asMapView : (asMapView = new AsMap(map));
598 }
599
600 @Override
601 public void clear() {
602 getMap().clear();
603 }
604
605 @Override
606 public boolean containsKey(final Object key) {
607 return getMap().containsKey(key);
608 }
609
610 @Override
611 public boolean containsMapping(final Object key, final Object value) {
612 final Collection<V> coll = getMap().get(key);
613 return coll != null && coll.contains(value);
614 }
615
616 @Override
617 public boolean containsValue(final Object value) {
618 return values().contains(value);
619 }
620
621
622
623
624
625
626 protected abstract Collection<V> createCollection();
627
628
629
630
631
632
633
634
635
636 protected void doReadObject(final ObjectInputStream in)
637 throws IOException, ClassNotFoundException {
638 final int entrySize = in.readInt();
639 for (int i = 0; i < entrySize; i++) {
640 @SuppressWarnings("unchecked")
641 final K key = (K) in.readObject();
642 final Collection<V> values = get(key);
643 final int valueSize = in.readInt();
644 for (int j = 0; j < valueSize; j++) {
645 @SuppressWarnings("unchecked")
646 final V value = (V) in.readObject();
647 values.add(value);
648 }
649 }
650 }
651
652
653
654
655
656
657
658 protected void doWriteObject(final ObjectOutputStream out) throws IOException {
659 out.writeInt(map.size());
660 for (final Map.Entry<K, Collection<V>> entry : map.entrySet()) {
661 out.writeObject(entry.getKey());
662 out.writeInt(entry.getValue().size());
663 for (final V value : entry.getValue()) {
664 out.writeObject(value);
665 }
666 }
667 }
668
669 @Override
670 public Collection<Entry<K, V>> entries() {
671 return entryValuesView != null ? entryValuesView : (entryValuesView = new EntryValues());
672 }
673
674 @Override
675 public boolean equals(final Object obj) {
676 if (this == obj) {
677 return true;
678 }
679 if (obj instanceof MultiValuedMap) {
680 return asMap().equals(((MultiValuedMap<?, ?>) obj).asMap());
681 }
682 return false;
683 }
684
685
686
687
688
689
690
691
692 @Override
693 public Collection<V> get(final K key) {
694 return wrappedCollection(key);
695 }
696
697
698
699
700
701
702 protected Map<K, ? extends Collection<V>> getMap() {
703 return map;
704 }
705
706 @Override
707 public int hashCode() {
708 return getMap().hashCode();
709 }
710
711 @Override
712 public boolean isEmpty() {
713 return getMap().isEmpty();
714 }
715
716
717
718
719
720
721
722
723
724
725
726 @Override
727 public MultiSet<K> keys() {
728 if (keysMultiSetView == null) {
729 keysMultiSetView = UnmodifiableMultiSet.unmodifiableMultiSet(new KeysMultiSet());
730 }
731 return keysMultiSetView;
732 }
733
734 @Override
735 public Set<K> keySet() {
736 return getMap().keySet();
737 }
738
739 @Override
740 public MapIterator<K, V> mapIterator() {
741 if (isEmpty()) {
742 return EmptyMapIterator.emptyMapIterator();
743 }
744 return new MultiValuedMapIterator();
745 }
746
747
748
749
750
751
752
753
754
755
756
757 @Override
758 public boolean put(final K key, final V value) {
759 Collection<V> coll = getMap().get(key);
760 if (coll == null) {
761 coll = createCollection();
762 if (coll.add(value)) {
763 map.put(key, coll);
764 return true;
765 }
766 return false;
767 }
768 return coll.add(value);
769 }
770
771
772
773
774
775
776
777
778
779 @Override
780 public boolean putAll(final K key, final Iterable<? extends V> values) {
781 Objects.requireNonNull(values, "values");
782
783 if (values instanceof Collection<?>) {
784 final Collection<? extends V> valueCollection = (Collection<? extends V>) values;
785 return !valueCollection.isEmpty() && get(key).addAll(valueCollection);
786 }
787 final Iterator<? extends V> it = values.iterator();
788 return it.hasNext() && CollectionUtils.addAll(get(key), it);
789 }
790
791
792
793
794
795
796
797
798
799
800
801
802
803 @Override
804 public boolean putAll(final Map<? extends K, ? extends V> map) {
805 Objects.requireNonNull(map, "map");
806 boolean changed = false;
807 for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
808 changed |= put(entry.getKey(), entry.getValue());
809 }
810 return changed;
811 }
812
813
814
815
816
817
818
819
820
821
822
823
824
825 @Override
826 public boolean putAll(final MultiValuedMap<? extends K, ? extends V> map) {
827 Objects.requireNonNull(map, "map");
828 boolean changed = false;
829 for (final Map.Entry<? extends K, ? extends V> entry : map.entries()) {
830 changed |= put(entry.getKey(), entry.getValue());
831 }
832 return changed;
833 }
834
835
836
837
838
839
840
841
842
843
844 @Override
845 public Collection<V> remove(final Object key) {
846 return CollectionUtils.emptyIfNull(getMap().remove(key));
847 }
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862 @Override
863 public boolean removeMapping(final Object key, final Object value) {
864 final Collection<V> coll = getMap().get(key);
865 if (coll == null) {
866 return false;
867 }
868 final boolean changed = coll.remove(value);
869 if (coll.isEmpty()) {
870 getMap().remove(key);
871 }
872 return changed;
873 }
874
875
876
877
878
879
880
881
882 @SuppressWarnings("unchecked")
883 protected void setMap(final Map<K, ? extends Collection<V>> map) {
884 this.map = (Map<K, Collection<V>>) map;
885 }
886
887
888
889
890
891
892
893
894 @Override
895 public int size() {
896
897
898
899
900 int size = 0;
901 for (final Collection<V> col : getMap().values()) {
902 size += col.size();
903 }
904 return size;
905 }
906
907 @Override
908 public String toString() {
909 return getMap().toString();
910 }
911
912
913
914
915
916
917
918
919 @Override
920 public Collection<V> values() {
921 final Collection<V> vs = valuesView;
922 return vs != null ? vs : (valuesView = new Values());
923 }
924
925 Collection<V> wrappedCollection(final K key) {
926 return new WrappedCollection(key);
927 }
928
929 }