/* Copyright (c) 2007-2009 Timothy Wall, All Rights Reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package com.sun.jna;
import java.io.File;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import junit.framework.TestCase;
public class JNAUnloadTest extends TestCase {
private static final String BUILDDIR =
System.getProperty("jna.builddir", "build"
+ (Platform.is64Bit() ? "-d64" : ""));
private static class TestLoader extends URLClassLoader {
public TestLoader(boolean fromJar) throws MalformedURLException {
super(new URL[] {
new File(BUILDDIR + (fromJar ? "/jna.jar" : "/classes")).toURI().toURL(),
}, null);
}
}
// Fails under clover
public void testUnloadFromJar() throws Exception {
File jar = new File(BUILDDIR + "/jna.jar");
assertTrue("Expected JNA jar file at " + jar + " is missing", jar.exists());
ClassLoader loader = new TestLoader(true);
Class cls = Class.forName("com.sun.jna.Native", true, loader);
assertEquals("Wrong class loader", loader, cls.getClassLoader());
Field field = cls.getDeclaredField("nativeLibraryPath");
field.setAccessible(true);
String path = (String)field.get(null);
assertTrue("Native library not unpacked from jar: " + path,
path.startsWith(System.getProperty("java.io.tmpdir")));
WeakReference ref = new WeakReference(cls);
WeakReference clref = new WeakReference(loader);
loader = null;
cls = null;
field = null;
System.gc();
for (int i=0;i < 100 && (ref.get() != null || clref.get() != null);i++) {
Thread.sleep(10);
System.gc();
}
assertNull("Class not GC'd: " + ref.get(), ref.get());
assertNull("ClassLoader not GC'd: " + clref.get(), clref.get());
File f = new File(path);
for (int i=0;i < 100 && f.exists();i++) {
Thread.sleep(10);
System.gc();
}
// NOTE: Temporary file removal on Windows only works on a Sun VM
try {
if (Platform.isWindows()) {
ClassLoader.class.getDeclaredField("nativeLibraries");
}
if (f.exists() && !f.delete()) {
assertFalse("Temporary native library still locked: " + path,
f.exists());
}
}
catch(Exception e) {
// Skip on non-supported VMs
}
try {
loader = new TestLoader(true);
cls = Class.forName("com.sun.jna.Native", true, loader);
}
catch(Throwable t) {
fail("Native library not unloaded: " + t.getMessage());
}
finally {
loader = null;
cls = null;
System.gc();
}
}
// Fails under clover
public void testUnload() throws Exception {
ClassLoader loader = new TestLoader(false);
Class cls = Class.forName("com.sun.jna.Native", true, loader);
assertEquals("Wrong class loader", loader, cls.getClassLoader());
Field field = cls.getDeclaredField("nativeLibraryPath");
field.setAccessible(true);
String path = (String)field.get(null);
assertNotNull("Native library not found", path);
WeakReference ref = new WeakReference(cls);
WeakReference clref = new WeakReference(loader);
loader = null;
cls = null;
field = null;
System.gc();
for (int i=0;i < 100 && (ref.get() != null || clref.get() != null);i++) {
Thread.sleep(10);
System.gc();
}
assertNull("Class not GC'd: " + ref.get(), ref.get());
assertNull("ClassLoader not GC'd: " + clref.get(), clref.get());
Throwable throwable = null;
// NOTE: IBM J9 needs some extra time to unload the native library,
// so try a few times before failing
for (int i=0;i < 100;i++) {
System.gc();
Thread.sleep(10);
try {
loader = new TestLoader(false);
cls = Class.forName("com.sun.jna.Native", true, loader);
break;
}
catch(Throwable t) {
loader = null;
throwable = t;
}
}
try {
if (loader == null)
fail("Native library not unloaded: " + throwable.getMessage());
}
finally {
loader = null;
cls = null;
System.gc();
}
}
public static void main(String[] args) {
junit.textui.TestRunner.run(JNAUnloadTest.class);
}
}