KickJava   Java API By Example, From Geeks To Geeks.

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


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.openide.util;
21
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.lang.ref.Reference JavaDoc;
24 import java.lang.ref.WeakReference JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.logging.Level JavaDoc;
29 import javax.swing.event.ChangeEvent JavaDoc;
30 import javax.swing.event.ChangeListener JavaDoc;
31 import org.netbeans.junit.MockServices;
32 import org.netbeans.junit.NbTestCase;
33 import org.openide.ErrorManager;
34
35 public class WeakListenersTest extends NbTestCase {
36
37     private static Thread JavaDoc activeQueueThread;
38
39     private ErrorManager log;
40     
41     public WeakListenersTest(String JavaDoc testName) {
42         super(testName);
43     }
44
45     protected int timeOut() {
46         return 5000;
47     }
48
49     protected Level JavaDoc logLevel() {
50         return Level.ALL;
51     }
52     
53     protected void setUp () throws Exception JavaDoc {
54         MockServices.setServices(ErrManager.class);
55         log = ErrorManager.getDefault().getInstance("TEST-" + getName());
56         
57         if (activeQueueThread == null) {
58             class WR extends WeakReference JavaDoc<Object JavaDoc> implements Runnable JavaDoc {
59                 public WR (Object JavaDoc o) {
60                     super (o, Utilities.activeReferenceQueue ());
61                 }
62                 public synchronized void run () {
63                     activeQueueThread = Thread.currentThread();
64                     notifyAll ();
65                 }
66             }
67             
68             Object JavaDoc obj = new Object JavaDoc ();
69             WR wr = new WR (obj);
70             synchronized (wr) {
71                 obj = null;
72                 assertGC ("Has to be cleared", wr);
73                 // and has to execute run method
74
while (activeQueueThread == null) {
75                     wr.wait ();
76                 }
77             }
78         }
79     }
80     
81     protected void runTest() throws Throwable JavaDoc {
82         assertNotNull ("ErrManager has to be in lookup", org.openide.util.Lookup.getDefault ().lookup (ErrManager.class));
83         ErrManager.messages.setLength(0);
84         
85         try {
86             super.runTest();
87         } catch (Throwable JavaDoc ex) {
88             throw new junit.framework.AssertionFailedError (
89                 ex.getMessage() + "\n" + ErrManager.messages.toString()
90             ).initCause(ex);
91         }
92     }
93     
94     
95     public void testOneCanCallHashCodeOrOnWeakListener () {
96         Listener JavaDoc l = new Listener JavaDoc ();
97         Object JavaDoc weak = WeakListeners.create (PropertyChangeListener JavaDoc.class, l, null);
98         weak.hashCode ();
99     }
100     
101     /** Useful for next test */
102     interface X extends java.util.EventListener JavaDoc {
103         public void invoke ();
104     }
105     /** Useful for next test */
106     class XImpl implements X {
107         public int cnt;
108         public void invoke () {
109             cnt++;
110         }
111     }
112     public void testCallingMethodsWithNoArgumentWorks() {
113         XImpl l = new XImpl ();
114         log.log("XImpl created: " + l);
115         X weak = (X)WeakListeners.create (X.class, l, null);
116         log.log("weak created: " + weak);
117         weak.invoke ();
118         log.log("invoked");
119         assertEquals ("One invocation", 1, l.cnt);
120     }
121
122     public void testReleaseOfListenerWithNullSource () throws Exception JavaDoc {
123         doTestReleaseOfListener (false);
124     }
125     
126     public void testReleaseOfListenerWithSource () throws Exception JavaDoc {
127         doTestReleaseOfListener (true);
128     }
129     
130     private void doTestReleaseOfListener (final boolean source) throws Exception JavaDoc {
131         Listener JavaDoc l = new Listener JavaDoc ();
132         
133         class MyButton extends javax.swing.JButton JavaDoc {
134             private Thread JavaDoc removedBy;
135             private int cnt;
136             
137             public synchronized void removePropertyChangeListener (PropertyChangeListener JavaDoc l) {
138                 // notify prior
139
log.log("removePropertyChangeListener: " + source + " cnt: " + cnt);
140                 if (source && cnt == 0) {
141                     notifyAll ();
142                     try {
143                         // wait for 1
144
log.log("wait for 1");
145                         wait ();
146                         log.log("wait for 1 over");
147                     } catch (InterruptedException JavaDoc ex) {
148                         fail ("Not happen");
149                     }
150                 }
151                 log.log("Super removePropertyChangeListener");
152                 super.removePropertyChangeListener (l);
153                 log.log("Super over removePropertyChangeListener");
154                 removedBy = Thread.currentThread();
155                 cnt++;
156                 notifyAll ();
157             }
158             
159             public synchronized void waitListener () throws Exception JavaDoc {
160                 int cnt = 0;
161                 while (removedBy == null) {
162                     log.log("waitListener, wait 500");
163                     wait (500);
164                     log.log("waitListener 500 Over");
165                     if (cnt++ == 5) {
166                         fail ("Time out: removePropertyChangeListener was not called at all");
167                     } else {
168                         log.log("Forced gc");
169                         System.gc ();
170                         System.runFinalization();
171                         log.log("after force runFinalization");
172                     }
173                 }
174             }
175         }
176         
177         MyButton button = new MyButton ();
178         log.log("Button is here");
179         java.beans.PropertyChangeListener JavaDoc weakL = WeakListeners.propertyChange (l, source ? button : null);
180         log.log("WeakListeners created: " + weakL);
181         button.addPropertyChangeListener(weakL);
182         log.log("WeakListeners attached");
183         assertTrue ("Weak listener is there", Arrays.asList (button.getPropertyChangeListeners()).indexOf (weakL) >= 0);
184         
185         button.setText("Ahoj");
186         log.log("setText changed to ahoj");
187         assertEquals ("Listener called once", 1, l.cnt);
188         
189         Reference JavaDoc<?> ref = new WeakReference JavaDoc<Object JavaDoc>(l);
190         log.log("Clearing listener");
191         l = null;
192         
193
194         synchronized (button) {
195             log.log("Before assertGC");
196             assertGC ("Can disappear", ref);
197             log.log("assertGC ok");
198             
199             if (source) {
200                 log.log("before wait");
201                 button.wait ();
202                 log.log("after wait");
203                 // this should not remove the listener twice
204
button.setText ("Hoj");
205                 log.log("after setText - > hoj");
206                 // go on (wait 1)
207
button.notify ();
208                 log.log("before wait listener");
209                 
210                 button.waitListener ();
211                 log.log("after waitListener");
212             } else {
213                 // trigger the even firing so weak listener knows from
214
// where to unregister
215
log.log("before setText -> Hoj");
216                 button.setText ("Hoj");
217                 log.log("after setText -> Hoj");
218             }
219             
220             log.log("before 2 waitListener");
221             button.waitListener ();
222             log.log("after 2 waitListener");
223             Thread.sleep (500);
224             log.log("Thread.sleep over");
225         }
226
227         assertEquals ("Weak listener has been removed", -1, Arrays.asList (button.getPropertyChangeListeners()).indexOf (weakL));
228         assertEquals ("Button released from a thread", activeQueueThread, button.removedBy);
229         assertEquals ("Unregister called just once", 1, button.cnt);
230         
231         // and because it is not here, it can be GCed
232
Reference JavaDoc<?> weakRef = new WeakReference JavaDoc<Object JavaDoc>(weakL);
233         weakL = null;
234         log.log("Doing assertGC at the end");
235         assertGC ("Weak listener can go away as well", weakRef);
236     }
237     
238     
239     public void testSourceCanBeGarbageCollected () {
240         javax.swing.JButton JavaDoc b = new javax.swing.JButton JavaDoc ();
241         Listener JavaDoc l = new Listener JavaDoc ();
242         
243         b.addPropertyChangeListener (WeakListeners.propertyChange (l, b));
244         
245         Reference JavaDoc<?> ref = new WeakReference JavaDoc<Object JavaDoc>(b);
246         b = null;
247         
248         assertGC ("Source can be GC", ref);
249     }
250     
251     public void testNamingListenerBehaviour () throws Exception JavaDoc {
252         Listener JavaDoc l = new Listener JavaDoc ();
253         ImplEventContext c = new ImplEventContext ();
254         javax.naming.event.NamingListener JavaDoc weakL = (javax.naming.event.NamingListener JavaDoc)WeakListeners.create (
255             javax.naming.event.ObjectChangeListener JavaDoc.class,
256             javax.naming.event.NamingListener JavaDoc.class,
257             l,
258             c
259         );
260         
261         c.addNamingListener("", javax.naming.event.EventContext.OBJECT_SCOPE, weakL);
262         assertEquals ("Weak listener is there", weakL, c.listener);
263         
264         Reference JavaDoc<?> ref = new WeakReference JavaDoc<Object JavaDoc>(l);
265         l = null;
266
267         synchronized (c) {
268             assertGC ("Can disappear", ref);
269             c.waitListener ();
270         }
271         assertNull ("Listener removed", c.listener);
272     }
273     
274     public void testExceptionIllegalState () {
275         Listener JavaDoc l = new Listener JavaDoc ();
276         try {
277             WeakListeners.create ((Class JavaDoc)PropertyChangeListener JavaDoc.class, (Class JavaDoc)javax.naming.event.NamingListener JavaDoc.class, l, null);
278             fail ("This shall not be allowed as NamingListener is not superclass of PropertyChangeListener");
279         } catch (IllegalArgumentException JavaDoc ex) {
280             // ok
281
}
282         
283         try {
284             WeakListeners.create ((Class JavaDoc)Object JavaDoc.class, l, null);
285             fail ("Not interface, it should fail");
286         } catch (IllegalArgumentException JavaDoc ex) {
287             // ok
288
}
289         
290         try {
291             WeakListeners.create ((Class JavaDoc)Object JavaDoc.class, (Class JavaDoc)Object JavaDoc.class, l, null);
292             fail ("Not interface, it should fail");
293         } catch (IllegalArgumentException JavaDoc ex) {
294             // ok
295
}
296         
297         try {
298             WeakListeners.create (PropertyChangeListener JavaDoc.class, Object JavaDoc.class, l, null);
299             fail ("Not interface, it should fail");
300         } catch (IllegalArgumentException JavaDoc ex) {
301             // ok
302
}
303     }
304     
305     public void testHowBigIsWeakListener () throws Exception JavaDoc {
306         Listener JavaDoc l = new Listener JavaDoc ();
307         javax.swing.JButton JavaDoc button = new javax.swing.JButton JavaDoc ();
308         ImplEventContext c = new ImplEventContext ();
309         
310         Object JavaDoc[] ignore = new Object JavaDoc[] {
311             l,
312             button,
313             c,
314             Utilities.activeReferenceQueue()
315         };
316         
317         
318         PropertyChangeListener JavaDoc pcl = WeakListeners.propertyChange(l, button);
319         assertSize ("Not too big (plus 32 from ReferenceQueue)", java.util.Collections.singleton (pcl), 112, ignore);
320         
321         Object JavaDoc ocl = WeakListeners.create (javax.naming.event.ObjectChangeListener JavaDoc.class, javax.naming.event.NamingListener JavaDoc.class, l, c);
322         assertSize ("A bit bigger (plus 32 from ReferenceQueue)", java.util.Collections.singleton (ocl), 128, ignore);
323         
324         Object JavaDoc nl = WeakListeners.create (javax.naming.event.NamingListener JavaDoc.class, l, c);
325         assertSize ("The same (plus 32 from ReferenceQueue)", java.util.Collections.singleton (nl), 128, ignore);
326         
327     }
328
329     public void testPrivateRemoveMethod() throws Exception JavaDoc {
330         PropChBean bean = new PropChBean();
331         Listener JavaDoc listener = new Listener JavaDoc();
332         PCL weakL = (PCL) WeakListeners.create(PCL.class, listener, bean);
333         Reference JavaDoc<?> ref = new WeakReference JavaDoc<Object JavaDoc>(listener);
334         
335         bean.addPCL(weakL);
336         
337         bean.listeners.firePropertyChange (null, null, null);
338         assertEquals ("One call to the listener", 1, listener.cnt);
339         listener.cnt = 0;
340         
341         listener = null;
342         assertGC("Listener wasn't GCed", ref);
343         
344         ref = new WeakReference JavaDoc<Object JavaDoc>(weakL);
345         weakL = null;
346         assertGC("WeakListener wasn't GCed", ref);
347         
348         // this shall enforce the removal of the listener
349
bean.listeners.firePropertyChange (null, null, null);
350         
351         assertEquals ("No listeners", 0, bean.listeners.getPropertyChangeListeners ().length);
352     }
353
354     public void testStaticRemoveMethod() throws Exception JavaDoc {
355         ChangeListener JavaDoc l = new ChangeListener JavaDoc() {public void stateChanged(ChangeEvent JavaDoc e) {}};
356         Singleton.addChangeListener(WeakListeners.change(l, Singleton.class));
357         assertEquals(1, Singleton.listeners.size());
358         Reference JavaDoc<?> r = new WeakReference JavaDoc<Object JavaDoc>(l);
359         l = null;
360         assertGC("could collect listener", r);
361         assertEquals("called remove method", 0, Singleton.listeners.size());
362     }
363     public static class Singleton {
364         public static List JavaDoc<ChangeListener JavaDoc> listeners = new ArrayList JavaDoc<ChangeListener JavaDoc>();
365         public static void addChangeListener(ChangeListener JavaDoc l) {
366             listeners.add(l);
367         }
368         public static void removeChangeListener(ChangeListener JavaDoc l) {
369             listeners.remove(l);
370         }
371     }
372     
373     private static final class Listener
374     implements PCL, java.beans.PropertyChangeListener JavaDoc, javax.naming.event.ObjectChangeListener JavaDoc {
375         public int cnt;
376         
377         public void propertyChange (java.beans.PropertyChangeEvent JavaDoc ev) {
378             cnt++;
379         }
380         
381         public void namingExceptionThrown(javax.naming.event.NamingExceptionEvent JavaDoc evt) {
382             cnt++;
383         }
384         
385         public void objectChanged(javax.naming.event.NamingEvent JavaDoc evt) {
386             cnt++;
387         }
388     } // end of Listener
389

390     private static final class ImplEventContext extends javax.naming.InitialContext JavaDoc
391     implements javax.naming.event.EventContext JavaDoc {
392         public javax.naming.event.NamingListener JavaDoc listener;
393         
394         public ImplEventContext () throws Exception JavaDoc {
395         }
396         
397         public void addNamingListener(javax.naming.Name JavaDoc target, int scope, javax.naming.event.NamingListener JavaDoc l) throws javax.naming.NamingException JavaDoc {
398             assertNull (listener);
399             listener = l;
400         }
401         
402         public void addNamingListener(String JavaDoc target, int scope, javax.naming.event.NamingListener JavaDoc l) throws javax.naming.NamingException JavaDoc {
403             assertNull (listener);
404             listener = l;
405         }
406         
407         public synchronized void removeNamingListener(javax.naming.event.NamingListener JavaDoc l) throws javax.naming.NamingException JavaDoc {
408             assertEquals ("Removing the same listener", listener, l);
409             listener = null;
410             notifyAll ();
411         }
412         
413         public boolean targetMustExist() throws javax.naming.NamingException JavaDoc {
414             return false;
415         }
416         
417         public synchronized void waitListener () throws Exception JavaDoc {
418             int cnt = 0;
419             while (listener != null) {
420                 wait (500);
421                 if (cnt++ == 5) {
422                     fail ("Time out: removeNamingListener was not called at all");
423                 } else {
424                     System.gc ();
425                     System.runFinalization();
426                 }
427             }
428         }
429         
430     }
431     
432     private static class PropChBean {
433         private java.beans.PropertyChangeSupport JavaDoc listeners = new java.beans.PropertyChangeSupport JavaDoc (this);
434         private void addPCL(PCL l) { listeners.addPropertyChangeListener (l); }
435         private void removePCL(PCL l) { listeners.removePropertyChangeListener (l); }
436     } // End of PropChBean class
437

438     // just a marker, its name will be used to construct the name of add/remove methods, e.g. addPCL, removePCL
439
private static interface PCL extends PropertyChangeListener JavaDoc {
440     } // End of PrivatePropL class
441

442     //
443
// Manager to delegate to
444
//
445
public static final class ErrManager extends org.openide.ErrorManager {
446         public static final StringBuffer JavaDoc messages = new StringBuffer JavaDoc ();
447         
448         private String JavaDoc prefix;
449         
450         public ErrManager () {
451             this (null);
452         }
453         public ErrManager (String JavaDoc prefix) {
454             this.prefix = prefix;
455         }
456         
457         public static ErrManager get () {
458             return (ErrManager)org.openide.util.Lookup.getDefault ().lookup (ErrManager.class);
459         }
460         
461         public Throwable JavaDoc annotate (Throwable JavaDoc t, int severity, String JavaDoc message, String JavaDoc localizedMessage, Throwable JavaDoc stackTrace, java.util.Date JavaDoc date) {
462             return t;
463         }
464         
465         public Throwable JavaDoc attachAnnotations (Throwable JavaDoc t, org.openide.ErrorManager.Annotation[] arr) {
466             return t;
467         }
468         
469         public org.openide.ErrorManager.Annotation[] findAnnotations (Throwable JavaDoc t) {
470             return null;
471         }
472         
473         public org.openide.ErrorManager getInstance (String JavaDoc name) {
474             if (
475                 name.startsWith ("org.openide.util.RequestProcessor") ||
476                 name.startsWith("TEST")
477             ) {
478                 return new ErrManager ('[' + name + ']');
479             } else {
480                 // either new non-logging or myself if I am non-logging
481
return new ErrManager ();
482             }
483         }
484         
485         public void log (int severity, String JavaDoc s) {
486             lastSeverity = severity;
487             lastText = s;
488             if (this != get()) {
489                 messages.append(prefix);
490                 messages.append(s);
491                 messages.append('\n');
492             }
493         }
494         
495         public void notify (int severity, Throwable JavaDoc t) {
496             lastThrowable = t;
497             lastSeverity = severity;
498         }
499         private static int lastSeverity;
500         private static Throwable JavaDoc lastThrowable;
501         private static String JavaDoc lastText;
502
503         public static void assertNotify (int sev, Throwable JavaDoc t) {
504             assertEquals ("Severity is same", sev, lastSeverity);
505             assertSame ("Throwable is the same", t, lastThrowable);
506             lastThrowable = null;
507             lastSeverity = -1;
508         }
509         
510         public static void assertLog (int sev, String JavaDoc t) {
511             assertEquals ("Severity is same", sev, lastSeverity);
512             assertEquals ("Text is the same", t, lastText);
513             lastText = null;
514             lastSeverity = -1;
515         }
516         
517     } // end of ErrManager
518

519 }
520
Popular Tags