Add code to load snappyjava library in java.library.path

This commit is contained in:
Taro L. Saito 2011-06-24 13:03:39 +09:00
parent 244e2183b6
commit c884620c8f
13 changed files with 136 additions and 125 deletions

View File

@ -7,4 +7,5 @@ Release
syntax: glob
*~
*.sdf
*.ipch
*.ipch
hs_err_pid*

View File

@ -49,4 +49,9 @@ public class SnappyError extends Error
this.errorCode = code;
}
@Override
public String getMessage() {
return String.format("[%s] %s", errorCode.name(), super.getMessage());
}
}

View File

@ -46,11 +46,15 @@ public enum SnappyErrorCode {
this.id = id;
}
public static String getErrorMessage(int id) {
public static SnappyErrorCode getErrorCode(int id) {
for (SnappyErrorCode code : SnappyErrorCode.values()) {
if (code.id == id)
return code.name();
return code;
}
return UNKNOWN.name();
return UNKNOWN;
}
public static String getErrorMessage(int id) {
return getErrorCode(id).name();
}
}

View File

@ -24,12 +24,16 @@
//--------------------------------------
package org.xerial.snappy;
import java.io.IOException;
/**
* Exception in snappy-java
*
* @deprecated Snappy-java now uses {@link IOException}
* @author leo
*
*/
@Deprecated
public class SnappyException extends Exception
{
private static final long serialVersionUID = 1L;
@ -37,13 +41,7 @@ public class SnappyException extends Exception
public final SnappyErrorCode errorCode;
public SnappyException(int code) {
SnappyErrorCode[] values = SnappyErrorCode.values();
if (code < 0 || code >= values.length) {
this.errorCode = SnappyErrorCode.UNKNOWN;
}
else {
this.errorCode = values[code];
}
this(SnappyErrorCode.getErrorCode(code));
}
public SnappyException(SnappyErrorCode errorCode) {
@ -64,6 +62,10 @@ public class SnappyException extends Exception
return errorCode;
}
public static void throwException(int errorCode) throws SnappyException {
throw new SnappyException(errorCode);
}
@Override
public String getMessage() {
return String.format("[%s] %s", errorCode.name(), super.getMessage());

View File

@ -84,14 +84,6 @@ public class SnappyLoader
private static boolean isInitialized = false;
private static boolean isLoaded = false;
private static ClassLoader getSystemClassLoader() {
ClassLoader cl = SnappyLoader.class.getClassLoader();
while (cl.getParent() != null) {
cl = cl.getParent();
}
return cl;
}
private static byte[] getByteCode(String resourcePath) throws IOException {
InputStream in = SnappyLoader.class.getResourceAsStream(resourcePath);
@ -107,74 +99,88 @@ public class SnappyLoader
return byteCodeBuf.toByteArray();
}
public static void load() {
public static boolean isNativeLibraryLoaded() {
return isLoaded;
}
if (!isInitialized) {
final String nativeLoaderClassName = "org.xerial.snappy.SnappyNativeLoader";
final String[] classesToPreload = new String[] { "org.xerial.snappy.SnappyNative",
"org.xerial.snappy.SnappyErrorCode" };
static void load() {
try {
Class.forName(nativeLoaderClassName);
// If this native loader class is already defined, it means that another class loader already loaded the native library of snappy
isInitialized = true;
return;
}
catch (ClassNotFoundException e) {
try {
// 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
List<byte[]> preloadClassByteCode = new ArrayList<byte[]>(classesToPreload.length);
for (String each : classesToPreload) {
preloadClassByteCode.add(getByteCode(String.format("/%s.class", each.replaceAll("\\.", "/"))));
}
if (isInitialized)
return;
// Create a new 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.class });
ClassLoader systemClassLoader = getSystemClassLoader();
// 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(systemClassLoader, nativeLoaderClassName, byteCode, 0, byteCode.length,
System.class.getProtectionDomain());
for (int i = 0; i < classesToPreload.length; ++i) {
byte[] b = preloadClassByteCode.get(i);
defineClass.invoke(systemClassLoader, classesToPreload[i], b, 0, b.length,
System.class.getProtectionDomain());
}
}
finally {
// Reset the accessibility to defineClass method
defineClass.setAccessible(false);
}
// Load the snappy loader class
Class< ? > loaderClass = systemClassLoader.loadClass(nativeLoaderClassName);
if (loaderClass != null) {
Method loadMethod = loaderClass.getDeclaredMethod("load", new Class[] { String.class });
File nativeLib = findNativeLibrary();
loadMethod.invoke(null, nativeLib.getAbsolutePath());
// And also, preload the other dependent classes
for (String each : classesToPreload) {
systemClassLoader.loadClass(each);
}
isInitialized = true;
}
}
catch (Exception e2) {
e2.printStackTrace();
}
}
isInitialized = true;
final String nativeLoaderClassName = "org.xerial.snappy.SnappyNativeLoader";
final String[] classesToPreload = new String[] { "org.xerial.snappy.SnappyNative",
"org.xerial.snappy.SnappyErrorCode" };
try {
Class.forName(nativeLoaderClassName);
// If this native loader class is already defined, it means that another class loader already loaded the native library of snappy
isLoaded = true;
return;
}
catch (ClassNotFoundException e) {
try {
// 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
List<byte[]> preloadClassByteCode = new ArrayList<byte[]>(classesToPreload.length);
for (String each : classesToPreload) {
preloadClassByteCode.add(getByteCode(String.format("/%s.class", each.replaceAll("\\.", "/"))));
}
// Create a new 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.class });
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// 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(systemClassLoader, nativeLoaderClassName, byteCode, 0, byteCode.length,
System.class.getProtectionDomain());
for (int i = 0; i < classesToPreload.length; ++i) {
byte[] b = preloadClassByteCode.get(i);
defineClass.invoke(systemClassLoader, classesToPreload[i], b, 0, b.length,
System.class.getProtectionDomain());
}
}
finally {
// Reset the accessibility to defineClass method
defineClass.setAccessible(false);
}
// Load the snappy loader class
Class< ? > loaderClass = systemClassLoader.loadClass(nativeLoaderClassName);
if (loaderClass != null) {
File nativeLib = findNativeLibrary();
if (nativeLib != null) {
// Load extracted or specified snappyjava native library.
Method loadMethod = loaderClass.getDeclaredMethod("load", new Class[] { String.class });
loadMethod.invoke(null, nativeLib.getAbsolutePath());
}
else {
// Load preinstalled snappyjava (in the path -Djava.library.path)
Method loadMethod = loaderClass.getDeclaredMethod("loadLibrary", new Class[] { String.class });
loadMethod.invoke(null, "snappyjava");
}
// And also, preload the other dependent classes
for (String each : classesToPreload) {
systemClassLoader.loadClass(each);
}
isLoaded = true;
}
}
catch (Exception e2) {
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, e.getMessage());
}
}
}
public static final String KEY_SNAPPY_LIB_PATH = "org.xerial.snappy.lib.path";
@ -272,20 +278,6 @@ public class SnappyLoader
}
}
private static synchronized boolean loadNativeLibrary(File libPath) {
if (libPath.exists()) {
try {
System.load(libPath.getAbsolutePath());
return true;
}
catch (UnsatisfiedLinkError e) {
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, e);
}
}
else
return false;
}
static File findNativeLibrary() {
// Try to load the library from org.xerial.snappy.lib.path library path */
String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH);
@ -320,28 +312,6 @@ public class SnappyLoader
return null;
}
private static void loadSnappyNativeLibrary() {
if (isLoaded)
return;
File nativeLibrary = findNativeLibrary();
if (nativeLibrary != null) {
if (loadNativeLibrary(nativeLibrary)) {
isLoaded = true;
return;
}
}
// Try to load snappyjava DLL in LD_LIBRARY_PATH
try {
System.loadLibrary("snappyjava");
isLoaded = true;
}
catch (UnsatisfiedLinkError e) {
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, e);
}
}
private static void getNativeLibraryFolderForTheCurrentOS() {
String osName = OSInfo.getOSName();
String archName = OSInfo.getArchName();

View File

@ -20,7 +20,6 @@
void throw_exception(JNIEnv *env, jclass self, int errorCode)
{
jmethodID mth_throwex = env->GetStaticMethodID(self, "throw_error", "(I)V");
if(mth_throwex == 0)
return;
env->CallStaticVoidMethod(self, mth_throwex, (jint) errorCode);

View File

@ -27,6 +27,7 @@ package org.xerial.snappy;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileOutputStream;
import java.security.ProtectionDomain;
import javassist.ClassPool;
@ -38,6 +39,7 @@ import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.junit.Ignore;
import org.junit.Test;
import org.xerial.util.FileResource;
import org.xerial.util.log.Logger;
public class SnappyLoaderTest
@ -59,14 +61,16 @@ public class SnappyLoaderTest
ClassPool pool = ClassPool.getDefault();
CtClass cl = pool.makeClass("org.xerial.snappy.SnappyNativeLoader");
cl.addField(CtField.make("static boolean isLoaded = false;", cl));
String body = "public static void load(String lib) {if(!isLoaded) { try { System.load(lib); isLoaded=true; } catch(Exception e) { e.printStackTrace(); } }}";
cl.addMethod(CtNewMethod.make(body, cl));
String m1 = FileResource.loadIntoString(SnappyLoaderTest.class, "load.code");
String m2 = FileResource.loadIntoString(SnappyLoaderTest.class, "loadLibrary.code");
cl.addMethod(CtNewMethod.make(m1, cl));
cl.addMethod(CtNewMethod.make(m2, cl));
ProtectionDomain systemPD = System.class.getProtectionDomain();
byte[] bytecode = cl.toBytecode();
// FileOutputStream f = new FileOutputStream("src/main/resources/org/xerial/snappy/SnappyNativeLoader.bytecode");
// f.write(bytecode);
// f.close();
FileOutputStream f = new FileOutputStream("src/main/resources/org/xerial/snappy/SnappyNativeLoader.bytecode");
f.write(bytecode);
f.close();
//Class< ? > loaderClass = cl.toClass(parent, System.class.getProtectionDomain());
//_logger.info(cl.getName());

View File

@ -297,7 +297,6 @@ public class SnappyTest
}
catch (IOException e) {
_logger.debug(e);
//assertEquals(SnappyErrorCode.FAILED_TO_UNCOMPRESS, e.errorCode);
}
}

View File

@ -0,0 +1,14 @@
public static void load(String lib) {
if(isLoaded)
return;
try {
System.load(lib);
isLoaded=true;
}
catch(Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,13 @@
public static void loadLibrary(String libname) {
if(isLoaded)
return;
try {
System.load(libname);
isLoaded=true;
}
catch(Exception e) {
e.printStackTrace();
}
}
}