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:
|
* HOMEPAGE:
|
||||||
* http://code.google.com/p/protobuf/
|
* 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,
|
This product optionally depends on 'SLF4J', a simple logging facade for Java,
|
||||||
which can be obtained at:
|
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>
|
<optional>true</optional>
|
||||||
</dependency>
|
</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 -->
|
<!-- Servlet API - completely optional -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<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