1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.collections.set;
  17. import java.util.Collection;
  18. import java.util.Iterator;
  19. import java.util.Set;
  20. import org.apache.commons.collections.CollectionUtils;
  21. import org.apache.commons.collections.collection.CompositeCollection;
  22. /**
  23. * Decorates a set of other sets to provide a single unified view.
  24. * <p>
  25. * Changes made to this set will actually be made on the decorated set.
  26. * Add and remove operations require the use of a pluggable strategy. If no
  27. * strategy is provided then add and remove are unsupported.
  28. *
  29. * @since Commons Collections 3.0
  30. * @version $Revision: 1.3 $ $Date: 2004/02/18 01:14:27 $
  31. *
  32. * @author Brian McCallister
  33. */
  34. public class CompositeSet extends CompositeCollection implements Set {
  35. /**
  36. * Create an empty CompositeSet
  37. */
  38. public CompositeSet() {
  39. super();
  40. }
  41. /**
  42. * Create a CompositeSet with just <code>set</code> composited
  43. * @param set The initial set in the composite
  44. */
  45. public CompositeSet(Set set) {
  46. super(set);
  47. }
  48. /**
  49. * Create a composite set with sets as the initial set of composited Sets
  50. */
  51. public CompositeSet(Set[] sets) {
  52. super(sets);
  53. }
  54. /**
  55. * Add a Set to this composite
  56. *
  57. * @param c Must implement Set
  58. * @throws IllegalArgumentException if c does not implement java.util.Set
  59. * or if a SetMutator is set, but fails to resolve a collision
  60. * @throws UnsupportedOperationException if there is no SetMutator set, or
  61. * a CollectionMutator is set instead of a SetMutator
  62. * @see org.apache.commons.collections.collection.CompositeCollection.CollectionMutator
  63. * @see SetMutator
  64. */
  65. public synchronized void addComposited(Collection c) {
  66. if (!(c instanceof Set)) {
  67. throw new IllegalArgumentException("Collections added must implement java.util.Set");
  68. }
  69. for (Iterator i = this.getCollections().iterator(); i.hasNext();) {
  70. Set set = (Set) i.next();
  71. Collection intersects = CollectionUtils.intersection(set, c);
  72. if (intersects.size() > 0) {
  73. if (this.mutator == null) {
  74. throw new UnsupportedOperationException(
  75. "Collision adding composited collection with no SetMutator set");
  76. }
  77. else if (!(this.mutator instanceof SetMutator)) {
  78. throw new UnsupportedOperationException(
  79. "Collision adding composited collection to a CompositeSet with a CollectionMutator instead of a SetMutator");
  80. }
  81. ((SetMutator) this.mutator).resolveCollision(this, set, (Set) c, intersects);
  82. if (CollectionUtils.intersection(set, c).size() > 0) {
  83. throw new IllegalArgumentException(
  84. "Attempt to add illegal entry unresolved by SetMutator.resolveCollision()");
  85. }
  86. }
  87. }
  88. super.addComposited(new Collection[]{c});
  89. }
  90. /**
  91. * Add two sets to this composite
  92. *
  93. * @throws IllegalArgumentException if c or d does not implement java.util.Set
  94. */
  95. public synchronized void addComposited(Collection c, Collection d) {
  96. if (!(c instanceof Set)) throw new IllegalArgumentException("Argument must implement java.util.Set");
  97. if (!(d instanceof Set)) throw new IllegalArgumentException("Argument must implement java.util.Set");
  98. this.addComposited(new Set[]{(Set) c, (Set) d});
  99. }
  100. /**
  101. * Add an array of sets to this composite
  102. * @param comps
  103. * @throws IllegalArgumentException if any of the collections in comps do not implement Set
  104. */
  105. public synchronized void addComposited(Collection[] comps) {
  106. for (int i = comps.length - 1; i >= 0; --i) {
  107. this.addComposited(comps[i]);
  108. }
  109. }
  110. /**
  111. * This can receive either a <code>CompositeCollection.CollectionMutator</code>
  112. * or a <code>CompositeSet.SetMutator</code>. If a
  113. * <code>CompositeCollection.CollectionMutator</code> is used than conflicts when adding
  114. * composited sets will throw IllegalArgumentException
  115. * <p>
  116. */
  117. public void setMutator(CollectionMutator mutator) {
  118. super.setMutator(mutator);
  119. }
  120. /* Set operations */
  121. /**
  122. * If a <code>CollectionMutator</code> is defined for this CompositeSet then this
  123. * method will be called anyway.
  124. *
  125. * @param obj Object to be removed
  126. * @return true if the object is removed, false otherwise
  127. */
  128. public boolean remove(Object obj) {
  129. for (Iterator i = this.getCollections().iterator(); i.hasNext();) {
  130. Set set = (Set) i.next();
  131. if (set.contains(obj)) return set.remove(obj);
  132. }
  133. return false;
  134. }
  135. /**
  136. * @see Set#equals
  137. */
  138. public boolean equals(Object obj) {
  139. if (obj instanceof Set) {
  140. Set set = (Set) obj;
  141. if (set.containsAll(this) && set.size() == this.size()) {
  142. return true;
  143. }
  144. }
  145. return false;
  146. }
  147. /**
  148. * @see Set#hashCode
  149. */
  150. public int hashCode() {
  151. int code = 0;
  152. for (Iterator i = this.iterator(); i.hasNext();) {
  153. Object next = i.next();
  154. code += (next != null ? next.hashCode() : 0);
  155. }
  156. return code;
  157. }
  158. /**
  159. * Define callbacks for mutation operations.
  160. * <p>
  161. * Defining remove() on implementations of SetMutator is pointless
  162. * as they are never called by CompositeSet.
  163. */
  164. public static interface SetMutator extends CompositeCollection.CollectionMutator {
  165. /**
  166. * <p>
  167. * Called when a Set is added to the CompositeSet and there is a
  168. * collision between existing and added sets.
  169. * </p>
  170. * <p>
  171. * If <code>added</code> and <code>existing</code> still have any intersects
  172. * after this method returns an IllegalArgumentException will be thrown.
  173. * </p>
  174. * @param comp The CompositeSet being modified
  175. * @param existing The Set already existing in the composite
  176. * @param added the Set being added to the composite
  177. * @param intersects the intersection of th existing and added sets
  178. */
  179. public void resolveCollision(CompositeSet comp, Set existing, Set added, Collection intersects);
  180. }
  181. }