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