mirror of
https://github.com/xerial/snappy-java.git
synced 2025-07-23 14:04:39 +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;
|
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;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getErrorMessage(int id) {
|
public static SnappyErrorCode getErrorCode(int id) {
|
||||||
for (SnappyErrorCode code : SnappyErrorCode.values()) {
|
for (SnappyErrorCode code : SnappyErrorCode.values()) {
|
||||||
if (code.id == id)
|
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;
|
package org.xerial.snappy;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception in snappy-java
|
* Exception in snappy-java
|
||||||
*
|
*
|
||||||
|
* @deprecated Snappy-java now uses {@link IOException}
|
||||||
* @author leo
|
* @author leo
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class SnappyException extends Exception
|
public class SnappyException extends Exception
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -37,13 +41,7 @@ public class SnappyException extends Exception
|
|||||||
public final SnappyErrorCode errorCode;
|
public final SnappyErrorCode errorCode;
|
||||||
|
|
||||||
public SnappyException(int code) {
|
public SnappyException(int code) {
|
||||||
SnappyErrorCode[] values = SnappyErrorCode.values();
|
this(SnappyErrorCode.getErrorCode(code));
|
||||||
if (code < 0 || code >= values.length) {
|
|
||||||
this.errorCode = SnappyErrorCode.UNKNOWN;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.errorCode = values[code];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SnappyException(SnappyErrorCode errorCode) {
|
public SnappyException(SnappyErrorCode errorCode) {
|
||||||
@ -64,6 +62,10 @@ public class SnappyException extends Exception
|
|||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void throwException(int errorCode) throws SnappyException {
|
||||||
|
throw new SnappyException(errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return String.format("[%s] %s", errorCode.name(), super.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 isInitialized = false;
|
||||||
private static boolean isLoaded = 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 {
|
private static byte[] getByteCode(String resourcePath) throws IOException {
|
||||||
|
|
||||||
InputStream in = SnappyLoader.class.getResourceAsStream(resourcePath);
|
InputStream in = SnappyLoader.class.getResourceAsStream(resourcePath);
|
||||||
@ -107,74 +99,88 @@ public class SnappyLoader
|
|||||||
return byteCodeBuf.toByteArray();
|
return byteCodeBuf.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void load() {
|
public static boolean isNativeLibraryLoaded() {
|
||||||
|
return isLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isInitialized) {
|
static void load() {
|
||||||
final String nativeLoaderClassName = "org.xerial.snappy.SnappyNativeLoader";
|
|
||||||
final String[] classesToPreload = new String[] { "org.xerial.snappy.SnappyNative",
|
|
||||||
"org.xerial.snappy.SnappyErrorCode" };
|
|
||||||
|
|
||||||
try {
|
if (isInitialized)
|
||||||
Class.forName(nativeLoaderClassName);
|
return;
|
||||||
// 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("\\.", "/"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new class from a byte code
|
isInitialized = true;
|
||||||
Class< ? > classLoader = Class.forName("java.lang.ClassLoader");
|
final String nativeLoaderClassName = "org.xerial.snappy.SnappyNativeLoader";
|
||||||
Method defineClass = classLoader.getDeclaredMethod("defineClass", new Class[] { String.class,
|
final String[] classesToPreload = new String[] { "org.xerial.snappy.SnappyNative",
|
||||||
byte[].class, int.class, int.class, ProtectionDomain.class });
|
"org.xerial.snappy.SnappyErrorCode" };
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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";
|
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() {
|
static File findNativeLibrary() {
|
||||||
// Try to load the library from org.xerial.snappy.lib.path library path */
|
// Try to load the library from org.xerial.snappy.lib.path library path */
|
||||||
String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH);
|
String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH);
|
||||||
@ -320,28 +312,6 @@ public class SnappyLoader
|
|||||||
return null;
|
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() {
|
private static void getNativeLibraryFolderForTheCurrentOS() {
|
||||||
String osName = OSInfo.getOSName();
|
String osName = OSInfo.getOSName();
|
||||||
String archName = OSInfo.getArchName();
|
String archName = OSInfo.getArchName();
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
void throw_exception(JNIEnv *env, jclass self, int errorCode)
|
void throw_exception(JNIEnv *env, jclass self, int errorCode)
|
||||||
{
|
{
|
||||||
jmethodID mth_throwex = env->GetStaticMethodID(self, "throw_error", "(I)V");
|
jmethodID mth_throwex = env->GetStaticMethodID(self, "throw_error", "(I)V");
|
||||||
|
|
||||||
if(mth_throwex == 0)
|
if(mth_throwex == 0)
|
||||||
return;
|
return;
|
||||||
env->CallStaticVoidMethod(self, mth_throwex, (jint) errorCode);
|
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 static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
|
|
||||||
import javassist.ClassPool;
|
import javassist.ClassPool;
|
||||||
@ -38,6 +39,7 @@ import org.codehaus.plexus.classworlds.ClassWorld;
|
|||||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.xerial.util.FileResource;
|
||||||
import org.xerial.util.log.Logger;
|
import org.xerial.util.log.Logger;
|
||||||
|
|
||||||
public class SnappyLoaderTest
|
public class SnappyLoaderTest
|
||||||
@ -59,14 +61,16 @@ public class SnappyLoaderTest
|
|||||||
ClassPool pool = ClassPool.getDefault();
|
ClassPool pool = ClassPool.getDefault();
|
||||||
CtClass cl = pool.makeClass("org.xerial.snappy.SnappyNativeLoader");
|
CtClass cl = pool.makeClass("org.xerial.snappy.SnappyNativeLoader");
|
||||||
cl.addField(CtField.make("static boolean isLoaded = false;", cl));
|
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(); } }}";
|
String m1 = FileResource.loadIntoString(SnappyLoaderTest.class, "load.code");
|
||||||
cl.addMethod(CtNewMethod.make(body, cl));
|
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();
|
ProtectionDomain systemPD = System.class.getProtectionDomain();
|
||||||
byte[] bytecode = cl.toBytecode();
|
byte[] bytecode = cl.toBytecode();
|
||||||
// FileOutputStream f = new FileOutputStream("src/main/resources/org/xerial/snappy/SnappyNativeLoader.bytecode");
|
FileOutputStream f = new FileOutputStream("src/main/resources/org/xerial/snappy/SnappyNativeLoader.bytecode");
|
||||||
// f.write(bytecode);
|
f.write(bytecode);
|
||||||
// f.close();
|
f.close();
|
||||||
|
|
||||||
//Class< ? > loaderClass = cl.toClass(parent, System.class.getProtectionDomain());
|
//Class< ? > loaderClass = cl.toClass(parent, System.class.getProtectionDomain());
|
||||||
//_logger.info(cl.getName());
|
//_logger.info(cl.getName());
|
||||||
|
@ -297,7 +297,6 @@ public class SnappyTest
|
|||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
_logger.debug(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