AbstractListValuedMap.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4.multimap;

  18. import java.util.Collection;
  19. import java.util.Collections;
  20. import java.util.List;
  21. import java.util.ListIterator;
  22. import java.util.Map;

  23. import org.apache.commons.collections4.ListUtils;
  24. import org.apache.commons.collections4.ListValuedMap;

  25. /**
  26.  * Abstract implementation of the {@link ListValuedMap} interface to simplify
  27.  * the creation of subclass implementations.
  28.  * <p>
  29.  * Subclasses specify a Map implementation to use as the internal storage and
  30.  * the List implementation to use as values.
  31.  * </p>
  32.  *
  33.  * @param <K> the type of the keys in this map
  34.  * @param <V> the type of the values in this map
  35.  * @since 4.1
  36.  */
  37. public abstract class AbstractListValuedMap<K, V> extends AbstractMultiValuedMap<K, V>
  38.         implements ListValuedMap<K, V> {

  39.     /** Values ListIterator */
  40.     private final class ValuesListIterator implements ListIterator<V> {

  41.         private final K key;
  42.         private List<V> values;
  43.         private ListIterator<V> iterator;

  44.         ValuesListIterator(final K key) {
  45.             this.key = key;
  46.             this.values = ListUtils.emptyIfNull(getMap().get(key));
  47.             this.iterator = values.listIterator();
  48.         }

  49.         ValuesListIterator(final K key, final int index) {
  50.             this.key = key;
  51.             this.values = ListUtils.emptyIfNull(getMap().get(key));
  52.             this.iterator = values.listIterator(index);
  53.         }

  54.         @Override
  55.         public void add(final V value) {
  56.             if (getMap().get(key) == null) {
  57.                 final List<V> list = createCollection();
  58.                 getMap().put(key, list);
  59.                 values = list;
  60.                 iterator = list.listIterator();
  61.             }
  62.             iterator.add(value);
  63.         }

  64.         @Override
  65.         public boolean hasNext() {
  66.             return iterator.hasNext();
  67.         }

  68.         @Override
  69.         public boolean hasPrevious() {
  70.             return iterator.hasPrevious();
  71.         }

  72.         @Override
  73.         public V next() {
  74.             return iterator.next();
  75.         }

  76.         @Override
  77.         public int nextIndex() {
  78.             return iterator.nextIndex();
  79.         }

  80.         @Override
  81.         public V previous() {
  82.             return iterator.previous();
  83.         }

  84.         @Override
  85.         public int previousIndex() {
  86.             return iterator.previousIndex();
  87.         }

  88.         @Override
  89.         public void remove() {
  90.             iterator.remove();
  91.             if (values.isEmpty()) {
  92.                 getMap().remove(key);
  93.             }
  94.         }

  95.         @Override
  96.         public void set(final V value) {
  97.             iterator.set(value);
  98.         }

  99.     }

  100.     /**
  101.      * Wrapped list to handle add and remove on the list returned by get(object)
  102.      */
  103.     private final class WrappedList extends WrappedCollection implements List<V> {

  104.         WrappedList(final K key) {
  105.             super(key);
  106.         }

  107.         @Override
  108.         public void add(final int index, final V value) {
  109.             List<V> list = getMapping();
  110.             if (list == null) {
  111.                 list = createCollection();
  112.                 getMap().put(key, list);
  113.             }
  114.             list.add(index, value);
  115.         }

  116.         @Override
  117.         public boolean addAll(final int index, final Collection<? extends V> c) {
  118.             List<V> list = getMapping();
  119.             if (list == null) {
  120.                 list = createCollection();
  121.                 final boolean changed = list.addAll(index, c);
  122.                 if (changed) {
  123.                     getMap().put(key, list);
  124.                 }
  125.                 return changed;
  126.             }
  127.             return list.addAll(index, c);
  128.         }

  129.         @Override
  130.         public boolean equals(final Object other) {
  131.             final List<V> list = getMapping();
  132.             if (list == null) {
  133.                 return Collections.emptyList().equals(other);
  134.             }
  135.             if (!(other instanceof List)) {
  136.                 return false;
  137.             }
  138.             final List<?> otherList = (List<?>) other;
  139.             return ListUtils.isEqualList(list, otherList);
  140.         }

  141.         @Override
  142.         public V get(final int index) {
  143.             final List<V> list = ListUtils.emptyIfNull(getMapping());
  144.             return list.get(index);
  145.         }

  146.         @Override
  147.         protected List<V> getMapping() {
  148.             return getMap().get(key);
  149.         }

  150.         @Override
  151.         public int hashCode() {
  152.             final List<V> list = getMapping();
  153.             return ListUtils.hashCodeForList(list);
  154.         }

  155.         @Override
  156.         public int indexOf(final Object o) {
  157.             final List<V> list = ListUtils.emptyIfNull(getMapping());
  158.             return list.indexOf(o);
  159.         }

  160.         @Override
  161.         public int lastIndexOf(final Object o) {
  162.             final List<V> list = ListUtils.emptyIfNull(getMapping());
  163.             return list.lastIndexOf(o);
  164.         }

  165.         @Override
  166.         public ListIterator<V> listIterator() {
  167.             return new ValuesListIterator(key);
  168.         }

  169.         @Override
  170.         public ListIterator<V> listIterator(final int index) {
  171.             return new ValuesListIterator(key, index);
  172.         }

  173.         @Override
  174.         public V remove(final int index) {
  175.             final List<V> list = ListUtils.emptyIfNull(getMapping());
  176.             final V value = list.remove(index);
  177.             if (list.isEmpty()) {
  178.                 AbstractListValuedMap.this.remove(key);
  179.             }
  180.             return value;
  181.         }

  182.         @Override
  183.         public V set(final int index, final V value) {
  184.             final List<V> list = ListUtils.emptyIfNull(getMapping());
  185.             return list.set(index, value);
  186.         }

  187.         @Override
  188.         public List<V> subList(final int fromIndex, final int toIndex) {
  189.             final List<V> list = ListUtils.emptyIfNull(getMapping());
  190.             return list.subList(fromIndex, toIndex);
  191.         }

  192.     }

  193.     /**
  194.      * Constructor needed for subclass serialization.
  195.      */
  196.     protected AbstractListValuedMap() {
  197.     }

  198.     /**
  199.      * A constructor that wraps, not copies
  200.      *
  201.      * @param map  the map to wrap, must not be null
  202.      * @throws NullPointerException if the map is null
  203.      */
  204.     protected AbstractListValuedMap(final Map<K, ? extends List<V>> map) {
  205.         super(map);
  206.     }

  207.     /**
  208.      * Creates a new value collection using the provided factory.
  209.      * @return a new list
  210.      */
  211.     @Override
  212.     protected abstract List<V> createCollection();

  213.     /**
  214.      * Gets the list of values associated with the specified key. This would
  215.      * return an empty list in case the mapping is not present
  216.      *
  217.      * @param key  the key to retrieve
  218.      * @return the {@code List} of values, will return an empty {@link List} for no mapping
  219.      */
  220.     @Override
  221.     public List<V> get(final K key) {
  222.         return wrappedCollection(key);
  223.     }

  224.     @Override
  225.     @SuppressWarnings("unchecked")
  226.     protected Map<K, List<V>> getMap() {
  227.         return (Map<K, List<V>>) super.getMap();
  228.     }

  229.     /**
  230.      * Removes all values associated with the specified key.
  231.      * <p>
  232.      * A subsequent {@code get(Object)} would return an empty list.
  233.      * </p>
  234.      *
  235.      * @param key  the key to remove values from
  236.      * @return the {@code List} of values removed, will return an empty,
  237.      *   unmodifiable list for no mapping found.
  238.      */
  239.     @Override
  240.     public List<V> remove(final Object key) {
  241.         return ListUtils.emptyIfNull(getMap().remove(key));
  242.     }

  243.     @Override
  244.     List<V> wrappedCollection(final K key) {
  245.         return new WrappedList(key);
  246.     }

  247. }