KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > wings > util > WeakPropertyChangeSupport


1 /*
2  * $Id: WeakPropertyChangeSupport.java,v 1.3 2004/12/01 07:54:30 hengels Exp $
3  * Copyright 2000,2005 wingS development team.
4  *
5  * This file is part of wingS (http://www.j-wings.org).
6  *
7  * wingS is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1
10  * of the License, or (at your option) any later version.
11  *
12  * Please see COPYING for the complete licence.
13  */

14 package org.wings.util;
15
16 import java.beans.PropertyChangeEvent JavaDoc;
17 import java.beans.PropertyChangeListener JavaDoc;
18 import java.lang.ref.ReferenceQueue JavaDoc;
19 import java.lang.ref.WeakReference JavaDoc;
20
21 /**
22  * This is a utility class that can be used by beans that support bound
23  * properties. You can use an instance of this class as a member field
24  * of your bean and delegate various work to it.
25  * <p/>
26  * This class is serializable. When it is serialized it will save
27  * (and restore) any listeners that are themselves serializable. Any
28  * non-serializable listeners will be skipped during serialization.
29  *
30  * @author <a HREF="mailto:haaf@mercatis.de">Holger Engels</a>
31  * @version $Revision: 1.3 $
32  */

33 public class WeakPropertyChangeSupport {
34     /**
35      * Constructs a <code>WeakPropertyChangeSupport</code> object.
36      *
37      * @param sourceBean The bean to be given as the source for any events.
38      */

39     public WeakPropertyChangeSupport(Object JavaDoc sourceBean) {
40         if (sourceBean == null) {
41             throw new NullPointerException JavaDoc();
42         }
43         source = sourceBean;
44     }
45
46     /**
47      * Add a PropertyChangeListener to the listener list.
48      * The listener is registered for all properties.
49      *
50      * @param listener The PropertyChangeListener to be added
51      */

52     public synchronized void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
53         if (listeners == null) {
54             listeners = new java.util.LinkedList JavaDoc();
55         } else
56             processQueue();
57         listeners.add(WeakEntry.create(listener, queue));
58     }
59
60     /**
61      * Remove a PropertyChangeListener from the listener list.
62      * This removes a PropertyChangeListener that was registered
63      * for all properties.
64      *
65      * @param listener The PropertyChangeListener to be removed
66      */

67     public synchronized void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
68         if (listeners == null) {
69             return;
70         } else
71             processQueue();
72         listeners.remove(WeakEntry.create(listener));
73     }
74
75     /**
76      * Add a PropertyChangeListener for a specific property. The listener
77      * will be invoked only when a call on firePropertyChange names that
78      * specific property.
79      *
80      * @param propertyName The name of the property to listen on.
81      * @param listener The PropertyChangeListener to be added
82      */

83     public synchronized void addPropertyChangeListener(String JavaDoc propertyName,
84                                                        PropertyChangeListener JavaDoc listener) {
85         if (children == null) {
86             children = new java.util.WeakHashMap JavaDoc();
87         }
88         WeakPropertyChangeSupport child = (WeakPropertyChangeSupport) children.get(propertyName);
89         if (child == null) {
90             child = new WeakPropertyChangeSupport(source);
91             children.put(propertyName, child);
92         }
93         child.addPropertyChangeListener(listener);
94     }
95
96     /**
97      * Remove a PropertyChangeListener for a specific property.
98      *
99      * @param propertyName The name of the property that was listened on.
100      * @param listener The PropertyChangeListener to be removed
101      */

102     public synchronized void removePropertyChangeListener(String JavaDoc propertyName,
103                                                           PropertyChangeListener JavaDoc listener) {
104         if (children == null) {
105             return;
106         }
107         WeakPropertyChangeSupport child = (WeakPropertyChangeSupport) children.get(propertyName);
108         if (child == null) {
109             return;
110         }
111         child.removePropertyChangeListener(listener);
112     }
113
114     /**
115      * Report a bound property update to any registered listeners.
116      * No event is fired if old and new are equal and non-null.
117      *
118      * @param propertyName The programmatic name of the property
119      * that was changed.
120      * @param oldValue The old value of the property.
121      * @param newValue The new value of the property.
122      */

123     public void firePropertyChange(String JavaDoc propertyName, Object JavaDoc oldValue, Object JavaDoc newValue) {
124         if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
125             return;
126         }
127
128         java.util.LinkedList JavaDoc targets = null;
129         WeakPropertyChangeSupport child = null;
130         synchronized (this) {
131             if (listeners != null) {
132                 targets = (java.util.LinkedList JavaDoc) listeners.clone();
133             }
134             if (children != null && propertyName != null) {
135                 child = (WeakPropertyChangeSupport) children.get(propertyName);
136             }
137         }
138
139         PropertyChangeEvent JavaDoc evt = new PropertyChangeEvent JavaDoc(source, propertyName, oldValue, newValue);
140
141         if (targets != null) {
142             for (int i = 0; i < targets.size(); i++) {
143                 WeakEntry entry = (WeakEntry) targets.get(i);
144                 PropertyChangeListener JavaDoc target = (PropertyChangeListener JavaDoc) entry.get();
145                 if (target != null)
146                     target.propertyChange(evt);
147             }
148         }
149
150         if (child != null) {
151             child.firePropertyChange(evt);
152         }
153     }
154
155     /**
156      * Report an int bound property update to any registered listeners.
157      * No event is fired if old and new are equal and non-null.
158      * <p/>
159      * This is merely a convenience wrapper around the more general
160      * firePropertyChange method that takes Object values.
161      *
162      * @param propertyName The programmatic name of the property
163      * that was changed.
164      * @param oldValue The old value of the property.
165      * @param newValue The new value of the property.
166      */

167     public void firePropertyChange(String JavaDoc propertyName, int oldValue, int newValue) {
168         if (oldValue == newValue) {
169             return;
170         }
171         firePropertyChange(propertyName, new Integer JavaDoc(oldValue), new Integer JavaDoc(newValue));
172     }
173
174
175     /**
176      * Report a boolean bound property update to any registered listeners.
177      * No event is fired if old and new are equal and non-null.
178      * <p/>
179      * This is merely a convenience wrapper around the more general
180      * firePropertyChange method that takes Object values.
181      *
182      * @param propertyName The programmatic name of the property
183      * that was changed.
184      * @param oldValue The old value of the property.
185      * @param newValue The new value of the property.
186      */

187     public void firePropertyChange(String JavaDoc propertyName,
188                                    boolean oldValue, boolean newValue) {
189         if (oldValue == newValue) {
190             return;
191         }
192         firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
193     }
194
195     /**
196      * Fire an existing PropertyChangeEvent to any registered listeners.
197      * No event is fired if the given event's old and new values are
198      * equal and non-null.
199      *
200      * @param evt The PropertyChangeEvent object.
201      */

202     public void firePropertyChange(PropertyChangeEvent JavaDoc evt) {
203         Object JavaDoc oldValue = evt.getOldValue();
204         Object JavaDoc newValue = evt.getNewValue();
205         String JavaDoc propertyName = evt.getPropertyName();
206         if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
207             return;
208         }
209
210         java.util.LinkedList JavaDoc targets = null;
211         WeakPropertyChangeSupport child = null;
212         synchronized (this) {
213             if (listeners != null) {
214                 targets = (java.util.LinkedList JavaDoc) listeners.clone();
215             }
216             if (children != null && propertyName != null) {
217                 child = (WeakPropertyChangeSupport) children.get(propertyName);
218             }
219         }
220
221         if (targets != null) {
222             for (int i = 0; i < targets.size(); i++) {
223                 WeakEntry entry = (WeakEntry) targets.get(i);
224                 PropertyChangeListener JavaDoc target = (PropertyChangeListener JavaDoc) entry.get();
225                 if (target != null)
226                     target.propertyChange(evt);
227             }
228         }
229         if (child != null) {
230             child.firePropertyChange(evt);
231         }
232     }
233
234     /**
235      * Check if there are any listeners for a specific property.
236      *
237      * @param propertyName the property name.
238      * @return true if there are ore or more listeners for the given property
239      */

240     public synchronized boolean hasListeners(String JavaDoc propertyName) {
241         if (listeners != null && !listeners.isEmpty()) {
242             // there is a generic listener
243
return true;
244         }
245         if (children != null) {
246             WeakPropertyChangeSupport child = (WeakPropertyChangeSupport) children.get(propertyName);
247             if (child != null && child.listeners != null) {
248                 return !child.listeners.isEmpty();
249             }
250         }
251         return false;
252     }
253
254     /**
255      * "listeners" lists all the generic listeners.
256      * <p/>
257      * This is transient - its state is written in the writeObject method.
258      */

259     transient private java.util.LinkedList JavaDoc listeners;
260
261     /**
262      * Hashtable for managing listeners for specific properties.
263      * Maps property names to WeakPropertyChangeSupport objects.
264      *
265      * @serial
266      */

267     private java.util.WeakHashMap JavaDoc children;
268
269     /**
270      * The object to be provided as the "source" for any generated events.
271      *
272      * @serial
273      */

274     private Object JavaDoc source;
275
276
277     private ReferenceQueue JavaDoc queue = new ReferenceQueue JavaDoc();
278
279     /**
280      * Remove all invalidated entries from the map, that is, remove all entries
281      * whose keys have been discarded. This method should be invoked once by
282      * each public mutator in this class. We don't invoke this method in
283      * public accessors because that can lead to surprising
284      * ConcurrentModificationExceptions.
285      */

286     private void processQueue() {
287         WeakEntry wk;
288         while ((wk = (WeakEntry) queue.poll()) != null) {
289             listeners.remove(wk);
290         }
291     }
292
293     static private class WeakEntry extends WeakReference JavaDoc {
294         private int hash; /* Hashcode of key, stored here since the key
295         may be tossed by the GC */

296
297         private WeakEntry(Object JavaDoc k) {
298             super(k);
299             hash = k.hashCode();
300         }
301
302         private static WeakEntry create(Object JavaDoc k) {
303             if (k == null)
304                 return null;
305             else
306                 return new WeakEntry(k);
307         }
308
309         private WeakEntry(Object JavaDoc k, ReferenceQueue JavaDoc q) {
310             super(k, q);
311             hash = k.hashCode();
312         }
313
314         private static WeakEntry create(Object JavaDoc k, ReferenceQueue JavaDoc q) {
315             if (k == null)
316                 return null;
317             else
318                 return new WeakEntry(k, q);
319         }
320
321         /* A WeakEntry is equal to another WeakEntry iff they both refer to objects
322          * that are, in turn, equal according to their own equals methods */

323         public boolean equals(Object JavaDoc o) {
324             if (this == o) return true;
325             if (!(o instanceof WeakEntry)) return false;
326             Object JavaDoc t = this.get();
327             Object JavaDoc u = ((WeakEntry) o).get();
328             if ((t == null) || (u == null)) return false;
329             if (t == u) return true;
330             return t.equals(u);
331         }
332
333         public int hashCode() {
334             return hash;
335         }
336     }
337 }
338
339
340
Popular Tags