From cf02ad2a1eb9035f96db22c8dce769baa63acdc6 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Wed, 7 Mar 2012 19:45:56 +0900 Subject: [PATCH] Add DetectionUtil which replaces UnsafeDetectUtil / Improve SpdyHeaderBlockJZlibDecompressor --- .../codec/spdy/SpdyHeaderBlockCompressor.java | 21 +----- .../SpdyHeaderBlockJZlibDecompressor.java | 36 ++++++++-- .../DetectionUtil.java} | 67 +++++++++++-------- .../io/netty/util/internal/QueueFactory.java | 4 +- 4 files changed, 72 insertions(+), 56 deletions(-) rename common/src/main/java/io/netty/util/{UnsafeDetectUtil.java => internal/DetectionUtil.java} (51%) diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockCompressor.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockCompressor.java index d52e7e17d9..af51caf6b1 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockCompressor.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockCompressor.java @@ -15,32 +15,15 @@ */ package io.netty.handler.codec.spdy; -import java.util.zip.Deflater; - import io.netty.buffer.ChannelBuffer; +import io.netty.util.internal.DetectionUtil; abstract class SpdyHeaderBlockCompressor { - private static final boolean USE_ZLIB; - - static { - boolean java7 = false; - try { - Deflater.class.getDeclaredMethod( - "deflate", - new Class[] { byte[].class, int.class, int.class, int.class }); - java7 = true; - } catch (Exception e) { - // Ignore - } - - USE_ZLIB = java7; - } - static SpdyHeaderBlockCompressor newInstance( int compressionLevel, int windowBits, int memLevel) { - if (USE_ZLIB) { + if (DetectionUtil.javaVersion() >= 7) { return new SpdyHeaderBlockZlibCompressor(compressionLevel); } else { return new SpdyHeaderBlockJZlibCompressor( diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockJZlibDecompressor.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockJZlibDecompressor.java index 21593aba40..4ac52da869 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockJZlibDecompressor.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlockJZlibDecompressor.java @@ -50,14 +50,36 @@ class SpdyHeaderBlockJZlibDecompressor extends SpdyHeaderBlockDecompressor { z.next_out_index = 0; z.avail_out = out.length; - int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH); - - if (resultCode == JZlib.Z_NEED_DICT) { - resultCode = z.inflateSetDictionary(SPDY_DICT, SPDY_DICT.length); - if (resultCode != JZlib.Z_OK) { - throw new CompressionException("ZStream dictionary failure"); + loop: for (;;) { + // Decompress 'in' into 'out' + int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH); + if (z.next_out_index > 0) { + decompressed.writeBytes(out, 0, z.next_out_index); + z.avail_out = out.length; + } + z.next_out_index = 0; + + switch (resultCode) { + case JZlib.Z_NEED_DICT: + resultCode = z.inflateSetDictionary(SPDY_DICT, SPDY_DICT.length); + if (resultCode != JZlib.Z_OK) { + throw new CompressionException("failed to set the dictionary: " + resultCode); + } + break; + case JZlib.Z_STREAM_END: + // Do not decode anymore. + z.inflateEnd(); + break loop; + case JZlib.Z_OK: + break; + case JZlib.Z_BUF_ERROR: + if (z.avail_in <= 0) { + break loop; + } + break; + default: + throw new CompressionException("decompression failure: " + resultCode); } - z.inflate(JZlib.Z_SYNC_FLUSH); } if (z.next_out_index > 0) { diff --git a/common/src/main/java/io/netty/util/UnsafeDetectUtil.java b/common/src/main/java/io/netty/util/internal/DetectionUtil.java similarity index 51% rename from common/src/main/java/io/netty/util/UnsafeDetectUtil.java rename to common/src/main/java/io/netty/util/internal/DetectionUtil.java index 4c88541ab1..2a749f0488 100644 --- a/common/src/main/java/io/netty/util/UnsafeDetectUtil.java +++ b/common/src/main/java/io/netty/util/internal/DetectionUtil.java @@ -13,52 +13,65 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.util; +package io.netty.util.internal; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.Deflater; /** - * Utility which checks if {@value #UNSAFE} class can be found in the classpath - * and that it can be accessed using "theUnsafe" field which is not true for all platforms, i.e Android - * where it is called "THE_ONE". + * Utility that detects various properties specific to the current runtime + * environment, such as Java version and the availability of the + * {@code sun.misc.Unsafe} object. */ -public final class UnsafeDetectUtil { +public final class DetectionUtil { - private static final String THE_UNSAFE = "theUnsafe"; - private static final String UNSAFE = "sun.misc.Unsafe"; - private static final boolean UNSAFE_FOUND = isUnsafeFound(AtomicInteger.class.getClassLoader()); + private static final int JAVA_VERSION = javaVersion0(); + private static final boolean HAS_UNSAFE = hasUnsafe(AtomicInteger.class.getClassLoader()); - public static boolean isUnsafeFound(ClassLoader loader) { - try { - Class unsafeClazz = Class.forName(UNSAFE, true, loader); - return hasUnsafeField(unsafeClazz); - } catch (ClassNotFoundException e) { - return false; - } catch (SecurityException e) { - return false; - } catch (PrivilegedActionException e) { - return false; - } + public static boolean hasUnsafe() { + return HAS_UNSAFE; } - + + public static int javaVersion() { + return JAVA_VERSION; + } + + private static boolean hasUnsafe(ClassLoader loader) { + try { + Class unsafeClazz = Class.forName("sun.misc.Unsafe", true, loader); + return hasUnsafeField(unsafeClazz); + } catch (Exception e) { + // Ignore + } + return false; + } + private static boolean hasUnsafeField(final Class unsafeClass) throws PrivilegedActionException { return AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override public Boolean run() throws Exception { - unsafeClass.getDeclaredField(THE_UNSAFE); + unsafeClass.getDeclaredField("theUnsafe"); return true; - } + } }); } - - public static boolean isUnsafeFound() { - return UNSAFE_FOUND; - } - private UnsafeDetectUtil() { + private static int javaVersion0() { + try { + Deflater.class.getDeclaredField("SYNC_FLUSH"); + return 7; + } catch (Exception e) { + // Ignore + } + + return 6; + } + + private DetectionUtil() { // only static method supported } } diff --git a/common/src/main/java/io/netty/util/internal/QueueFactory.java b/common/src/main/java/io/netty/util/internal/QueueFactory.java index 29b53acfd5..557e20a536 100644 --- a/common/src/main/java/io/netty/util/internal/QueueFactory.java +++ b/common/src/main/java/io/netty/util/internal/QueueFactory.java @@ -18,15 +18,13 @@ package io.netty.util.internal; import java.util.Collection; import java.util.concurrent.BlockingQueue; -import io.netty.util.UnsafeDetectUtil; - /** * This factory should be used to create the "optimal" {@link BlockingQueue} * instance for the running JVM. */ public final class QueueFactory { - private static final boolean useUnsafe = UnsafeDetectUtil.isUnsafeFound(QueueFactory.class.getClassLoader()); + private static final boolean useUnsafe = DetectionUtil.hasUnsafe(); private QueueFactory() { // only use static methods!