mirror of
https://github.com/xerial/snappy-java.git
synced 2025-04-08 19:35:08 +02:00
Add code to load snappyjava library in java.library.path
This commit is contained in:
parent
244e2183b6
commit
c884620c8f
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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());
|
||||
|
@ -297,7 +297,6 @@ public class SnappyTest
|
||||
}
|
||||
catch (IOException e) {
|
||||
_logger.debug(e);
|
||||
//assertEquals(SnappyErrorCode.FAILED_TO_UNCOMPRESS, e.errorCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
14
src/test/java/org/xerial/snappy/load.code
Executable file
14
src/test/java/org/xerial/snappy/load.code
Executable 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
src/test/java/org/xerial/snappy/loadLibrary.code
Executable file
13
src/test/java/org/xerial/snappy/loadLibrary.code
Executable 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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user