use static call instead of call by reflection

This commit is contained in:
Taro L. Saito 2011-08-01 18:22:48 +09:00
parent 94b879fe12
commit 8d49dddbba
1 changed files with 64 additions and 47 deletions

View File

@ -170,65 +170,82 @@ public class SnappyLoader
e.printStackTrace();
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, e.getMessage());
}
// Prepare SnappyNativeLoader or LocalSnappyNativeLoader
Class< ? > nativeLoader = prepareNativeLoader();
// Load the code
loadNativeLibrary(nativeLoader);
}
else {
if (!isLoaded) {
// load locally
File nativeLib = findNativeLibrary();
if (nativeLib != null) {
System.load(nativeLib.getAbsolutePath());
}
else {
// Load preinstalled snappyjava (in the path -Djava.library.path)
System.loadLibrary("snappyjava");
}
try {
api = (SnappyNativeAPI) Class.forName("org.xerial.snappy.SnappyNative").newInstance();
isLoaded = true;
}
catch (Exception e) {
e.printStackTrace(System.err);
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, e.getMessage());
}
}
}
// Prepare SnappyNativeLoader or LocalSnappyNativeLoader
Class< ? > nativeLoader = prepareNativeLoader();
// Load the code
loadNativeLibrary(nativeLoader);
return api;
}
private static Class< ? > prepareNativeLoader() {
boolean useNativeCodeInjection = !Boolean.parseBoolean(System.getProperty(KEY_SNAPPY_DISABLE_NATIVE_INJECTION,
"false"));
try {
if (!useNativeCodeInjection) {
// Use the local loader
return LocalSnappyNativeLoader.class;
// Use parent class loader to load SnappyNative, since Tomcat, which uses different class loaders for each webapps, cannot load JNI interface twice
final String nativeLoaderClassName = "org.xerial.snappy.SnappyNativeLoader";
ClassLoader rootClassLoader = getRootClassLoader();
// Load a byte code
byte[] byteCode = getByteCode("/org/xerial/snappy/SnappyNativeLoader.bytecode");
// In addition, we need to load the other dependent classes (e.g., SnappyNative and SnappyException) using the system class loader
final String[] classesToPreload = new String[] { "org.xerial.snappy.SnappyNativeAPI",
"org.xerial.snappy.SnappyNative", "org.xerial.snappy.SnappyErrorCode" };
List<byte[]> preloadClassByteCode = new ArrayList<byte[]>(classesToPreload.length);
for (String each : classesToPreload) {
preloadClassByteCode.add(getByteCode(String.format("/%s.class", each.replaceAll("\\.", "/"))));
}
else {
// Use parent class loader to load SnappyNative, since Tomcat, which uses different class loaders for each webapps, cannot load JNI interface twice
final String nativeLoaderClassName = "org.xerial.snappy.SnappyNativeLoader";
ClassLoader rootClassLoader = getRootClassLoader();
// Load a byte code
byte[] byteCode = getByteCode("/org/xerial/snappy/SnappyNativeLoader.bytecode");
// In addition, we need to load the other dependent classes (e.g., SnappyNative and SnappyException) using the system class loader
final String[] classesToPreload = new String[] { "org.xerial.snappy.SnappyNativeAPI",
"org.xerial.snappy.SnappyNative", "org.xerial.snappy.SnappyErrorCode" };
List<byte[]> preloadClassByteCode = new ArrayList<byte[]>(classesToPreload.length);
for (String each : classesToPreload) {
preloadClassByteCode.add(getByteCode(String.format("/%s.class", each.replaceAll("\\.", "/"))));
// Create SnappyNative class from a byte code
Class< ? > classLoader = Class.forName("java.lang.ClassLoader");
Method defineClass = classLoader.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class,
int.class, int.class });
//ProtectionDomain pd = System.class.getProtectionDomain();
// ClassLoader.defineClass is a protected method, so we have to make it accessible
defineClass.setAccessible(true);
try {
// Create a new class using a ClassLoader#defineClass
defineClass.invoke(rootClassLoader, nativeLoaderClassName, byteCode, 0, byteCode.length);
for (int i = 0; i < classesToPreload.length; ++i) {
byte[] b = preloadClassByteCode.get(i);
defineClass.invoke(rootClassLoader, classesToPreload[i], b, 0, b.length);
}
// Create SnappyNative class from a byte code
Class< ? > classLoader = Class.forName("java.lang.ClassLoader");
Method defineClass = classLoader.getDeclaredMethod("defineClass", new Class[] { String.class,
byte[].class, int.class, int.class });
//ProtectionDomain pd = System.class.getProtectionDomain();
// ClassLoader.defineClass is a protected method, so we have to make it accessible
defineClass.setAccessible(true);
try {
// Create a new class using a ClassLoader#defineClass
defineClass.invoke(rootClassLoader, nativeLoaderClassName, byteCode, 0, byteCode.length);
for (int i = 0; i < classesToPreload.length; ++i) {
byte[] b = preloadClassByteCode.get(i);
defineClass.invoke(rootClassLoader, classesToPreload[i], b, 0, b.length);
}
}
finally {
// Reset the accessibility to defineClass method
defineClass.setAccessible(false);
}
// Load the SnappyNativeLoader class
return rootClassLoader.loadClass(nativeLoaderClassName);
}
finally {
// Reset the accessibility to defineClass method
defineClass.setAccessible(false);
}
// Load the SnappyNativeLoader class
return rootClassLoader.loadClass(nativeLoaderClassName);
}
catch (Exception e) {
e.printStackTrace(System.err);