001    /*
002     * Copyright (C) 2008 Google Inc.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.collect;
018    
019    import static com.google.common.base.Preconditions.checkNotNull;
020    
021    import com.google.common.annotations.GwtCompatible;
022    import com.google.common.annotations.GwtIncompatible;
023    
024    import java.io.Serializable;
025    import java.util.Arrays;
026    import java.util.Collection;
027    import java.util.Iterator;
028    import java.util.LinkedHashMap;
029    import java.util.Map;
030    
031    import javax.annotation.Nullable;
032    
033    /**
034     * An immutable {@link Multimap}. Does not permit null keys or values.
035     *
036     * <p>Unlike {@link Multimaps#unmodifiableMultimap(Multimap)}, which is
037     * a <i>view</i> of a separate multimap which can still change, an instance of
038     * {@code ImmutableMultimap} contains its own data and will <i>never</i>
039     * change. {@code ImmutableMultimap} is convenient for
040     * {@code public static final} multimaps ("constant multimaps") and also lets
041     * you easily make a "defensive copy" of a multimap provided to your class by
042     * a caller.
043     *
044     * <p><b>Note</b>: Although this class is not final, it cannot be subclassed as
045     * it has no public or protected constructors. Thus, instances of this class
046     * are guaranteed to be immutable.
047     *
048     * @author Jared Levy
049     * @since 2 (imported from Google Collections Library)
050     */
051    @GwtCompatible(emulated = true)
052    public abstract class ImmutableMultimap<K, V>
053        implements Multimap<K, V>, Serializable {
054    
055      /** Returns an empty multimap. */
056      public static <K, V> ImmutableMultimap<K, V> of() {
057        return ImmutableListMultimap.of();
058      }
059    
060      /**
061       * Returns an immutable multimap containing a single entry.
062       */
063      public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1) {
064        return ImmutableListMultimap.of(k1, v1);
065      }
066    
067      /**
068       * Returns an immutable multimap containing the given entries, in order.
069       */
070      public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2) {
071        return ImmutableListMultimap.of(k1, v1, k2, v2);
072      }
073    
074      /**
075       * Returns an immutable multimap containing the given entries, in order.
076       */
077      public static <K, V> ImmutableMultimap<K, V> of(
078          K k1, V v1, K k2, V v2, K k3, V v3) {
079        return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3);
080      }
081    
082      /**
083       * Returns an immutable multimap containing the given entries, in order.
084       */
085      public static <K, V> ImmutableMultimap<K, V> of(
086          K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
087        return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4);
088      }
089    
090      /**
091       * Returns an immutable multimap containing the given entries, in order.
092       */
093      public static <K, V> ImmutableMultimap<K, V> of(
094          K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
095        return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
096      }
097    
098      // looking for of() with > 5 entries? Use the builder instead.
099    
100      /**
101       * Returns a new builder. The generated builder is equivalent to the builder
102       * created by the {@link Builder} constructor.
103       */
104      public static <K, V> Builder<K, V> builder() {
105        return new Builder<K, V>();
106      }
107    
108      /**
109       * Multimap for {@link ImmutableMultimap.Builder} that maintains key and
110       * value orderings, allows duplicate values, and performs better than
111       * {@link LinkedListMultimap}.
112       */
113      private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
114        BuilderMultimap() {
115          super(new LinkedHashMap<K, Collection<V>>());
116        }
117        @Override Collection<V> createCollection() {
118          return Lists.newArrayList();
119        }
120        private static final long serialVersionUID = 0;
121      }
122    
123      /**
124       * A builder for creating immutable multimap instances, especially
125       * {@code public static final} multimaps ("constant multimaps"). Example:
126       * <pre>   {@code
127       *
128       *   static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
129       *       new ImmutableMultimap.Builder<String, Integer>()
130       *           .put("one", 1)
131       *           .putAll("several", 1, 2, 3)
132       *           .putAll("many", 1, 2, 3, 4, 5)
133       *           .build();}</pre>
134       *
135       * <p>Builder instances can be reused - it is safe to call {@link #build}
136       * multiple times to build multiple multimaps in series. Each multimap
137       * contains the key-value mappings in the previously created multimaps.
138       */
139      public static class Builder<K, V> {
140        private final Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>();
141    
142        /**
143         * Creates a new builder. The returned builder is equivalent to the builder
144         * generated by {@link ImmutableMultimap#builder}.
145         */
146        public Builder() {}
147    
148        /**
149         * Adds a key-value mapping to the built multimap.
150         */
151        public Builder<K, V> put(K key, V value) {
152          builderMultimap.put(checkNotNull(key), checkNotNull(value));
153          return this;
154        }
155    
156        /**
157         * Stores a collection of values with the same key in the built multimap.
158         *
159         * @throws NullPointerException if {@code key}, {@code values}, or any
160         *     element in {@code values} is null. The builder is left in an invalid
161         *     state.
162         */
163        public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
164          Collection<V> valueList = builderMultimap.get(checkNotNull(key));
165          for (V value : values) {
166            valueList.add(checkNotNull(value));
167          }
168          return this;
169        }
170    
171        /**
172         * Stores an array of values with the same key in the built multimap.
173         *
174         * @throws NullPointerException if the key or any value is null. The builder
175         *     is left in an invalid state.
176         */
177        public Builder<K, V> putAll(K key, V... values) {
178          return putAll(key, Arrays.asList(values));
179        }
180    
181        /**
182         * Stores another multimap's entries in the built multimap. The generated
183         * multimap's key and value orderings correspond to the iteration ordering
184         * of the {@code multimap.asMap()} view, with new keys and values following
185         * any existing keys and values.
186         *
187         * @throws NullPointerException if any key or value in {@code multimap} is
188         *     null. The builder is left in an invalid state.
189         */
190        public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) {
191          for (Map.Entry<? extends K, ? extends Collection<? extends V>> entry
192              : multimap.asMap().entrySet()) {
193            putAll(entry.getKey(), entry.getValue());
194          }
195          return this;
196        }
197    
198        /**
199         * Returns a newly-created immutable multimap.
200         */
201        public ImmutableMultimap<K, V> build() {
202          return copyOf(builderMultimap);
203        }
204      }
205    
206      /**
207       * Returns an immutable multimap containing the same mappings as
208       * {@code multimap}. The generated multimap's key and value orderings
209       * correspond to the iteration ordering of the {@code multimap.asMap()} view.
210       *
211       * <p><b>Note:</b> Despite what the method name suggests, if
212       * {@code multimap} is an {@code ImmutableMultimap}, no copy will actually be
213       * performed, and the given multimap itself will be returned.
214       *
215       * @throws NullPointerException if any key or value in {@code multimap} is
216       *     null
217       */
218      public static <K, V> ImmutableMultimap<K, V> copyOf(
219          Multimap<? extends K, ? extends V> multimap) {
220        if (multimap instanceof ImmutableMultimap) {
221          @SuppressWarnings("unchecked") // safe since multimap is not writable
222          ImmutableMultimap<K, V> kvMultimap
223              = (ImmutableMultimap<K, V>) multimap;
224          return kvMultimap;
225        } else {
226          return ImmutableListMultimap.copyOf(multimap);
227        }
228      }
229    
230      final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map;
231      final transient int size;
232    
233      // These constants allow the deserialization code to set final fields. This
234      // holder class makes sure they are not initialized unless an instance is
235      // deserialized.
236      @GwtIncompatible("java serialization is not supported")
237      static class FieldSettersHolder {
238        // Eclipse doesn't like the raw ImmutableMultimap
239        @SuppressWarnings("unchecked")
240        static final Serialization.FieldSetter<ImmutableMultimap>
241            MAP_FIELD_SETTER = Serialization.getFieldSetter(
242            ImmutableMultimap.class, "map");
243        // Eclipse doesn't like the raw ImmutableMultimap
244        @SuppressWarnings("unchecked")
245        static final Serialization.FieldSetter<ImmutableMultimap>
246            SIZE_FIELD_SETTER = Serialization.getFieldSetter(
247            ImmutableMultimap.class, "size");
248      }
249    
250      ImmutableMultimap(ImmutableMap<K, ? extends ImmutableCollection<V>> map,
251          int size) {
252        this.map = map;
253        this.size = size;
254      }
255    
256      // mutators (not supported)
257    
258      /**
259       * Guaranteed to throw an exception and leave the multimap unmodified.
260       *
261       * @throws UnsupportedOperationException always
262       */
263      public ImmutableCollection<V> removeAll(Object key) {
264        throw new UnsupportedOperationException();
265      }
266    
267      /**
268       * Guaranteed to throw an exception and leave the multimap unmodified.
269       *
270       * @throws UnsupportedOperationException always
271       */
272      public ImmutableCollection<V> replaceValues(K key,
273          Iterable<? extends V> values) {
274        throw new UnsupportedOperationException();
275      }
276    
277      /**
278       * Guaranteed to throw an exception and leave the multimap unmodified.
279       *
280       * @throws UnsupportedOperationException always
281       */
282      public void clear() {
283        throw new UnsupportedOperationException();
284      }
285    
286      /**
287       * Returns an immutable collection of the values for the given key.  If no
288       * mappings in the multimap have the provided key, an empty immutable
289       * collection is returned. The values are in the same order as the parameters
290       * used to build this multimap.
291       */
292      public abstract ImmutableCollection<V> get(K key);
293    
294      /**
295       * Guaranteed to throw an exception and leave the multimap unmodified.
296       *
297       * @throws UnsupportedOperationException always
298       */
299      public boolean put(K key, V value) {
300        throw new UnsupportedOperationException();
301      }
302    
303      /**
304       * Guaranteed to throw an exception and leave the multimap unmodified.
305       *
306       * @throws UnsupportedOperationException always
307       */
308      public boolean putAll(K key, Iterable<? extends V> values) {
309        throw new UnsupportedOperationException();
310      }
311    
312      /**
313       * Guaranteed to throw an exception and leave the multimap unmodified.
314       *
315       * @throws UnsupportedOperationException always
316       */
317      public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
318        throw new UnsupportedOperationException();
319      }
320    
321      /**
322       * Guaranteed to throw an exception and leave the multimap unmodified.
323       *
324       * @throws UnsupportedOperationException always
325       */
326      public boolean remove(Object key, Object value) {
327        throw new UnsupportedOperationException();
328      }
329    
330      // accessors
331    
332      public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
333        Collection<V> values = map.get(key);
334        return values != null && values.contains(value);
335      }
336    
337      public boolean containsKey(@Nullable Object key) {
338        return map.containsKey(key);
339      }
340    
341      public boolean containsValue(@Nullable Object value) {
342        for (Collection<V> valueCollection : map.values()) {
343          if (valueCollection.contains(value)) {
344            return true;
345          }
346        }
347        return false;
348      }
349    
350      public boolean isEmpty() {
351        return size == 0;
352      }
353    
354      public int size() {
355        return size;
356      }
357    
358      @Override public boolean equals(@Nullable Object object) {
359        if (object instanceof Multimap) {
360          Multimap<?, ?> that = (Multimap<?, ?>) object;
361          return this.map.equals(that.asMap());
362        }
363        return false;
364      }
365    
366      @Override public int hashCode() {
367        return map.hashCode();
368      }
369    
370      @Override public String toString() {
371        return map.toString();
372      }
373    
374      // views
375    
376      /**
377       * Returns an immutable set of the distinct keys in this multimap. These keys
378       * are ordered according to when they first appeared during the construction
379       * of this multimap.
380       */
381      public ImmutableSet<K> keySet() {
382        return map.keySet();
383      }
384    
385      /**
386       * Returns an immutable map that associates each key with its corresponding
387       * values in the multimap.
388       */
389      @SuppressWarnings("unchecked") // a widening cast
390      public ImmutableMap<K, Collection<V>> asMap() {
391        return (ImmutableMap) map;
392      }
393    
394      private transient ImmutableCollection<Map.Entry<K, V>> entries;
395    
396      /**
397       * Returns an immutable collection of all key-value pairs in the multimap. Its
398       * iterator traverses the values for the first key, the values for the second
399       * key, and so on.
400       */
401      public ImmutableCollection<Map.Entry<K, V>> entries() {
402        ImmutableCollection<Map.Entry<K, V>> result = entries;
403        return (result == null)
404            ? (entries = new EntryCollection<K, V>(this)) : result;
405      }
406    
407      private static class EntryCollection<K, V>
408          extends ImmutableCollection<Map.Entry<K, V>> {
409        final ImmutableMultimap<K, V> multimap;
410    
411        EntryCollection(ImmutableMultimap<K, V> multimap) {
412          this.multimap = multimap;
413        }
414    
415        @Override public UnmodifiableIterator<Map.Entry<K, V>> iterator() {
416          final Iterator<? extends Map.Entry<K, ? extends ImmutableCollection<V>>>
417              mapIterator = this.multimap.map.entrySet().iterator();
418    
419          return new UnmodifiableIterator<Map.Entry<K, V>>() {
420            K key;
421            Iterator<V> valueIterator;
422    
423            public boolean hasNext() {
424              return (key != null && valueIterator.hasNext())
425                  || mapIterator.hasNext();
426            }
427    
428            public Map.Entry<K, V> next() {
429              if (key == null || !valueIterator.hasNext()) {
430                Map.Entry<K, ? extends ImmutableCollection<V>> entry
431                    = mapIterator.next();
432                key = entry.getKey();
433                valueIterator = entry.getValue().iterator();
434              }
435              return Maps.immutableEntry(key, valueIterator.next());
436            }
437          };
438        }
439    
440        public int size() {
441          return multimap.size();
442        }
443    
444        @Override public boolean contains(Object object) {
445          if (object instanceof Map.Entry) {
446            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
447            return multimap.containsEntry(entry.getKey(), entry.getValue());
448          }
449          return false;
450        }
451    
452        private static final long serialVersionUID = 0;
453      }
454    
455      private transient ImmutableMultiset<K> keys;
456    
457      /**
458       * Returns a collection, which may contain duplicates, of all keys. The number
459       * of times a key appears in the returned multiset equals the number of
460       * mappings the key has in the multimap. Duplicate keys appear consecutively
461       * in the multiset's iteration order.
462       */
463      public ImmutableMultiset<K> keys() {
464        ImmutableMultiset<K> result = keys;
465        return (result == null) ? (keys = createKeys()) : result;
466      }
467    
468      private ImmutableMultiset<K> createKeys() {
469        ImmutableMultiset.Builder<K> builder = ImmutableMultiset.builder();
470        for (Map.Entry<K, ? extends ImmutableCollection<V>> entry
471            : map.entrySet()) {
472          builder.addCopies(entry.getKey(), entry.getValue().size());
473        }
474        return builder.build();
475      }
476    
477      private transient ImmutableCollection<V> values;
478    
479      /**
480       * Returns an immutable collection of the values in this multimap. Its
481       * iterator traverses the values for the first key, the values for the second
482       * key, and so on.
483       */
484      public ImmutableCollection<V> values() {
485        ImmutableCollection<V> result = values;
486        return (result == null) ? (values = new Values<V>(this)) : result;
487      }
488    
489      private static class Values<V> extends ImmutableCollection<V> {
490        final Multimap<?, V> multimap;
491    
492        Values(Multimap<?, V> multimap) {
493          this.multimap = multimap;
494        }
495    
496        @Override public UnmodifiableIterator<V> iterator() {
497          final Iterator<? extends Map.Entry<?, V>> entryIterator
498              = multimap.entries().iterator();
499          return new UnmodifiableIterator<V>() {
500            public boolean hasNext() {
501              return entryIterator.hasNext();
502            }
503            public V next() {
504              return entryIterator.next().getValue();
505            }
506          };
507        }
508    
509        public int size() {
510          return multimap.size();
511        }
512    
513        private static final long serialVersionUID = 0;
514      }
515    
516      private static final long serialVersionUID = 0;
517    }