KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > bridge > EventQueue


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.bridge;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.util.*;
24
25 import org.openide.src.*;
26
27 /**
28  * Event/change queue that collects modification events made to a model in one locked
29  * level of operations. After the model is unlocked, the events are merged up to the
30  * parent. Upon unlocking the model entirely, the top-level queue will contain
31  * both PropertyChangeEvents generated during the model locked operation and summary
32  * changes that should be fired to CommitListeners.
33  *
34  * @author sdedic
35  * @version
36  */

37 class EventQueue extends Object JavaDoc {
38     /**
39      * The queue contains a stream of PropertyChangeEvents fired from locked operation(s), in the
40      * order of their creation/firing.
41      */

42     Collection eventQueue;
43     /**
44      * Map of elements -> event queue. Events are sorted by their creation time in the
45      * queue; new elements are appended at the end.
46      */

47     Map sourceMap;
48
49     /**
50      * Map that collects elements that have been changes and their corresponding
51      * original properties (in a form of cloned element).
52      */

53     Map changedElements;
54     
55     /**
56      * Set that collects new elements.
57      */

58     Set newElements;
59     
60     /**
61      * Set that collects elements that have been removed.
62      */

63     Set removedElements;
64     
65     /**
66      * The parent event queue that collects events originating in the outer lock.
67      */

68     EventQueue parent;
69     
70     private boolean firingEvents;
71     
72     /** Constructs an event queue, optionally linking it to a parent event queue.
73      */

74     public EventQueue(EventQueue parent) {
75         this.parent = parent;
76     }
77
78     /**
79      * Creates a notice that an element was changed. If the element is not registered
80      * with the event queue, it is cloned to obtain the old version and put into the
81      * element queue.
82      */

83     public void elementChanged(Element el, Element oldVersion) {
84         if (containsChanges(el))
85             return;
86         if (changedElements == null)
87             changedElements = new HashMap(17);
88         changedElements.put(el, oldVersion);
89     }
90
91     /**
92      * Helper method that creates a notice that an element was changed. The passed
93      * impl is asked to clone itself, if the element is not found in the changed
94      * map already.
95      */

96     public void elementChanged(ElementImpl impl) {
97         Element el = impl.getElement();
98         if (containsChanges(el))
99             return;
100         if (changedElements == null)
101             changedElements = new HashMap(17);
102         changedElements.put(el, impl.cloneSelf());
103     }
104     
105     /**
106      * Creates a notice that an element was created.
107      */

108     public void elementCreated(Element el) {
109         if (newElements == null)
110             newElements = new HashSet(17);
111         newElements.add(el);
112     }
113     
114     /**
115      * Creates a notice that the element was removed.
116      */

117     public void elementRemoved(Element el) {
118         if (newElements != null)
119             newElements.remove(el);
120         if (removedElements == null)
121             removedElements = new HashSet(17);
122         removedElements.add(el);
123     }
124     
125     /**
126      * Determines whether there's already a change notification for the passed element.
127      * @return true, if the element was already reported as changed.
128      */

129     public boolean containsChanges(Element el) {
130         if (newElements != null &&
131             newElements.contains(el))
132             return true;
133         if (changedElements != null &&
134             changedElements.containsKey(el))
135             return true;
136         // PENDING: investigate efficiency of the cloning in nested transaction. If
137
// the cost is too high, then the parent need to be checked for the same conditions
138
// too before returning false.
139
return false;
140     }
141     
142     /**
143      * Records a property change event that occurs on a particular element. The change
144      * is recorded into the element's queue.
145      */

146     public synchronized void addPropertyChange(ElementImpl impl, PropertyChangeEvent JavaDoc evt) {
147         Object JavaDoc source = impl;
148         Collection queue = getQueue(source);
149         queue.add(evt);
150         if (eventQueue == null)
151             eventQueue = new LinkedList();
152         eventQueue.add(impl);
153         eventQueue.add(evt);
154     }
155     
156     /**
157      * Master method that fires PropertyChange events from the queues collected so far.
158      */

159     public void fireEvents() {
160         synchronized (this) {
161             if (firingEvents)
162                 return;
163             firingEvents = true;
164         }
165         for (Collection col = pollEventQueue(); col != null && !col.isEmpty(); col = pollEventQueue()) {
166             for (Iterator it = col.iterator(); it.hasNext(); ) {
167                 ElementImpl impl = (ElementImpl)it.next();
168                 PropertyChangeEvent JavaDoc evt = (PropertyChangeEvent JavaDoc)it.next();
169                 impl.firePropertyChangeEvent(evt);
170             }
171         }
172         synchronized (this) {
173             firingEvents = false;
174         }
175     }
176     
177     private void fireElementEvents(ElementImpl impl, Collection eventQueue) {
178         for (Iterator it = eventQueue.iterator(); it.hasNext(); ) {
179             PropertyChangeEvent JavaDoc evt = (PropertyChangeEvent JavaDoc)it.next();
180             impl.firePropertyChangeEvent(evt);
181         }
182     }
183     
184     private synchronized Map pollEvents() {
185         Map m = sourceMap;
186         sourceMap = null;
187         return m;
188     }
189     
190     private synchronized Collection pollEventQueue() {
191         Collection c = eventQueue;
192         eventQueue = null;
193         sourceMap = null;
194         return c;
195     }
196     
197     private synchronized Collection getQueue(Object JavaDoc source) {
198         Collection c;
199         
200         if (sourceMap == null) {
201             sourceMap = new HashMap(17);
202             c = null;
203         } else {
204             c = (Collection)sourceMap.get(source);
205         }
206         
207         if (c != null)
208             return c;
209         c = new LinkedList();
210         sourceMap.put(source, c);
211         return c;
212     }
213     
214     /**
215      * Fixates change events - for each changed element, it creates a snapshot of it to
216      * record its exact state at the time of unlock for the reference of listeners that
217      * are contacted out of the locked exec region.
218      */

219     public void fixupChanges() {
220         if (changedElements == null)
221             return;
222         for (Iterator it = changedElements.entrySet().iterator(); it.hasNext(); ) {
223             Map.Entry en = (Map.Entry)it.next();
224             Element source = (Element)en.getKey();
225             Element oldSnapshot = (Element)en.getValue();
226             
227             ElementImpl impl = (ElementImpl)source.getCookie(ElementImpl.class);
228             // impl != null!
229
Element newSnapshot = impl.cloneSelf();
230             
231             en.setValue(new Object JavaDoc[] { oldSnapshot, newSnapshot });
232         }
233     }
234     
235     private void mergeChild(EventQueue other) {
236         if (other.removedElements != null) {
237             // discard any information about elements that were previously
238
// created. Discard all such elements from the removed set
239
if (newElements != null) {
240                 Collection copy = new HashSet(other.removedElements);
241                 other.removedElements.removeAll(newElements);
242                 newElements.removeAll(copy);
243             }
244             if (removedElements == null)
245                 removedElements = other.removedElements;
246             else
247                 removedElements.addAll(other.removedElements);
248         }
249         if (other.newElements != null) {
250             if (newElements == null)
251                 newElements = other.newElements;
252             else
253                 newElements.addAll(other.newElements);
254         }
255         if (other.changedElements != null) {
256             if (newElements != null) {
257                 other.changedElements.keySet().removeAll(newElements);
258             }
259             if (changedElements != null)
260                 other.changedElements.putAll(changedElements);
261             changedElements = other.changedElements;
262         }
263         if (other.sourceMap != null) {
264             mergePropertyEventMaps(other.sourceMap);
265         }
266         if (other.eventQueue != null) {
267             if (eventQueue == null)
268                 eventQueue = other.eventQueue;
269             else
270                 eventQueue.addAll(other.eventQueue);
271         }
272     }
273
274     /**
275      * Merges the otherMap of property changes events into this one; the events are
276      * merged so that they are appended at the end of the existing queue, if the
277      * element's queue already exists, or the whole queue for an element is copied
278      * into out map.
279      */

280     private synchronized void mergePropertyEventMaps(Map otherMap) {
281         if (sourceMap == null) {
282             sourceMap = otherMap;
283             return;
284         }
285         for (Iterator otherIterator = otherMap.entrySet().iterator();
286             otherIterator.hasNext(); ) {
287             Map.Entry otherEntry = (Map.Entry)otherIterator.next();
288             Object JavaDoc otherKey = otherEntry.getKey();
289             Collection myQueue = (Collection)sourceMap.get(otherKey);
290
291             if (myQueue == null)
292                 sourceMap.put(otherKey, otherEntry.getValue());
293             else
294                 myQueue.addAll((Collection)otherEntry.getValue());
295         }
296     }
297
298     /**
299      * Merges all information in this queue into the parent one, if there's any.
300      * The operation is destructive for this instance.
301      */

302     public void mergeToParent() {
303         if (parent == null)
304             return;
305         parent.mergeChild(this);
306     }
307     
308     public final Map getChangedElements() {
309         return this.changedElements;
310     }
311     
312     public final Set getCreatedElements() {
313         return this.newElements;
314     }
315     
316     public final Set getRemovedElements() {
317         return this.removedElements;
318     }
319     
320     public final EventQueue getParent() {
321         return this.parent;
322     }
323     
324     public void clearSummary() {
325         newElements = removedElements = null;
326         changedElements = null;
327     }
328     
329     public boolean isEmpty() {
330         if (newElements != null && !newElements.isEmpty())
331             return false;
332         if (changedElements != null && !changedElements.isEmpty())
333             return false;
334         return removedElements == null || removedElements.isEmpty();
335     }
336 }
337
Popular Tags