You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by tr...@apache.org on 2006/03/12 04:16:36 UTC

svn commit: r385235 - in /directory/trunks/mina: ./ filter-compression/ filter-compression/lib/ filter-compression/src/ filter-compression/src/main/ filter-compression/src/main/java/ filter-compression/src/main/java/org/ filter-compression/src/main/jav...

Author: trustin
Date: Sat Mar 11 19:16:33 2006
New Revision: 385235

URL: http://svn.apache.org/viewcvs?rev=385235&view=rev
Log:
Related issue: DIRMINA-179 (Stream compression support)
* Applied Vinod's patch
** Removed algorithm parameter because ZLib is the only algorithm for now.  We'll have to provide an interface such as CompressionAlgorithm and let user provide it as a parameter.
* systemPath in pom.xml doesn't work well with the bundled Eclipse plugin; upgraded to 2.1


Added:
    directory/trunks/mina/filter-compression/
    directory/trunks/mina/filter-compression/LICENSE.txt   (with props)
    directory/trunks/mina/filter-compression/NOTICE.txt   (with props)
    directory/trunks/mina/filter-compression/lib/
    directory/trunks/mina/filter-compression/lib/jzlib-1.0.7.jar   (with props)
    directory/trunks/mina/filter-compression/pom.xml   (with props)
    directory/trunks/mina/filter-compression/src/
    directory/trunks/mina/filter-compression/src/main/
    directory/trunks/mina/filter-compression/src/main/java/
    directory/trunks/mina/filter-compression/src/main/java/org/
    directory/trunks/mina/filter-compression/src/main/java/org/apache/
    directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/
    directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/
    directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/CompressionFilter.java   (with props)
    directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/support/
    directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/support/Zlib.java   (with props)
    directory/trunks/mina/filter-compression/src/test/
    directory/trunks/mina/filter-compression/src/test/java/
    directory/trunks/mina/filter-compression/src/test/java/org/
    directory/trunks/mina/filter-compression/src/test/java/org/apache/
    directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/
    directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/
    directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/CompressionFilterTest.java   (with props)
    directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/support/
    directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/support/ZlibTest.java   (with props)
Modified:
    directory/trunks/mina/pom.xml

Added: directory/trunks/mina/filter-compression/LICENSE.txt
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/LICENSE.txt?rev=385235&view=auto
==============================================================================
--- directory/trunks/mina/filter-compression/LICENSE.txt (added)
+++ directory/trunks/mina/filter-compression/LICENSE.txt Sat Mar 11 19:16:33 2006
@@ -0,0 +1,20 @@
+/*
+ *                           Apache License
+ *                      Version 2.0, January 2004
+ *                   http://www.apache.org/licenses/
+ *
+ *   Copyright ${pom.inceptionYear} Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */

Propchange: directory/trunks/mina/filter-compression/LICENSE.txt
------------------------------------------------------------------------------
    svn:executable = *

Added: directory/trunks/mina/filter-compression/NOTICE.txt
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/NOTICE.txt?rev=385235&view=auto
==============================================================================
--- directory/trunks/mina/filter-compression/NOTICE.txt (added)
+++ directory/trunks/mina/filter-compression/NOTICE.txt Sat Mar 11 19:16:33 2006
@@ -0,0 +1,2 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).

Propchange: directory/trunks/mina/filter-compression/NOTICE.txt
------------------------------------------------------------------------------
    svn:executable = *

Added: directory/trunks/mina/filter-compression/lib/jzlib-1.0.7.jar
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/lib/jzlib-1.0.7.jar?rev=385235&view=auto
==============================================================================
Binary file - no diff available.

Propchange: directory/trunks/mina/filter-compression/lib/jzlib-1.0.7.jar
------------------------------------------------------------------------------
    svn:executable = *

Propchange: directory/trunks/mina/filter-compression/lib/jzlib-1.0.7.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: directory/trunks/mina/filter-compression/pom.xml
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/pom.xml?rev=385235&view=auto
==============================================================================
--- directory/trunks/mina/filter-compression/pom.xml (added)
+++ directory/trunks/mina/filter-compression/pom.xml Sat Mar 11 19:16:33 2006
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.mina</groupId>
+    <artifactId>build</artifactId>
+    <version>0.9.3-SNAPSHOT</version>
+  </parent>
+  <artifactId>mina-filter-compression</artifactId>
+  <name>Apache MINA Stream Compression Filter</name>
+  <packaging>jar</packaging>  
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.directory.mina</groupId>
+      <artifactId>mina-core</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>1.0-rc5</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>1.2_Java1.3</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>jcraft</groupId>
+      <artifactId>jzlib</artifactId>
+      <version>1.0.7</version>
+      <scope>system</scope>
+      <systemPath>${basedir}/lib/jzlib-1.0.7.jar</systemPath>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.4</source>
+          <target>1.4</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+

Propchange: directory/trunks/mina/filter-compression/pom.xml
------------------------------------------------------------------------------
    svn:executable = *

Added: directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/CompressionFilter.java
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/CompressionFilter.java?rev=385235&view=auto
==============================================================================
--- directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/CompressionFilter.java (added)
+++ directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/CompressionFilter.java Sat Mar 11 19:16:33 2006
@@ -0,0 +1,272 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.apache.mina.filter;
+
+import java.io.IOException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoFilter;
+import org.apache.mina.common.IoFilterAdapter;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.support.Zlib;
+
+/**
+ * An {@link IoFilter} which compresses all data using
+ * <a href="http://www.jcraft.com/jzlib/">JZlib</a>.
+ * Support for the LZW (DLCZ) algorithm is also planned.
+ * <p>
+ * This filter only supports compression using the <tt>PARTIAL FLUSH</tt> method,
+ * since that is the only method useful when doing stream level compression.
+ * <p>
+ * This filter supports compression/decompression of the input and output
+ * channels selectively.  It can also be enabled/disabled on the fly.
+ * <p>
+ * This filter does not discard the zlib objects, keeping them around for the
+ * entire life of the filter.  This is because the zlib dictionary needs to
+ * be built up over time, which is used during compression and decompression.
+ * Over time, as repetitive data is sent over the wire, the compression efficiency
+ * steadily increases.
+ * <p>
+ * Note that the zlib header is written only once. It is not necessary that
+ * the data received after processing by this filter may not be complete due
+ * to packet fragmentation.
+ * <p>
+ * It goes without saying that the other end of this stream should also have a
+ * compatible compressor/decompressor using the same algorithm.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ */
+public class CompressionFilter extends IoFilterAdapter
+{
+    /**
+     * Max compression level.  Will give the highest compression ratio, but
+     * will also take more cpu time and is the slowest.
+     */
+    public static final int COMPRESSION_MAX = Zlib.COMPRESSION_MAX;
+
+    /**
+     * Provides the best speed at the price of a low compression ratio.
+     */
+    public static final int COMPRESSION_MIN = Zlib.COMPRESSION_MIN;
+
+    /**
+     * No compression done on the data.
+     */
+    public static final int COMPRESSION_NONE = Zlib.COMPRESSION_NONE;
+
+    /**
+     * The default compression level used. Provides the best balance
+     * between speed and compression
+     */
+    public static final int COMPRESSION_DEFAULT = Zlib.COMPRESSION_DEFAULT;
+
+    /**
+     * A session attribute that stores the {@link Zlib} object used for compression.
+     */
+    private static final String DEFLATER = CompressionFilter.class.getName()
+            + ".Deflater";
+
+    /**
+     * A session attribute that stores the {@link Zlib} object used for decompression.
+     */
+    private static final String INFLATER = CompressionFilter.class.getName()
+            + ".Inflater";
+
+    /**
+     * A flag that allows you to disable compression once.
+     */
+    public static final String DISABLE_COMPRESSION_ONCE = CompressionFilter.class
+            .getName()
+            + ".DisableCompressionOnce";
+
+    private boolean compressInbound = true;
+    private boolean compressOutbound = true;
+    private int compressionLevel;
+
+    /**
+     * Creates a new instance which compresses outboud data and decompresses
+     * inbound data with default compression level.
+     */
+    public CompressionFilter()
+    {
+        this( true, true, COMPRESSION_DEFAULT );
+    }
+
+    /**
+     * Creates a new instance which compresses outboud data and decompresses
+     * inbound data with the specified <tt>compressionLevel</tt>.
+     * 
+     * @param compressionLevel the level of compression to be used. Must
+     *                         be one of {@link #COMPRESSION_DEFAULT},
+     *                         {@link #COMPRESSION_MAX},
+     *                         {@link #COMPRESSION_MIN}, and
+     *                         {@link #COMPRESSION_NONE}.
+     */
+    public CompressionFilter( final int compressionLevel )
+    {
+        this( true, true, compressionLevel );
+    }
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param compressInbound <tt>true</tt> if data read is to be decompressed
+     * @param compressOutbound <tt>true</tt> if data written is to be compressed
+     * @param compressionLevel the level of compression to be used. Must
+     *                         be one of {@link #COMPRESSION_DEFAULT},
+     *                         {@link #COMPRESSION_MAX},
+     *                         {@link #COMPRESSION_MIN}, and
+     *                         {@link #COMPRESSION_NONE}.
+     */
+    public CompressionFilter(
+            final boolean compressInbound,
+            final boolean compressOutbound,
+            final int compressionLevel )
+    {
+        this.compressionLevel = compressionLevel;
+        this.compressInbound = compressInbound;
+        this.compressOutbound = compressOutbound;
+    }
+
+    public void messageReceived( NextFilter nextFilter,
+            IoSession session, Object message ) throws Exception
+    {
+        if( !compressInbound )
+        {
+            nextFilter.messageReceived( session, message );
+            return;
+        }
+
+        Zlib inflater = ( Zlib ) session.getAttribute( INFLATER );
+        if( inflater == null )
+        {
+            throw new IllegalStateException();
+        }
+
+        ByteBuffer inBuffer = ( ByteBuffer ) message;
+        ByteBuffer outBuffer = inflater.inflate( inBuffer );
+
+        nextFilter.messageReceived( session, outBuffer );
+    }
+
+    /*
+     * @see org.apache.mina.common.IoFilter#filterWrite(org.apache.mina.common.IoFilter.NextFilter, org.apache.mina.common.IoSession, org.apache.mina.common.IoFilter.WriteRequest)
+     */
+    public void filterWrite( NextFilter nextFilter,
+            IoSession session, WriteRequest writeRequest ) throws IOException
+    {
+        if( !compressOutbound )
+        {
+            nextFilter.filterWrite( session, writeRequest );
+            return;
+        }
+
+        if( session.containsAttribute( DISABLE_COMPRESSION_ONCE ) )
+        {
+            // Remove the marker attribute because it is temporary.
+            session.removeAttribute( DISABLE_COMPRESSION_ONCE );
+            nextFilter.filterWrite( session, writeRequest );
+            return;
+        }
+
+        Zlib deflater = ( Zlib ) session.getAttribute( DEFLATER );
+        if( deflater == null )
+        {
+            throw new IllegalStateException();
+        }
+
+        ByteBuffer inBuffer = ( ByteBuffer ) writeRequest.getMessage();
+
+        ByteBuffer outBuf = deflater.deflate( inBuffer );
+
+        nextFilter.filterWrite( session, new WriteRequest( outBuf, writeRequest
+                .getFuture() ) );
+    }
+
+    public void onPreAdd( IoFilterChain parent, String name, NextFilter nextFilter ) throws Exception
+    {
+        if( parent.contains( CompressionFilter.class ) )
+        {
+            throw new IllegalStateException( "A filter chain cannot contain more than" +
+                    " one Stream Compression filter." );
+        }
+
+        Zlib deflater = new Zlib( compressionLevel, Zlib.MODE_DEFLATER );
+        Zlib inflater = new Zlib( compressionLevel, Zlib.MODE_INFLATER );
+
+        IoSession session = parent.getSession();
+
+        session.setAttribute( DEFLATER, deflater );
+        session.setAttribute( INFLATER, inflater );
+    }
+
+    /**
+     * Returns <tt>true</tt> if incoming data is being compressed.
+     */
+    public boolean isCompressInbound()
+    {
+        return compressInbound;
+    }
+
+    /**
+     * Sets if incoming data has to be compressed.
+     */
+    public void setCompressInbound( boolean compressInbound )
+    {
+        this.compressInbound = compressInbound;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the filter is compressing data being written.
+     */
+    public boolean isCompressOutbound()
+    {
+        return compressOutbound;
+    }
+
+    /**
+     * Set if outgoing data has to be compressed.
+     */
+    public void setCompressOutbound( boolean compressOutbound )
+    {
+        this.compressOutbound = compressOutbound;
+    }
+
+    public void onPostRemove( IoFilterChain parent, String name, NextFilter nextFilter ) throws Exception
+    {
+        super.onPostRemove( parent, name, nextFilter );
+        IoSession session = parent.getSession();
+        if( session == null )
+        {
+            return;
+        }
+
+        Zlib inflater = ( Zlib ) session.getAttribute( INFLATER );
+        Zlib deflater = ( Zlib ) session.getAttribute( DEFLATER );
+        if( deflater != null )
+        {
+            deflater.cleanUp();
+        }
+
+        if( inflater != null )
+        {
+            inflater.cleanUp();
+        }
+    }
+}

Propchange: directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/CompressionFilter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/support/Zlib.java
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/support/Zlib.java?rev=385235&view=auto
==============================================================================
--- directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/support/Zlib.java (added)
+++ directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/support/Zlib.java Sat Mar 11 19:16:33 2006
@@ -0,0 +1,194 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.apache.mina.filter.support;
+
+import java.io.IOException;
+
+import org.apache.mina.common.ByteBuffer;
+
+import com.jcraft.jzlib.JZlib;
+import com.jcraft.jzlib.ZStream;
+
+/**
+ * A helper class for interfacing with the JZlib library. This class acts both
+ * as a compressor and decompressor, but only as one at a time.  The only
+ * flush method supported is <tt>Z_FLUSH_SYNC</tt> also known as <tt>Z_PARTIAL_FLUSH</tt>
+ *
+ * @author The Apache Directory MINA subproject (mina-dev@directory.apache.org)
+ */
+public class Zlib
+{
+    public static final int COMPRESSION_MAX = JZlib.Z_BEST_COMPRESSION;
+    public static final int COMPRESSION_MIN = JZlib.Z_BEST_SPEED;
+    public static final int COMPRESSION_NONE = JZlib.Z_NO_COMPRESSION;
+    public static final int COMPRESSION_DEFAULT = JZlib.Z_DEFAULT_COMPRESSION;
+
+    public static final int MODE_DEFLATER = 1;
+    public static final int MODE_INFLATER = 2;
+
+    private int compressionLevel;
+    private ZStream zStream = null;
+    private int mode = -1;
+
+    /**
+     * @param compressionLevel the level of compression that should be used
+     * @param mode the mode in which the instance will operate. Can be either 
+     * of <tt>MODE_DEFLATER</tt> or <tt>MODE_INFLATER</tt>
+     */
+    public Zlib( int compressionLevel, int mode )
+    {
+        switch( compressionLevel )
+        {
+        case COMPRESSION_MAX:
+        case COMPRESSION_MIN:
+        case COMPRESSION_NONE:
+        case COMPRESSION_DEFAULT:
+            this.compressionLevel = compressionLevel;
+            break;
+        default:
+            throw new IllegalArgumentException( "invalid compression level specified" );
+        }
+
+        // create a new instance of ZStream. This will be done only once.
+        zStream = new ZStream();
+
+        switch( mode )
+        {
+        case MODE_DEFLATER:
+            zStream.deflateInit( this.compressionLevel );
+            break;
+        case MODE_INFLATER:
+            zStream.inflateInit();
+            break;
+        default:
+            throw new IllegalArgumentException( "invalid mode specified" );
+        }
+        this.mode = mode;
+    }
+
+    /**
+     * @param inBuffer the {@link ByteBuffer} to be decompressed. The contents
+     * of the buffer are transferred into a local byte array and the buffer is
+     * flipped and returned intact.
+     * @return the decompressed data. If not passed to the MINA methods that 
+     * release the buffer automatically, the buffer has to be manually released 
+     * @throws IOException if the decompression of the data failed for some reason.
+     */
+    public ByteBuffer inflate( ByteBuffer inBuffer ) throws IOException
+    {
+        if( mode == MODE_DEFLATER )
+        {
+            throw new IllegalStateException( "not initialized as INFLATER" );
+        }
+
+        byte[] inBytes = new byte[ inBuffer.limit() ];
+        inBuffer.get( inBytes ).flip();
+
+        byte[] outBytes = new byte[ inBytes.length * 2 ];
+        ByteBuffer outBuffer = ByteBuffer.allocate( outBytes.length );
+        outBuffer.setAutoExpand( true );
+
+        zStream.next_in = inBytes;
+        zStream.next_in_index = 0;
+        zStream.avail_in = inBytes.length;
+        zStream.next_out = outBytes;
+        zStream.next_out_index = 0;
+        zStream.avail_out = outBytes.length;
+        int retval = 0;
+
+        do
+        {
+            retval = zStream.inflate( JZlib.Z_PARTIAL_FLUSH );
+            switch( retval )
+            {
+            case JZlib.Z_OK:
+                // completed decompression, lets copy data and get out
+            case JZlib.Z_BUF_ERROR:
+                // need more space for output. store current output and get more
+                outBuffer.put( outBytes, 0, zStream.next_out_index );
+                zStream.next_out_index = 0;
+                zStream.avail_out = outBytes.length;
+                break;
+            default:
+                // unknown error
+                outBuffer.release();
+                outBuffer = null;
+                if( zStream.msg == null )
+                    throw new IOException( "Unknown error. Error code : " + retval );
+                else
+                    throw new IOException( "Unknown error. Error code : " + retval
+                            + " and message : " + zStream.msg );
+            }
+        } while( zStream.avail_in > 0 );
+
+        return outBuffer.flip();
+    }
+
+    /**
+     * @param inBuffer the buffer to be compressed. The contents are transferred
+     * into a local byte array and the buffer is flipped and returned intact.
+     * @return the buffer with the compressed data. If not passed to any of the
+     * MINA methods that automatically release the buffer, the buffer has to be
+     * released manually.
+     * @throws IOException if the compression of teh buffer failed for some reason
+     */
+    public ByteBuffer deflate( ByteBuffer inBuffer ) throws IOException
+    {
+        if( mode == MODE_INFLATER )
+        {
+            throw new IllegalStateException( "not initialized as DEFLATER" );
+        }
+
+        byte[] inBytes = new byte[ inBuffer.limit() ];
+        inBuffer.get( inBytes ).flip();
+
+        // according to spec, destination buffer should be 0.1% larger
+        // than source length plus 12 bytes. We add a single byte to safeguard
+        // against rounds that round down to the smaller value
+        int outLen = (int) Math.round( inBytes.length * 1.001 ) + 1 + 12;
+        byte[] outBytes = new byte[ outLen ];
+
+        zStream.next_in = inBytes;
+        zStream.next_in_index = 0;
+        zStream.avail_in = inBytes.length;
+        zStream.next_out = outBytes;
+        zStream.next_out_index = 0;
+        zStream.avail_out = outBytes.length;
+
+        int retval = zStream.deflate( JZlib.Z_SYNC_FLUSH );
+        if( retval != JZlib.Z_OK )
+        {
+            outBytes = null;
+            inBytes = null;
+            throw new IOException( "Compression failed with return value : " + retval );
+        }
+
+        ByteBuffer outBuf = ByteBuffer.wrap( outBytes, 0, zStream.next_out_index );
+
+        return outBuf;
+    }
+
+    /**
+     * Cleans up the resources used by the compression library.
+     */
+    public void cleanUp()
+    {
+        if( zStream != null )
+            zStream.free();
+    }
+}
\ No newline at end of file

Propchange: directory/trunks/mina/filter-compression/src/main/java/org/apache/mina/filter/support/Zlib.java
------------------------------------------------------------------------------
    svn:executable = *

Added: directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/CompressionFilterTest.java
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/CompressionFilterTest.java?rev=385235&view=auto
==============================================================================
--- directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/CompressionFilterTest.java (added)
+++ directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/CompressionFilterTest.java Sat Mar 11 19:16:33 2006
@@ -0,0 +1,209 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.apache.mina.filter;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.IoFilter.NextFilter;
+import org.apache.mina.filter.support.Zlib;
+import org.apache.mina.common.IoFilter.WriteRequest;
+import org.easymock.MockControl;
+import org.easymock.AbstractMatcher;
+
+import junit.framework.TestCase;
+
+/**
+ * @author The Apache Directory MINA subproject (mina-dev@directory.apache.org)
+ *
+ */
+public class CompressionFilterTest extends TestCase
+{
+    private MockControl mockSession;
+    private MockControl mockNextFilter;
+    private MockControl mockIoFilterChain;
+    private IoSession session;
+    private NextFilter nextFilter;
+    private IoFilterChain ioFilterChain;
+    private CompressionFilter filter;
+    private Zlib deflater;
+    private Zlib inflater;
+    private Zlib actualDeflater;
+    private Zlib actualInflater;
+
+    // the sample data to be used for testing
+    String strCompress =
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  " +
+            "The quick brown fox jumps over the lazy dog.  ";
+
+    protected void setUp()
+    {
+        // create the necessary mock controls.
+        mockSession = MockControl.createControl( IoSession.class );
+        mockNextFilter = MockControl.createControl( NextFilter.class );
+        mockIoFilterChain = MockControl.createControl( IoFilterChain.class );
+
+        // set the default matcher
+        mockNextFilter.setDefaultMatcher( new DataMatcher() );
+
+        session = ( IoSession ) mockSession.getMock();
+        nextFilter = ( NextFilter ) mockNextFilter.getMock();
+        ioFilterChain = ( IoFilterChain ) mockIoFilterChain.getMock();
+
+        // create an instance of the filter
+        filter = new CompressionFilter( CompressionFilter.COMPRESSION_MAX );
+
+        // deflater and inflater that will be used by the filter
+        deflater = new Zlib( Zlib.COMPRESSION_MAX, Zlib.MODE_DEFLATER );
+        inflater = new Zlib( Zlib.COMPRESSION_MAX, Zlib.MODE_INFLATER );
+
+        // create instances of the deflater and inflater to help test the output
+        actualDeflater = new Zlib( Zlib.COMPRESSION_MAX, Zlib.MODE_DEFLATER );
+        actualInflater = new Zlib( Zlib.COMPRESSION_MAX, Zlib.MODE_INFLATER );
+    }
+
+    public void testCompression() throws Exception
+    {
+        // prepare the input data
+        ByteBuffer buf = ByteBuffer.wrap( strCompress.getBytes( "UTF8" ) );
+        ByteBuffer actualOutput = actualDeflater.deflate( buf );
+        WriteRequest writeRequest = new WriteRequest( buf );
+
+        // record all the mock calls
+        ioFilterChain.contains( CompressionFilter.class );
+        mockIoFilterChain.setReturnValue( false );
+
+        ioFilterChain.getSession();
+        mockIoFilterChain.setReturnValue( session );
+
+        session.setAttribute( CompressionFilter.class.getName() + ".Deflater", deflater );
+        mockSession.setDefaultMatcher( new DataMatcher() );
+        mockSession.setReturnValue( null, MockControl.ONE );
+
+        session.setAttribute( CompressionFilter.class.getName() + ".Inflater", inflater );
+        mockSession.setReturnValue( null, MockControl.ONE );
+
+        session.containsAttribute( CompressionFilter.DISABLE_COMPRESSION_ONCE );
+        mockSession.setReturnValue( false );
+
+        session.getAttribute( CompressionFilter.class.getName() + ".Deflater" );
+        mockSession.setReturnValue( deflater );
+
+        nextFilter.filterWrite( session, new WriteRequest( actualOutput ) );
+
+        // switch to playback mode
+        mockSession.replay();
+        mockIoFilterChain.replay();
+        mockNextFilter.replay();
+
+        // make the actual calls on the filter
+        filter.onPreAdd( ioFilterChain, "CompressionFilter", nextFilter );
+        filter.filterWrite( nextFilter, session, writeRequest );
+
+        // verify that all the calls happened as recorded
+        mockNextFilter.verify();
+
+        assertTrue( true );
+    }
+
+    public void testDecompression() throws Exception
+    {
+        // prepare the input data
+        ByteBuffer buf = ByteBuffer.wrap( strCompress.getBytes( "UTF8" ) );
+        ByteBuffer byteInput = actualDeflater.deflate( buf );
+        ByteBuffer actualOutput = actualInflater.inflate( byteInput );
+
+        // record all the mock calls
+        ioFilterChain.contains( CompressionFilter.class );
+        mockIoFilterChain.setReturnValue( false );
+
+        ioFilterChain.getSession();
+        mockIoFilterChain.setReturnValue( session );
+
+        session.setAttribute( CompressionFilter.class.getName() + ".Deflater", deflater );
+        mockSession.setDefaultMatcher( new DataMatcher() );
+        mockSession.setReturnValue( null, MockControl.ONE );
+
+        session.setAttribute( CompressionFilter.class.getName() + ".Inflater", inflater );
+        mockSession.setReturnValue( null, MockControl.ONE );
+
+        session.getAttribute( CompressionFilter.class.getName() + ".Inflater" );
+        mockSession.setReturnValue( inflater );
+
+        nextFilter.messageReceived( session, actualOutput );
+
+        // switch to playback mode
+        mockSession.replay();
+        mockIoFilterChain.replay();
+        mockNextFilter.replay();
+
+        // make the actual calls on the filter
+        filter.onPreAdd( ioFilterChain, "CompressionFilter", nextFilter );
+        filter.messageReceived( nextFilter, session, byteInput );
+
+        // verify that all the calls happened as recorded
+        mockNextFilter.verify();
+
+        assertTrue( true );
+    }
+
+    /**
+     * A matcher used to check if the actual and expected outputs matched
+     * 
+     * @author The Apache Directory MINA subproject (mina-dev@directory.apache.org)
+     */
+    class DataMatcher extends AbstractMatcher
+    {
+        protected boolean argumentMatches( Object arg0, Object arg1 )
+        {
+            // we need to only verify the ByteBuffer output
+            if( arg0 instanceof WriteRequest )
+            {
+                WriteRequest expected = (WriteRequest) arg0;
+                WriteRequest actual = (WriteRequest) arg1;
+                ByteBuffer bExpected = (ByteBuffer) expected.getMessage();
+                ByteBuffer bActual = (ByteBuffer) actual.getMessage();
+                return bExpected.equals( bActual );
+            }
+            return true;
+        }
+    }
+}

Propchange: directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/CompressionFilterTest.java
------------------------------------------------------------------------------
    svn:executable = *

Added: directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/support/ZlibTest.java
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/support/ZlibTest.java?rev=385235&view=auto
==============================================================================
--- directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/support/ZlibTest.java (added)
+++ directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/support/ZlibTest.java Sat Mar 11 19:16:33 2006
@@ -0,0 +1,132 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.apache.mina.filter.support;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import org.apache.mina.common.ByteBuffer;
+
+import junit.framework.TestCase;
+
+/**
+ * @author The Apache Directory MINA subproject (mina-dev@directory.apache.org)
+ */
+public class ZlibTest extends TestCase
+{
+    private Zlib deflater = null;
+    private Zlib inflater = null;
+
+    protected void setUp() throws Exception
+    {
+        deflater = new Zlib( Zlib.COMPRESSION_MAX, Zlib.MODE_DEFLATER );
+        inflater = new Zlib( Zlib.COMPRESSION_MAX, Zlib.MODE_INFLATER );
+    }
+
+    public void testCompression() throws Exception
+    {
+        String strInput = "";
+
+        // increase the count to as many as required to generate a long 
+        // string for input
+        for( int i = 0; i < 10; i++ )
+        {
+            strInput += "The quick brown fox jumps over the lazy dog.  ";
+        }
+        ByteBuffer byteInput = ByteBuffer.wrap( strInput.getBytes( "UTF8" ) );
+
+        // increase the count to have the compression and decompression 
+        // done using the same instance of Zlib
+        for( int i = 0; i < 5; i++ )
+        {
+            ByteBuffer byteCompressed = deflater.deflate( byteInput );
+            ByteBuffer byteUncompressed = inflater.inflate( byteCompressed );
+            String strOutput = byteUncompressed.getString( Charset.forName( "UTF8" )
+                    .newDecoder() );
+            assertTrue( strOutput.equals( strInput ) );
+        }
+    }
+
+    public void testCorruptedData() throws Exception
+    {
+        String strInput = "Hello World";
+        ByteBuffer byteInput = ByteBuffer.wrap( strInput.getBytes( "UTF8" ) );
+
+        ByteBuffer byteCompressed = deflater.deflate( byteInput );
+        // change the contents to something else. Since this doesn't check
+        // for integrity, it wont throw an exception
+        byteCompressed.put( 5, (byte) 0xa );
+        ByteBuffer byteUncompressed = inflater.inflate( byteCompressed );
+        String strOutput = byteUncompressed.getString( Charset.forName( "UTF8" )
+                .newDecoder() );
+        assertFalse( strOutput.equals( strInput ) );
+    }
+
+    public void testCorruptedHeader() throws Exception
+    {
+        String strInput = "Hello World";
+        ByteBuffer byteInput = ByteBuffer.wrap( strInput.getBytes( "UTF8" ) );
+
+        ByteBuffer byteCompressed = deflater.deflate( byteInput );
+        // write a bad value into the zlib header. Make sure that
+        // the decompression fails
+        byteCompressed.put( 0, (byte) 0xca );
+        try
+        {
+            inflater.inflate( byteCompressed );
+        }
+        catch( IOException e )
+        {
+            assertTrue( true );
+            return;
+        }
+        assertTrue( false );
+    }
+
+    public void testFragments() throws Exception
+    {
+        String strInput = "";
+        for( int i = 0; i < 10; i++ )
+        {
+            strInput += "The quick brown fox jumps over the lazy dog.  ";
+        }
+        ByteBuffer byteInput = ByteBuffer.wrap( strInput.getBytes( "UTF8" ) );
+        ByteBuffer byteCompressed = null;
+
+        for( int i = 0; i < 5; i++ )
+        {
+            byteCompressed = deflater.deflate( byteInput );
+            if( i == 0 )
+            {
+                // decompress the first compressed output since it contains
+                // the zlib header, which will not be generated for further
+                // compressions done with the same instance
+                ByteBuffer byteUncompressed = inflater.inflate( byteCompressed );
+                String strOutput = byteUncompressed.getString( Charset.forName( "UTF8" )
+                        .newDecoder() );
+                assertTrue( strOutput.equals( strInput ) );
+            }
+        }
+        // check if the last compressed data block can be decompressed
+        // successfully.
+        ByteBuffer byteUncompressed = inflater.inflate( byteCompressed );
+        String strOutput = byteUncompressed.getString( Charset.forName( "UTF8" )
+                .newDecoder() );
+        assertTrue( strOutput.equals( strInput ) );
+    }
+}

Propchange: directory/trunks/mina/filter-compression/src/test/java/org/apache/mina/filter/support/ZlibTest.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: directory/trunks/mina/pom.xml
URL: http://svn.apache.org/viewcvs/directory/trunks/mina/pom.xml?rev=385235&r1=385234&r2=385235&view=diff
==============================================================================
--- directory/trunks/mina/pom.xml (original)
+++ directory/trunks/mina/pom.xml Sat Mar 11 19:16:33 2006
@@ -153,6 +153,7 @@
         <module>filter-ssl</module>
         <module>filter-codec-asn1</module>
         <module>filter-codec-netty</module>
+        <module>filter-compression</module>
         <module>integration-spring</module>
         <module>examples</module>
       </modules>
@@ -167,6 +168,7 @@
         <module>core</module>
         <module>filter-codec-asn1</module>
         <module>filter-codec-netty</module>
+        <module>filter-compression</module>
       </modules>
       <build>
         <plugins>
@@ -253,6 +255,11 @@
           <finalName>mina-${pom.version}</finalName>
           <includeSite>true</includeSite>
         </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-eclipse-plugin</artifactId>
+        <version>2.1</version>
       </plugin>
     </plugins>
   </build>