001: /*
002: * Copyright 2003-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.collections.set;
017:
018: import java.util.Collection;
019: import java.util.Iterator;
020: import java.util.Set;
021:
022: import org.apache.commons.collections.CollectionUtils;
023: import org.apache.commons.collections.collection.CompositeCollection;
024:
025: /**
026: * Decorates a set of other sets to provide a single unified view.
027: * <p>
028: * Changes made to this set will actually be made on the decorated set.
029: * Add operations require the use of a pluggable strategy.
030: * If no strategy is provided then add is unsupported.
031: *
032: * @since Commons Collections 3.0
033: * @version $Revision: 155406 $ $Date: 2005-02-26 12:55:26 +0000 (Sat, 26 Feb 2005) $
034: *
035: * @author Brian McCallister
036: */
037: public class CompositeSet extends CompositeCollection implements Set {
038: /**
039: * Create an empty CompositeSet
040: */
041: public CompositeSet() {
042: super ();
043: }
044:
045: /**
046: * Create a CompositeSet with just <code>set</code> composited
047: * @param set The initial set in the composite
048: */
049: public CompositeSet(Set set) {
050: super (set);
051: }
052:
053: /**
054: * Create a composite set with sets as the initial set of composited Sets
055: */
056: public CompositeSet(Set[] sets) {
057: super (sets);
058: }
059:
060: /**
061: * Add a Set to this composite
062: *
063: * @param c Must implement Set
064: * @throws IllegalArgumentException if c does not implement java.util.Set
065: * or if a SetMutator is set, but fails to resolve a collision
066: * @throws UnsupportedOperationException if there is no SetMutator set, or
067: * a CollectionMutator is set instead of a SetMutator
068: * @see org.apache.commons.collections.collection.CompositeCollection.CollectionMutator
069: * @see SetMutator
070: */
071: public synchronized void addComposited(Collection c) {
072: if (!(c instanceof Set)) {
073: throw new IllegalArgumentException(
074: "Collections added must implement java.util.Set");
075: }
076:
077: for (Iterator i = this .getCollections().iterator(); i.hasNext();) {
078: Set set = (Set) i.next();
079: Collection intersects = CollectionUtils
080: .intersection(set, c);
081: if (intersects.size() > 0) {
082: if (this .mutator == null) {
083: throw new UnsupportedOperationException(
084: "Collision adding composited collection with no SetMutator set");
085: } else if (!(this .mutator instanceof SetMutator)) {
086: throw new UnsupportedOperationException(
087: "Collision adding composited collection to a CompositeSet with a CollectionMutator instead of a SetMutator");
088: }
089: ((SetMutator) this .mutator).resolveCollision(this , set,
090: (Set) c, intersects);
091: if (CollectionUtils.intersection(set, c).size() > 0) {
092: throw new IllegalArgumentException(
093: "Attempt to add illegal entry unresolved by SetMutator.resolveCollision()");
094: }
095: }
096: }
097: super .addComposited(new Collection[] { c });
098: }
099:
100: /**
101: * Add two sets to this composite
102: *
103: * @throws IllegalArgumentException if c or d does not implement java.util.Set
104: */
105: public synchronized void addComposited(Collection c, Collection d) {
106: if (!(c instanceof Set))
107: throw new IllegalArgumentException(
108: "Argument must implement java.util.Set");
109: if (!(d instanceof Set))
110: throw new IllegalArgumentException(
111: "Argument must implement java.util.Set");
112: this .addComposited(new Set[] { (Set) c, (Set) d });
113: }
114:
115: /**
116: * Add an array of sets to this composite
117: * @param comps
118: * @throws IllegalArgumentException if any of the collections in comps do not implement Set
119: */
120: public synchronized void addComposited(Collection[] comps) {
121: for (int i = comps.length - 1; i >= 0; --i) {
122: this .addComposited(comps[i]);
123: }
124: }
125:
126: /**
127: * This can receive either a <code>CompositeCollection.CollectionMutator</code>
128: * or a <code>CompositeSet.SetMutator</code>. If a
129: * <code>CompositeCollection.CollectionMutator</code> is used than conflicts when adding
130: * composited sets will throw IllegalArgumentException
131: * <p>
132: */
133: public void setMutator(CollectionMutator mutator) {
134: super .setMutator(mutator);
135: }
136:
137: /* Set operations */
138:
139: /**
140: * If a <code>CollectionMutator</code> is defined for this CompositeSet then this
141: * method will be called anyway.
142: *
143: * @param obj Object to be removed
144: * @return true if the object is removed, false otherwise
145: */
146: public boolean remove(Object obj) {
147: for (Iterator i = this .getCollections().iterator(); i.hasNext();) {
148: Set set = (Set) i.next();
149: if (set.contains(obj))
150: return set.remove(obj);
151: }
152: return false;
153: }
154:
155: /**
156: * @see Set#equals
157: */
158: public boolean equals(Object obj) {
159: if (obj instanceof Set) {
160: Set set = (Set) obj;
161: if (set.containsAll(this ) && set.size() == this .size()) {
162: return true;
163: }
164: }
165: return false;
166: }
167:
168: /**
169: * @see Set#hashCode
170: */
171: public int hashCode() {
172: int code = 0;
173: for (Iterator i = this .iterator(); i.hasNext();) {
174: Object next = i.next();
175: code += (next != null ? next.hashCode() : 0);
176: }
177: return code;
178: }
179:
180: /**
181: * Define callbacks for mutation operations.
182: * <p>
183: * Defining remove() on implementations of SetMutator is pointless
184: * as they are never called by CompositeSet.
185: */
186: public static interface SetMutator extends
187: CompositeCollection.CollectionMutator {
188: /**
189: * <p>
190: * Called when a Set is added to the CompositeSet and there is a
191: * collision between existing and added sets.
192: * </p>
193: * <p>
194: * If <code>added</code> and <code>existing</code> still have any intersects
195: * after this method returns an IllegalArgumentException will be thrown.
196: * </p>
197: * @param comp The CompositeSet being modified
198: * @param existing The Set already existing in the composite
199: * @param added the Set being added to the composite
200: * @param intersects the intersection of th existing and added sets
201: */
202: public void resolveCollision(CompositeSet comp, Set existing,
203: Set added, Collection intersects);
204: }
205: }
|