Add DetectionUtil which replaces UnsafeDetectUtil / Improve SpdyHeaderBlockJZlibDecompressor

This commit is contained in:
Trustin Lee 2012-03-07 19:45:56 +09:00
parent 34e328f606
commit cf02ad2a1e
4 changed files with 72 additions and 56 deletions

View File

@ -15,32 +15,15 @@
*/ */
package io.netty.handler.codec.spdy; package io.netty.handler.codec.spdy;
import java.util.zip.Deflater;
import io.netty.buffer.ChannelBuffer; import io.netty.buffer.ChannelBuffer;
import io.netty.util.internal.DetectionUtil;
abstract class SpdyHeaderBlockCompressor { 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( static SpdyHeaderBlockCompressor newInstance(
int compressionLevel, int windowBits, int memLevel) { int compressionLevel, int windowBits, int memLevel) {
if (USE_ZLIB) { if (DetectionUtil.javaVersion() >= 7) {
return new SpdyHeaderBlockZlibCompressor(compressionLevel); return new SpdyHeaderBlockZlibCompressor(compressionLevel);
} else { } else {
return new SpdyHeaderBlockJZlibCompressor( return new SpdyHeaderBlockJZlibCompressor(

View File

@ -50,14 +50,36 @@ class SpdyHeaderBlockJZlibDecompressor extends SpdyHeaderBlockDecompressor {
z.next_out_index = 0; z.next_out_index = 0;
z.avail_out = out.length; z.avail_out = out.length;
int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH); loop: for (;;) {
// Decompress 'in' into 'out'
if (resultCode == JZlib.Z_NEED_DICT) { int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH);
resultCode = z.inflateSetDictionary(SPDY_DICT, SPDY_DICT.length); if (z.next_out_index > 0) {
if (resultCode != JZlib.Z_OK) { decompressed.writeBytes(out, 0, z.next_out_index);
throw new CompressionException("ZStream dictionary failure"); 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) { if (z.next_out_index > 0) {

View File

@ -13,52 +13,65 @@
* License for the specific language governing permissions and limitations * License for the specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package io.netty.util; package io.netty.util.internal;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.Deflater;
/** /**
* Utility which checks if {@value #UNSAFE} class can be found in the classpath * Utility that detects various properties specific to the current runtime
* and that it can be accessed using "theUnsafe" field which is not true for all platforms, i.e Android * environment, such as Java version and the availability of the
* where it is called "THE_ONE". * {@code sun.misc.Unsafe} object.
*/ */
public final class UnsafeDetectUtil { public final class DetectionUtil {
private static final String THE_UNSAFE = "theUnsafe"; private static final int JAVA_VERSION = javaVersion0();
private static final String UNSAFE = "sun.misc.Unsafe"; private static final boolean HAS_UNSAFE = hasUnsafe(AtomicInteger.class.getClassLoader());
private static final boolean UNSAFE_FOUND = isUnsafeFound(AtomicInteger.class.getClassLoader());
public static boolean isUnsafeFound(ClassLoader loader) { public static boolean hasUnsafe() {
try { return HAS_UNSAFE;
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 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 { private static boolean hasUnsafeField(final Class<?> unsafeClass) throws PrivilegedActionException {
return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() { return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
@Override
public Boolean run() throws Exception { public Boolean run() throws Exception {
unsafeClass.getDeclaredField(THE_UNSAFE); unsafeClass.getDeclaredField("theUnsafe");
return true; 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 // only static method supported
} }
} }

View File

@ -18,15 +18,13 @@ package io.netty.util.internal;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import io.netty.util.UnsafeDetectUtil;
/** /**
* This factory should be used to create the "optimal" {@link BlockingQueue} * This factory should be used to create the "optimal" {@link BlockingQueue}
* instance for the running JVM. * instance for the running JVM.
*/ */
public final class QueueFactory { public final class QueueFactory {
private static final boolean useUnsafe = UnsafeDetectUtil.isUnsafeFound(QueueFactory.class.getClassLoader()); private static final boolean useUnsafe = DetectionUtil.hasUnsafe();
private QueueFactory() { private QueueFactory() {
// only use static methods! // only use static methods!