001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.openide.util;
043:
044: import java.lang.ref.Reference;
045: import java.lang.ref.ReferenceQueue;
046: import java.lang.ref.WeakReference;
047: import java.net.URL;
048: import java.net.URLClassLoader;
049: import org.netbeans.junit.NbTestCase;
050:
051: public class UtilitiesActiveQueueTest extends NbTestCase {
052:
053: public UtilitiesActiveQueueTest(String testName) {
054: super (testName);
055: }
056:
057: public void testRunnableReferenceIsExecuted() throws Exception {
058: Object obj = new Object();
059: RunnableRef ref = new RunnableRef(obj);
060: synchronized (ref) {
061: obj = null;
062: assertGC("Should be GCed quickly", ref);
063: ref.wait();
064: assertTrue("Run method has been executed", ref.executed);
065: }
066: }
067:
068: public void testRunnablesAreProcessedOneByOne() throws Exception {
069: Object obj = new Object();
070: RunnableRef ref = new RunnableRef(obj);
071: ref.wait = true;
072:
073: synchronized (ref) {
074: obj = null;
075: assertGC("Is garbage collected", ref);
076: ref.wait();
077: assertTrue("Still not executed, it is blocked",
078: !ref.executed);
079: }
080:
081: RunnableRef after = new RunnableRef(new Object());
082: synchronized (after) {
083: assertGC("Is garbage collected", after);
084: after.wait(100); // will fail
085: assertTrue("Even if GCed, still not processed",
086: !after.executed);
087: }
088:
089: synchronized (after) {
090: synchronized (ref) {
091: ref.notify();
092: ref.wait();
093: assertTrue("Processed", ref.executed);
094: }
095: after.wait();
096: assertTrue("Processed too", after.executed);
097: }
098: }
099:
100: public void testCallingPublicMethodsThrowsExceptions() {
101: try {
102: Utilities.activeReferenceQueue().poll();
103: fail("One should not call public method from outside");
104: } catch (RuntimeException ex) {
105: }
106: try {
107: Utilities.activeReferenceQueue().remove();
108: fail("One should not call public method from outside");
109: } catch (InterruptedException ex) {
110: }
111: try {
112: Utilities.activeReferenceQueue().remove(10);
113: fail("One should not call public method from outside");
114: } catch (InterruptedException ex) {
115: }
116: }
117:
118: public void testMemoryLeak() throws Exception {
119: final Class<?> u1 = Utilities.class;
120: class L extends URLClassLoader {
121: public L() {
122: super (new URL[] { u1.getProtectionDomain()
123: .getCodeSource().getLocation() }, u1
124: .getClassLoader().getParent());
125: }
126:
127: protected Class<?> loadClass(String name, boolean resolve)
128: throws ClassNotFoundException {
129: if (name.equals(u1.getName())
130: || name.startsWith(u1.getName() + "$")) {
131: Class c = findLoadedClass(name);
132: if (c == null) {
133: c = findClass(name);
134: }
135: if (resolve) {
136: resolveClass(c);
137: }
138: return c;
139: } else {
140: return super .loadClass(name, resolve);
141: }
142: }
143: }
144: ClassLoader l = new L();
145: Class<?> u2 = l.loadClass(u1.getName());
146: assertEquals(l, u2.getClassLoader());
147: Object obj = new Object();
148: @SuppressWarnings("unchecked")
149: ReferenceQueue<Object> q = (ReferenceQueue<Object>) u2
150: .getMethod("activeReferenceQueue").invoke(null);
151: RunnableRef ref = new RunnableRef(obj, q);
152: synchronized (ref) {
153: obj = null;
154: assertGC("Ref should be GC'ed as usual", ref);
155: ref.wait();
156: assertTrue("Run method has been executed", ref.executed);
157: }
158: Reference<?> r = new WeakReference<Object>(u2);
159: q = null;
160: u2 = null;
161: l = null;
162: assertGC("#86625: Utilities.class can also be collected now", r);
163: }
164:
165: private static class RunnableRef extends WeakReference<Object>
166: implements Runnable {
167: public boolean wait;
168: public boolean entered;
169: public boolean executed;
170:
171: public RunnableRef(Object o) {
172: this (o, Utilities.activeReferenceQueue());
173: }
174:
175: public RunnableRef(Object o, ReferenceQueue<Object> q) {
176: super (o, q);
177: }
178:
179: public synchronized void run() {
180: entered = true;
181: if (wait) {
182: // notify we are here
183: notify();
184: try {
185: wait();
186: } catch (InterruptedException ex) {
187: }
188: }
189: executed = true;
190:
191: notifyAll();
192: }
193: }
194: }
|