17dd252788645e940eada959bdde927426e2531c9Paul Duffin/*
27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2005 The Guava Authors
37dd252788645e940eada959bdde927426e2531c9Paul Duffin *
47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License.
67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at
77dd252788645e940eada959bdde927426e2531c9Paul Duffin *
87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
97dd252788645e940eada959bdde927426e2531c9Paul Duffin *
107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software
117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and
147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License.
157dd252788645e940eada959bdde927426e2531c9Paul Duffin */
167dd252788645e940eada959bdde927426e2531c9Paul Duffin
177dd252788645e940eada959bdde927426e2531c9Paul Duffinpackage com.google.common.base;
187dd252788645e940eada959bdde927426e2531c9Paul Duffin
197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.testing.GcFinalization;
207dd252788645e940eada959bdde927426e2531c9Paul Duffin
217dd252788645e940eada959bdde927426e2531c9Paul Duffinimport junit.framework.TestCase;
227dd252788645e940eada959bdde927426e2531c9Paul Duffin
237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.Closeable;
247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.ref.WeakReference;
257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Constructor;
267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Field;
277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URL;
287dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.net.URLClassLoader;
297dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.CodeSource;
307dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.Permission;
317dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.PermissionCollection;
327dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.Policy;
337dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.security.ProtectionDomain;
347dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Callable;
357dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Semaphore;
367dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.TimeUnit;
377dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.atomic.AtomicReference;
387dd252788645e940eada959bdde927426e2531c9Paul Duffin
397dd252788645e940eada959bdde927426e2531c9Paul Duffin/**
407dd252788645e940eada959bdde927426e2531c9Paul Duffin * Tests that the {@code ClassLoader} of {@link FinalizableReferenceQueue} can be unloaded. These
417dd252788645e940eada959bdde927426e2531c9Paul Duffin * tests are separate from {@link FinalizableReferenceQueueTest} so that they can be excluded from
427dd252788645e940eada959bdde927426e2531c9Paul Duffin * coverage runs, as the coverage system interferes with them.
437dd252788645e940eada959bdde927426e2531c9Paul Duffin *
447dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author Eamonn McManus
457dd252788645e940eada959bdde927426e2531c9Paul Duffin */
467dd252788645e940eada959bdde927426e2531c9Paul Duffinpublic class FinalizableReferenceQueueClassLoaderUnloadingTest extends TestCase {
477dd252788645e940eada959bdde927426e2531c9Paul Duffin
487dd252788645e940eada959bdde927426e2531c9Paul Duffin  /*
497dd252788645e940eada959bdde927426e2531c9Paul Duffin   * The following tests check that the use of FinalizableReferenceQueue does not prevent the
507dd252788645e940eada959bdde927426e2531c9Paul Duffin   * ClassLoader that loaded that class from later being garbage-collected. If anything continues
517dd252788645e940eada959bdde927426e2531c9Paul Duffin   * to reference the FinalizableReferenceQueue class then its ClassLoader cannot be
527dd252788645e940eada959bdde927426e2531c9Paul Duffin   * garbage-collected, even if there are no more instances of FinalizableReferenceQueue itself.
537dd252788645e940eada959bdde927426e2531c9Paul Duffin   * The code in FinalizableReferenceQueue goes to considerable trouble to ensure that there are
547dd252788645e940eada959bdde927426e2531c9Paul Duffin   * no such references and the tests here check that that trouble has not been in vain.
557dd252788645e940eada959bdde927426e2531c9Paul Duffin   *
567dd252788645e940eada959bdde927426e2531c9Paul Duffin   * When we reference FinalizableReferenceQueue in this test, we are referencing a class that is
577dd252788645e940eada959bdde927426e2531c9Paul Duffin   * loaded by this test and that will obviously remain loaded for as long as the test is running.
587dd252788645e940eada959bdde927426e2531c9Paul Duffin   * So in order to check ClassLoader garbage collection we need to create a new ClassLoader and
597dd252788645e940eada959bdde927426e2531c9Paul Duffin   * make it load its own version of FinalizableReferenceQueue. Then we need to interact with that
607dd252788645e940eada959bdde927426e2531c9Paul Duffin   * parallel version through reflection in order to exercise the parallel
617dd252788645e940eada959bdde927426e2531c9Paul Duffin   * FinalizableReferenceQueue, and then check that the parallel ClassLoader can be
627dd252788645e940eada959bdde927426e2531c9Paul Duffin   * garbage-collected after that.
637dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
647dd252788645e940eada959bdde927426e2531c9Paul Duffin
657dd252788645e940eada959bdde927426e2531c9Paul Duffin  public static class MyFinalizableWeakReference extends FinalizableWeakReference<Object> {
667dd252788645e940eada959bdde927426e2531c9Paul Duffin    public MyFinalizableWeakReference(Object x, FinalizableReferenceQueue queue) {
677dd252788645e940eada959bdde927426e2531c9Paul Duffin      super(x, queue);
687dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
697dd252788645e940eada959bdde927426e2531c9Paul Duffin
707dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override
717dd252788645e940eada959bdde927426e2531c9Paul Duffin    public void finalizeReferent() {
727dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
737dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
747dd252788645e940eada959bdde927426e2531c9Paul Duffin
757dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static class PermissivePolicy extends Policy {
767dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override
777dd252788645e940eada959bdde927426e2531c9Paul Duffin    public boolean implies(ProtectionDomain pd, Permission perm) {
787dd252788645e940eada959bdde927426e2531c9Paul Duffin      return true;
797dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
807dd252788645e940eada959bdde927426e2531c9Paul Duffin
817dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override
827dd252788645e940eada959bdde927426e2531c9Paul Duffin    public PermissionCollection getPermissions(CodeSource codesource) {
837dd252788645e940eada959bdde927426e2531c9Paul Duffin      throw new AssertionError();
847dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
857dd252788645e940eada959bdde927426e2531c9Paul Duffin
867dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override
877dd252788645e940eada959bdde927426e2531c9Paul Duffin    public void refresh() {
887dd252788645e940eada959bdde927426e2531c9Paul Duffin      throw new AssertionError();
897dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
907dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
917dd252788645e940eada959bdde927426e2531c9Paul Duffin
927dd252788645e940eada959bdde927426e2531c9Paul Duffin  private WeakReference<ClassLoader> useFrqInSeparateLoader() throws Exception {
937dd252788645e940eada959bdde927426e2531c9Paul Duffin    final URLClassLoader myLoader = (URLClassLoader) getClass().getClassLoader();
947dd252788645e940eada959bdde927426e2531c9Paul Duffin    final URL[] urls = myLoader.getURLs();
957dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader sepLoader = new URLClassLoader(urls, myLoader.getParent());
967dd252788645e940eada959bdde927426e2531c9Paul Duffin    // sepLoader is the loader that we will use to load the parallel FinalizableReferenceQueue (FRQ)
977dd252788645e940eada959bdde927426e2531c9Paul Duffin    // and friends, and that we will eventually expect to see garbage-collected. The assumption
987dd252788645e940eada959bdde927426e2531c9Paul Duffin    // is that the ClassLoader of this test is a URLClassLoader, and that it loads FRQ itself
997dd252788645e940eada959bdde927426e2531c9Paul Duffin    // rather than delegating to a parent ClassLoader. If this assumption is violated the test will
1007dd252788645e940eada959bdde927426e2531c9Paul Duffin    // fail and will need to be rewritten.
1017dd252788645e940eada959bdde927426e2531c9Paul Duffin
1027dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> frqC = FinalizableReferenceQueue.class;
1037dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> sepFrqC = sepLoader.loadClass(frqC.getName());
1047dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNotSame(frqC, sepFrqC);
1057dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Check the assumptions above.
1067dd252788645e940eada959bdde927426e2531c9Paul Duffin
1077dd252788645e940eada959bdde927426e2531c9Paul Duffin    // FRQ tries to load the Finalizer class (for the reference-collecting thread) in a few ways.
1087dd252788645e940eada959bdde927426e2531c9Paul Duffin    // If the class is accessible to the system ClassLoader (ClassLoader.getSystemClassLoader())
1097dd252788645e940eada959bdde927426e2531c9Paul Duffin    // then FRQ does not bother to load Finalizer.class through a separate ClassLoader. That happens
1107dd252788645e940eada959bdde927426e2531c9Paul Duffin    // in our test environment, which foils the purpose of this test, so we disable the logic for
1117dd252788645e940eada959bdde927426e2531c9Paul Duffin    // our test by setting a static field. We are changing the field in the parallel version of FRQ
1127dd252788645e940eada959bdde927426e2531c9Paul Duffin    // and each test creates its own one of those, so there is no test interference here.
1137dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> sepFrqSystemLoaderC =
1147dd252788645e940eada959bdde927426e2531c9Paul Duffin        sepLoader.loadClass(FinalizableReferenceQueue.SystemLoader.class.getName());
1157dd252788645e940eada959bdde927426e2531c9Paul Duffin    Field disabled = sepFrqSystemLoaderC.getDeclaredField("disabled");
1167dd252788645e940eada959bdde927426e2531c9Paul Duffin    disabled.setAccessible(true);
1177dd252788645e940eada959bdde927426e2531c9Paul Duffin    disabled.set(null, true);
1187dd252788645e940eada959bdde927426e2531c9Paul Duffin
1197dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Now make a parallel FRQ and an associated FinalizableWeakReference to an object, in order to
1207dd252788645e940eada959bdde927426e2531c9Paul Duffin    // exercise some classes from the parallel ClassLoader.
1217dd252788645e940eada959bdde927426e2531c9Paul Duffin    AtomicReference<Object> sepFrqA = new AtomicReference<Object>(sepFrqC.newInstance());
1220888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Class<?> sepFwrC = sepLoader.loadClass(MyFinalizableWeakReference.class.getName());
1230888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Constructor<?> sepFwrCons = sepFwrC.getConstructor(Object.class, sepFrqC);
1247dd252788645e940eada959bdde927426e2531c9Paul Duffin    // The object that we will wrap in FinalizableWeakReference is a Stopwatch.
1257dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> sepStopwatchC = sepLoader.loadClass(Stopwatch.class.getName());
1267dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertSame(sepLoader, sepStopwatchC.getClassLoader());
1277dd252788645e940eada959bdde927426e2531c9Paul Duffin    AtomicReference<Object> sepStopwatchA =
1280888a09821a98ac0680fad765217302858e70fa4Paul Duffin        new AtomicReference<Object>(sepStopwatchC.getMethod("createUnstarted").invoke(null));
1290888a09821a98ac0680fad765217302858e70fa4Paul Duffin    AtomicReference<WeakReference<?>> sepStopwatchRef = new AtomicReference<WeakReference<?>>(
1300888a09821a98ac0680fad765217302858e70fa4Paul Duffin        (WeakReference<?>) sepFwrCons.newInstance(sepStopwatchA.get(), sepFrqA.get()));
1317dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNotNull(sepStopwatchA.get());
1327dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Clear all references to the Stopwatch and wait for it to be gc'd.
1337dd252788645e940eada959bdde927426e2531c9Paul Duffin    sepStopwatchA.set(null);
1347dd252788645e940eada959bdde927426e2531c9Paul Duffin    GcFinalization.awaitClear(sepStopwatchRef.get());
1357dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Return a weak reference to the parallel ClassLoader. This is the reference that should
1367dd252788645e940eada959bdde927426e2531c9Paul Duffin    // eventually become clear if there are no other references to the ClassLoader.
1377dd252788645e940eada959bdde927426e2531c9Paul Duffin    return new WeakReference<ClassLoader>(sepLoader);
1387dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1397dd252788645e940eada959bdde927426e2531c9Paul Duffin
1407dd252788645e940eada959bdde927426e2531c9Paul Duffin  private void doTestUnloadable() throws Exception {
1417dd252788645e940eada959bdde927426e2531c9Paul Duffin    WeakReference<ClassLoader> loaderRef = useFrqInSeparateLoader();
1427dd252788645e940eada959bdde927426e2531c9Paul Duffin    GcFinalization.awaitClear(loaderRef);
1437dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1447dd252788645e940eada959bdde927426e2531c9Paul Duffin
1457dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testUnloadableWithoutSecurityManager() throws Exception {
1467dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Test that the use of a FinalizableReferenceQueue does not subsequently prevent the
1477dd252788645e940eada959bdde927426e2531c9Paul Duffin    // loader of that class from being garbage-collected.
1487dd252788645e940eada959bdde927426e2531c9Paul Duffin    SecurityManager oldSecurityManager = System.getSecurityManager();
1497dd252788645e940eada959bdde927426e2531c9Paul Duffin    try {
1507dd252788645e940eada959bdde927426e2531c9Paul Duffin      System.setSecurityManager(null);
1517dd252788645e940eada959bdde927426e2531c9Paul Duffin      doTestUnloadable();
1527dd252788645e940eada959bdde927426e2531c9Paul Duffin    } finally {
1537dd252788645e940eada959bdde927426e2531c9Paul Duffin      System.setSecurityManager(oldSecurityManager);
1547dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1557dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1567dd252788645e940eada959bdde927426e2531c9Paul Duffin
1577dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testUnloadableWithSecurityManager() throws Exception {
1587dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Test that the use of a FinalizableReferenceQueue does not subsequently prevent the
1597dd252788645e940eada959bdde927426e2531c9Paul Duffin    // loader of that class from being garbage-collected even if there is a SecurityManager.
1607dd252788645e940eada959bdde927426e2531c9Paul Duffin    // The SecurityManager environment makes such leaks more likely because when you create
1617dd252788645e940eada959bdde927426e2531c9Paul Duffin    // a URLClassLoader with a SecurityManager, the creating code's AccessControlContext is
1627dd252788645e940eada959bdde927426e2531c9Paul Duffin    // captured, and that references the creating code's ClassLoader.
1637dd252788645e940eada959bdde927426e2531c9Paul Duffin    Policy oldPolicy = Policy.getPolicy();
1647dd252788645e940eada959bdde927426e2531c9Paul Duffin    SecurityManager oldSecurityManager = System.getSecurityManager();
1657dd252788645e940eada959bdde927426e2531c9Paul Duffin    try {
1667dd252788645e940eada959bdde927426e2531c9Paul Duffin      Policy.setPolicy(new PermissivePolicy());
1677dd252788645e940eada959bdde927426e2531c9Paul Duffin      System.setSecurityManager(new SecurityManager());
1687dd252788645e940eada959bdde927426e2531c9Paul Duffin      doTestUnloadable();
1697dd252788645e940eada959bdde927426e2531c9Paul Duffin    } finally {
1707dd252788645e940eada959bdde927426e2531c9Paul Duffin      System.setSecurityManager(oldSecurityManager);
1717dd252788645e940eada959bdde927426e2531c9Paul Duffin      Policy.setPolicy(oldPolicy);
1727dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1737dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1747dd252788645e940eada959bdde927426e2531c9Paul Duffin
1757dd252788645e940eada959bdde927426e2531c9Paul Duffin  public static class FrqUser implements Callable<WeakReference<Object>> {
1767dd252788645e940eada959bdde927426e2531c9Paul Duffin    public static FinalizableReferenceQueue frq = new FinalizableReferenceQueue();
1777dd252788645e940eada959bdde927426e2531c9Paul Duffin    public static final Semaphore finalized = new Semaphore(0);
1787dd252788645e940eada959bdde927426e2531c9Paul Duffin
1797dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override
1807dd252788645e940eada959bdde927426e2531c9Paul Duffin    public WeakReference<Object> call() {
1817dd252788645e940eada959bdde927426e2531c9Paul Duffin      WeakReference<Object> wr = new FinalizableWeakReference<Object>(new Integer(23), frq) {
1827dd252788645e940eada959bdde927426e2531c9Paul Duffin        @Override
1837dd252788645e940eada959bdde927426e2531c9Paul Duffin        public void finalizeReferent() {
1847dd252788645e940eada959bdde927426e2531c9Paul Duffin          finalized.release();
1857dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
1867dd252788645e940eada959bdde927426e2531c9Paul Duffin      };
1877dd252788645e940eada959bdde927426e2531c9Paul Duffin      return wr;
1887dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1897dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1907dd252788645e940eada959bdde927426e2531c9Paul Duffin
1917dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testUnloadableInStaticFieldIfClosed() throws Exception {
1927dd252788645e940eada959bdde927426e2531c9Paul Duffin    Policy oldPolicy = Policy.getPolicy();
1937dd252788645e940eada959bdde927426e2531c9Paul Duffin    SecurityManager oldSecurityManager = System.getSecurityManager();
1947dd252788645e940eada959bdde927426e2531c9Paul Duffin    try {
1957dd252788645e940eada959bdde927426e2531c9Paul Duffin      Policy.setPolicy(new PermissivePolicy());
1967dd252788645e940eada959bdde927426e2531c9Paul Duffin      System.setSecurityManager(new SecurityManager());
1977dd252788645e940eada959bdde927426e2531c9Paul Duffin      WeakReference<ClassLoader> loaderRef = doTestUnloadableInStaticFieldIfClosed();
1987dd252788645e940eada959bdde927426e2531c9Paul Duffin      GcFinalization.awaitClear(loaderRef);
1997dd252788645e940eada959bdde927426e2531c9Paul Duffin    } finally {
2007dd252788645e940eada959bdde927426e2531c9Paul Duffin      System.setSecurityManager(oldSecurityManager);
2017dd252788645e940eada959bdde927426e2531c9Paul Duffin      Policy.setPolicy(oldPolicy);
2027dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2037dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2047dd252788645e940eada959bdde927426e2531c9Paul Duffin
2057dd252788645e940eada959bdde927426e2531c9Paul Duffin  // If you have a FinalizableReferenceQueue that is a static field of one of the classes of your
2067dd252788645e940eada959bdde927426e2531c9Paul Duffin  // app (like the FrqUser class above), then the app's ClassLoader will never be gc'd. The reason
2077dd252788645e940eada959bdde927426e2531c9Paul Duffin  // is that we attempt to run a thread in a separate ClassLoader that will detect when the FRQ
2087dd252788645e940eada959bdde927426e2531c9Paul Duffin  // is no longer referenced, meaning that the app's ClassLoader has been gc'd, and when that
2097dd252788645e940eada959bdde927426e2531c9Paul Duffin  // happens. But the thread's supposedly separate ClassLoader actually has a reference to the app's
2107dd252788645e940eada959bdde927426e2531c9Paul Duffin  // ClasLoader via its AccessControlContext. It does not seem to be possible to make a
2117dd252788645e940eada959bdde927426e2531c9Paul Duffin  // URLClassLoader without capturing this reference, and it probably would not be desirable for
2127dd252788645e940eada959bdde927426e2531c9Paul Duffin  // security reasons anyway. Therefore, the FRQ.close() method provides a way to stop the thread
2137dd252788645e940eada959bdde927426e2531c9Paul Duffin  // explicitly. This test checks that calling that method does allow an app's ClassLoader to be
2147dd252788645e940eada959bdde927426e2531c9Paul Duffin  // gc'd even if there is a still a FinalizableReferenceQueue in a static field. (Setting the field
2157dd252788645e940eada959bdde927426e2531c9Paul Duffin  // to null would also work, but only if there are no references to the FRQ anywhere else.)
2167dd252788645e940eada959bdde927426e2531c9Paul Duffin  private WeakReference<ClassLoader> doTestUnloadableInStaticFieldIfClosed() throws Exception {
2177dd252788645e940eada959bdde927426e2531c9Paul Duffin    final URLClassLoader myLoader = (URLClassLoader) getClass().getClassLoader();
2187dd252788645e940eada959bdde927426e2531c9Paul Duffin    final URL[] urls = myLoader.getURLs();
2197dd252788645e940eada959bdde927426e2531c9Paul Duffin    URLClassLoader sepLoader = new URLClassLoader(urls, myLoader.getParent());
2207dd252788645e940eada959bdde927426e2531c9Paul Duffin
2217dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> frqC = FinalizableReferenceQueue.class;
2227dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> sepFrqC = sepLoader.loadClass(frqC.getName());
2237dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNotSame(frqC, sepFrqC);
2247dd252788645e940eada959bdde927426e2531c9Paul Duffin
2257dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> sepFrqSystemLoaderC =
2267dd252788645e940eada959bdde927426e2531c9Paul Duffin        sepLoader.loadClass(FinalizableReferenceQueue.SystemLoader.class.getName());
2277dd252788645e940eada959bdde927426e2531c9Paul Duffin    Field disabled = sepFrqSystemLoaderC.getDeclaredField("disabled");
2287dd252788645e940eada959bdde927426e2531c9Paul Duffin    disabled.setAccessible(true);
2297dd252788645e940eada959bdde927426e2531c9Paul Duffin    disabled.set(null, true);
2307dd252788645e940eada959bdde927426e2531c9Paul Duffin
2317dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> frqUserC = FrqUser.class;
2327dd252788645e940eada959bdde927426e2531c9Paul Duffin    Class<?> sepFrqUserC = sepLoader.loadClass(frqUserC.getName());
2337dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNotSame(frqUserC, sepFrqUserC);
2347dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertSame(sepLoader, sepFrqUserC.getClassLoader());
2357dd252788645e940eada959bdde927426e2531c9Paul Duffin
2360888a09821a98ac0680fad765217302858e70fa4Paul Duffin    Callable<?> sepFrqUser = (Callable<?>) sepFrqUserC.newInstance();
2370888a09821a98ac0680fad765217302858e70fa4Paul Duffin    WeakReference<?> finalizableWeakReference = (WeakReference<?>) sepFrqUser.call();
2387dd252788645e940eada959bdde927426e2531c9Paul Duffin
2397dd252788645e940eada959bdde927426e2531c9Paul Duffin    GcFinalization.awaitClear(finalizableWeakReference);
2407dd252788645e940eada959bdde927426e2531c9Paul Duffin
2417dd252788645e940eada959bdde927426e2531c9Paul Duffin    Field sepFrqUserFinalizedF = sepFrqUserC.getField("finalized");
2427dd252788645e940eada959bdde927426e2531c9Paul Duffin    Semaphore finalizeCount = (Semaphore) sepFrqUserFinalizedF.get(null);
2437dd252788645e940eada959bdde927426e2531c9Paul Duffin    boolean finalized = finalizeCount.tryAcquire(5, TimeUnit.SECONDS);
2447dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertTrue(finalized);
2457dd252788645e940eada959bdde927426e2531c9Paul Duffin
2467dd252788645e940eada959bdde927426e2531c9Paul Duffin    Field sepFrqUserFrqF = sepFrqUserC.getField("frq");
2477dd252788645e940eada959bdde927426e2531c9Paul Duffin    Closeable frq = (Closeable) sepFrqUserFrqF.get(null);
2487dd252788645e940eada959bdde927426e2531c9Paul Duffin    frq.close();
2497dd252788645e940eada959bdde927426e2531c9Paul Duffin
2507dd252788645e940eada959bdde927426e2531c9Paul Duffin    return new WeakReference<ClassLoader>(sepLoader);
2517dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2527dd252788645e940eada959bdde927426e2531c9Paul Duffin}
253