mirror of
https://github.com/xerial/snappy-java.git
synced 2025-07-25 15:04:32 +02:00
Add a trick to delegate native library loading to the parent class loader
This commit is contained in:
parent
4301cfd9bd
commit
dc0e8a3150
7
pom.xml
7
pom.xml
@ -232,5 +232,12 @@
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<version>3.14.0-GA</version>
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -24,6 +24,7 @@
|
||||
//--------------------------------------
|
||||
package org.xerial.snappy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@ -49,9 +50,9 @@ public class Snappy
|
||||
* @param input
|
||||
* the input data
|
||||
* @return the compressed byte array
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static byte[] compress(byte[] input) throws SnappyException {
|
||||
public static byte[] compress(byte[] input) throws IOException {
|
||||
return rawCompress(input, input.length);
|
||||
}
|
||||
|
||||
@ -65,11 +66,11 @@ public class Snappy
|
||||
* @param output
|
||||
* @param outputOffset
|
||||
* @return byte size of the compressed data
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
* when failed to access the input/output buffer
|
||||
*/
|
||||
public static int compress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
|
||||
throws SnappyException {
|
||||
throws IOException {
|
||||
return rawCompress(input, inputOffset, inputLength, output, outputOffset);
|
||||
}
|
||||
|
||||
@ -87,7 +88,7 @@ public class Snappy
|
||||
* @throws SnappyError
|
||||
* when the input is not a direct buffer
|
||||
*/
|
||||
public static int compress(ByteBuffer uncompressed, ByteBuffer compressed) throws SnappyException {
|
||||
public static int compress(ByteBuffer uncompressed, ByteBuffer compressed) throws IOException {
|
||||
|
||||
if (!uncompressed.isDirect())
|
||||
throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
|
||||
@ -131,7 +132,7 @@ public class Snappy
|
||||
return rawCompress(input, input.length * 2); // short uses 2 bytes
|
||||
}
|
||||
|
||||
public static byte[] compress(String s) throws SnappyException {
|
||||
public static byte[] compress(String s) throws IOException {
|
||||
try {
|
||||
return compress(s, "UTF-8");
|
||||
}
|
||||
@ -140,7 +141,7 @@ public class Snappy
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] compress(String s, String encoding) throws UnsupportedEncodingException, SnappyException {
|
||||
public static byte[] compress(String s, String encoding) throws UnsupportedEncodingException, IOException {
|
||||
byte[] data = s.getBytes(encoding);
|
||||
return compress(data);
|
||||
}
|
||||
@ -160,7 +161,7 @@ public class Snappy
|
||||
* uncompressed data. Takes time proportional to the input length, but is
|
||||
* usually at least a factor of four faster than actual decompression.
|
||||
*/
|
||||
public static boolean isValidCompressedBuffer(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static boolean isValidCompressedBuffer(byte[] input, int offset, int length) throws IOException {
|
||||
if (input == null)
|
||||
throw new NullPointerException("input is null");
|
||||
return SnappyNative.isValidCompressedBuffer(input, offset, length);
|
||||
@ -172,7 +173,7 @@ public class Snappy
|
||||
* uncompressed data. Takes time proportional to the input length, but is
|
||||
* usually at least a factor of four faster than actual decompression.
|
||||
*/
|
||||
public static boolean isValidCompressedBuffer(byte[] input) throws SnappyException {
|
||||
public static boolean isValidCompressedBuffer(byte[] input) throws IOException {
|
||||
return isValidCompressedBuffer(input, 0, input.length);
|
||||
}
|
||||
|
||||
@ -182,7 +183,7 @@ public class Snappy
|
||||
* Takes time proportional to the input length, but is usually at least a
|
||||
* factor of four faster than actual decompression.
|
||||
*/
|
||||
public static boolean isValidCompressedBuffer(ByteBuffer compressed) throws SnappyException {
|
||||
public static boolean isValidCompressedBuffer(ByteBuffer compressed) throws IOException {
|
||||
return SnappyNative.isValidCompressedBuffer(compressed, compressed.position(), compressed.remaining());
|
||||
}
|
||||
|
||||
@ -230,10 +231,10 @@ public class Snappy
|
||||
* @param outputOffset
|
||||
* byte offset at the output array
|
||||
* @return byte size of the compressed data
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static int rawCompress(Object input, int inputOffset, int inputLength, byte[] output, int outputOffset)
|
||||
throws SnappyException {
|
||||
throws IOException {
|
||||
if (input == null || output == null)
|
||||
throw new NullPointerException("input or output is null");
|
||||
|
||||
@ -262,10 +263,10 @@ public class Snappy
|
||||
* @param outputOffset
|
||||
* byte offset
|
||||
* @return the byte size of the uncompressed data
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static int rawUncompress(byte[] input, int inputOffset, int inputLength, Object output, int outputOffset)
|
||||
throws SnappyException {
|
||||
throws IOException {
|
||||
if (input == null || output == null)
|
||||
throw new NullPointerException("input or output is null");
|
||||
return SnappyNative.rawUncompress(input, inputOffset, inputLength, output, outputOffset);
|
||||
@ -276,9 +277,9 @@ public class Snappy
|
||||
*
|
||||
* @param input
|
||||
* @return the uncompressed byte array
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static byte[] uncompress(byte[] input) throws SnappyException {
|
||||
public static byte[] uncompress(byte[] input) throws IOException {
|
||||
byte[] result = new byte[Snappy.uncompressedLength(input)];
|
||||
int byteSize = Snappy.uncompress(input, 0, input.length, result, 0);
|
||||
return result;
|
||||
@ -300,10 +301,10 @@ public class Snappy
|
||||
* @param output
|
||||
* @param outputOffset
|
||||
* @return the byte size of the uncompressed data
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static int uncompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
|
||||
throws SnappyException {
|
||||
throws IOException {
|
||||
return rawUncompress(input, inputOffset, inputLength, output, outputOffset);
|
||||
}
|
||||
|
||||
@ -323,12 +324,12 @@ public class Snappy
|
||||
* output of the the uncompressed data. It uses buffer[pot()..]
|
||||
* @return uncompressed data size
|
||||
*
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
* when failed to uncompress the given input
|
||||
* @throws SnappyError
|
||||
* when the input is not a direct buffer
|
||||
*/
|
||||
public static int uncompress(ByteBuffer compressed, ByteBuffer uncompressed) throws SnappyException {
|
||||
public static int uncompress(ByteBuffer compressed, ByteBuffer uncompressed) throws IOException {
|
||||
|
||||
if (!compressed.isDirect())
|
||||
throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
|
||||
@ -347,18 +348,18 @@ public class Snappy
|
||||
return decompressedSize;
|
||||
}
|
||||
|
||||
public static char[] uncompressCharArray(byte[] input) throws SnappyException {
|
||||
public static char[] uncompressCharArray(byte[] input) throws IOException {
|
||||
return uncompressCharArray(input, 0, input.length);
|
||||
}
|
||||
|
||||
public static char[] uncompressCharArray(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static char[] uncompressCharArray(byte[] input, int offset, int length) throws IOException {
|
||||
int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
|
||||
char[] result = new char[uncompressedLength / 2];
|
||||
int byteSize = SnappyNative.rawUncompress(input, offset, length, result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double[] uncompressDoubleArray(byte[] input) throws SnappyException {
|
||||
public static double[] uncompressDoubleArray(byte[] input) throws IOException {
|
||||
int uncompressedLength = Snappy.uncompressedLength(input, 0, input.length);
|
||||
double[] result = new double[uncompressedLength / 8];
|
||||
int byteSize = SnappyNative.rawUncompress(input, 0, input.length, result, 0);
|
||||
@ -371,11 +372,11 @@ public class Snappy
|
||||
*
|
||||
* @param input
|
||||
* @return umcompressed byte size of the the given input data
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
* when failed to uncompress the given input. The error code is
|
||||
* {@link SnappyErrorCode#PARSING_ERROR}
|
||||
*/
|
||||
public static int uncompressedLength(byte[] input) throws SnappyException {
|
||||
public static int uncompressedLength(byte[] input) throws IOException {
|
||||
return SnappyNative.uncompressedLength(input, 0, input.length);
|
||||
}
|
||||
|
||||
@ -387,11 +388,11 @@ public class Snappy
|
||||
* @param offset
|
||||
* @param length
|
||||
* @return umcompressed byte size of the the given input data
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
* when failed to uncompress the given input. The error code is
|
||||
* {@link SnappyErrorCode#PARSING_ERROR}
|
||||
*/
|
||||
public static int uncompressedLength(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static int uncompressedLength(byte[] input, int offset, int length) throws IOException {
|
||||
if (input == null)
|
||||
throw new NullPointerException("input is null");
|
||||
|
||||
@ -409,8 +410,7 @@ public class Snappy
|
||||
}
|
||||
}
|
||||
|
||||
public static CompressedDataLength getUncompressedLength(byte[] input, int offset, int limit)
|
||||
throws SnappyException {
|
||||
public static CompressedDataLength getUncompressedLength(byte[] input, int offset, int limit) throws IOException {
|
||||
if (input == null)
|
||||
throw new NullPointerException("input is null");
|
||||
|
||||
@ -463,64 +463,64 @@ public class Snappy
|
||||
* @param compressed
|
||||
* input data [pos() ... limit())
|
||||
* @return uncompressed byte length of the given input
|
||||
* @throws SnappyException
|
||||
* @throws IOException
|
||||
* when failed to uncompress the given input. The error code is
|
||||
* {@link SnappyErrorCode#PARSING_ERROR}
|
||||
* @throws SnappyError
|
||||
* when the input is not a direct buffer
|
||||
*/
|
||||
public static int uncompressedLength(ByteBuffer compressed) throws SnappyException {
|
||||
public static int uncompressedLength(ByteBuffer compressed) throws IOException {
|
||||
if (!compressed.isDirect())
|
||||
throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
|
||||
|
||||
return SnappyNative.uncompressedLength(compressed, compressed.position(), compressed.remaining());
|
||||
}
|
||||
|
||||
public static float[] uncompressFloatArray(byte[] input) throws SnappyException {
|
||||
public static float[] uncompressFloatArray(byte[] input) throws IOException {
|
||||
return uncompressFloatArray(input, 0, input.length);
|
||||
}
|
||||
|
||||
public static float[] uncompressFloatArray(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static float[] uncompressFloatArray(byte[] input, int offset, int length) throws IOException {
|
||||
int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
|
||||
float[] result = new float[uncompressedLength / 4];
|
||||
int byteSize = SnappyNative.rawUncompress(input, offset, length, result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] uncompressIntArray(byte[] input) throws SnappyException {
|
||||
public static int[] uncompressIntArray(byte[] input) throws IOException {
|
||||
return uncompressIntArray(input, 0, input.length);
|
||||
}
|
||||
|
||||
public static int[] uncompressIntArray(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static int[] uncompressIntArray(byte[] input, int offset, int length) throws IOException {
|
||||
int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
|
||||
int[] result = new int[uncompressedLength / 4];
|
||||
int byteSize = SnappyNative.rawUncompress(input, offset, length, result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static long[] uncompressLongArray(byte[] input) throws SnappyException {
|
||||
public static long[] uncompressLongArray(byte[] input) throws IOException {
|
||||
return uncompressLongArray(input, 0, input.length);
|
||||
}
|
||||
|
||||
public static long[] uncompressLongArray(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static long[] uncompressLongArray(byte[] input, int offset, int length) throws IOException {
|
||||
int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
|
||||
long[] result = new long[uncompressedLength / 8];
|
||||
int byteSize = SnappyNative.rawUncompress(input, offset, length, result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static short[] uncompressShortArray(byte[] input) throws SnappyException {
|
||||
public static short[] uncompressShortArray(byte[] input) throws IOException {
|
||||
return uncompressShortArray(input, 0, input.length);
|
||||
}
|
||||
|
||||
public static short[] uncompressShortArray(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static short[] uncompressShortArray(byte[] input, int offset, int length) throws IOException {
|
||||
int uncompressedLength = Snappy.uncompressedLength(input, offset, length);
|
||||
short[] result = new short[uncompressedLength / 2];
|
||||
int byteSize = SnappyNative.rawUncompress(input, offset, length, result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String uncompressString(byte[] input) throws SnappyException {
|
||||
public static String uncompressString(byte[] input) throws IOException {
|
||||
try {
|
||||
return uncompressString(input, "UTF-8");
|
||||
}
|
||||
@ -529,7 +529,7 @@ public class Snappy
|
||||
}
|
||||
}
|
||||
|
||||
public static String uncompressString(byte[] input, int offset, int length) throws SnappyException {
|
||||
public static String uncompressString(byte[] input, int offset, int length) throws IOException {
|
||||
try {
|
||||
return uncompressString(input, offset, length, "UTF-8");
|
||||
}
|
||||
@ -538,14 +538,14 @@ public class Snappy
|
||||
}
|
||||
}
|
||||
|
||||
public static String uncompressString(byte[] input, int offset, int length, String encoding)
|
||||
throws SnappyException, UnsupportedEncodingException {
|
||||
public static String uncompressString(byte[] input, int offset, int length, String encoding) throws IOException,
|
||||
UnsupportedEncodingException {
|
||||
byte[] uncompressed = new byte[uncompressedLength(input, offset, length)];
|
||||
int compressedSize = uncompress(input, offset, length, uncompressed, 0);
|
||||
return new String(uncompressed, encoding);
|
||||
}
|
||||
|
||||
public static String uncompressString(byte[] input, String encoding) throws SnappyException,
|
||||
public static String uncompressString(byte[] input, String encoding) throws IOException,
|
||||
UnsupportedEncodingException {
|
||||
byte[] uncompressed = uncompress(input);
|
||||
return new String(uncompressed, encoding);
|
||||
|
@ -45,4 +45,12 @@ public enum SnappyErrorCode {
|
||||
private SnappyErrorCode(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static String getErrorMessage(int id) {
|
||||
for (SnappyErrorCode code : SnappyErrorCode.values()) {
|
||||
if (code.id == id)
|
||||
return code.name();
|
||||
}
|
||||
return UNKNOWN.name();
|
||||
}
|
||||
}
|
||||
|
@ -95,16 +95,11 @@ public class SnappyInputStream extends InputStream
|
||||
finishedReading = true;
|
||||
|
||||
// Uncompress
|
||||
try {
|
||||
int uncompressedLength = Snappy.uncompressedLength(compressed, 0, cursor);
|
||||
uncompressed = new byte[uncompressedLength];
|
||||
Snappy.uncompress(compressed, 0, cursor, uncompressed, 0);
|
||||
this.uncompressedCursor = 0;
|
||||
this.uncompressedLimit = uncompressedLength;
|
||||
}
|
||||
catch (SnappyException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
int uncompressedLength = Snappy.uncompressedLength(compressed, 0, cursor);
|
||||
uncompressed = new byte[uncompressedLength];
|
||||
Snappy.uncompress(compressed, 0, cursor, uncompressed, 0);
|
||||
this.uncompressedCursor = 0;
|
||||
this.uncompressedLimit = uncompressedLength;
|
||||
|
||||
}
|
||||
|
||||
@ -160,7 +155,7 @@ public class SnappyInputStream extends InputStream
|
||||
}
|
||||
uncompressedLimit = actualUncompressedLength;
|
||||
}
|
||||
catch (SnappyException e) {
|
||||
catch (IOException e) {
|
||||
throw new IOException("failed to uncompress the chunk: " + e.getMessage());
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,9 @@ import java.net.URL;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@ -77,13 +80,97 @@ import java.util.Properties;
|
||||
*/
|
||||
public class SnappyLoader
|
||||
{
|
||||
private static boolean isLoaded = false;
|
||||
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);
|
||||
assert (in != null);
|
||||
byte[] buf = new byte[1024];
|
||||
ByteArrayOutputStream byteCodeBuf = new ByteArrayOutputStream();
|
||||
for (int readLength; (readLength = in.read(buf)) != -1;) {
|
||||
byteCodeBuf.write(buf, 0, readLength);
|
||||
}
|
||||
in.close();
|
||||
|
||||
return byteCodeBuf.toByteArray();
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
|
||||
if (!isInitialized) {
|
||||
final String nativeLoaderClassName = "org.xerial.snappy.SnappyNativeLoader";
|
||||
final String[] preloadClass = 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
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
try {
|
||||
// Load a byte code
|
||||
byte[] byteCode = getByteCode("/org/xerial/snappy/SnappyNativeLoader.bytecode");
|
||||
// In addition, load the SnappyNative and SnappyException class in the system class loader
|
||||
List<byte[]> preloadClassByteCode = new ArrayList<byte[]>(preloadClass.length);
|
||||
for (String each : preloadClass) {
|
||||
preloadClassByteCode.add(getByteCode(String.format("/%s.class", each.replaceAll("\\.", "/"))));
|
||||
}
|
||||
|
||||
// Create a new class to the system class loader
|
||||
Class< ? > classLoader = Class.forName("java.lang.ClassLoader");
|
||||
java.lang.reflect.Method defineClass = classLoader.getDeclaredMethod("defineClass", new Class[] {
|
||||
String.class, byte[].class, int.class, int.class, ProtectionDomain.class });
|
||||
|
||||
ClassLoader systemClassLoader = getSystemClassLoader();
|
||||
defineClass.setAccessible(true);
|
||||
try {
|
||||
// Load SnappyNativeLoader
|
||||
defineClass.invoke(systemClassLoader, nativeLoaderClassName, byteCode, 0, byteCode.length,
|
||||
System.class.getProtectionDomain());
|
||||
|
||||
for (int i = 0; i < preloadClass.length; ++i) {
|
||||
byte[] b = preloadClassByteCode.get(i);
|
||||
defineClass.invoke(systemClassLoader, preloadClass[i], b, 0, b.length,
|
||||
System.class.getProtectionDomain());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
defineClass.setAccessible(false);
|
||||
}
|
||||
|
||||
// Load the loader class
|
||||
Class< ? > loaderClass = systemClassLoader.loadClass(nativeLoaderClassName);
|
||||
if (loaderClass != null) {
|
||||
java.lang.reflect.Method loadMethod = loaderClass.getDeclaredMethod("load",
|
||||
new Class[] { String.class });
|
||||
File nativeLib = findNativeLibrary();
|
||||
loadMethod.invoke(null, nativeLib.getAbsolutePath());
|
||||
|
||||
for (String each : preloadClass) {
|
||||
systemClassLoader.loadClass(each);
|
||||
}
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e2) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean load() {
|
||||
if (!isLoaded) {
|
||||
loadSnappyNativeLibrary();
|
||||
}
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public static final String KEY_SNAPPY_LIB_PATH = "org.xerial.snappy.lib.path";
|
||||
@ -101,7 +188,6 @@ public class SnappyLoader
|
||||
*/
|
||||
static String md5sum(InputStream input) throws IOException {
|
||||
BufferedInputStream in = new BufferedInputStream(input);
|
||||
|
||||
try {
|
||||
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
|
||||
DigestInputStream digestInputStream = new DigestInputStream(in, digest);
|
||||
@ -128,8 +214,7 @@ public class SnappyLoader
|
||||
* @param targetFolder
|
||||
* @return
|
||||
*/
|
||||
private static boolean extractAndLoadLibraryFile(String libFolderForCurrentOS, String libraryFileName,
|
||||
String targetFolder) {
|
||||
private static File extractLibraryFile(String libFolderForCurrentOS, String libraryFileName, String targetFolder) {
|
||||
String nativeLibraryFilePath = libFolderForCurrentOS + "/" + libraryFileName;
|
||||
final String prefix = "snappy-" + getVersion() + "-";
|
||||
String extractedLibFileName = prefix + libraryFileName;
|
||||
@ -142,7 +227,7 @@ public class SnappyLoader
|
||||
String md5sum2 = md5sum(new FileInputStream(extractedLibFile));
|
||||
|
||||
if (md5sum1.equals(md5sum2)) {
|
||||
return loadNativeLibrary(targetFolder, extractedLibFileName);
|
||||
return new File(targetFolder, extractedLibFileName);
|
||||
}
|
||||
else {
|
||||
// remove old native library file
|
||||
@ -154,10 +239,10 @@ public class SnappyLoader
|
||||
}
|
||||
}
|
||||
|
||||
// extract a native library file into the target directory
|
||||
// Extract a native library file into the target directory
|
||||
InputStream reader = SnappyLoader.class.getResourceAsStream(nativeLibraryFilePath);
|
||||
FileOutputStream writer = new FileOutputStream(extractedLibFile);
|
||||
byte[] buffer = new byte[1024];
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead = 0;
|
||||
while ((bytesRead = reader.read(buffer)) != -1) {
|
||||
writer.write(buffer, 0, bytesRead);
|
||||
@ -175,52 +260,46 @@ public class SnappyLoader
|
||||
catch (Throwable e) {}
|
||||
}
|
||||
|
||||
return loadNativeLibrary(targetFolder, extractedLibFileName);
|
||||
return new File(targetFolder, extractedLibFileName);
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.err.println(e.getMessage());
|
||||
return false;
|
||||
e.printStackTrace(System.err);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static synchronized boolean loadNativeLibrary(String path, String name) {
|
||||
File libPath = new File(path, name);
|
||||
private static synchronized boolean loadNativeLibrary(File libPath) {
|
||||
if (libPath.exists()) {
|
||||
|
||||
try {
|
||||
System.load(new File(path, name).getAbsolutePath());
|
||||
System.load(libPath.getAbsolutePath());
|
||||
return true;
|
||||
}
|
||||
catch (UnsatisfiedLinkError e) {
|
||||
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, e);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void loadSnappyNativeLibrary() {
|
||||
if (isLoaded)
|
||||
return;
|
||||
static File findNativeLibrary() {
|
||||
// Try to load the library from org.xerial.snappy.lib.path library path */
|
||||
String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH);
|
||||
String snappyNativeLibraryName = System.getProperty(KEY_SNAPPY_LIB_NAME);
|
||||
|
||||
if (System.getProperty(KEY_SNAPPY_DISABLE_BUNDLED_LIBS, "false").equals("false")) {
|
||||
// Try to load the library from org.xerial.snappy.lib.path library path */
|
||||
String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH);
|
||||
String snappyNativeLibraryName = System.getProperty(KEY_SNAPPY_LIB_NAME);
|
||||
|
||||
// Resolve the library file name with a suffix (e.g., dll, .so, etc.)
|
||||
if (snappyNativeLibraryName == null)
|
||||
snappyNativeLibraryName = System.mapLibraryName("snappyjava");
|
||||
|
||||
if (snappyNativeLibraryPath != null) {
|
||||
if (loadNativeLibrary(snappyNativeLibraryPath, snappyNativeLibraryName)) {
|
||||
isLoaded = true;
|
||||
return;
|
||||
}
|
||||
File nativeLib = new File(snappyNativeLibraryPath, snappyNativeLibraryName);
|
||||
if (nativeLib.exists())
|
||||
return nativeLib;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Load an OS-dependent native library inside a jar file
|
||||
snappyNativeLibraryPath = "/org/xerial/snappy/native/" + OSInfo.getNativeLibFolderPathForCurrentOS();
|
||||
|
||||
@ -230,10 +309,22 @@ public class SnappyLoader
|
||||
System.getProperty("java.io.tmpdir"))).getAbsolutePath();
|
||||
|
||||
// Extract and load a native library inside the jar file
|
||||
if (extractAndLoadLibraryFile(snappyNativeLibraryPath, snappyNativeLibraryName, tempFolder)) {
|
||||
isLoaded = true;
|
||||
return;
|
||||
}
|
||||
return extractLibraryFile(snappyNativeLibraryPath, snappyNativeLibraryName, tempFolder);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void loadSnappyNativeLibrary() {
|
||||
if (isLoaded)
|
||||
return;
|
||||
|
||||
File nativeLibrary = findNativeLibrary();
|
||||
if (nativeLibrary != null) {
|
||||
if (loadNativeLibrary(nativeLibrary)) {
|
||||
isLoaded = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
//--------------------------------------
|
||||
package org.xerial.snappy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
@ -35,37 +36,38 @@ import java.nio.ByteBuffer;
|
||||
public class SnappyNative
|
||||
{
|
||||
|
||||
native static String nativeLibraryVersion();
|
||||
public native static String nativeLibraryVersion();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Generic compression/decompression routines.
|
||||
// ------------------------------------------------------------------------
|
||||
native static int rawCompress(ByteBuffer input, int inputOffset, int inputLength, ByteBuffer compressed,
|
||||
int outputOffset) throws SnappyException;
|
||||
public native static int rawCompress(ByteBuffer input, int inputOffset, int inputLength, ByteBuffer compressed,
|
||||
int outputOffset) throws IOException;
|
||||
|
||||
native static int rawCompress(Object input, int inputOffset, int inputByteLength, Object output, int outputOffset);
|
||||
public native static int rawCompress(Object input, int inputOffset, int inputByteLength, Object output,
|
||||
int outputOffset);
|
||||
|
||||
native static int rawUncompress(ByteBuffer compressed, int inputOffset, int inputLength, ByteBuffer uncompressed,
|
||||
int outputOffset) throws SnappyException;
|
||||
public native static int rawUncompress(ByteBuffer compressed, int inputOffset, int inputLength,
|
||||
ByteBuffer uncompressed, int outputOffset) throws IOException;
|
||||
|
||||
native static int rawUncompress(Object input, int inputOffset, int inputLength, Object output, int outputOffset)
|
||||
throws SnappyException;
|
||||
public native static int rawUncompress(Object input, int inputOffset, int inputLength, Object output,
|
||||
int outputOffset) throws IOException;
|
||||
|
||||
// Returns the maximal size of the compressed representation of
|
||||
// input data that is "source_bytes" bytes in length;
|
||||
native static int maxCompressedLength(int source_bytes);
|
||||
public native static int maxCompressedLength(int source_bytes);
|
||||
|
||||
// This operation takes O(1) time.
|
||||
native static int uncompressedLength(ByteBuffer compressed, int offset, int len) throws SnappyException;
|
||||
public native static int uncompressedLength(ByteBuffer compressed, int offset, int len) throws IOException;
|
||||
|
||||
native static int uncompressedLength(Object input, int offset, int len) throws SnappyException;
|
||||
public native static int uncompressedLength(Object input, int offset, int len) throws IOException;
|
||||
|
||||
native static boolean isValidCompressedBuffer(ByteBuffer compressed, int offset, int len) throws SnappyException;
|
||||
public native static boolean isValidCompressedBuffer(ByteBuffer compressed, int offset, int len) throws IOException;
|
||||
|
||||
native static boolean isValidCompressedBuffer(Object input, int offset, int len) throws SnappyException;
|
||||
public native static boolean isValidCompressedBuffer(Object input, int offset, int len) throws IOException;
|
||||
|
||||
protected static void throw_error(int errorCode) throws SnappyException {
|
||||
throw new SnappyException(errorCode);
|
||||
protected static void throw_error(int errorCode) throws IOException {
|
||||
throw new IOException(SnappyErrorCode.getErrorMessage(errorCode));
|
||||
}
|
||||
|
||||
}
|
||||
|
BIN
src/main/java/org/xerial/snappy/SnappyNativeLoader.bytecode
Executable file
BIN
src/main/java/org/xerial/snappy/SnappyNativeLoader.bytecode
Executable file
Binary file not shown.
@ -121,15 +121,10 @@ public class SnappyOutputStream extends OutputStream
|
||||
return; // no need to dump
|
||||
|
||||
// Compress and dump the buffer content
|
||||
try {
|
||||
int compressedSize = Snappy.compress(uncompressed, 0, cursor, compressed, 0);
|
||||
writeInt(out, compressedSize);
|
||||
out.write(compressed, 0, compressedSize);
|
||||
cursor = 0;
|
||||
}
|
||||
catch (SnappyException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
int compressedSize = Snappy.compress(uncompressed, 0, cursor, compressed, 0);
|
||||
writeInt(out, compressedSize);
|
||||
out.write(compressed, 0, compressedSize);
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,8 +24,19 @@
|
||||
//--------------------------------------
|
||||
package org.xerial.snappy;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtField;
|
||||
import javassist.CtNewMethod;
|
||||
|
||||
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.log.Logger;
|
||||
|
||||
@ -33,6 +44,7 @@ public class SnappyLoaderTest
|
||||
{
|
||||
private static Logger _logger = Logger.getLogger(SnappyLoaderTest.class);
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void loadFromSytemClassLoader() throws Exception {
|
||||
|
||||
@ -41,8 +53,53 @@ public class SnappyLoaderTest
|
||||
ClassRealm L1 = cw.newRealm("l1", parent);
|
||||
ClassRealm L2 = cw.newRealm("l2", parent);
|
||||
|
||||
File nativeLib = SnappyLoader.findNativeLibrary();
|
||||
assertNotNull(nativeLib);
|
||||
|
||||
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));
|
||||
|
||||
ProtectionDomain systemPD = System.class.getProtectionDomain();
|
||||
byte[] bytecode = cl.toBytecode();
|
||||
// FileOutputStream f = new FileOutputStream("src/main/java/org/xerial/snappy/SnappyNativeLoader.bytecode");
|
||||
// f.write(bytecode);
|
||||
// f.close();
|
||||
|
||||
//Class< ? > loaderClass = cl.toClass(parent, System.class.getProtectionDomain());
|
||||
//_logger.info(cl.getName());
|
||||
//Class< ? > loaderClass = cl.toClass();
|
||||
|
||||
Class< ? > classLoader = Class.forName("java.lang.ClassLoader");
|
||||
java.lang.reflect.Method defineClass = classLoader.getDeclaredMethod("defineClass", new Class[] { String.class,
|
||||
byte[].class, int.class, int.class, ProtectionDomain.class });
|
||||
|
||||
defineClass.setAccessible(true);
|
||||
defineClass.invoke(parent, cl.getName(), bytecode, 0, bytecode.length, System.class.getProtectionDomain());
|
||||
|
||||
Class< ? > forName = parent.loadClass("org.xerial.snappy.SnappyNativeLoader");
|
||||
_logger.info(forName.toString());
|
||||
|
||||
//Class< ? > snappyClass = L1.loadClass("org.xerial.snappy.Snappy"); // not found
|
||||
//_logger.info(snappyClass.getName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load() throws Exception {
|
||||
//SnappyLoader.load();
|
||||
// Class< ? > c1 = Class.forName("org.xerial.snappy.SnappyNative");
|
||||
// Class< ? > c2 = Class.forName("org.xerial.snappy.Snappy");
|
||||
// ClassLoader cl1 = c1.getClassLoader();
|
||||
// ClassLoader cl2 = c2.getClassLoader();
|
||||
// Method m = c1.getDeclaredMethod("nativeLibraryVersion");
|
||||
// m.setAccessible(true);
|
||||
// String version = (String) m.invoke(null);
|
||||
// _logger.info(version);
|
||||
|
||||
//_logger.info(SnappyNative.nativeLibraryVersion());
|
||||
_logger.info(Snappy.getNativeLibraryVersion());
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ package org.xerial.snappy;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.junit.Assert;
|
||||
@ -294,9 +295,16 @@ public class SnappyTest
|
||||
byte[] uncompressed = Snappy.uncompress(b);
|
||||
fail("cannot reach here since the input is invalid data");
|
||||
}
|
||||
catch (SnappyException e) {
|
||||
assertEquals(SnappyErrorCode.FAILED_TO_UNCOMPRESS, e.errorCode);
|
||||
catch (IOException e) {
|
||||
//assertEquals(SnappyErrorCode.FAILED_TO_UNCOMPRESS, e.errorCode);
|
||||
}
|
||||
// catch (Exception e) {
|
||||
// Class< ? > c = e.getClass();
|
||||
// ClassLoader cl = c.getClassLoader();
|
||||
//
|
||||
// ClassLoader cl2 = SnappyException.class.getClassLoader();
|
||||
// _logger.error(e);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user