KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > databinding > observable > set > UnionSet


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.core.databinding.observable.set;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.core.databinding.observable.Diffs;
22 import org.eclipse.core.databinding.observable.Realm;
23 import org.eclipse.core.internal.databinding.observable.IStalenessConsumer;
24 import org.eclipse.core.internal.databinding.observable.StalenessTracker;
25
26 /**
27  * Represents a set consisting of the union of elements from one or more other
28  * sets. This object does not need to be explicitly disposed. If nobody is
29  * listening to the UnionSet, the set will remove its listeners.
30  *
31  * <p>
32  * This class is thread safe. All state accessing methods must be invoked from
33  * the {@link Realm#isCurrent() current realm}. Methods for adding and removing
34  * listeners may be invoked from any thread.
35  * </p>
36  *
37  * @since 1.0
38  */

39 public final class UnionSet extends ObservableSet {
40
41     /**
42      * child sets
43      */

44     private IObservableSet[] childSets;
45
46     private boolean stale = false;
47
48     /**
49      * Map of elements onto Integer reference counts. This map is constructed
50      * when the first listener is added to the union set. Null if nobody is
51      * listening to the UnionSet.
52      */

53     private HashMap JavaDoc refCounts = null;
54
55     private StalenessTracker stalenessTracker;
56
57     /**
58      * @param childSets
59      */

60     public UnionSet(IObservableSet[] childSets) {
61         super(childSets[0].getRealm(), null, childSets[0].getElementType());
62         this.childSets = childSets;
63         this.stalenessTracker = new StalenessTracker(childSets,
64                 stalenessConsumer);
65     }
66
67     private ISetChangeListener childSetChangeListener = new ISetChangeListener() {
68         public void handleSetChange(SetChangeEvent event) {
69             processAddsAndRemoves(event.diff.getAdditions(), event.diff.getRemovals());
70         }
71     };
72
73     private IStalenessConsumer stalenessConsumer = new IStalenessConsumer() {
74         public void setStale(boolean stale) {
75             boolean oldStale = UnionSet.this.stale;
76             UnionSet.this.stale = stale;
77             if (stale && !oldStale) {
78                 fireStale();
79             }
80         }
81     };
82
83     public boolean isStale() {
84         checkRealm();
85         if (refCounts != null) {
86             return stale;
87         }
88
89         for (int i = 0; i < childSets.length; i++) {
90             IObservableSet childSet = childSets[i];
91
92             if (childSet.isStale()) {
93                 return true;
94             }
95         }
96         return false;
97     }
98
99     private void processAddsAndRemoves(Set JavaDoc adds, Set JavaDoc removes) {
100         Set JavaDoc addsToFire = new HashSet JavaDoc();
101         Set JavaDoc removesToFire = new HashSet JavaDoc();
102
103         for (Iterator JavaDoc iter = adds.iterator(); iter.hasNext();) {
104             Object JavaDoc added = iter.next();
105
106             Integer JavaDoc refCount = (Integer JavaDoc) refCounts.get(added);
107             if (refCount == null) {
108                 refCounts.put(added, new Integer JavaDoc(1));
109                 addsToFire.add(added);
110             } else {
111                 int refs = refCount.intValue();
112                 refCount = new Integer JavaDoc(refs + 1);
113                 refCounts.put(added, refCount);
114             }
115         }
116
117         for (Iterator JavaDoc iter = removes.iterator(); iter.hasNext();) {
118             Object JavaDoc removed = iter.next();
119
120             Integer JavaDoc refCount = (Integer JavaDoc) refCounts.get(removed);
121             if (refCount != null) {
122                 int refs = refCount.intValue();
123                 if (refs <= 1) {
124                     removesToFire.add(removed);
125                     refCounts.remove(removed);
126                 } else {
127                     refCount = new Integer JavaDoc(refCount.intValue() - 1);
128                     refCounts.put(removed, refCount);
129                 }
130             }
131         }
132
133         // just in case the removes overlapped with the adds
134
addsToFire.removeAll(removesToFire);
135
136         if (addsToFire.size() > 0 || removesToFire.size() > 0) {
137             fireSetChange(Diffs.createSetDiff(addsToFire, removesToFire));
138         }
139     }
140
141     protected void firstListenerAdded() {
142         super.firstListenerAdded();
143
144         refCounts = new HashMap JavaDoc();
145         for (int i = 0; i < childSets.length; i++) {
146             IObservableSet next = childSets[i];
147             next.addSetChangeListener(childSetChangeListener);
148             incrementRefCounts(next);
149         }
150         stalenessTracker = new StalenessTracker(childSets, stalenessConsumer);
151         setWrappedSet(refCounts.keySet());
152     }
153
154     protected void lastListenerRemoved() {
155         super.lastListenerRemoved();
156
157         for (int i = 0; i < childSets.length; i++) {
158             IObservableSet next = childSets[i];
159
160             next.removeSetChangeListener(childSetChangeListener);
161             stalenessTracker.removeObservable(next);
162         }
163         refCounts = null;
164         stalenessTracker = null;
165         setWrappedSet(null);
166     }
167
168     private ArrayList JavaDoc incrementRefCounts(Collection JavaDoc added) {
169         ArrayList JavaDoc adds = new ArrayList JavaDoc();
170
171         for (Iterator JavaDoc iter = added.iterator(); iter.hasNext();) {
172             Object JavaDoc next = iter.next();
173
174             Integer JavaDoc refCount = (Integer JavaDoc) refCounts.get(next);
175             if (refCount == null) {
176                 adds.add(next);
177                 refCount = new Integer JavaDoc(1);
178                 refCounts.put(next, refCount);
179             } else {
180                 refCount = new Integer JavaDoc(refCount.intValue() + 1);
181                 refCounts.put(next, refCount);
182             }
183         }
184         return adds;
185     }
186
187     protected void getterCalled() {
188         super.getterCalled();
189         if (refCounts == null) {
190             // no listeners, recompute
191
setWrappedSet(computeElements());
192         }
193     }
194
195     private Set JavaDoc computeElements() {
196         // If there is no cached value, compute the union from scratch
197
if (refCounts == null) {
198             Set JavaDoc result = new HashSet JavaDoc();
199             for (int i = 0; i < childSets.length; i++) {
200                 result.addAll(childSets[i]);
201             }
202             return result;
203         }
204
205         // Else there is a cached value. Return it.
206
return refCounts.keySet();
207     }
208
209 }
210
Popular Tags