KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > WeakListeners


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 package org.openide.util;
20
21 import java.awt.event.FocusListener JavaDoc;
22
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.VetoableChangeListener JavaDoc;
25
26 import java.util.EventListener JavaDoc;
27
28 import javax.swing.event.ChangeListener JavaDoc;
29 import javax.swing.event.DocumentListener JavaDoc;
30
31
32 /** A generic weak listener factory.
33  * Creates a weak implementation of a listener of type <CODE>lType</CODE>.
34  *
35  * In the following examples, I'll use following naming:<BR>
36  * There are four objects involved in weak listener usage:<UL>
37  * <LI>The event <em>source</em> object
38  * <LI>The <em>observer</em> - object that wants to listen on <em>source</em>
39  * <LI>The <em>listener</em> - the implementation of the corresponding
40  * <code>*Listener</code> interface, sometimes the observer itself but
41  * often some observer's inner class delegating the events to the observer.
42  * <LI>The <em>weak listener</em> implementation.
43  * </UL>
44  * The examples are written for ChangeListener. The <code>Utilities</code>
45  * have factory methods for the most common listeners used in NetBeans
46  * and also one universal factory method you can use for other listeners.
47  *
48  * <H2>How to use it:</H2>
49  * Here is an example how to write a listener/observer and make it listen
50  * on some source:
51  * <pre>
52  * public class ListenerObserver implements ChangeListener {
53  * private void registerTo(Source source) {
54  * source.addChangeListener({@link
55                 #change(javax.swing.event.ChangeListener, java.lang.Object)
56  * WeakListeners.changeListener} (this, source));
57  * }
58  *
59  * public void stateChanged(ChangeEvent e) {
60  * doSomething();
61  * }
62  * }
63  * </pre>
64  * You can also factor out the listener implementation to some other class
65  * if you don't want to expose the stateChanged method (better technique):
66  * <pre>
67  * public class Observer {
68  * <b>private Listener listener;</b>
69  *
70  * private void registerTo(Source source) {
71  * <b>listener = new Listener()</b>;
72  * source.addChangeListener({@link
73                 #change(javax.swing.event.ChangeListener, java.lang.Object)
74  * WeakListeners.change} (listener, source));
75  * }
76  *
77  * private class Listener implements ChangeListener {
78  * public void stateChanged(ChangeEvent e) {
79  * doSomething();
80  * }
81  * }
82  * }
83  * </pre>
84  * Note: The observer keeps the reference to the listener, it won't work
85  * otherwise, see below.
86  *
87  * <P>You can also use the universal factory for other listeners:
88  * <pre>
89  * public class Observer implements SomeListener {
90  * private void registerTo(Source source) {
91  * source.addSomeListener((SomeListener){@link
92  * #create(java.lang.Class, java.util.EventListener, java.lang.Object)
93  * WeakListeners.create} (
94  * SomeListener.class, this, source));
95  * }
96  *
97  * public void someEventHappened(SomeEvent e) {
98  * doSomething();
99  * }
100  * }
101  * </pre>
102  *
103  * <H2>How to <font color=red>not</font> use it:</H2>
104  * Here are examples of a common mistakes done when using <em>weak listener</em>:
105  * <pre>
106  * public class Observer {
107  * private void registerTo(Source source) {
108  * source.addChangeListener(WeakListeners.change(<b>new Listener()</b>, source));
109  * }
110  *
111  * private class Listener implements ChangeListener {
112  * public void stateChanged(ChangeEvent e) {
113  * doSomething();
114  * }
115  * }
116  * }
117  * </pre>
118  * Mistake: There is nobody holding strong reference to the Listener instance,
119  * so it may be freed on the next GC cycle.
120  *
121  * <BR><pre>
122  * public class ListenerObserver implements ChangeListener {
123  * private void registerTo(Source source) {
124  * source.addChangeListener(WeakListeners.change(this, <b>null</b>));
125  * }
126  *
127  * public void stateChanged(ChangeEvent e) {
128  * doSomething();
129  * }
130  * }
131  * </pre>
132  * Mistake: The weak listener is unable to unregister itself from the source
133  * once the listener is freed. For explanation, read below.
134  *
135  <H2>How does it work:</H2>
136  * <P>The <em>weak listener</em> is used as a reference-weakening wrapper
137  * around the listener. It is itself strongly referenced from the implementation
138  * of the source (e.g. from its <code>EventListenerList</code>) but it references
139  * the listener only through <code>WeakReference</code>. It also weak-references
140  * the source. Listener, on the other hand, usually strongly references
141  * the observer (typically through the outer class reference).
142  *
143  * This means that: <OL>
144  * <LI>If the listener is not strong-referenced from elsewhere, it can be
145  * thrown away on the next GC cycle. This is why you can't use
146  * <code>WeakListeners.change(new MyListener(), ..)</code> as the only reference
147  * to the listener will be the weak one from the weak listener.
148  * <LI>If the listener-observer pair is not strong-referenced from elsewhere
149  * it can be thrown away on the next GC cycle. This is what the
150  * <em>weak listener</em> was invented for.
151  * <LI>If the source is not strong-referenced from anywhere, it can be
152  * thrown away on the next GC cycle taking the weak listener with it,
153  * but not the listener and the observer if they are still strong-referenced
154  * (unusual case, but possible).
155  * </OL>
156  *
157  * <P>Now what happens when the listener/observer is removed from memory:<UL>
158  * <LI>The weak listener is notified that the reference to the listener was cleared.
159  * <LI>It tries to unregister itself from the source. This is why it needs
160  * the reference to the source for the registration. The unregistration
161  * is done using reflection, usually looking up the method
162  * <code>remove&lt;listenerType&gt;</code> of the source and calling it.
163  * </UL>
164  *
165  * <P>This may fail if the source don't have the expected <code>remove*</code>
166  * method and/or if you provide wrong reference to source. In that case
167  * the weak listener instance will stay in memory and registered by the source,
168  * while the listener and observer will be freed.
169  *
170  * <P>There is still one fallback method - if some event come to a weak listener
171  * and the listener is already freed, the weak listener tries to unregister
172  * itself from the object the event came from.
173  *
174  * @since 4.10
175  */

176 public final class WeakListeners {
177     /** No instances.
178      */

179     private WeakListeners() {
180     }
181
182     /** Generic factory method to create weak listener for any listener
183      * interface.
184      *
185      * @param lType the type of listener to create. It can be any interface,
186      * but only interfaces are allowed.
187      * @param l the listener to delegate to, <CODE>l</CODE> must be an instance
188      * of <CODE>lType</CODE>
189      * @param source the source that the listener should detach from when
190      * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
191      * @return an instance of <CODE>lType</CODE> delegating all the interface
192      * calls to <CODE>l</CODE>.
193      */

194     public static <T extends EventListener JavaDoc> T create(Class JavaDoc<T> lType, T l, Object JavaDoc source) {
195         if (!lType.isInterface()) {
196             throw new IllegalArgumentException JavaDoc("Not interface: " + lType);
197         }
198
199         return WeakListenerImpl.create(lType, lType, l, source);
200     }
201
202     /** The most generic factory method to create weak listener for any listener
203      * interface that moreover behaves like a listener of another type.
204      * This can be useful to correctly remove listeners from a source when
205      * hierarchies of listeners are used.
206      * <P>
207      * For example {@link javax.naming.event.EventContext} allows to add an
208      * instance of {@link javax.naming.event.ObjectChangeListener} but using
209      * method <code>addNamingListener</code>. Method <code>removeNamingListener</code>
210      * is then used to remove it. To help the weak listener support to correctly
211      * find the right method one have to use:
212      * <PRE>
213      * ObjectChangeListener l = (ObjectChangeListener)WeakListeners.create (
214      * ObjectChangeListener.class, // the actual class of the returned listener
215      * NamingListener.class, // but it always will be used as NamingListener
216      * yourObjectListener,
217      * someContext
218      * );
219      * someContext.addNamingListener ("", 0, l);
220      * </PRE>
221      * This will correctly create <code>ObjectChangeListener</code>
222      * and unregister it by
223      * calling <code>removeNamingListener</code>.
224      *
225      * @param lType the type the listener shall implement. It can be any interface,
226      * but only interfaces are allowed.
227      * @param apiType the interface the returned object will be used as. It
228      * shall be equal to <code>lType</code> or its superinterface
229      * @param l the listener to delegate to, <CODE>l</CODE> must be an instance
230      * of <CODE>lType</CODE>
231      * @param source the source that the listener should detach from when
232      * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
233      * @return an instance of <CODE>lType</CODE> delegating all the interface
234      * calls to <CODE>l</CODE>.
235      * @since 4.12
236      */

237     public static <T extends EventListener JavaDoc> T create(Class JavaDoc<T> lType, Class JavaDoc<? super T> apiType, T l, Object JavaDoc source) {
238         if (!lType.isInterface()) {
239             throw new IllegalArgumentException JavaDoc("Not interface: " + lType);
240         }
241
242         if (!apiType.isInterface()) {
243             throw new IllegalArgumentException JavaDoc("Not interface: " + apiType);
244         }
245
246         if (!apiType.isAssignableFrom(lType)) {
247             throw new IllegalArgumentException JavaDoc(apiType + " has to be assignableFrom " + lType); // NOI18N
248
}
249
250         return WeakListenerImpl.create(lType, apiType, l, source);
251     }
252
253     /** Creates a weak implementation of PropertyChangeListener.
254      *
255      * @param l the listener to delegate to
256      * @param source the source that the listener should detach from when
257      * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
258      * @return a PropertyChangeListener delegating to <CODE>l</CODE>.
259      */

260     public static PropertyChangeListener JavaDoc propertyChange(PropertyChangeListener JavaDoc l, Object JavaDoc source) {
261         WeakListenerImpl.PropertyChange wl = new WeakListenerImpl.PropertyChange(l);
262         wl.setSource(source);
263
264         return wl;
265     }
266
267     /** Creates a weak implementation of VetoableChangeListener.
268      *
269      * @param l the listener to delegate to
270      * @param source the source that the listener should detach from when
271      * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
272      * @return a VetoableChangeListener delegating to <CODE>l</CODE>.
273      */

274     public static VetoableChangeListener JavaDoc vetoableChange(VetoableChangeListener JavaDoc l, Object JavaDoc source) {
275         WeakListenerImpl.VetoableChange wl = new WeakListenerImpl.VetoableChange(l);
276         wl.setSource(source);
277
278         return wl;
279     }
280
281     /** Creates a weak implementation of DocumentListener.
282      *
283      * @param l the listener to delegate to
284      * @param source the source that the listener should detach from when
285      * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
286      * @return a DocumentListener delegating to <CODE>l</CODE>.
287      */

288     public static DocumentListener JavaDoc document(DocumentListener JavaDoc l, Object JavaDoc source) {
289         WeakListenerImpl.Document wl = new WeakListenerImpl.Document(l);
290         wl.setSource(source);
291
292         return wl;
293     }
294
295     /** Creates a weak implementation of ChangeListener.
296      *
297      * @param l the listener to delegate to
298      * @param source the source that the listener should detach from when
299      * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
300      * @return a ChangeListener delegating to <CODE>l</CODE>.
301      */

302     public static ChangeListener JavaDoc change(ChangeListener JavaDoc l, Object JavaDoc source) {
303         WeakListenerImpl.Change wl = new WeakListenerImpl.Change(l);
304         wl.setSource(source);
305
306         return wl;
307     }
308 }
309
Popular Tags