You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tn...@apache.org on 2014/03/25 23:01:08 UTC
svn commit: r1581553 [1/2] - in /commons/proper/collections/trunk/src:
main/java/org/apache/commons/collections4/
main/java/org/apache/commons/collections4/multimap/
test/java/org/apache/commons/collections4/multimap/ test/resources/data/test/
Author: tn
Date: Tue Mar 25 22:01:07 2014
New Revision: 1581553
URL: http://svn.apache.org/r1581553
Log:
[COLLECTIONS-508] Initial commit of new MultiValuedMap interface + implementations. Thanks to Dipanjan Laha.
Added:
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java (with props)
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java (with props)
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java (with props)
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java (with props)
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java (with props)
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java (with props)
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java (with props)
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java (with props)
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java (with props)
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java (with props)
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java (with props)
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java (with props)
commons/proper/collections/trunk/src/test/resources/data/test/MultiValuedHashMap.emptyCollection.version4.1.obj (with props)
commons/proper/collections/trunk/src/test/resources/data/test/MultiValuedHashMap.fullCollection.version4.1.obj (with props)
commons/proper/collections/trunk/src/test/resources/data/test/TransformedMultiValuedMap.emptyCollection.version4.1.obj (with props)
commons/proper/collections/trunk/src/test/resources/data/test/TransformedMultiValuedMap.fullCollection.version4.1.obj (with props)
commons/proper/collections/trunk/src/test/resources/data/test/UnmodifiableMultiValuedMap.emptyCollection.version4.1.obj (with props)
commons/proper/collections/trunk/src/test/resources/data/test/UnmodifiableMultiValuedMap.fullCollection.version4.1.obj (with props)
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4;
+
+import java.util.List;
+
+/**
+ * Defines a map that holds a list of values against each key.
+ * <p>
+ * A <code>ListValuedMap</code> is a Map with slightly different semantics:
+ * <ul>
+ * <li>Putting a value into the map will add the value to a Collection at that key.</li>
+ * <li>Getting a value will return a Collection, holding all the values put to that key.</li>
+ * </ul>
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public interface ListValuedMap<K, V> extends MultiValuedMap<K, V> {
+
+ /**
+ * Gets the list of values associated with the specified key.
+ * <p>
+ * Implementations typically return <code>null</code> if no values have been
+ * mapped to the key, however the implementation may choose to return an
+ * empty collection.
+ * <p>
+ * Implementations may choose to return a clone of the internal collection.
+ *
+ * @param key the key to retrieve
+ * @return the <code>Collection</code> of values, implementations should
+ * return <code>null</code> for no mapping, but may return an empty collection
+ * @throws ClassCastException if the key is of an invalid type
+ * @throws NullPointerException if the key is null and null keys are invalid
+ */
+ List<V> get(Object key);
+
+ /**
+ * Removes all values associated with the specified key.
+ * <p>
+ * Implementations typically return <code>null</code> from a subsequent
+ * <code>get(Object)</code>, however they may choose to return an empty
+ * collection.
+ *
+ * @param key the key to remove values from
+ * @return the <code>Collection</code> of values removed, implementations
+ * should return <code>null</code> for no mapping found, but may
+ * return an empty collection
+ * @throws UnsupportedOperationException if the map is unmodifiable
+ * @throws ClassCastException if the key is of an invalid type
+ * @throws NullPointerException if the key is null and null keys are invalid
+ */
+ List<V> remove(Object key);
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/ListValuedMap.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Defines a map that holds a collection of values against each key.
+ * <p>
+ * A <code>MultiValuedMap</code> is a Map with slightly different semantics:
+ * <ul>
+ * <li>Putting a value into the map will add the value to a Collection at that key.</li>
+ * <li>Getting a value will return a Collection, holding all the values put to that key.</li>
+ * </ul>
+ * <p>
+ * For example:
+ * <pre>
+ * MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
+ * map.put(key, "A");
+ * map.put(key, "B");
+ * map.put(key, "C");
+ * Collection<String> coll = map.get(key);
+ * </pre>
+ * <p>
+ * <code>coll</code> will be a collection containing "A", "B", "C".
+ * <p>
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public interface MultiValuedMap<K, V> {
+ // Query operations
+
+ /**
+ * Gets the total size of the map.
+ * <p>
+ * Implementations would return the total size of the map which is the count
+ * of the values from all keys.
+ *
+ * @return the total size of the map
+ */
+ int size();
+
+ /**
+ * Returns <tt>true</tt> if this map contains no key-value mappings.
+ *
+ * @return <tt>true</tt> if this map contains no key-value mappings
+ */
+ boolean isEmpty();
+
+ /**
+ * Returns <tt>true</tt> if this map contains a mapping for the specified
+ * key. More formally, returns <tt>true</tt> if and only if this map
+ * contains a mapping for a key <tt>k</tt> such that
+ * <tt>(key==null ? k==null : key.equals(k))</tt>. (There can be at most one
+ * such mapping.)
+ *
+ * @param key key whose presence in this map is to be tested
+ * @return <tt>true</tt> if this map contains a mapping for the specified key
+ * @throws ClassCastException if the key is of an inappropriate type for this map (optional)
+ * @throws NullPointerException if the specified key is null and this map
+ * does not permit null keys (optional)
+ */
+ boolean containsKey(Object key);
+
+ /**
+ * Checks whether the map contains at least one mapping for the specified value.
+ *
+ * @param value the value to search for
+ * @return true if the map contains the value
+ * @throws ClassCastException if the value is of an invalid type
+ * @throws NullPointerException if the value is null and null value are invalid
+ */
+ boolean containsValue(Object value);
+
+ /**
+ * Checks whether the map contains a mapping for the specified key and value.
+ *
+ * @param key the key to search for
+ * @param value the value to search for
+ * @return true if the map contains the value
+ */
+ boolean containsMapping(Object key, Object value);
+
+ /**
+ * Gets the collection of values associated with the specified key.
+ * <p>
+ * Implementations are free to declare that they return
+ * <code>Collection</code> subclasses such as <code>List</code> or
+ * <code>Set</code>.
+ * <p>
+ * Implementations typically return <code>null</code> if no values have been
+ * mapped to the key, however the implementation may choose to return an
+ * empty collection.
+ * <p>
+ * Implementations may choose to return a clone of the internal collection.
+ *
+ * @param key the key to retrieve
+ * @return the <code>Collection</code> of values, implementations should
+ * return <code>null</code> for no mapping, but may return an empty collection
+ * @throws ClassCastException if the key is of an invalid type
+ * @throws NullPointerException if the key is null and null keys are invalid
+ */
+ Collection<V> get(Object key);
+
+ // Modification operations
+
+ /**
+ * Adds the value to the collection associated with the specified key.
+ * <p>
+ * Unlike a normal <code>Map</code> the previous value is not replaced.
+ * Instead the new value is added to the collection stored against the key.
+ * The collection may be a <code>List</code>, <code>Set</code> or other
+ * collection dependent on implementation.
+ *
+ * @param key the key to store against
+ * @param value the value to add to the collection at the key
+ * @return typically the value added if the map changed and null if the map
+ * did not change
+ * @throws UnsupportedOperationException if the map is unmodifiable
+ * @throws ClassCastException if the key or value is of an invalid type
+ * @throws NullPointerException if the key or value is null and null is invalid
+ * @throws IllegalArgumentException if the key or value is invalid
+ */
+ V put(K key, V value);
+
+ /**
+ * Adds Iterable values to the collection associated with the specified key.
+ *
+ * @param key the key to store against
+ * @param values the values to add to the collection at the key, null ignored
+ * @return true if this map changed
+ */
+ boolean putAll(K key, Iterable<? extends V> values);
+
+ /**
+ * Copies all of the mappings from the specified map to this map (optional
+ * operation). The effect of this call is equivalent to that of calling
+ * {@link #put(Object,Object) put(k, v)} on this map once for each mapping
+ * from key <tt>k</tt> to value <tt>v</tt> in the specified map. The
+ * behavior of this operation is undefined if the specified map is modified
+ * while the operation is in progress.
+ *
+ * @param m mappings to be stored in this map
+ * @throws UnsupportedOperationException if the <tt>putAll</tt> operation is
+ * not supported by this map
+ * @throws ClassCastException if the class of a key or value in the
+ * specified map prevents it from being stored in this map
+ * @throws NullPointerException if the specified map is null, or if this map
+ * does not permit null keys or values, and the specified map
+ * contains null keys or values
+ * @throws IllegalArgumentException if some property of a key or value in
+ * the specified map prevents it from being stored in this map
+ */
+ void putAll(Map<? extends K, ? extends V> m);
+
+ /**
+ * Copies all of the mappings from the specified MultiValuedMap to this map
+ * (optional operation). The effect of this call is equivalent to that of
+ * calling {@link #put(Object,Object) put(k, v)} on this map once for each
+ * mapping from key <tt>k</tt> to value <tt>v</tt> in the specified map. The
+ * behavior of this operation is undefined if the specified map is modified
+ * while the operation is in progress.
+ *
+ * @param m mappings to be stored in this map
+ * @throws UnsupportedOperationException if the <tt>putAll</tt> operation is
+ * not supported by this map
+ * @throws ClassCastException if the class of a key or value in the
+ * specified map prevents it from being stored in this map
+ * @throws NullPointerException if the specified map is null, or if this map
+ * does not permit null keys or values, and the specified map
+ * contains null keys or values
+ * @throws IllegalArgumentException if some property of a key or value in
+ * the specified map prevents it from being stored in this map
+ */
+ void putAll(MultiValuedMap<? extends K, ? extends V> m);
+
+ /**
+ * Removes all values associated with the specified key.
+ * <p>
+ * Implementations typically return <code>null</code> from a subsequent
+ * <code>get(Object)</code>, however they may choose to return an empty
+ * collection.
+ *
+ * @param key the key to remove values from
+ * @return the <code>Collection</code> of values removed, implementations
+ * should return <code>null</code> for no mapping found, but may
+ * return an empty collection
+ * @throws UnsupportedOperationException if the map is unmodifiable
+ * @throws ClassCastException if the key is of an invalid type
+ * @throws NullPointerException if the key is null and null keys are invalid
+ */
+ Collection<V> remove(Object key);
+
+ /**
+ * Removes a key-value mapping from the map.
+ * <p>
+ * The item is removed from the collection mapped to the specified key.
+ * Other values attached to that key are unaffected.
+ * <p>
+ * If the last value for a key is removed, implementations typically return
+ * <code>null</code> from a subsequent <code>get(Object)</code>, however
+ * they may choose to return an empty collection.
+ *
+ * @param key the key to remove from
+ * @param item the item to remove
+ * @return {@code true} if the mapping was removed, {@code false} otherwise
+ * @throws UnsupportedOperationException if the map is unmodifiable
+ * @throws ClassCastException if the key or value is of an invalid type
+ * @throws NullPointerException if the key or value is null and null is
+ * invalid
+ */
+ boolean removeMapping(K key, V item);
+
+ /**
+ * Removes all of the mappings from this map (optional operation).
+ * The map will be empty after this call returns.
+ *
+ * @throws UnsupportedOperationException if the map is unmodifiable
+ */
+ void clear();
+
+ // Views
+
+ /**
+ * Returns a {@link Collection} view of the mappings contained in this map.
+ * The collection is backed by the map, so changes to the map are reflected
+ * in this, and vice-versa.
+ *
+ * @return a set view of the mappings contained in this map
+ */
+ Collection<Entry<K, V>> entries();
+
+ /**
+ * Returns a {@link Bag} view of the key mapping contained in this map.
+ * <p>
+ * Implementations typically return a Bag of keys with its values count as
+ * the count of the Bag. This bag is backed by the map, so any changes in
+ * the map is reflected here.
+ *
+ * @return a bag view of the key mapping contained in this map
+ */
+ Bag<K> keys();
+
+ /**
+ * Returns a {@link Set} view of the keys contained in this map. The set is
+ * backed by the map, so changes to the map are reflected in the set, and
+ * vice-versa. If the map is modified while an iteration over the set is in
+ * progress (except through the iterator's own <tt>remove</tt> operation),
+ * the results of the iteration are undefined. The set supports element
+ * removal, which removes the corresponding mapping from the map, via the
+ * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, <tt>removeAll</tt>,
+ * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not support
+ * the <tt>add</tt> or <tt>addAll</tt> operations.
+ *
+ * @return a set view of the keys contained in this map
+ */
+ Set<K> keySet();
+
+ /**
+ * Gets a collection containing all the values in the map.
+ * <p>
+ * Implementations typically return a collection containing the combination
+ * of values from all keys.
+ *
+ * @return a collection view of the values contained in this map
+ */
+ Collection<V> values();
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,694 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4.multimap;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.AbstractCollection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.Factory;
+import org.apache.commons.collections4.MultiValuedMap;
+import org.apache.commons.collections4.Transformer;
+import org.apache.commons.collections4.bag.HashBag;
+import org.apache.commons.collections4.functors.InstantiateFactory;
+import org.apache.commons.collections4.iterators.EmptyIterator;
+import org.apache.commons.collections4.iterators.IteratorChain;
+import org.apache.commons.collections4.iterators.LazyIteratorChain;
+import org.apache.commons.collections4.iterators.TransformIterator;
+
+/**
+ * Abstract implementation of the {@link MultiValuedMap} interface to simplify
+ * the creation of subclass implementations.
+ * <p>
+ * Subclasses specify a Map implementation to use as the internal storage.
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Serializable {
+
+ /** Serialization Version */
+ private static final long serialVersionUID = 7994988366330224277L;
+
+ /** The factory for creating value collections. */
+ private final Factory<? extends Collection<V>> collectionFactory;
+
+ /** The values view */
+ private transient Collection<V> valuesView;
+
+ /** The EntryValues view */
+ private transient EntryValues entryValuesView;
+
+ /** The KeyBag view */
+ private transient KeysBag keysBagView;
+
+ /** The map used to store the data */
+ private final Map<K, Collection<V>> map;
+
+ /**
+ * Constructor that wraps (not copies).
+ *
+ * @param <C> the collection type
+ * @param map the map to wrap, must not be null
+ * @param collectionClazz the collection class
+ * @throws IllegalArgumentException if the map is null
+ */
+ @SuppressWarnings("unchecked")
+ protected <C extends Collection<V>> AbstractMultiValuedMap(final Map<K, ? super C> map,
+ final Class<C> collectionClazz) {
+ if (map == null) {
+ throw new IllegalArgumentException("Map must not be null");
+ }
+ this.map = (Map<K, Collection<V>>) map;
+ this.collectionFactory = new InstantiateFactory<C>(collectionClazz);
+ }
+
+ /**
+ * Gets the map being wrapped.
+ *
+ * @return the wrapped map
+ */
+ protected Map<K, Collection<V>> getMap() {
+ return map;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean containsKey(Object key) {
+ return getMap().containsKey(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean containsValue(final Object value) {
+ final Set<Map.Entry<K, Collection<V>>> pairs = getMap().entrySet();
+ if (pairs != null) {
+ for (final Map.Entry<K, Collection<V>> entry : pairs) {
+ if (entry.getValue().contains(value)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean containsMapping(Object key, Object value) {
+ final Collection<V> col = get(key);
+ if (col == null) {
+ return false;
+ }
+ return col.contains(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<Entry<K, V>> entries() {
+ return entryValuesView != null ? entryValuesView : (entryValuesView = new EntryValues());
+ }
+
+ /**
+ * Gets the collection of values associated with the specified key.
+ *
+ * @param key the key to retrieve
+ * @return the <code>Collection</code> of values, will return
+ * <code>null</code> for no mapping
+ * @throws ClassCastException if the key is of an invalid type
+ */
+ public Collection<V> get(Object key) {
+ return getMap().get(key);
+ }
+
+ /**
+ * Removes all values associated with the specified key.
+ * <p>
+ * A subsequent <code>get(Object)</code> would return null collection.
+ *
+ * @param key the key to remove values from
+ * @return the <code>Collection</code> of values removed, will return
+ * <code>null</code> for no mapping found.
+ * @throws ClassCastException if the key is of an invalid type
+ */
+ public Collection<V> remove(Object key) {
+ return getMap().remove(key);
+ }
+
+ /**
+ * Removes a specific value from map.
+ * <p>
+ * The item is removed from the collection mapped to the specified key.
+ * Other values attached to that key are unaffected.
+ * <p>
+ * If the last value for a key is removed, <code>null</code> would be
+ * returned from a subsequent <code>get(Object)</code>.
+ *
+ * @param key the key to remove from
+ * @param item the item to remove
+ * @return {@code true} if the mapping was removed, {@code false} otherwise
+ */
+ public boolean removeMapping(K key, V item) {
+ boolean result = false;
+ final Collection<V> col = get(key);
+ if (col == null) {
+ return false;
+ }
+ result = col.remove(item);
+ if (!result) {
+ return false;
+ }
+ if (col.isEmpty()) {
+ remove(key);
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return getMap().isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<K> keySet() {
+ return getMap().keySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size() {
+ int size = 0;
+ for (Collection<V> col : getMap().values()) {
+ size += col.size();
+ }
+ return size;
+ }
+
+ /**
+ * Gets a collection containing all the values in the map.
+ * <p>
+ * Returns a collection containing all the values from all keys.
+ *
+ * @return a collection view of the values contained in this map
+ */
+ public Collection<V> values() {
+ final Collection<V> vs = valuesView;
+ return vs != null ? vs : (valuesView = new Values());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clear() {
+ getMap().clear();
+ }
+
+ /**
+ * Adds the value to the collection associated with the specified key.
+ * <p>
+ * Unlike a normal <code>Map</code> the previous value is not replaced.
+ * Instead the new value is added to the collection stored against the key.
+ *
+ * @param key the key to store against
+ * @param value the value to add to the collection at the key
+ * @return the value added if the map changed and null if the map did not
+ * change
+ */
+ public V put(K key, V value) {
+ boolean result = false;
+ Collection<V> coll = get(key);
+ if (coll == null) {
+ coll = createCollection();
+ coll.add(value);
+ if (coll.size() > 0) {
+ // only add if non-zero size to maintain class state
+ getMap().put(key, coll);
+ result = true; // map definitely changed
+ }
+ } else {
+ result = coll.add(value);
+ }
+ return result ? value : null;
+ }
+
+ /**
+ * Copies all of the mappings from the specified map to this map. The effect
+ * of this call is equivalent to that of calling {@link #put(Object,Object)
+ * put(k, v)} on this map once for each mapping from key <tt>k</tt> to value
+ * <tt>v</tt> in the specified map. The behavior of this operation is
+ * undefined if the specified map is modified while the operation is in
+ * progress.
+ *
+ * @param map mappings to be stored in this map
+ */
+ public void putAll(final Map<? extends K, ? extends V> map) {
+ if (map != null) {
+ for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ put((K) entry.getKey(), (V) entry.getValue());
+ }
+ }
+ }
+
+ /**
+ * Copies all of the mappings from the specified MultiValuedMap to this map.
+ * The effect of this call is equivalent to that of calling
+ * {@link #put(Object,Object) put(k, v)} on this map once for each mapping
+ * from key <tt>k</tt> to value <tt>v</tt> in the specified map. The
+ * behavior of this operation is undefined if the specified map is modified
+ * while the operation is in progress.
+ *
+ * @param map mappings to be stored in this map
+ */
+ @SuppressWarnings("unchecked")
+ public void putAll(MultiValuedMap<? extends K, ? extends V> map) {
+ if (map != null) {
+ for (final K key : map.keySet()) {
+ putAll(key, (Collection<V>) map.get(key));
+ }
+ }
+ }
+
+ /**
+ * Returns a {@link Bag} view of the key mapping contained in this map.
+ * <p>
+ * Returns a Bag of keys with its values count as the count of the Bag. This
+ * bag is backed by the map, so any changes in the map is reflected here.
+ * Any method which modifies this bag like <tt>add</tt>, <tt>remove</tt>,
+ * <tt>Iterator.remove</tt> etc throws
+ * <code>UnsupportedOperationException</code>
+ *
+ * @return a bag view of the key mapping contained in this map
+ */
+ public Bag<K> keys() {
+ return keysBagView != null ? keysBagView : (keysBagView = new KeysBag());
+ }
+
+ /**
+ * Adds Iterable values to the collection associated with the specified key.
+ *
+ * @param key the key to store against
+ * @param values the values to add to the collection at the key, null
+ * ignored
+ * @return true if this map changed
+ */
+ public boolean putAll(final K key, final Iterable<? extends V> values) {
+ if (values == null || values.iterator() == null || !values.iterator().hasNext()) {
+ return false;
+ }
+ Iterator<? extends V> it = values.iterator();
+ boolean result = false;
+ Collection<V> coll = get(key);
+ if (coll == null) {
+ coll = createCollection(); // might produce a non-empty collection
+ while (it.hasNext()) {
+ coll.add(it.next());
+ }
+ if (coll.size() > 0) {
+ // only add if non-zero size to maintain class state
+ getMap().put(key, coll);
+ result = true; // map definitely changed
+ }
+ } else {
+ while (it.hasNext()) {
+ boolean tmpResult = coll.add(it.next());
+ if (!result && tmpResult) {
+ // If any one of the values have been added, the map has
+ // changed
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets an iterator for the collection mapped to the specified key.
+ *
+ * @param key the key to get an iterator for
+ * @return the iterator of the collection at the key, empty iterator if key
+ * not in map
+ */
+ public Iterator<V> iterator(final Object key) {
+ if (!containsKey(key)) {
+ return EmptyIterator.<V> emptyIterator();
+ }
+ return new ValuesIterator(key);
+ }
+
+ /**
+ * Gets the size of the collection mapped to the specified key.
+ *
+ * @param key the key to get size for
+ * @return the size of the collection at the key, zero if key not in map
+ */
+ public int size(final Object key) {
+ final Collection<V> coll = get(key);
+ if (coll == null) {
+ return 0;
+ }
+ return coll.size();
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof MultiValuedMap == false) {
+ return false;
+ }
+ MultiValuedMap<?, ?> other = (MultiValuedMap<?, ?>) obj;
+ if (other.size() != size()) {
+ return false;
+ }
+ Iterator it = keySet().iterator();
+ while (it.hasNext()) {
+ Object key = it.next();
+ Collection<?> col = get(key);
+ Collection<?> otherCol = other.get(key);
+ if (otherCol == null) {
+ return false;
+ }
+ if (col.size() != otherCol.size()) {
+ return false;
+ }
+ for (Object value : col) {
+ if (!otherCol.contains(value)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return getMap().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getMap().toString();
+ }
+
+ // -----------------------------------------------------------------------
+
+ protected Collection<V> createCollection() {
+ return collectionFactory.create();
+ }
+
+ // -----------------------------------------------------------------------
+
+ /**
+ * Inner class that provides a Bag<K> keys view
+ */
+ private class KeysBag implements Bag<K> {
+
+ public boolean addAll(Collection<? extends K> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean contains(Object o) {
+ return getMap().containsKey(o);
+ }
+
+ public boolean isEmpty() {
+ return getMap().isEmpty();
+ }
+
+ public Object[] toArray() {
+ final Object[] result = new Object[size()];
+ int i = 0;
+ final Iterator<K> it = getMap().keySet().iterator();
+ while (it.hasNext()) {
+ final K current = it.next();
+ for (int index = getCount(current); index > 0; index--) {
+ result[i++] = current;
+ }
+ }
+ return result;
+ }
+
+ public <T> T[] toArray(T[] array) {
+ final int size = size();
+ if (array.length < size) {
+ @SuppressWarnings("unchecked")
+ // safe as both are of type T
+ final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
+ array = unchecked;
+ }
+
+ int i = 0;
+ final Iterator<K> it = getMap().keySet().iterator();
+ while (it.hasNext()) {
+ final K current = it.next();
+ for (int index = getCount(current); index > 0; index--) {
+ // unsafe, will throw ArrayStoreException if types are not
+ // compatible, see javadoc
+ @SuppressWarnings("unchecked")
+ final T unchecked = (T) current;
+ array[i++] = unchecked;
+ }
+ }
+ while (i < array.length) {
+ array[i++] = null;
+ }
+ return array;
+ }
+
+ public int getCount(Object object) {
+ int count = 0;
+ Collection<V> col = AbstractMultiValuedMap.this.getMap().get(object);
+ if (col != null) {
+ count = col.size();
+ }
+ return count;
+ }
+
+ public boolean add(K object) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean add(K object, int nCopies) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean remove(Object object) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean remove(Object object, int nCopies) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Set<K> uniqueSet() {
+ return keySet();
+ }
+
+ public int size() {
+ return AbstractMultiValuedMap.this.size();
+ }
+
+ public boolean containsAll(Collection<?> coll) {
+ if (coll instanceof Bag) {
+ return containsAll((Bag<?>) coll);
+ }
+ return containsAll(new HashBag<Object>(coll));
+ }
+
+ private boolean containsAll(final Bag<?> other) {
+ final Iterator<?> it = other.uniqueSet().iterator();
+ while (it.hasNext()) {
+ final Object current = it.next();
+ if (getCount(current) < other.getCount(current)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean removeAll(Collection<?> coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean retainAll(Collection<?> coll) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Iterator<K> iterator() {
+ return new LazyIteratorChain<K>() {
+
+ final Iterator<K> keyIterator = getMap().keySet().iterator();
+
+ @Override
+ protected Iterator<? extends K> nextIterator(int count) {
+ if (!keyIterator.hasNext()) {
+ return null;
+ }
+ final K key = keyIterator.next();
+ final Iterator<V> colIterator = getMap().get(key).iterator();
+ Iterator<K> nextIt = new Iterator<K>() {
+
+ public boolean hasNext() {
+ return colIterator.hasNext();
+ }
+
+ public K next() {
+ colIterator.next();// Increment the iterator
+ // The earlier statement would throw
+ // NoSuchElementException anyway in case it ends
+ return key;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return nextIt;
+ }
+ };
+ }
+
+ }
+
+ /**
+ * Inner class that provides the Entry<K, V> view
+ */
+ private class EntryValues extends AbstractCollection<Entry<K, V>> {
+
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ return new LazyIteratorChain<Entry<K, V>>() {
+
+ final Collection<K> keysCol = new ArrayList<K>(getMap().keySet());
+ final Iterator<K> keyIterator = keysCol.iterator();
+
+ @Override
+ protected Iterator<? extends Entry<K, V>> nextIterator(int count) {
+ if (!keyIterator.hasNext()) {
+ return null;
+ }
+ final K key = keyIterator.next();
+ final Transformer<V, Entry<K, V>> entryTransformer = new Transformer<V, Entry<K, V>>() {
+
+ public Entry<K, V> transform(final V input) {
+ return new Entry<K, V>() {
+
+ public K getKey() {
+ return key;
+ }
+
+ public V getValue() {
+ return input;
+ }
+
+ public V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ return new TransformIterator<V, Entry<K, V>>(new ValuesIterator(key), entryTransformer);
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return AbstractMultiValuedMap.this.size();
+ }
+
+ }
+
+ /**
+ * Inner class that provides the values view.
+ */
+ private class Values extends AbstractCollection<V> {
+ @Override
+ public Iterator<V> iterator() {
+ final IteratorChain<V> chain = new IteratorChain<V>();
+ for (final K k : keySet()) {
+ chain.addIterator(new ValuesIterator(k));
+ }
+ return chain;
+ }
+
+ @Override
+ public int size() {
+ return AbstractMultiValuedMap.this.size();
+ }
+
+ @Override
+ public void clear() {
+ AbstractMultiValuedMap.this.clear();
+ }
+ }
+
+ /**
+ * Inner class that provides the values iterator.
+ */
+ private class ValuesIterator implements Iterator<V> {
+ private final Object key;
+ private final Collection<V> values;
+ private final Iterator<V> iterator;
+
+ public ValuesIterator(final Object key) {
+ this.key = key;
+ this.values = get(key);
+ this.iterator = values.iterator();
+ }
+
+ public void remove() {
+ iterator.remove();
+ if (values.isEmpty()) {
+ AbstractMultiValuedMap.this.remove(key);
+ }
+ }
+
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ public V next() {
+ return iterator.next();
+ }
+ }
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4.multimap;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.MultiValuedMap;
+
+/**
+ * Decorates another <code>MultiValuedMap</code> to provide additional behaviour.
+ * <p>
+ * Each method call made on this <code>MultiValuedMap</code> is forwarded to the
+ * decorated <code>MultiValuedMap</code>. This class is used as a framework to
+ * build to extensions such as synchronized and unmodifiable behaviour.
+ *
+ * @param <K> the type of key elements
+ * @param <V> the type of value elements
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class AbstractMultiValuedMapDecorator<K, V>
+ implements MultiValuedMap<K, V>, Serializable {
+
+ /** Serialization version */
+ private static final long serialVersionUID = -9184930955231260637L;
+
+ /** MultiValuedMap to decorate */
+ private final MultiValuedMap<K, V> map;
+
+ /**
+ * Constructor that wraps (not copies).
+ *
+ * @param map the map to decorate, must not be null
+ * @throws IllegalArgumentException if the map is null
+ */
+ protected AbstractMultiValuedMapDecorator(final MultiValuedMap<K, V> map) {
+ if (map == null) {
+ throw new IllegalArgumentException("MultiValuedMap must not be null");
+ }
+ this.map = map;
+ }
+
+ protected MultiValuedMap<K, V> decorated() {
+ return map;
+ }
+
+ public int size() {
+ return decorated().size();
+ }
+
+ public boolean isEmpty() {
+ return decorated().isEmpty();
+ }
+
+ public boolean containsKey(Object key) {
+ return decorated().containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ return decorated().containsValue(value);
+ }
+
+ public boolean containsMapping(Object key, Object value) {
+ return decorated().containsMapping(key, value);
+ }
+
+ public Collection<V> get(Object key) {
+ return decorated().get(key);
+ }
+
+ public Collection<V> remove(Object key) {
+ return decorated().remove(key);
+ }
+
+ public boolean removeMapping(K key, V item) {
+ return decorated().removeMapping(key, item);
+ }
+
+ public void clear() {
+ decorated().clear();
+ }
+
+ public V put(K key, V value) {
+ return decorated().put(key, value);
+ }
+
+ public Set<K> keySet() {
+ return decorated().keySet();
+ }
+
+ public Collection<Entry<K, V>> entries() {
+ return decorated().entries();
+ }
+
+ public Bag<K> keys() {
+ return decorated().keys();
+ }
+
+ public Collection<V> values() {
+ return decorated().values();
+ }
+
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ return decorated().putAll(key, values);
+ }
+
+ public void putAll(Map<? extends K, ? extends V> m) {
+ decorated().putAll(m);
+ }
+
+ public void putAll(MultiValuedMap<? extends K, ? extends V> m) {
+ decorated().putAll(m);
+ }
+
+ @Override
+ public boolean equals(final Object object) {
+ if (object == this) {
+ return true;
+ }
+ return decorated().equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return decorated().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return decorated().toString();
+ }
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4.multimap;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.collections4.MultiValuedMap;
+
+/**
+ * Implements a {@link MultiValuedMap}, using a {@link HashMap} to provide data
+ * storage. This is the standard implementation of a MultiValuedMap
+ * <p>
+ * A <code>MultiValuedMap</code> is a Map with slightly different semantics.
+ * Putting a value into the map will add the value to a Collection at that key.
+ * Getting a value will return a Collection, holding all the values put to that
+ * key
+ * <p>
+ * In addition, this implementation allows the type of collection used for the
+ * values to be controlled. By default, an <code>ArrayList</code> is used,
+ * however a <code>Class<? extends Collection></code> to instantiate the value
+ * collection may be specified.
+ * <p>
+ * <strong>Note that MultiValuedHashMap is not synchronized and is not
+ * thread-safe.</strong> If you wish to use this map from multiple threads
+ * concurrently, you must use appropriate synchronization. This class may throw
+ * exceptions when accessed by concurrent threads without synchronization.
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class MultiValuedHashMap<K, V> extends AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V> {
+
+ /** Serialization Version */
+ private static final long serialVersionUID = -5845183518195365857L;
+
+ /**
+ * Creates a MultiValuedHashMap which maps keys to collections of type
+ * <code>collectionClass</code>.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param <C> the collection class type
+ * @param collectionClass the type of the collection class
+ * @return a new MultiValuedMap
+ */
+ public static <K, V, C extends Collection<V>> MultiValuedMap<K, V> multiValuedMap(
+ final Class<C> collectionClass) {
+ return new MultiValuedHashMap<K, V>(collectionClass);
+ }
+
+ /**
+ * Creates a MultiValueMap based on a <code>HashMap</code> which stores the
+ * multiple values in an <code>ArrayList</code>.
+ */
+ @SuppressWarnings("unchecked")
+ public MultiValuedHashMap() {
+ this(ArrayList.class);
+ }
+
+ /**
+ * Creates a MultiValuedHashMap copying all the mappings of the given map.
+ *
+ * @param map a <code>MultiValuedMap</code> to copy into this map
+ */
+ @SuppressWarnings("unchecked")
+ public MultiValuedHashMap(final MultiValuedMap<? extends K, ? extends V> map) {
+ this(ArrayList.class);
+ super.putAll(map);
+ }
+
+ /**
+ * Creates a MultiValuedHashMap copying all the mappings of the given map.
+ *
+ * @param map a <code>Map</code> to copy into this map
+ */
+ @SuppressWarnings("unchecked")
+ public MultiValuedHashMap(final Map<? extends K, ? extends V> map) {
+ this(ArrayList.class);
+ super.putAll(map);
+ }
+
+ /**
+ * Creates a MultiValuedHashMap which creates the value collections using
+ * the supplied <code>collectionClazz</code>.
+ *
+ * @param <C> the collection type
+ * @param collectionClazz the class of the <code>Collection</code> to use to
+ * create the value collections
+ */
+ protected <C extends Collection<V>> MultiValuedHashMap(final Class<C> collectionClazz) {
+ super(new HashMap<K, Collection<V>>(), collectionClazz);
+ }
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4.multimap;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections4.MultiValuedMap;
+import org.apache.commons.collections4.Transformer;
+import org.apache.commons.collections4.map.LinkedMap;
+
+/**
+ * Decorates another <code>MultiValuedMap</code> to transform objects that are added.
+ * <p>
+ * This class affects the MultiValuedMap put methods. Thus objects must be
+ * removed or searched for using their transformed form. For example, if the
+ * transformation converts Strings to Integers, you must use the Integer form to
+ * remove objects.
+ * <p>
+ * <strong>Note that TransformedMultiValuedMap is not synchronized and is not thread-safe.</strong>
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class TransformedMultiValuedMap<K, V> extends AbstractMultiValuedMapDecorator<K, V> {
+
+ /** Serialization Version */
+ private static final long serialVersionUID = -1254147899086470720L;
+
+ private final Transformer<? super K, ? extends K> keyTransformer;
+
+ private final Transformer<? super V, ? extends V> valueTransformer;
+
+ /**
+ * Factory method to create a transforming MultiValuedMap.
+ * <p>
+ * If there are any elements already in the map being decorated, they are
+ * NOT transformed. Contrast this with
+ * {@link #transformedMap(MultiValuedMap, Transformer, Transformer)}.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the MultiValuedMap to decorate, must not be null
+ * @param keyTransformer the transformer to use for key conversion, null
+ * means no transformation
+ * @param valueTransformer the transformer to use for value conversion, null
+ * means no transformation
+ * @return a new transformed MultiValuedMap
+ * @throws IllegalArgumentException if map is null
+ */
+ public static <K, V> TransformedMultiValuedMap<K, V> transformingMap(final MultiValuedMap<K, V> map,
+ final Transformer<? super K, ? extends K> keyTransformer,
+ final Transformer<? super V, ? extends V> valueTransformer) {
+ return new TransformedMultiValuedMap<K, V>(map, keyTransformer, valueTransformer);
+ }
+
+ /**
+ * Factory method to create a transforming MultiValuedMap that will
+ * transform existing contents of the specified map.
+ * <p>
+ * If there are any elements already in the map being decorated, they will
+ * be transformed by this method. Contrast this with
+ * {@link #transformingMap(MultiValuedMap, Transformer, Transformer)}.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the MultiValuedMap to decorate, must not be null
+ * @param keyTransformer the transformer to use for key conversion, null
+ * means no transformation
+ * @param valueTransformer the transformer to use for value conversion, null
+ * means no transformation
+ * @return a new transformed MultiValuedMap
+ * @throws IllegalArgumentException if map is null
+ */
+ public static <K, V> TransformedMultiValuedMap<K, V> transformedMap(final MultiValuedMap<K, V> map,
+ final Transformer<? super K, ? extends K> keyTransformer,
+ final Transformer<? super V, ? extends V> valueTransformer) {
+ final TransformedMultiValuedMap<K, V> decorated =
+ new TransformedMultiValuedMap<K, V>(map, keyTransformer, valueTransformer);
+ if (map.size() > 0) {
+ MultiValuedMap<K, V> transformed = decorated.transformMultiValuedMap(map);
+ decorated.clear();
+ // to avoid double transform
+ decorated.decorated().putAll(transformed);
+ }
+ return decorated;
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Constructor that wraps (not copies).
+ * <p>
+ * If there are any elements already in the collection being decorated, they
+ * are NOT transformed.
+ *
+ * @param map the MultiValuedMap to decorate, must not be null
+ * @param keyTransformer the transformer to use for key conversion, null
+ * means no conversion
+ * @param valueTransformer the transformer to use for value conversion, null
+ * means no conversion
+ * @throws IllegalArgumentException if map is null
+ */
+ protected TransformedMultiValuedMap(MultiValuedMap<K, V> map,
+ Transformer<? super K, ? extends K> keyTransformer, Transformer<? super V, ? extends V> valueTransformer) {
+ super(map);
+ this.keyTransformer = keyTransformer;
+ this.valueTransformer = valueTransformer;
+ }
+
+ /**
+ * Transforms a key.
+ * <p>
+ * The transformer itself may throw an exception if necessary.
+ *
+ * @param object the object to transform
+ * @return the transformed object
+ */
+ protected K transformKey(final K object) {
+ if (keyTransformer == null) {
+ return object;
+ }
+ return keyTransformer.transform(object);
+ }
+
+ /**
+ * Transforms a value.
+ * <p>
+ * The transformer itself may throw an exception if necessary.
+ *
+ * @param object the object to transform
+ * @return the transformed object
+ */
+ protected V transformValue(final V object) {
+ if (valueTransformer == null) {
+ return object;
+ }
+ return valueTransformer.transform(object);
+ }
+
+ /**
+ * Transforms a map.
+ * <p>
+ * The transformer itself may throw an exception if necessary.
+ *
+ * @param map the map to transform
+ * @return the transformed object
+ */
+ @SuppressWarnings("unchecked")
+ protected Map<K, V> transformMap(final Map<? extends K, ? extends V> map) {
+ if (map.isEmpty()) {
+ return (Map<K, V>) map;
+ }
+ final Map<K, V> result = new LinkedMap<K, V>(map.size());
+
+ for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ result.put(transformKey(entry.getKey()), transformValue(entry.getValue()));
+ }
+ return result;
+ }
+
+ /**
+ * Transforms a MultiValuedMap.
+ * <p>
+ * The transformer itself may throw an exception if necessary.
+ *
+ * @param map the MultiValuedMap to transform
+ * @return the transformed object
+ */
+ @SuppressWarnings("unchecked")
+ protected MultiValuedMap<K, V> transformMultiValuedMap(final MultiValuedMap<? extends K, ? extends V> map) {
+ if (map.isEmpty()) {
+ return (MultiValuedMap<K, V>) map;
+ }
+ final MultiValuedMap<K, V> result = new MultiValuedHashMap<K, V>();
+
+ for (final Map.Entry<? extends K, ? extends V> entry : map.entries()) {
+ result.put(transformKey(entry.getKey()), transformValue(entry.getValue()));
+ }
+ return result;
+ }
+
+ @Override
+ public V put(K key, V value) {
+ K transformedKey = transformKey(key);
+ V transformedValue = transformValue(value);
+ return decorated().put(transformedKey, transformedValue);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ if (values == null || values.iterator() == null || !values.iterator().hasNext()) {
+ return false;
+ }
+ K transformedKey = transformKey(key);
+ List<V> transformedValues = new LinkedList<V>();
+ Iterator<V> it = (Iterator<V>) values.iterator();
+ while (it.hasNext()) {
+ transformedValues.add(transformValue(it.next()));
+ }
+ return decorated().putAll(transformedKey, transformedValues);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ if (m == null) {
+ return;
+ }
+ decorated().putAll(transformMap(m));
+ }
+
+ @Override
+ public void putAll(MultiValuedMap<? extends K, ? extends V> m) {
+ if (m == null) {
+ return;
+ }
+ decorated().putAll(transformMultiValuedMap(m));
+ }
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4.multimap;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.MultiValuedMap;
+import org.apache.commons.collections4.Unmodifiable;
+import org.apache.commons.collections4.bag.UnmodifiableBag;
+import org.apache.commons.collections4.collection.UnmodifiableCollection;
+import org.apache.commons.collections4.set.UnmodifiableSet;
+
+/**
+ * Decorates another {@link MultiValuedMap} to ensure it can't be altered.
+ * <p>
+ * Attempts to modify it will result in an UnsupportedOperationException.
+ *
+ * @param <K> the type of key elements
+ * @param <V> the type of value elements
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class UnmodifiableMultiValuedMap<K, V>
+ extends AbstractMultiValuedMapDecorator<K, V> implements Unmodifiable {
+
+ /** Serialization version */
+ private static final long serialVersionUID = 1418669828214151566L;
+
+ /**
+ * Factory method to create an unmodifiable MultiValuedMap.
+ * <p>
+ * If the map passed in is already unmodifiable, it is returned.
+ *
+ * @param <K> the type of key elements
+ * @param <V> the type of value elements
+ * @param map the map to decorate, must not be null
+ * @return an unmodifiable MultiValuedMap
+ * @throws IllegalArgumentException if map is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <K, V> UnmodifiableMultiValuedMap<K, V>
+ unmodifiableMultiValuedMap(MultiValuedMap<? extends K, ? extends V> map) {
+ if (map instanceof Unmodifiable) {
+ return (UnmodifiableMultiValuedMap<K, V>) map;
+ }
+ return new UnmodifiableMultiValuedMap<K, V>(map);
+ }
+
+ /**
+ * Constructor that wraps (not copies).
+ *
+ * @param map the MultiValuedMap to decorate, must not be null
+ * @throws IllegalArgumentException if the map is null
+ */
+ @SuppressWarnings("unchecked")
+ private UnmodifiableMultiValuedMap(final MultiValuedMap<? extends K, ? extends V> map) {
+ super((MultiValuedMap<K, V>) map);
+ }
+
+ @Override
+ public Collection<V> remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeMapping(K key, V item) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return UnmodifiableSet.<K>unmodifiableSet(decorated().keySet());
+ }
+
+ @Override
+ public Collection<Entry<K, V>> entries() {
+ return UnmodifiableCollection.<Entry<K, V>>unmodifiableCollection(decorated().entries());
+ }
+
+ @Override
+ public Bag<K> keys() {
+ return UnmodifiableBag.<K>unmodifiableBag(decorated().keys());
+ }
+
+ @Override
+ public Collection<V> values() {
+ return UnmodifiableCollection.<V>unmodifiableCollection(decorated().values());
+ }
+
+ @Override
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putAll(MultiValuedMap<? extends K, ? extends V> m) {
+ throw new UnsupportedOperationException();
+ }
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java?rev=1581553&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java Tue Mar 25 22:01:07 2014
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package contains implementations of the {@link org.apache.commons.collections4.MultiValuedMap} interfaces.
+ * A MultiValuedMap holds a collection of values against each key.
+ * <p>
+ * The following implementations are provided in the package:
+ * <ul>
+ * <li>MultiValuedHashMap - implementation that uses a HashMap to store the data
+ * </ul>
+ * <p>
+ * The following decorators are provided in the package:
+ * <ul>
+ * <li>Transformed - transforms elements added to the MultiValuedMap
+ * <li>Unmodifiable - ensures the collection cannot be altered
+ * </ul>
+ *
+ * @version $Id$
+ */
+package org.apache.commons.collections4.multimap;
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/package-info.java
------------------------------------------------------------------------------
svn:mime-type = text/plain