psteitz 2003/12/14 13:42:55 Modified: collections/src/java/org/apache/commons/collections/collection CompositeCollection.java collections/src/test/org/apache/commons/collections/collection TestCompositeCollection.java collections/src/test/org/apache/commons/collections/map TestAll.java collections/src/test/org/apache/commons/collections/set TestAll.java Added: collections/src/java/org/apache/commons/collections/map CompositeMap.java collections/src/java/org/apache/commons/collections/set CompositeSet.java collections/src/test/org/apache/commons/collections/map TestCompositeMap.java collections/src/test/org/apache/commons/collections/set TestCompositeSet.java Log: Added CompositeSet, CompositeMap contributed by Brian McCallister. Revision Changes Path 1.3 +5 -5 jakarta-commons/collections/src/java/org/apache/commons/collections/collection/CompositeCollection.java Index: CompositeCollection.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/collection/CompositeCollection.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- CompositeCollection.java 3 Dec 2003 11:37:44 -0000 1.2 +++ CompositeCollection.java 14 Dec 2003 21:42:55 -0000 1.3 @@ -68,7 +68,7 @@ import org.apache.commons.collections.list.UnmodifiableList; /** - * Decorates a other collections to provide a single unified view. + * Decorates a collection of other collections to provide a single unified view. * <p> * Changes made to this collection will actually be made on the decorated collection. * Add and remove operations require the use of a pluggable strategy. If no @@ -103,7 +103,7 @@ * @param coll a collection to decorate */ public CompositeCollection(Collection coll) { - super(); + this(); this.addComposited(coll); } @@ -114,7 +114,7 @@ * @param colls an array of collections to decorate */ public CompositeCollection(Collection[] colls) { - super(); + this(); this.addComposited(colls); } 1.1 jakarta-commons/collections/src/java/org/apache/commons/collections/map/CompositeMap.java Index: CompositeMap.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/map/CompositeMap.java,v 1.1 2003/12/14 21:42:55 psteitz Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.collections.map; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.collection.CompositeCollection; import org.apache.commons.collections.set.CompositeSet; /** * Decorates a map of other maps to provide a single unified view. * <p> * Changes made to this map will actually be made on the decorated map. * Add and remove operations require the use of a pluggable strategy. If no * strategy is provided then add and remove are unsupported. * * @since Commons Collections 3.0 * @version $Revision: 1.1 $ $Date: 2003/12/14 21:42:55 $ * * @author Brian McCallister */ public class CompositeMap implements Map { /** Array of all maps in the composite */ private Map[] composite = null; /** Handle mutation operations */ private MapMutator mutator = null; /** * Create a new, empty, CompositeMap */ public CompositeMap() { this(new Map[]{}, null); } /** * Create a new CompositeMap with two composited Map instances * @param one First Map to be composited * @param two Second Map to be composited * @throws IllegalArgumentException if there is a key collision */ public CompositeMap(Map one, Map two) { this(new Map[]{one, two}, null); } /** * Create a new CompositeMap with two composited Map instances * @param one First Map to be composited * @param two Second Map to be composited * @param mutator MapMutator to be used for mutation operations */ public CompositeMap(Map one, Map two, MapMutator mutator) { this(new Map[]{one, two}, mutator); } /** * Create a new CompositeMap which composites all of the Map instances in the * argument. It copies the argument array, it does not use it directly. * @param composite Maps to be composited * @throws IllegalArgumentException if there is a key collision */ public CompositeMap(Map[] composite) { this(composite, null); } /** * Create a new CompositeMap which composites all of the Map instances in the * argument. It copies the argument array, it does not use it directly. * @param composite Maps to be composited * @param mutator MapMutator to be used for mutation operations */ public CompositeMap(Map[] composite, MapMutator mutator) { this.mutator = mutator; this.composite = new Map[0]; for (int i = composite.length - 1; i >= 0; --i) { this.addComposited(composite[i]); } } /** * Specify the MapMutator to be used by mutation operations * @param mutator The MapMutator to be used for mutation delegation */ public void setMutator(MapMutator mutator) { this.mutator = mutator; } /** * Add an additional Map to the composite * * @param map Map to be added to the composite * @throws IllegalArgumentException if there is a key collision and there is no * MapMutator set to handle it. */ public synchronized void addComposited(Map map) throws IllegalArgumentException { for (int i = composite.length - 1; i >= 0; --i) { Collection intersect = CollectionUtils.intersection(this.composite[i].keySet(), map.keySet()); if (intersect.size() != 0) { if (this.mutator == null) { throw new IllegalArgumentException("Key collision adding Map to CompositeMap"); } else { this.mutator.resolveCollision(this, this.composite[i], map, intersect); } } } Map[] temp = new Map[this.composite.length + 1]; System.arraycopy(this.composite, 0, temp, 0, this.composite.length); temp[temp.length - 1] = map; this.composite = temp; } /** * Remove a Map from the composite * * @param map The Map to be removed from the composite * @return The removed Map or <code>null</code> if map is not in the composite */ public synchronized Map removeComposited(Map map) { int size = this.composite.length; for (int i = 0; i < size; ++i) { if (this.composite[i].equals(map)) { Map[] temp = new Map[size - 1]; System.arraycopy(this.composite, 0, temp, 0, i); System.arraycopy(this.composite, i + 1, temp, i, size - i - 1); this.composite = temp; return map; } } return null; } /* Map Implementation */ /** * Calls <code>clear()</code> on all composited Maps * * @throws UnsupportedOperationException if any of the composited Maps do not support clear() */ public void clear() { for (int i = this.composite.length - 1; i >= 0; --i) { this.composite[i].clear(); } } /** * 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 at 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 key is <tt>null</tt> and this map * does not not permit <tt>null</tt> keys (optional). */ public boolean containsKey(Object key) { for (int i = this.composite.length - 1; i >= 0; --i) { if (this.composite[i].containsKey(key)) return true; } return false; } /** * Returns <tt>true</tt> if this map maps one or more keys to the * specified value. More formally, returns <tt>true</tt> if and only if * this map contains at least one mapping to a value <tt>v</tt> such that * <tt>(value==null ? v==null : value.equals(v))</tt>. This operation * will probably require time linear in the map size for most * implementations of the <tt>Map</tt> interface. * * @param value value whose presence in this map is to be tested. * @return <tt>true</tt> if this map maps one or more keys to the * specified value. * @throws ClassCastException if the value is of an inappropriate type for * this map (optional). * @throws NullPointerException if the value is <tt>null</tt> and this map * does not not permit <tt>null</tt> values (optional). */ public boolean containsValue(Object value) { for (int i = this.composite.length - 1; i >= 0; --i) { if (this.composite[i].containsValue(value)) return true; } return false; } /** * Returns a set view of the mappings contained in this map. Each element * in the returned set is a [EMAIL PROTECTED] Map.Entry}. 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, * 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. * <p> * This implementation returns a <code>CompositeSet</code> which * composites the entry sets from all of the composited maps. * * @see CompositeSet * @return a set view of the mappings contained in this map. */ public Set entrySet() { CompositeSet entries = new CompositeSet(); for (int i = this.composite.length - 1; i >= 0; --i) { entries.addComposited(this.composite[i].entrySet()); } return entries; } /** * Returns the value to which this map maps the specified key. Returns * <tt>null</tt> if the map contains no mapping for this key. A return * value of <tt>null</tt> does not <i>necessarily</i> indicate that the * map contains no mapping for the key; it's also possible that the map * explicitly maps the key to <tt>null</tt>. The <tt>containsKey</tt> * operation may be used to distinguish these two cases. * * <p>More formally, if this map contains a mapping from a key * <tt>k</tt> to a value <tt>v</tt> such that <tt>(key==null ? k==null : * key.equals(k))</tt>, then this method returns <tt>v</tt>; otherwise * it returns <tt>null</tt>. (There can be at most one such mapping.) * * @param key key whose associated value is to be returned. * @return the value to which this map maps the specified key, or * <tt>null</tt> if the map contains no mapping for this key. * * @throws ClassCastException if the key is of an inappropriate type for * this map (optional). * @throws NullPointerException key is <tt>null</tt> and this map does not * not permit <tt>null</tt> keys (optional). * * @see #containsKey(Object) */ public Object get(Object key) { for (int i = this.composite.length - 1; i >= 0; --i) { if (this.composite[i].containsKey(key)) return this.composite[i].get(key); } return null; } /** * Returns <tt>true</tt> if this map contains no key-value mappings. * * @return <tt>true</tt> if this map contains no key-value mappings. */ public boolean isEmpty() { for (int i = this.composite.length - 1; i >= 0; --i) { if (!this.composite[i].isEmpty()) return false; } return true; } /** * Returns a 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, 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 add or <tt>addAll</tt> operations. * <p> * This implementation returns a <code>CompositeSet</code> which * composites the key sets from all of the composited maps. * * @return a set view of the keys contained in this map. */ public Set keySet() { CompositeSet keys = new CompositeSet(); for (int i = this.composite.length - 1; i >= 0; --i) { keys.addComposited(this.composite[i].keySet()); } return keys; } /** * Associates the specified value with the specified key in this map * (optional operation). If the map previously contained a mapping for * this key, the old value is replaced by the specified value. (A map * <tt>m</tt> is said to contain a mapping for a key <tt>k</tt> if and only * if [EMAIL PROTECTED] #containsKey(Object) m.containsKey(k)} would return * <tt>true</tt>.)) * * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. * @return previous value associated with specified key, or <tt>null</tt> * if there was no mapping for key. A <tt>null</tt> return can * also indicate that the map previously associated <tt>null</tt> * with the specified key, if the implementation supports * <tt>null</tt> values. * * @throws UnsupportedOperationException if no MapMutator has been specified * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map. * @throws IllegalArgumentException if some aspect of this key or value * prevents it from being stored in this map. * @throws NullPointerException this map does not permit <tt>null</tt> * keys or values, and the specified key or value is * <tt>null</tt>. */ public Object put(Object key, Object value) { if (this.mutator == null) throw new UnsupportedOperationException("No mutator specified"); return this.mutator.put(this, this.composite, key, value); } /** * 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 [EMAIL PROTECTED] #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 unspecified if the * specified map is modified while the operation is in progress. * * @param t Mappings to be stored in this map. * * @throws UnsupportedOperationException if the <tt>putAll</tt> method 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 IllegalArgumentException some aspect of a key or value in the * specified map prevents it from being stored in this map. * @throws NullPointerException the specified map is <tt>null</tt>, or if * this map does not permit <tt>null</tt> keys or values, and the * specified map contains <tt>null</tt> keys or values. */ public void putAll(Map t) { if (this.mutator == null) throw new UnsupportedOperationException("No mutator specified"); this.mutator.putAll(this, this.composite, t); } /** * Removes the mapping for this key from this map if it is present * (optional operation). More formally, if this map contains a mapping * from key <tt>k</tt> to value <tt>v</tt> such that * <code>(key==null ? k==null : key.equals(k))</code>, that mapping * is removed. (The map can contain at most one such mapping.) * * <p>Returns the value to which the map previously associated the key, or * <tt>null</tt> if the map contained no mapping for this key. (A * <tt>null</tt> return can also indicate that the map previously * associated <tt>null</tt> with the specified key if the implementation * supports <tt>null</tt> values.) The map will not contain a mapping for * the specified key once the call returns. * * @param key key whose mapping is to be removed from the map. * @return previous value associated with specified key, or <tt>null</tt> * if there was no mapping for key. * * @throws ClassCastException if the key is of an inappropriate type for * the composited map (optional). * @throws NullPointerException if the key is <tt>null</tt> and the composited map * does not not permit <tt>null</tt> keys (optional). * @throws UnsupportedOperationException if the <tt>remove</tt> method is * not supported by the composited map containing the key */ public Object remove(Object key) { for (int i = this.composite.length - 1; i >= 0; --i) { if (this.composite[i].containsKey(key)) return this.composite[i].remove(key); } return null; } /** * Returns the number of key-value mappings in this map. If the * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns * <tt>Integer.MAX_VALUE</tt>. * * @return the number of key-value mappings in this map. */ public int size() { int size = 0; for (int i = this.composite.length - 1; i >= 0; --i) { size += this.composite[i].size(); } return size; } /** * Returns a collection view of the values contained in this map. The * collection is backed by the map, so changes to the map are reflected in * the collection, and vice-versa. If the map is modified while an * iteration over the collection is in progress, the results of the * iteration are undefined. The collection supports element removal, * which removes the corresponding mapping from the map, via the * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>, * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> operations. * It does not support the add or <tt>addAll</tt> operations. * * @return a collection view of the values contained in this map. */ public Collection values() { CompositeCollection keys = new CompositeCollection(); for (int i = this.composite.length - 1; i >= 0; --i) { keys.addComposited(this.composite[i].values()); } return keys; } /** * @see Map#hashCode */ public int hashCode() { int code = 0; for (Iterator i = this.entrySet().iterator(); i.hasNext();) { code += i.next().hashCode(); } return code; } /** * @see Map#equals */ public boolean equals(Object obj) { if (obj instanceof Map) { Map map = (Map) obj; return (this.entrySet().equals(map.entrySet())); } return false; } /** * This interface allows definition for all of the indeterminate * mutators in a CompositeMap, as well as providing a hook for * callbacks on key collisions. */ public static interface MapMutator { /** * Called when adding a new Composited Map results in a * key collision. * * @param composite the CompositeMap withthe collision * @param existing the Map already in the composite which contains the * offending key * @param added the Map being added * @param intersect the intersection of the keysets of the existing and added maps */ public void resolveCollision(CompositeMap composite, Map existing, Map added, Collection intersect); /** * Called when the CompositeMap.put() method is invoked. * * @param map the CompositeMap which is being modified * @param composited array of Maps in the CompositeMap being modified * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. * @return previous value associated with specified key, or <tt>null</tt> * if there was no mapping for key. A <tt>null</tt> return can * also indicate that the map previously associated <tt>null</tt> * with the specified key, if the implementation supports * <tt>null</tt> values. * * @throws UnsupportedOperationException if not defined * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map. * @throws IllegalArgumentException if some aspect of this key or value * prevents it from being stored in this map. * @throws NullPointerException this map does not permit <tt>null</tt> * keys or values, and the specified key or value is * <tt>null</tt>. */ public Object put(CompositeMap map, Map[] composited, Object key, Object value); /** * Called when the CompositeMap.putAll() method is invoked. * * @param map the CompositeMap which is being modified * @param composited array of Maps in the CompositeMap being modified * @param t Mappings to be stored in this CompositeMap * * @throws UnsupportedOperationException if not defined * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map. * @throws IllegalArgumentException if some aspect of this key or value * prevents it from being stored in this map. * @throws NullPointerException this map does not permit <tt>null</tt> * keys or values, and the specified key or value is * <tt>null</tt>. */ public void putAll(CompositeMap map, Map[] composited, Map t); } } 1.1 jakarta-commons/collections/src/java/org/apache/commons/collections/set/CompositeSet.java Index: CompositeSet.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/set/CompositeSet.java,v 1.1 2003/12/14 21:42:55 psteitz Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.collections.set; import java.util.Collection; import java.util.Iterator; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.collection.CompositeCollection; /** * Decorates a set of other sets to provide a single unified view. * <p> * Changes made to this set will actually be made on the decorated set. * Add and remove operations require the use of a pluggable strategy. If no * strategy is provided then add and remove are unsupported. * * @since Commons Collections 3.0 * @version $Revision: 1.1 $ $Date: 2003/12/14 21:42:55 $ * * @author Brian McCallister */ public class CompositeSet extends CompositeCollection implements Set { /** * Create an empty CompositeSet */ public CompositeSet() { super(); } /** * Create a CompositeSet with just <code>set</code> composited * @param set The initial set in the composite */ public CompositeSet(Set set) { super(set); } /** * Create a composite set with sets as the initial set of composited Sets */ public CompositeSet(Set[] sets) { super(sets); } /** * Add a Set to this composite * * @param c Must implement Set * @throws IllegalArgumentException if c does not implement java.util.Set * or if a SetMutator is set, but fails to resolve a collision * @throws UnsupportedOperationException if there is no SetMutator set, or * a CollectionMutator is set instead of a SetMutator * @see org.apache.commons.collections.collection.CompositeCollection.CollectionMutator * @see SetMutator */ public synchronized void addComposited(Collection c) { if (!(c instanceof Set)) { throw new IllegalArgumentException("Collections added must implement java.util.Set"); } for (Iterator i = this.getCollections().iterator(); i.hasNext();) { Set set = (Set) i.next(); Collection intersects = CollectionUtils.intersection(set, c); if (intersects.size() > 0) { if (this.mutator == null) { throw new UnsupportedOperationException( "Collision adding composited collection with no SetMutator set"); } else if (!(this.mutator instanceof SetMutator)) { throw new UnsupportedOperationException( "Collision adding composited collection to a CompositeSet with a CollectionMutator instead of a SetMutator"); } ((SetMutator) this.mutator).resolveCollision(this, set, (Set) c, intersects); if (CollectionUtils.intersection(set, c).size() > 0) { throw new IllegalArgumentException( "Attempt to add illegal entry unresolved by SetMutator.resolveCollision()"); } } } super.addComposited(new Collection[]{c}); } /** * Add two sets to this composite * * @throws IllegalArgumentException if c or d does not implement java.util.Set */ public synchronized void addComposited(Collection c, Collection d) { if (!(c instanceof Set)) throw new IllegalArgumentException("Argument must implement java.util.Set"); if (!(d instanceof Set)) throw new IllegalArgumentException("Argument must implement java.util.Set"); this.addComposited(new Set[]{(Set) c, (Set) d}); } /** * Add an array of sets to this composite * @param comps * @throws IllegalArgumentException if any of the collections in comps do not implement Set */ public synchronized void addComposited(Collection[] comps) { for (int i = comps.length - 1; i >= 0; --i) { this.addComposited(comps[i]); } } /** * This can receive either a <code>CompositeCollection.CollectionMutator</code> * or a <code>CompositeSet.SetMutator</code>. If a * <code>CompositeCollection.CollectionMutator</code> is used than conflicts when adding * composited sets will throw IllegalArgumentException * <p> */ public void setMutator(CollectionMutator mutator) { super.setMutator(mutator); } /* Set operations */ /** * If a <code>CollectionMutator</code> is defined for this CompositeSet then this * method will be called anyway. * * @param obj Object to be removed * @return true if the object is removed, false otherwise */ public boolean remove(Object obj) { for (Iterator i = this.getCollections().iterator(); i.hasNext();) { Set set = (Set) i.next(); if (set.contains(obj)) return set.remove(obj); } return false; } /** * @see Set#equals */ public boolean equals(Object obj) { if (obj instanceof Set) { Set set = (Set) obj; if (set.containsAll(this) && set.size() == this.size()) { return true; } } return false; } /** * @see Set#hashCode */ public int hashCode() { int code = 0; for (Iterator i = this.iterator(); i.hasNext();) { Object next = i.next(); code += (next != null ? next.hashCode() : 0); } return code; } /** * Define callbacks for mutation operations. * <p> * Defining remove() on implementations of SetMutator is pointless * as they are never called by CompositeSet. */ public static interface SetMutator extends CompositeCollection.CollectionMutator { /** * <p> * Called when a Set is added to the CompositeSet and there is a * collision between existing and added sets. * </p> * <p> * If <code>added</code> and <code>existing</code> still have any intersects * after this method returns an IllegalArgumentException will be thrown. * </p> * @param comp The CompositeSet being modified * @param existing The Set already existing in the composite * @param added the Set being added to the composite * @param intersects the intersection of th existing and added sets */ public void resolveCollision(CompositeSet comp, Set existing, Set added, Collection intersects); } } 1.4 +4 -4 jakarta-commons/collections/src/test/org/apache/commons/collections/collection/TestCompositeCollection.java Index: TestCompositeCollection.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/collection/TestCompositeCollection.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- TestCompositeCollection.java 18 Nov 2003 22:37:18 -0000 1.3 +++ TestCompositeCollection.java 14 Dec 2003 21:42:55 -0000 1.4 @@ -116,7 +116,7 @@ } /** - * Full collection consists of 5 collections, each with one element + * Full collection consists of 4 collections, each with one element */ public Collection makeFullCollection() { CompositeCollection compositeCollection = new CompositeCollection(); @@ -130,7 +130,7 @@ } /** - * Full collection should look like a collection with 5 elements + * Full collection should look like a collection with 4 elements */ public Collection makeConfirmedFullCollection() { Collection collection = new HashSet(); 1.11 +3 -2 jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestAll.java Index: TestAll.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestAll.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- TestAll.java 7 Dec 2003 01:23:54 -0000 1.10 +++ TestAll.java 14 Dec 2003 21:42:55 -0000 1.11 @@ -83,6 +83,7 @@ public static Test suite() { TestSuite suite = new TestSuite(); + suite.addTest(TestCompositeMap.suite()); suite.addTest(TestFlat3Map.suite()); suite.addTest(TestHashedMap.suite()); suite.addTest(TestIdentityMap.suite()); 1.1 jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestCompositeMap.java Index: TestCompositeMap.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestCompositeMap.java,v 1.1 2003/12/14 21:42:55 psteitz Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.collections.map; import junit.framework.Test; import junit.framework.TestSuite; import junit.framework.Assert; import java.util.Map; import java.util.HashMap; import java.util.Collection; /** * Extension of [EMAIL PROTECTED] AbstractTestMap} for exercising the * [EMAIL PROTECTED] CompositeMap} implementation. * * @since Commons Collections 3.0 * @version $Revision: 1.1 $ $Date: 2003/12/14 21:42:55 $ * * @author Brian McCallister */ public class TestCompositeMap extends AbstractTestMap { /** used as a flag in MapMutator tests */ private boolean pass = false; public TestCompositeMap(String testName) { super(testName); } public static Test suite() { return new TestSuite(TestCompositeMap.class); } public void setUp() throws Exception { super.setUp(); this.pass = false; } public static void main(String args[]) { String[] testCaseName = {TestCompositeMap.class.getName()}; junit.textui.TestRunner.main(testCaseName); } public Map makeEmptyMap() { CompositeMap map = new CompositeMap(); map.addComposited(new HashMap()); map.setMutator(new CompositeMap.MapMutator() { public void resolveCollision(CompositeMap composite, Map existing, Map added, Collection intersect) { // Do nothing } public Object put(CompositeMap map, Map[] composited, Object key, Object value) { return composited[0].put(key, value); } public void putAll(CompositeMap map, Map[] composited, Map t) { composited[0].putAll(t); } }); return map; } private Map buildOne() { HashMap map = new HashMap(); map.put("1", "one"); map.put("2", "two"); return map; } public Map buildTwo() { HashMap map = new HashMap(); map.put("3", "three"); map.put("4", "four"); return map; } public void testGet() { CompositeMap map = new CompositeMap(buildOne(), buildTwo()); Assert.assertEquals("one", map.get("1")); Assert.assertEquals("four", map.get("4")); } public void testAddComposited() { CompositeMap map = new CompositeMap(buildOne(), buildTwo()); HashMap three = new HashMap(); three.put("5", "five"); map.addComposited(three); assertTrue(map.containsKey("5")); try { map.addComposited(three); fail("Expecting IllegalArgumentException."); } catch (IllegalArgumentException ex) { // expected } } public void testRemoveComposited() { CompositeMap map = new CompositeMap(buildOne(), buildTwo()); HashMap three = new HashMap(); three.put("5", "five"); map.addComposited(three); assertTrue(map.containsKey("5")); map.removeComposited(three); assertFalse(map.containsKey("5")); map.removeComposited(buildOne()); assertFalse(map.containsKey("2")); } public void testRemoveFromUnderlying() { CompositeMap map = new CompositeMap(buildOne(), buildTwo()); HashMap three = new HashMap(); three.put("5", "five"); map.addComposited(three); assertTrue(map.containsKey("5")); //Now remove "5" three.remove("5"); assertFalse(map.containsKey("5")); } public void testRemoveFromComposited() { CompositeMap map = new CompositeMap(buildOne(), buildTwo()); HashMap three = new HashMap(); three.put("5", "five"); map.addComposited(three); assertTrue(map.containsKey("5")); //Now remove "5" map.remove("5"); assertFalse(three.containsKey("5")); } public void testResolveCollision() { CompositeMap map = new CompositeMap(buildOne(), buildTwo(), new CompositeMap.MapMutator() { public void resolveCollision(CompositeMap composite, Map existing, Map added, Collection intersect) { pass = true; } public Object put(CompositeMap map, Map[] composited, Object key, Object value) { throw new UnsupportedOperationException(); } public void putAll(CompositeMap map, Map[] composited, Map t) { throw new UnsupportedOperationException(); } }); map.addComposited(buildOne()); assertTrue(pass); } public void testPut() { CompositeMap map = new CompositeMap(buildOne(), buildTwo(), new CompositeMap.MapMutator() { public void resolveCollision(CompositeMap composite, Map existing, Map added, Collection intersect) { throw new UnsupportedOperationException(); } public Object put(CompositeMap map, Map[] composited, Object key, Object value) { pass = true; return "foo"; } public void putAll(CompositeMap map, Map[] composited, Map t) { throw new UnsupportedOperationException(); } }); map.put("willy", "wonka"); assertTrue(pass); } public void testPutAll() { CompositeMap map = new CompositeMap(buildOne(), buildTwo(), new CompositeMap.MapMutator() { public void resolveCollision(CompositeMap composite, Map existing, Map added, Collection intersect) { throw new UnsupportedOperationException(); } public Object put(CompositeMap map, Map[] composited, Object key, Object value) { throw new UnsupportedOperationException(); } public void putAll(CompositeMap map, Map[] composited, Map t) { pass = true; } }); map.putAll(null); assertTrue(pass); } } 1.3 +3 -2 jakarta-commons/collections/src/test/org/apache/commons/collections/set/TestAll.java Index: TestAll.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/set/TestAll.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- TestAll.java 3 Dec 2003 11:19:10 -0000 1.2 +++ TestAll.java 14 Dec 2003 21:42:55 -0000 1.3 @@ -83,6 +83,7 @@ public static Test suite() { TestSuite suite = new TestSuite(); + suite.addTest(TestCompositeSet.suite()); suite.addTest(TestListOrderedSet.suite()); suite.addTest(TestPredicatedSet.suite()); suite.addTest(TestPredicatedSortedSet.suite()); 1.1 jakarta-commons/collections/src/test/org/apache/commons/collections/set/TestCompositeSet.java Index: TestCompositeSet.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/set/TestCompositeSet.java,v 1.1 2003/12/14 21:42:55 psteitz Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.collections.set; import junit.framework.Test; import junit.framework.TestSuite; import org.apache.commons.collections.collection.CompositeCollection; import java.util.Set; import java.util.HashSet; import java.util.Collection; /** * Extension of [EMAIL PROTECTED] AbstractTestSet} for exercising the * [EMAIL PROTECTED] CompositeSet} implementation. * * @since Commons Collections 3.0 * @version $Revision: 1.1 $ $Date: 2003/12/14 21:42:55 $ * * @author Brian McCallister * @author Phil Steitz */ public class TestCompositeSet extends AbstractTestSet { public TestCompositeSet(String name) { super(name); } public static Test suite() { return new TestSuite(TestCompositeSet.class); } public Set makeEmptySet() { final HashSet contained = new HashSet(); CompositeSet set = new CompositeSet(contained); set.setMutator(new CompositeSet.SetMutator() { public void resolveCollision(CompositeSet comp, Set existing, Set added, Collection intersects) { throw new IllegalArgumentException(); } public boolean add(CompositeCollection composite, Collection[] collections, Object obj) { return contained.add(obj); } public boolean addAll(CompositeCollection composite, Collection[] collections, Collection coll) { return contained.addAll(coll); } public boolean remove(CompositeCollection composite, Collection[] collections, Object obj) { return contained.remove(obj); } }); return set; } public Set buildOne() { HashSet set = new HashSet(); set.add("1"); set.add("2"); return set; } public Set buildTwo() { HashSet set = new HashSet(); set.add("3"); set.add("4"); return set; } public void testContains() { CompositeSet set = new CompositeSet(new Set[]{buildOne(), buildTwo()}); assertTrue(set.contains("1")); } public void testRemoveUnderlying() { Set one = buildOne(); Set two = buildTwo(); CompositeSet set = new CompositeSet(new Set[]{one, two}); one.remove("1"); assertFalse(set.contains("1")); two.remove("3"); assertFalse(set.contains("3")); } public void testRemoveComposited() { Set one = buildOne(); Set two = buildTwo(); CompositeSet set = new CompositeSet(new Set[]{one, two}); set.remove("1"); assertFalse(one.contains("1")); set.remove("3"); assertFalse(one.contains("3")); } public void testFailedCollisionResolution() { Set one = buildOne(); Set two = buildTwo(); CompositeSet set = new CompositeSet(new Set[]{one, two}); set.setMutator(new CompositeSet.SetMutator() { public void resolveCollision(CompositeSet comp, Set existing, Set added, Collection intersects) { } public boolean add(CompositeCollection composite, Collection[] collections, Object obj) { throw new UnsupportedOperationException(); } public boolean addAll(CompositeCollection composite, Collection[] collections, Collection coll) { throw new UnsupportedOperationException(); } public boolean remove(CompositeCollection composite, Collection[] collections, Object obj) { throw new UnsupportedOperationException(); } }); HashSet three = new HashSet(); three.add("1"); try { set.addComposited(three); fail("IllegalArgumentException should have been thrown"); } catch (IllegalArgumentException e) { // expected } } public void testAddComposited() { Set one = buildOne(); Set two = buildTwo(); CompositeSet set = new CompositeSet(); set.addComposited(one, two); CompositeSet set2 = new CompositeSet(buildOne()); set2.addComposited(buildTwo()); assertTrue(set.equals(set2)); HashSet set3 = new HashSet(); set3.add("1"); set3.add("2"); set3.add("3"); HashSet set4 = new HashSet(); set4.add("4"); CompositeSet set5 = new CompositeSet(set3); set5.addComposited(set4); assertTrue(set.equals(set5)); try { set.addComposited(set3); fail("Expecting UnsupportedOperationException."); } catch (UnsupportedOperationException ex) { // expected } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]