001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.multimap; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.List; 022import java.util.ListIterator; 023import java.util.Map; 024 025import org.apache.commons.collections4.ListUtils; 026import org.apache.commons.collections4.ListValuedMap; 027 028/** 029 * Abstract implementation of the {@link ListValuedMap} interface to simplify 030 * the creation of subclass implementations. 031 * <p> 032 * Subclasses specify a Map implementation to use as the internal storage and 033 * the List implementation to use as values. 034 * 035 * @param <K> the type of the keys in this map 036 * @param <V> the type of the values in this map 037 * @since 4.1 038 */ 039public abstract class AbstractListValuedMap<K, V> extends AbstractMultiValuedMap<K, V> 040 implements ListValuedMap<K, V> { 041 042 /** 043 * Constructor needed for subclass serialisation. 044 */ 045 protected AbstractListValuedMap() { 046 super(); 047 } 048 049 /** 050 * A constructor that wraps, not copies 051 * 052 * @param map the map to wrap, must not be null 053 * @throws NullPointerException if the map is null 054 */ 055 protected AbstractListValuedMap(final Map<K, ? extends List<V>> map) { 056 super(map); 057 } 058 059 // ----------------------------------------------------------------------- 060 @Override 061 @SuppressWarnings("unchecked") 062 protected Map<K, List<V>> getMap() { 063 return (Map<K, List<V>>) super.getMap(); 064 } 065 066 /** 067 * Creates a new value collection using the provided factory. 068 * @return a new list 069 */ 070 @Override 071 protected abstract List<V> createCollection(); 072 073 // ----------------------------------------------------------------------- 074 /** 075 * Gets the list of values associated with the specified key. This would 076 * return an empty list in case the mapping is not present 077 * 078 * @param key the key to retrieve 079 * @return the {@code List} of values, will return an empty {@link List} for no mapping 080 */ 081 @Override 082 public List<V> get(final K key) { 083 return wrappedCollection(key); 084 } 085 086 @Override 087 List<V> wrappedCollection(final K key) { 088 return new WrappedList(key); 089 } 090 091 /** 092 * Removes all values associated with the specified key. 093 * <p> 094 * A subsequent <code>get(Object)</code> would return an empty list. 095 * 096 * @param key the key to remove values from 097 * @return the <code>List</code> of values removed, will return an empty, 098 * unmodifiable list for no mapping found. 099 */ 100 @Override 101 public List<V> remove(final Object key) { 102 return ListUtils.emptyIfNull(getMap().remove(key)); 103 } 104 105 // ----------------------------------------------------------------------- 106 /** 107 * Wrapped list to handle add and remove on the list returned by get(object) 108 */ 109 private class WrappedList extends WrappedCollection implements List<V> { 110 111 public WrappedList(final K key) { 112 super(key); 113 } 114 115 @Override 116 protected List<V> getMapping() { 117 return getMap().get(key); 118 } 119 120 @Override 121 public void add(final int index, final V value) { 122 List<V> list = getMapping(); 123 if (list == null) { 124 list = createCollection(); 125 getMap().put(key, list); 126 } 127 list.add(index, value); 128 } 129 130 @Override 131 public boolean addAll(final int index, final Collection<? extends V> c) { 132 List<V> list = getMapping(); 133 if (list == null) { 134 list = createCollection(); 135 final boolean changed = list.addAll(index, c); 136 if (changed) { 137 getMap().put(key, list); 138 } 139 return changed; 140 } 141 return list.addAll(index, c); 142 } 143 144 @Override 145 public V get(final int index) { 146 final List<V> list = ListUtils.emptyIfNull(getMapping()); 147 return list.get(index); 148 } 149 150 @Override 151 public int indexOf(final Object o) { 152 final List<V> list = ListUtils.emptyIfNull(getMapping()); 153 return list.indexOf(o); 154 } 155 156 @Override 157 public int lastIndexOf(final Object o) { 158 final List<V> list = ListUtils.emptyIfNull(getMapping()); 159 return list.lastIndexOf(o); 160 } 161 162 @Override 163 public ListIterator<V> listIterator() { 164 return new ValuesListIterator(key); 165 } 166 167 @Override 168 public ListIterator<V> listIterator(final int index) { 169 return new ValuesListIterator(key, index); 170 } 171 172 @Override 173 public V remove(final int index) { 174 final List<V> list = ListUtils.emptyIfNull(getMapping()); 175 final V value = list.remove(index); 176 if (list.isEmpty()) { 177 AbstractListValuedMap.this.remove(key); 178 } 179 return value; 180 } 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 188 @Override 189 public List<V> subList(final int fromIndex, final int toIndex) { 190 final List<V> list = ListUtils.emptyIfNull(getMapping()); 191 return list.subList(fromIndex, toIndex); 192 } 193 194 @Override 195 public boolean equals(final Object other) { 196 final List<V> list = getMapping(); 197 if (list == null) { 198 return Collections.emptyList().equals(other); 199 } 200 if (!(other instanceof List)) { 201 return false; 202 } 203 final List<?> otherList = (List<?>) other; 204 return ListUtils.isEqualList(list, otherList); 205 } 206 207 @Override 208 public int hashCode() { 209 final List<V> list = getMapping(); 210 return ListUtils.hashCodeForList(list); 211 } 212 213 } 214 215 /** Values ListIterator */ 216 private class ValuesListIterator implements ListIterator<V> { 217 218 private final K key; 219 private List<V> values; 220 private ListIterator<V> iterator; 221 222 public ValuesListIterator(final K key) { 223 this.key = key; 224 this.values = ListUtils.emptyIfNull(getMap().get(key)); 225 this.iterator = values.listIterator(); 226 } 227 228 public ValuesListIterator(final K key, final int index) { 229 this.key = key; 230 this.values = ListUtils.emptyIfNull(getMap().get(key)); 231 this.iterator = values.listIterator(index); 232 } 233 234 @Override 235 public void add(final V value) { 236 if (getMap().get(key) == null) { 237 final List<V> list = createCollection(); 238 getMap().put(key, list); 239 this.values = list; 240 this.iterator = list.listIterator(); 241 } 242 this.iterator.add(value); 243 } 244 245 @Override 246 public boolean hasNext() { 247 return iterator.hasNext(); 248 } 249 250 @Override 251 public boolean hasPrevious() { 252 return iterator.hasPrevious(); 253 } 254 255 @Override 256 public V next() { 257 return iterator.next(); 258 } 259 260 @Override 261 public int nextIndex() { 262 return iterator.nextIndex(); 263 } 264 265 @Override 266 public V previous() { 267 return iterator.previous(); 268 } 269 270 @Override 271 public int previousIndex() { 272 return iterator.previousIndex(); 273 } 274 275 @Override 276 public void remove() { 277 iterator.remove(); 278 if (values.isEmpty()) { 279 getMap().remove(key); 280 } 281 } 282 283 @Override 284 public void set(final V value) { 285 iterator.set(value); 286 } 287 288 } 289 290}