Relates issue: NETTY-80 Compression codec
* Initial implementation of jzlib based zlib compression handler
This commit is contained in:
parent
2b2d53ff62
commit
a7132ee08e
@ -57,6 +57,14 @@ interchange format, which can be obtained at:
|
||||
* HOMEPAGE:
|
||||
* http://code.google.com/p/protobuf/
|
||||
|
||||
This product optionally depends on 'JZlib', a re-implementation of zlib in pure
|
||||
Java, which can be obtained at:
|
||||
|
||||
* LICENSE:
|
||||
* license/LICENSE.jzlib.txt (BSD Style License)
|
||||
* HOMEPAGE:
|
||||
* http://www.jcraft.com/jzlib/
|
||||
|
||||
This product optionally depends on 'SLF4J', a simple logging facade for Java,
|
||||
which can be obtained at:
|
||||
|
||||
|
26
license/LICENSE.jzlib.txt
Normal file
26
license/LICENSE.jzlib.txt
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2000,2001,2002,2003,2004 ymnk, JCraft,Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
9
pom.xml
9
pom.xml
@ -77,6 +77,15 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- JCraft JZlib - completely optional -->
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jzlib</artifactId>
|
||||
<version>1.0.7</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Servlet API - completely optional -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2009 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jboss.netty.handler.codec.compression;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipelineCoverage;
|
||||
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
|
||||
|
||||
import com.jcraft.jzlib.JZlib;
|
||||
import com.jcraft.jzlib.ZStream;
|
||||
import com.jcraft.jzlib.ZStreamException;
|
||||
|
||||
/**
|
||||
* Decompresses a {@link ChannelBuffer} using the deflate algorithm.
|
||||
*
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Trustin Lee (tlee@redhat.com)
|
||||
* @version $Rev$, $Date$
|
||||
*/
|
||||
@ChannelPipelineCoverage("one")
|
||||
public class ZlibDecoder extends OneToOneDecoder {
|
||||
|
||||
private final ZStream z = new ZStream();
|
||||
|
||||
// TODO Auto-detect wrappers (zlib, gzip, nowrapper as a fallback)
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public ZlibDecoder() {
|
||||
z.inflateInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
|
||||
if (!(msg instanceof ChannelBuffer)) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
try {
|
||||
// Configure input.
|
||||
ChannelBuffer compressed = (ChannelBuffer) msg;
|
||||
byte[] in = new byte[compressed.readableBytes()];
|
||||
compressed.readBytes(in);
|
||||
z.next_in = in;
|
||||
z.next_in_index = 0;
|
||||
z.avail_in = in.length;
|
||||
|
||||
// Configure output.
|
||||
byte[] out = new byte[in.length << 1];
|
||||
ChannelBuffer decompressed = ChannelBuffers.dynamicBuffer(
|
||||
compressed.order(), out.length,
|
||||
ctx.getChannel().getConfig().getBufferFactory());
|
||||
z.next_out = out;
|
||||
z.next_out_index = 0;
|
||||
z.avail_out = out.length;
|
||||
|
||||
do {
|
||||
// Decompress 'in' into 'out'
|
||||
int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH);
|
||||
switch (resultCode) {
|
||||
case JZlib.Z_OK:
|
||||
case JZlib.Z_BUF_ERROR:
|
||||
decompressed.writeBytes(out, 0, z.next_out_index);
|
||||
z.next_out_index = 0;
|
||||
z.avail_out = out.length;
|
||||
break;
|
||||
default:
|
||||
throw new ZStreamException(
|
||||
"decompression failure (" + resultCode + ")" +
|
||||
(z.msg != null? ": " + z.msg : ""));
|
||||
}
|
||||
} while (z.avail_in > 0);
|
||||
|
||||
if (decompressed.writerIndex() != 0) { // readerIndex is always 0
|
||||
return decompressed;
|
||||
} else {
|
||||
return ChannelBuffers.EMPTY_BUFFER;
|
||||
}
|
||||
} finally {
|
||||
// Deference the external references explicitly to tell the VM that
|
||||
// the allocated byte arrays are temporary so that the call stack
|
||||
// can be utilized.
|
||||
// I'm not sure if the modern VMs do this optimization though.
|
||||
z.next_in = null;
|
||||
z.next_out = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2009 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jboss.netty.handler.codec.compression;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipelineCoverage;
|
||||
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
|
||||
|
||||
import com.jcraft.jzlib.JZlib;
|
||||
import com.jcraft.jzlib.ZStream;
|
||||
import com.jcraft.jzlib.ZStreamException;
|
||||
|
||||
/**
|
||||
* Compresses a {@link ChannelBuffer} using the deflate algorithm.
|
||||
*
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Trustin Lee (tlee@redhat.com)
|
||||
* @version $Rev$, $Date$
|
||||
*/
|
||||
@ChannelPipelineCoverage("one")
|
||||
public class ZlibEncoder extends OneToOneEncoder {
|
||||
|
||||
private final ZStream z = new ZStream();
|
||||
|
||||
// TODO 'do not compress' once option
|
||||
// TODO support three wrappers - zlib (default), gzip (unsupported by jzlib, but easy to implement), nowrap
|
||||
|
||||
/**
|
||||
* Creates a new GZip encoder with the default compression level
|
||||
* ({@link JZlib#Z_DEFAULT_COMPRESSION}).
|
||||
*/
|
||||
public ZlibEncoder() {
|
||||
this(JZlib.Z_DEFAULT_COMPRESSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GZip encoder with the specified {@code compressionLevel}.
|
||||
*
|
||||
* @param compressionLevel
|
||||
* the compression level, as specified in {@link JZlib}.
|
||||
* The common values are
|
||||
* {@link JZlib#Z_BEST_COMPRESSION},
|
||||
* {@link JZlib#Z_BEST_SPEED},
|
||||
* {@link JZlib#Z_DEFAULT_COMPRESSION}, and
|
||||
* {@link JZlib#Z_NO_COMPRESSION}.
|
||||
*/
|
||||
public ZlibEncoder(int compressionLevel) {
|
||||
z.deflateInit(compressionLevel, false); // Default: ZLIB format
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
|
||||
if (!(msg instanceof ChannelBuffer)) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
try {
|
||||
// Configure input.
|
||||
ChannelBuffer uncompressed = (ChannelBuffer) msg;
|
||||
byte[] in = new byte[uncompressed.readableBytes()];
|
||||
uncompressed.readBytes(in);
|
||||
z.next_in = in;
|
||||
z.next_in_index = 0;
|
||||
z.avail_in = in.length;
|
||||
|
||||
// Configure output.
|
||||
byte[] out = new byte[(int) Math.ceil(in.length * 1.001) + 12];
|
||||
z.next_out = out;
|
||||
z.next_out_index = 0;
|
||||
z.avail_out = out.length;
|
||||
|
||||
// Note that Z_PARTIAL_FLUSH has been deprecated.
|
||||
int resultCode = z.deflate(JZlib.Z_SYNC_FLUSH);
|
||||
if (resultCode != JZlib.Z_OK) {
|
||||
throw new ZStreamException(
|
||||
"compression failure (" + resultCode + ")" +
|
||||
(z.msg != null? ": " + z.msg : ""));
|
||||
}
|
||||
|
||||
if (z.next_out_index != 0) {
|
||||
return ctx.getChannel().getConfig().getBufferFactory().getBuffer(
|
||||
uncompressed.order(), out, 0, z.next_out_index);
|
||||
} else {
|
||||
return ChannelBuffers.EMPTY_BUFFER;
|
||||
}
|
||||
} finally {
|
||||
// Deference the external references explicitly to tell the VM that
|
||||
// the allocated byte arrays are temporary so that the call stack
|
||||
// can be utilized.
|
||||
// I'm not sure if the modern VMs do this optimization though.
|
||||
z.next_in = null;
|
||||
z.next_out = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2009 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat licenses this file to you under the Apache License, version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encoder and decoder which compresses and decompresses {@link ChannelBuffer}s
|
||||
* in a compression format such as <a href="http://en.wikipedia.org/wiki/Zlib">zlib</a>,
|
||||
* <a href="http://en.wikipedia.org/wiki/Gzip">gzip</a>, and
|
||||
* <a href="http://en.wikipedia.org/wiki/Bzip2">bzip2</a>.
|
||||
*
|
||||
* @apiviz.exclude \.codec\.(?!compression)[a-z0-9]+\.
|
||||
*/
|
||||
package org.jboss.netty.handler.codec.compression;
|
||||
// TODO Implement bzip2 handlers
|
Loading…
Reference in New Issue
Block a user