diff --git a/pom.xml b/pom.xml index da9f090..e30528a 100755 --- a/pom.xml +++ b/pom.xml @@ -232,5 +232,12 @@ jar test + + org.javassist + javassist + 3.14.0-GA + jar + test + diff --git a/src/main/java/org/xerial/snappy/Snappy.java b/src/main/java/org/xerial/snappy/Snappy.java index d31c972..efebec4 100755 --- a/src/main/java/org/xerial/snappy/Snappy.java +++ b/src/main/java/org/xerial/snappy/Snappy.java @@ -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); diff --git a/src/main/java/org/xerial/snappy/SnappyErrorCode.java b/src/main/java/org/xerial/snappy/SnappyErrorCode.java index efdddc4..187b059 100755 --- a/src/main/java/org/xerial/snappy/SnappyErrorCode.java +++ b/src/main/java/org/xerial/snappy/SnappyErrorCode.java @@ -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(); + } } diff --git a/src/main/java/org/xerial/snappy/SnappyInputStream.java b/src/main/java/org/xerial/snappy/SnappyInputStream.java index c94e747..04ca9d4 100755 --- a/src/main/java/org/xerial/snappy/SnappyInputStream.java +++ b/src/main/java/org/xerial/snappy/SnappyInputStream.java @@ -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()); } diff --git a/src/main/java/org/xerial/snappy/SnappyLoader.java b/src/main/java/org/xerial/snappy/SnappyLoader.java index 8ee6a9c..2c31e5b 100755 --- a/src/main/java/org/xerial/snappy/SnappyLoader.java +++ b/src/main/java/org/xerial/snappy/SnappyLoader.java @@ -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 preloadClassByteCode = new ArrayList(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; } } diff --git a/src/main/java/org/xerial/snappy/SnappyNative.java b/src/main/java/org/xerial/snappy/SnappyNative.java index cbe8a14..42e0882 100755 --- a/src/main/java/org/xerial/snappy/SnappyNative.java +++ b/src/main/java/org/xerial/snappy/SnappyNative.java @@ -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)); } } diff --git a/src/main/java/org/xerial/snappy/SnappyNativeLoader.bytecode b/src/main/java/org/xerial/snappy/SnappyNativeLoader.bytecode new file mode 100755 index 0000000..a66950e Binary files /dev/null and b/src/main/java/org/xerial/snappy/SnappyNativeLoader.bytecode differ diff --git a/src/main/java/org/xerial/snappy/SnappyOutputStream.java b/src/main/java/org/xerial/snappy/SnappyOutputStream.java index 67af407..63407cf 100755 --- a/src/main/java/org/xerial/snappy/SnappyOutputStream.java +++ b/src/main/java/org/xerial/snappy/SnappyOutputStream.java @@ -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 diff --git a/src/test/java/org/xerial/snappy/SnappyLoaderTest.java b/src/test/java/org/xerial/snappy/SnappyLoaderTest.java index db5583b..dab9fb4 100755 --- a/src/test/java/org/xerial/snappy/SnappyLoaderTest.java +++ b/src/test/java/org/xerial/snappy/SnappyLoaderTest.java @@ -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()); + } } diff --git a/src/test/java/org/xerial/snappy/SnappyTest.java b/src/test/java/org/xerial/snappy/SnappyTest.java index dc8b0ab..b60982e 100755 --- a/src/test/java/org/xerial/snappy/SnappyTest.java +++ b/src/test/java/org/xerial/snappy/SnappyTest.java @@ -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); + // } }