You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by mw...@apache.org on 2008/08/13 01:24:27 UTC

svn commit: r685367 [1/2] - in /mina/trunk/core/src: main/java/org/apache/mina/util/byteaccess/ test/java/org/apache/mina/util/byteaccess/

Author: mwebb
Date: Tue Aug 12 16:24:26 2008
New Revision: 685367

URL: http://svn.apache.org/viewvc?rev=685367&view=rev
Log:
Adding in the Composite IoBuffer code.  This is the initial check-in of the code.  I have verified all of the unit tests and code for any problems.

Added:
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/AbstractByteArray.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/BufferByteArray.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArray.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayFactory.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayList.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayPool.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArray.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeBase.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeReader.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeWriter.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteReader.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteWriter.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeReader.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoRelativeWriter.java
    mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/SimpleByteArrayFactory.java
    mina/trunk/core/src/test/java/org/apache/mina/util/byteaccess/
    mina/trunk/core/src/test/java/org/apache/mina/util/byteaccess/ByteAccessTest.java

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/AbstractByteArray.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/AbstractByteArray.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/AbstractByteArray.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/AbstractByteArray.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+/**
+ * 
+ * Abstract class that implements {@link ByteArray}.  This class will only be 
+ * used internally and should not be used by end users.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+abstract class AbstractByteArray implements ByteArray
+{
+
+    /**
+     * @inheritDoc
+     */
+    public final int length()
+    {
+        return last() - first();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    @Override
+    public final boolean equals( Object other )
+    {
+        // Optimization: compare pointers.
+        if ( other == this )
+        {
+            return true;
+        }
+        // Compare types.
+        if ( !( other instanceof ByteArray ) )
+        {
+            return false;
+        }
+        ByteArray otherByteArray = ( ByteArray ) other;
+        // Compare properties.
+        if ( first() != otherByteArray.first() || last() != otherByteArray.last()
+            || !order().equals( otherByteArray.order() ) )
+        {
+            return false;
+        }
+        // Compare bytes.
+        Cursor cursor = cursor();
+        Cursor otherCursor = otherByteArray.cursor();
+        for ( int remaining = cursor.getRemaining(); remaining > 0; )
+        {
+            // Optimization: prefer int comparisons over byte comparisons
+            if ( remaining >= 4 )
+            {
+                int i = cursor.getInt();
+                int otherI = otherCursor.getInt();
+                if ( i != otherI )
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                byte b = cursor.get();
+                byte otherB = otherCursor.get();
+                if ( b != otherB )
+                {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/BufferByteArray.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/BufferByteArray.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/BufferByteArray.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/BufferByteArray.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,556 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+import java.util.Collections;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * A <code>ByteArray</code> backed by a <code>IoBuffer</code>. This class
+ * is abstract. Subclasses need to override the <code>free()</code> method. An
+ * implementation backed by a heap <code>IoBuffer</code> can be created with
+ * a <code>SimpleByteArrayFactory</code>.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public abstract class BufferByteArray extends AbstractByteArray
+{
+
+    /**
+     * The backing <code>IoBuffer</code>.
+     */
+    protected IoBuffer bb;
+
+    /**
+     * 
+     * Creates a new instance of BufferByteArray and uses the supplied
+     * {@link IoBuffer} to back this class
+     *
+     * @param bb
+     *  The backing buffer
+     */
+    public BufferByteArray( IoBuffer bb )
+    {
+        this.bb = bb;
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public Iterable<IoBuffer> getIoBuffers()
+    {
+        return Collections.singletonList( bb );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public IoBuffer getSingleIoBuffer()
+    {
+        return bb;
+    }
+
+
+    /**
+     * @inheritDoc
+     * 
+     * Calling <code>free()</code> on the returned slice has no effect.
+     */
+    public ByteArray slice( int index, int length )
+    {
+        int oldLimit = bb.limit();
+        bb.position( index );
+        bb.limit( index + length );
+        IoBuffer slice = bb.slice();
+        bb.limit( oldLimit );
+        return new BufferByteArray( slice )
+        {
+
+            @Override
+            public void free()
+            {
+                // Do nothing.
+            }
+        };
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public abstract void free();
+
+
+    /**
+     * @inheritDoc
+     */
+    public Cursor cursor()
+    {
+        return new CursorImpl();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public Cursor cursor( int index )
+    {
+        return new CursorImpl( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public int first()
+    {
+        return 0;
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public int last()
+    {
+        return bb.limit();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public ByteOrder order()
+    {
+        return bb.order();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void order( ByteOrder order )
+    {
+        bb.order( order );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public byte get( int index )
+    {
+        return bb.get( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void put( int index, byte b )
+    {
+        bb.put( index, b );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void get( int index, IoBuffer other )
+    {
+        bb.position( index );
+        other.put( bb );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void put( int index, IoBuffer other )
+    {
+        bb.position( index );
+        bb.put( other );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public short getShort( int index )
+    {
+        return bb.getShort( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putShort( int index, short s )
+    {
+        bb.putShort( index, s );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public int getInt( int index )
+    {
+        return bb.getInt( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putInt( int index, int i )
+    {
+        bb.putInt( index, i );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public long getLong( int index )
+    {
+        return bb.getLong( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putLong( int index, long l )
+    {
+        bb.putLong( index, l );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public float getFloat( int index )
+    {
+        return bb.getFloat( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putFloat( int index, float f )
+    {
+        bb.putFloat( index, f );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public double getDouble( int index )
+    {
+        return bb.getDouble( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putDouble( int index, double d )
+    {
+        bb.putDouble( index, d );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public char getChar( int index )
+    {
+        return bb.getChar( index );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putChar( int index, char c )
+    {
+        bb.putChar( index, c );
+    }
+
+    private class CursorImpl implements Cursor
+    {
+
+        private int index;
+
+
+        public CursorImpl()
+        {
+            // This space intentionally blank.
+        }
+
+
+        public CursorImpl( int index )
+        {
+            setIndex( index );
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public int getRemaining()
+        {
+            return last() - index;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public boolean hasRemaining()
+        {
+            return getRemaining() > 0;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public int getIndex()
+        {
+            return index;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void setIndex( int index )
+        {
+            if ( index < 0 || index > last() )
+            {
+                throw new IndexOutOfBoundsException();
+            }
+            this.index = index;
+        }
+
+
+        public void skip( int length )
+        {
+            setIndex( index + length );
+        }
+
+
+        public ByteArray slice( int length )
+        {
+            ByteArray slice = BufferByteArray.this.slice( index, length );
+            index += length;
+            return slice;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public ByteOrder order()
+        {
+            return BufferByteArray.this.order();
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public byte get()
+        {
+            byte b = BufferByteArray.this.get( index );
+            index += 1;
+            return b;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void put( byte b )
+        {
+            BufferByteArray.this.put( index, b );
+            index += 1;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void get( IoBuffer bb )
+        {
+            int size = Math.min( getRemaining(), bb.remaining() );
+            BufferByteArray.this.get( index, bb );
+            index += size;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void put( IoBuffer bb )
+        {
+            int size = bb.remaining();
+            BufferByteArray.this.put( index, bb );
+            index += size;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public short getShort()
+        {
+            short s = BufferByteArray.this.getShort( index );
+            index += 2;
+            return s;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putShort( short s )
+        {
+            BufferByteArray.this.putShort( index, s );
+            index += 2;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public int getInt()
+        {
+            int i = BufferByteArray.this.getInt( index );
+            index += 4;
+            return i;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putInt( int i )
+        {
+            BufferByteArray.this.putInt( index, i );
+            index += 4;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public long getLong()
+        {
+            long l = BufferByteArray.this.getLong( index );
+            index += 8;
+            return l;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putLong( long l )
+        {
+            BufferByteArray.this.putLong( index, l );
+            index += 8;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public float getFloat()
+        {
+            float f = BufferByteArray.this.getFloat( index );
+            index += 4;
+            return f;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putFloat( float f )
+        {
+            BufferByteArray.this.putFloat( index, f );
+            index += 4;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public double getDouble()
+        {
+            double d = BufferByteArray.this.getDouble( index );
+            index += 8;
+            return d;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putDouble( double d )
+        {
+            BufferByteArray.this.putDouble( index, d );
+            index += 8;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public char getChar()
+        {
+            char c = BufferByteArray.this.getChar( index );
+            index += 2;
+            return c;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putChar( char c )
+        {
+            BufferByteArray.this.putChar( index, c );
+            index += 2;
+        }
+    }
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArray.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArray.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArray.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArray.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Represents a sequence of bytes that can be read or written directly or
+ * through a cursor.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface ByteArray extends IoAbsoluteReader, IoAbsoluteWriter
+{
+
+    /**
+     * @inheritDoc
+     */
+    int first();
+
+
+    /**
+     * @inheritDoc
+     */
+    int last();
+
+
+    /**
+     * @inheritDoc
+     */
+    ByteOrder order();
+
+
+    /**
+     * Set the byte order of the array.
+     */
+    void order( ByteOrder order );
+
+
+    /**
+     * Remove any resources associated with this object. Using the object after
+     * this method is called may result in undefined behaviour.
+     */
+    void free();
+
+
+    /**
+     * Get the sequence of <code>IoBuffer</code>s that back this array.
+     * Compared to <code>getSingleIoBuffer()</code>, this method should be
+     * relatively efficient for all implementations.
+     */
+    Iterable<IoBuffer> getIoBuffers();
+
+
+    /**
+     * Gets a single <code>IoBuffer</code> that backs this array. Some
+     * implementations may initially have data split across multiple buffers, so
+     * calling this method may require a new buffer to be allocated and
+     * populated.
+     */
+    IoBuffer getSingleIoBuffer();
+
+
+    /**
+     * A ByteArray is equal to another ByteArray if they start and end at the
+     * same index, have the same byte order, and contain the same bytes at each
+     * index.
+     */
+    public boolean equals( Object other );
+
+
+    /**
+     * @inheritDoc
+     */
+    byte get( int index );
+
+
+    /**
+     * @inheritDoc
+     */
+    public void get( int index, IoBuffer bb );
+
+
+    /**
+     * @inheritDoc
+     */
+    int getInt( int index );
+
+
+    /**
+     * Get a cursor starting at index 0 (which may not be the start of the array).
+     */
+    Cursor cursor();
+
+
+    /**
+     * Get a cursor starting at the given index.
+     */
+    Cursor cursor( int index );
+
+    /**
+     * Provides relocatable, relative access to the underlying array. Multiple
+     * cursors may be used simultaneously, and cursors will stay consistent with
+     * the underlying array, even across modifications.
+     *
+     * Should this be <code>Cloneable</code> to allow cheap mark/position
+     * emulation?
+     */
+    public interface Cursor extends IoRelativeReader, IoRelativeWriter
+    {
+
+        /**
+         * Gets the current index of the cursor.
+         */
+        int getIndex();
+
+
+        /**
+         * Sets the current index of the cursor. No bounds checking will occur
+         * until an access occurs.
+         */
+        void setIndex( int index );
+
+
+        /**
+         * @inheritDoc
+         */
+        int getRemaining();
+
+
+        /**
+         * @inheritDoc
+         */
+        boolean hasRemaining();
+
+
+        /**
+         * @inheritDoc
+         */
+        byte get();
+
+
+        /**
+         * @inheritDoc
+         */
+        void get( IoBuffer bb );
+
+
+        /**
+         * @inheritDoc
+         */
+        int getInt();
+    }
+
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayFactory.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayFactory.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayFactory.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayFactory.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+/**
+ * A factory for <code>ByteArray</code>s.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface ByteArrayFactory
+{
+    /**
+     * Creates an instance of {@link ByteArray} of size specified by the 
+     * size parameter.
+     *
+     * @param size
+     *  The size of the ByteArray
+     * @return
+     *  The ByteArray
+     */
+    ByteArray create( int size );
+}
\ No newline at end of file

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayList.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayList.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayList.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayList.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,309 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import java.util.NoSuchElementException;
+
+
+/**
+ * A linked list that stores <code>ByteArray</code>s and maintains several useful invariants.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+class ByteArrayList
+{
+
+    /**
+     * A {@link Node} which indicates the start and end of the list and does not
+     * hold a value. The value of <code>next</code> is the first item in the
+     * list. The value of of <code>previous</code> is the last item in the list.
+     */
+    private final Node header;
+
+    /**
+     * The first byte in the array list
+     */
+    private int firstByte;
+
+    /**
+     * The last byte in the array list
+     */
+    private int lastByte;
+
+    /**
+     * 
+     * Creates a new instance of ByteArrayList.
+     *
+     */
+    protected ByteArrayList()
+    {
+        header = new Node();
+    }
+
+    /**
+     * 
+     * Returns the last byte in the array list
+     *
+     * @return
+     *  The last byte in the array list
+     */
+    public int lastByte()
+    {
+        return lastByte;
+    }
+
+    /**
+     * 
+     * Returns the first byte in the array list
+     *
+     * @return
+     *  The first byte in the array list
+     */
+    public int firstByte()
+    {
+        return firstByte;
+    }
+
+    /**
+     * 
+     * Check to see if this is empty
+     *
+     * @return
+     *  True if empty, otherwise false
+     */
+    public boolean isEmpty()
+    {
+        return header.next == header;
+    }
+
+    /**
+     * Returns the first node in the byte array
+     *
+     * @return
+     *  
+     */
+    public Node getFirst()
+    {
+        return header.getNextNode();
+    }
+
+    /**
+     * Returns the last {@link Node} in the list
+     *
+     * @return
+     *  The last node in the list
+     */
+    public Node getLast()
+    {
+        return header.getPreviousNode();
+    }
+
+    /**
+     * Adds the specified {@link ByteArray} to 
+     * the beginning of the list
+     *
+     * @param ba
+     *  The ByteArray to be added to the list
+     */
+    public void addFirst( ByteArray ba )
+    {
+        addNode( new Node( ba ), header.next );
+        firstByte -= ba.last();
+    }
+
+    /**
+     * Add the specified {@link ByteArray} to 
+     * the end of the list 
+     *
+     * @param ba
+     *  The ByteArray to be added to the list
+     */
+    public void addLast( ByteArray ba )
+    {
+        addNode( new Node( ba ), header );
+        lastByte += ba.last();
+    }
+
+    /**
+     * Removes the first node from this list
+     *
+     * @return
+     *  The node that was removed
+     */
+    public Node removeFirst()
+    {
+        Node node = header.getNextNode();
+        firstByte += node.ba.last();
+        return removeNode( node );
+    }
+
+    /**
+     * Removes the last node in this list
+     *
+     * @return
+     *  The node that was taken off of the list
+     */
+    public Node removeLast()
+    {
+        Node node = header.getPreviousNode();
+        lastByte -= node.ba.last();
+        return removeNode( node );
+    }
+
+
+    //-----------------------------------------------------------------------
+
+    /**
+     * Inserts a new node into the list.
+     *
+     * @param nodeToInsert  new node to insert
+     * @param insertBeforeNode  node to insert before
+     * @throws NullPointerException if either node is null
+     */
+    protected void addNode( Node nodeToInsert, Node insertBeforeNode )
+    {
+        // Insert node.
+        nodeToInsert.next = insertBeforeNode;
+        nodeToInsert.previous = insertBeforeNode.previous;
+        insertBeforeNode.previous.next = nodeToInsert;
+        insertBeforeNode.previous = nodeToInsert;
+    }
+
+
+    /**
+     * Removes the specified node from the list.
+     *
+     * @param node  the node to remove
+     * @throws NullPointerException if <code>node</code> is null
+     */
+    protected Node removeNode( Node node )
+    {
+        // Remove node.
+        node.previous.next = node.next;
+        node.next.previous = node.previous;
+        node.removed = true;
+        return node;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A node within the linked list.
+     * <p>
+     * From Commons Collections 3.1, all access to the <code>value</code> property
+     * is via the methods on this class.
+     */
+    public class Node
+    {
+
+        /** A pointer to the node before this node */
+        private Node previous;
+        
+        /** A pointer to the node after this node */
+        private Node next;
+        
+        /** The ByteArray contained within this node */
+        private ByteArray ba;
+        
+        private boolean removed;
+
+
+        /**
+         * Constructs a new header node.
+         */
+        private Node()
+        {
+            super();
+            previous = this;
+            next = this;
+        }
+
+
+        /**
+         * Constructs a new node with a value.
+         */
+        private Node( ByteArray ba )
+        {
+            super();
+            
+            if ( ba == null )
+            {
+                throw new NullPointerException( "ByteArray must not be null." );
+            }
+            this.ba = ba;
+        }
+
+
+        /**
+         * Gets the previous node.
+         *
+         * @return the previous node
+         */
+        public Node getPreviousNode()
+        {
+            if ( !hasPreviousNode() )
+            {
+                throw new NoSuchElementException();
+            }
+            return previous;
+        }
+
+
+        /**
+         * Gets the next node.
+         *
+         * @return the next node
+         */
+        public Node getNextNode()
+        {
+            if ( !hasNextNode() )
+            {
+                throw new NoSuchElementException();
+            }
+            return next;
+        }
+
+
+        public boolean hasPreviousNode()
+        {
+            return previous != header;
+        }
+
+
+        public boolean hasNextNode()
+        {
+            return next != header;
+        }
+
+
+        public ByteArray getByteArray()
+        {
+            return ba;
+        }
+
+
+        public boolean isRemoved()
+        {
+            return removed;
+        }
+    }
+
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayPool.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayPool.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayPool.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/ByteArrayPool.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,179 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import java.util.ArrayList;
+import java.util.Stack;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Creates <code>ByteArray</code>s, using a pool to reduce allocation where possible.
+ *
+ * WARNING: This code has never been run!
+ * 
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public class ByteArrayPool implements ByteArrayFactory
+{
+
+    private final int MAX_BITS = 32;
+
+    private boolean freed;
+    private final boolean direct;
+    private ArrayList<Stack<DirectBufferByteArray>> freeBuffers;
+    private int freeBufferCount = 0;
+    private long freeMemory = 0;
+    private final int maxFreeBuffers;
+    private final int maxFreeMemory;
+
+    /**
+     * Creates a new instance of ByteArrayPool.
+     *
+     * @param direct
+     *  If we should use direct buffers
+     * @param maxFreeBuffers
+     *  The maximum number of free buffers
+     * @param maxFreeMemory
+     *  The maximum amount of free memory allowed
+     */
+    public ByteArrayPool( boolean direct, int maxFreeBuffers, int maxFreeMemory )
+    {
+        this.direct = direct;
+        freeBuffers = new ArrayList<Stack<DirectBufferByteArray>>();
+        for ( int i = 0; i < MAX_BITS; i++ )
+        {
+            freeBuffers.add( new Stack<DirectBufferByteArray>() );
+        }
+        this.maxFreeBuffers = maxFreeBuffers;
+        this.maxFreeMemory = maxFreeMemory;
+        this.freed = false;
+    }
+
+    /**
+     * Creates a new instance of a {@link ByteArray}
+     * 
+     * @param size
+     *  The size of the array to build
+     */
+    public ByteArray create( int size )
+    {
+        if ( size < 1 )
+        {
+            throw new IllegalArgumentException( "Buffer size must be at least 1: " + size );
+        }
+        int bits = bits( size );
+        synchronized ( this )
+        {
+            if ( !freeBuffers.isEmpty() )
+            {
+                DirectBufferByteArray ba = freeBuffers.get( bits ).pop();
+                ba.setFreed( false );
+                ba.getSingleIoBuffer().limit( size );
+                return ba;
+            }
+        }
+        IoBuffer bb;
+        int bbSize = 1 << bits;
+        bb = IoBuffer.allocate( bbSize, direct );
+        bb.limit( size );
+        DirectBufferByteArray ba = new DirectBufferByteArray( bb );
+        ba.setFreed( false );
+        return ba;
+    }
+
+
+    private int bits( int index )
+    {
+        int bits = 0;
+        while ( 1 << bits < index )
+        {
+            bits++;
+        }
+        return bits;
+    }
+
+    /**
+     * Frees the buffers
+     *
+     */
+    public void free()
+    {
+        synchronized ( this )
+        {
+            if ( freed )
+            {
+                throw new IllegalStateException( "Already freed." );
+            }
+            freed = true;
+            freeBuffers.clear();
+            freeBuffers = null;
+        }
+    }
+
+    private class DirectBufferByteArray extends BufferByteArray
+    {
+
+        public boolean freed;
+
+
+        public DirectBufferByteArray( IoBuffer bb )
+        {
+            super( bb );
+        }
+
+
+        public void setFreed( boolean freed )
+        {
+            this.freed = freed;
+        }
+
+
+        @Override
+        public void free()
+        {
+            synchronized ( this )
+            {
+                if ( freed )
+                {
+                    throw new IllegalStateException( "Already freed." );
+                }
+                freed = true;
+            }
+            int bits = bits( last() );
+            synchronized ( ByteArrayPool.this )
+            {
+                if ( freeBuffers != null && freeBufferCount < maxFreeBuffers && freeMemory + last() <= maxFreeMemory )
+                {
+                    freeBuffers.get( bits ).push( this );
+                    freeBufferCount++;
+                    freeMemory += last();
+                    return;
+                }
+            }
+        }
+
+    }
+
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArray.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArray.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArray.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArray.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,1251 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.util.byteaccess.ByteArrayList.Node;
+
+
+/**
+ * A ByteArray composed of other ByteArrays. Optimised for fast relative access
+ * via cursors. Absolute access methods are provided, but may perform poorly.
+ *
+ * TODO: Write about laziness of cursor implementation - how movement doesn't
+ * happen until actual get/put.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public final class CompositeByteArray extends AbstractByteArray
+{
+
+    /**
+     * Allows for efficient detection of component boundaries when using a cursor.
+     *
+     * TODO: Is this interface right?
+     */
+    public interface CursorListener
+    {
+
+        /**
+         * Called when the first component in the composite is entered by the cursor.
+         */
+        public void enteredFirstComponent( int componentIndex, ByteArray component );
+
+
+        /**
+         * Called when the next component in the composite is entered by the cursor.
+         */
+        public void enteredNextComponent( int componentIndex, ByteArray component );
+
+
+        /**
+         * Called when the previous component in the composite is entered by the cursor.
+         */
+        public void enteredPreviousComponent( int componentIndex, ByteArray component );
+
+
+        /**
+         * Called when the last component in the composite is entered by the cursor.
+         */
+        public void enteredLastComponent( int componentIndex, ByteArray component );
+
+    }
+
+    /**
+     * Stores the underlying <code>ByteArray</code>s.
+     */
+    private final ByteArrayList bas = new ByteArrayList();
+
+    /**
+     * The byte order for data in the buffer
+     */
+    private ByteOrder order;
+
+    /**
+     * May be used in <code>getSingleIoBuffer</code>. Optional.
+     */
+    private final ByteArrayFactory byteArrayFactory;
+
+    /**
+     * Creates a new instance of CompositeByteArray.
+     */
+    public CompositeByteArray()
+    {
+        this( null );
+    }
+
+    /**
+     * 
+     * Creates a new instance of CompositeByteArray.
+     *
+     * @param byteArrayFactory
+     *  The factory used to create the ByteArray objects
+     */
+    public CompositeByteArray( ByteArrayFactory byteArrayFactory )
+    {
+        this.byteArrayFactory = byteArrayFactory;
+    }
+
+    /**
+     * Returns the first {@link ByteArray} in the list
+     *
+     * @return
+     *  The first ByteArray in the list
+     */
+    public ByteArray getFirst()
+    {
+        if ( bas.isEmpty() )
+        {
+            return null;
+        }
+        else
+        {
+            return bas.getFirst().getByteArray();
+        }
+    }
+
+    /**
+     * Adds the specified {@link ByteArray} to the first
+     * position in the list
+     *
+     * @param ba
+     *  The ByteArray to add to the list
+     */
+    public void addFirst( ByteArray ba )
+    {
+        addHook( ba );
+        bas.addFirst( ba );
+    }
+
+    /**
+     * Remove the first {@link ByteArray} in the list
+     *
+     * @return
+     *  The first ByteArray in the list
+     */
+    public ByteArray removeFirst()
+    {
+        Node node = bas.removeFirst();
+        return node == null ? null : node.getByteArray();
+    }
+
+
+    /**
+     * Remove component <code>ByteArray</code>s to the given index (splitting
+     * them if necessary) and returning them in a single <code>ByteArray</code>.
+     * The caller is responsible for freeing the returned object.
+     *
+     * TODO: Document free behaviour more thoroughly.
+     */
+    public ByteArray removeTo( int index )
+    {
+        if ( index < first() || index > last() )
+        {
+            throw new IndexOutOfBoundsException();
+        }
+        // Optimisation when removing exactly one component.
+        //        if (index == start() + getFirst().length()) {
+        //            ByteArray component = getFirst();
+        //            removeFirst();
+        //            return component;
+        //        }
+        // Removing
+        CompositeByteArray prefix = new CompositeByteArray( byteArrayFactory );
+        int remaining = index - first();
+        while ( remaining > 0 )
+        {
+            ByteArray component = removeFirst();
+            if ( component.last() <= remaining )
+            {
+                // Remove entire component.
+                prefix.addLast( component );
+                remaining -= component.last();
+            }
+            else
+            {
+                // Remove part of component. Do this by removing entire
+                // component then readding remaining bytes.
+                // TODO: Consider using getIoBuffers(), as would avoid
+                // performance problems for nested ComponentByteArrays.
+                IoBuffer bb = component.getSingleIoBuffer();
+                // get the limit of the buffer
+                int originalLimit = bb.limit();
+                // set the position to the beginning of the buffer
+                bb.position( 0 );
+                // set the limit of the buffer to what is remaining
+                bb.limit( remaining );
+                // create a new IoBuffer, sharing the data with 'bb'
+                IoBuffer bb1 = bb.slice();
+                // set the position at the end of the buffer
+                bb.position( remaining );
+                // gets the limit of the buffer
+                bb.limit( originalLimit );
+                // create a new IoBuffer, sharing teh data with 'bb'
+                IoBuffer bb2 = bb.slice();
+                // create a new ByteArray with 'bb1'
+                ByteArray ba1 = new BufferByteArray( bb1 )
+                {
+                    @Override
+                    public void free()
+                    {
+                        // Do not free.  This will get freed 
+                    }
+                };
+                // add the new ByteArray to the CompositeByteArray
+                prefix.addLast( ba1 );
+                remaining -= ba1.last();
+                
+                // final for anonymous inner class
+                final ByteArray componentFinal = component; 
+                ByteArray ba2 = new BufferByteArray( bb2 )
+                {
+                    @Override
+                    public void free()
+                    {
+                        componentFinal.free();
+                    }
+                };
+                // add the new ByteArray to the CompositeByteArray
+                addFirst( ba2 );
+            }
+        }
+        
+        // return the CompositeByteArray
+        return prefix;
+    }
+
+    /**
+     * Adds the specified {@link ByteArray} to the end of the list
+     *
+     * @param ba
+     *  The ByteArray to add to the end of the list
+     */
+    public void addLast( ByteArray ba )
+    {
+        addHook( ba );
+        bas.addLast( ba );
+    }
+
+    /**
+     * Removes the last {@link ByteArray} in the list
+     *
+     * @return
+     *  The ByteArray that was removed
+     */
+    public ByteArray removeLast()
+    {
+        Node node = bas.removeLast();
+        return node == null ? null : node.getByteArray();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void free()
+    {
+        while ( !bas.isEmpty() )
+        {
+            Node node = bas.getLast();
+            node.getByteArray().free();
+            bas.removeLast();
+        }
+    }
+
+
+    private void checkBounds( int index, int accessSize )
+    {
+        int lower = index;
+        int upper = index + accessSize;
+        if ( lower < first() )
+        {
+            throw new IndexOutOfBoundsException( "Index " + lower + " less than start " + first() + "." );
+        }
+        if ( upper > last() )
+        {
+            throw new IndexOutOfBoundsException( "Index " + upper + " greater than length " + last() + "." );
+        }
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public Iterable<IoBuffer> getIoBuffers()
+    {
+        if ( bas.isEmpty() )
+        {
+            return Collections.emptyList();
+        }
+        Collection<IoBuffer> result = new ArrayList<IoBuffer>();
+        Node node = bas.getFirst();
+        for ( IoBuffer bb : node.getByteArray().getIoBuffers() )
+        {
+            result.add( bb );
+        }
+        while ( node.hasNextNode() )
+        {
+            node = node.getNextNode();
+            for ( IoBuffer bb : node.getByteArray().getIoBuffers() )
+            {
+                result.add( bb );
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public IoBuffer getSingleIoBuffer()
+    {
+        if ( byteArrayFactory == null )
+        {
+            throw new IllegalStateException(
+                "Can't get single buffer from CompositeByteArray unless it has a ByteArrayFactory." );
+        }
+        if ( bas.isEmpty() )
+        {
+            ByteArray ba = byteArrayFactory.create( 1 );
+            return ba.getSingleIoBuffer();
+        }
+        int actualLength = last() - first();
+        {
+            Node node = bas.getFirst();
+            ByteArray ba = node.getByteArray();
+            if ( ba.last() == actualLength )
+            {
+                return ba.getSingleIoBuffer();
+            }
+        }
+        // Replace all nodes with a single node.
+        ByteArray target = byteArrayFactory.create( actualLength );
+        IoBuffer bb = target.getSingleIoBuffer();
+        Cursor cursor = cursor();
+        cursor.put( bb ); // Copy all existing data into target IoBuffer.
+        while ( !bas.isEmpty() )
+        {
+            Node node = bas.getLast();
+            ByteArray component = node.getByteArray();
+            bas.removeLast();
+            component.free();
+        }
+        bas.addLast( target );
+        return bb;
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public Cursor cursor()
+    {
+        return new CursorImpl();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public Cursor cursor( int index )
+    {
+        return new CursorImpl( index );
+    }
+
+
+    /**
+     * Get a cursor starting at index 0 (which may not be the start of the
+     * array) and with the given listener.
+     * 
+     * @param listener
+     *  Returns a new {@link Cursor} instance
+     */
+    public Cursor cursor( CursorListener listener )
+    {
+        return new CursorImpl( listener );
+    }
+
+
+    /**
+     * Get a cursor starting at the given index and with the given listener.
+     * 
+     * @param index
+     *  The position of the array to start the Cursor at
+     * @param listener
+     *  The listener for the Cursor that is returned
+     */
+    public Cursor cursor( int index, CursorListener listener )
+    {
+        return new CursorImpl( index, listener );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public ByteArray slice( int index, int length )
+    {
+        return cursor( index ).slice( length );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public byte get( int index )
+    {
+        return cursor( index ).get();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void put( int index, byte b )
+    {
+        cursor( index ).put( b );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void get( int index, IoBuffer bb )
+    {
+        cursor( index ).get( bb );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void put( int index, IoBuffer bb )
+    {
+        cursor( index ).put( bb );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public int first()
+    {
+        return bas.firstByte();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public int last()
+    {
+        return bas.lastByte();
+    }
+
+
+    /**
+     * This method should be called prior to adding any component
+     * <code>ByteArray</code> to a composite.
+     *
+     * @param ba
+     *  The component to add.
+     */
+    private void addHook( ByteArray ba )
+    {
+        // Check first() is zero, otherwise cursor might not work.
+        // TODO: Remove this restriction?
+        if ( ba.first() != 0 )
+        {
+            throw new IllegalArgumentException( "Cannot add byte array that doesn't start from 0: " + ba.first() );
+        }
+        // Check order.
+        if ( order == null )
+        {
+            order = ba.order();
+        }
+        else if ( !order.equals( ba.order() ) )
+        {
+            throw new IllegalArgumentException( "Cannot add byte array with different byte order: " + ba.order() );
+        }
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public ByteOrder order()
+    {
+        if ( order == null )
+        {
+            throw new IllegalStateException( "Byte order not yet set." );
+        }
+        return order;
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void order( ByteOrder order )
+    {
+        if ( order == null || !order.equals( this.order ) )
+        {
+            this.order = order;
+            if ( !bas.isEmpty() )
+            {
+                for ( Node node = bas.getFirst(); node.hasNextNode(); node = node.getNextNode() )
+                {
+                    node.getByteArray().order( order );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public short getShort( int index )
+    {
+        return cursor( index ).getShort();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putShort( int index, short s )
+    {
+        cursor( index ).putShort( s );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public int getInt( int index )
+    {
+        return cursor( index ).getInt();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putInt( int index, int i )
+    {
+        cursor( index ).putInt( i );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public long getLong( int index )
+    {
+        return cursor( index ).getLong();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putLong( int index, long l )
+    {
+        cursor( index ).putLong( l );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public float getFloat( int index )
+    {
+        return cursor( index ).getFloat();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putFloat( int index, float f )
+    {
+        cursor( index ).putFloat( f );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public double getDouble( int index )
+    {
+        return cursor( index ).getDouble();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putDouble( int index, double d )
+    {
+        cursor( index ).putDouble( d );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public char getChar( int index )
+    {
+        return cursor( index ).getChar();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putChar( int index, char c )
+    {
+        cursor( index ).putChar( c );
+    }
+
+    private class CursorImpl implements Cursor
+    {
+
+        private int index;
+
+        private final CursorListener listener;
+
+        private Node componentNode;
+
+        // Index of start of current component.
+        private int componentIndex;
+
+        // Cursor within current component.
+        private ByteArray.Cursor componentCursor;
+
+
+        public CursorImpl()
+        {
+            this( 0, null );
+        }
+
+
+        public CursorImpl( int index )
+        {
+            this( index, null );
+        }
+
+
+        public CursorImpl( CursorListener listener )
+        {
+            this( 0, listener );
+        }
+
+
+        public CursorImpl( int index, CursorListener listener )
+        {
+            this.index = index;
+            this.listener = listener;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public int getIndex()
+        {
+            return index;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void setIndex( int index )
+        {
+            checkBounds( index, 0 );
+            this.index = index;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void skip( int length )
+        {
+            setIndex( index + length );
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public ByteArray slice( int length )
+        {
+            CompositeByteArray slice = new CompositeByteArray( byteArrayFactory );
+            int remaining = length;
+            while ( remaining > 0 )
+            {
+                prepareForAccess( remaining );
+                int componentSliceSize = Math.min( remaining, componentCursor.getRemaining() );
+                ByteArray componentSlice = componentCursor.slice( componentSliceSize );
+                slice.addLast( componentSlice );
+                index += componentSliceSize;
+                remaining -= componentSliceSize;
+            }
+            return slice;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public ByteOrder order()
+        {
+            return CompositeByteArray.this.order();
+        }
+
+
+        private void prepareForAccess( int accessSize )
+        {
+            // Handle removed node. Do this first so we can remove the reference
+            // even if bounds checking fails.
+            if ( componentNode != null && componentNode.isRemoved() )
+            {
+                componentNode = null;
+                componentCursor = null;
+            }
+
+            // Bounds checks
+            checkBounds( index, accessSize );
+
+            // Remember the current node so we can later tell whether or not we
+            // need to create a new cursor.
+            Node oldComponentNode = componentNode;
+
+            // Handle missing node.
+            if ( componentNode == null )
+            {
+                int basMidpoint = ( last() - first() ) / 2 + first();
+                if ( index <= basMidpoint )
+                {
+                    // Search from the start.
+                    componentNode = bas.getFirst();
+                    componentIndex = first();
+                    if ( listener != null )
+                    {
+                        listener.enteredFirstComponent( componentIndex, componentNode.getByteArray() );
+                    }
+                }
+                else
+                {
+                    // Search from the end.
+                    componentNode = bas.getLast();
+                    componentIndex = last() - componentNode.getByteArray().last();
+                    if ( listener != null )
+                    {
+                        listener.enteredLastComponent( componentIndex, componentNode.getByteArray() );
+                    }
+                }
+            }
+
+            // Go back, if necessary.
+            while ( index < componentIndex )
+            {
+                componentNode = componentNode.getPreviousNode();
+                componentIndex -= componentNode.getByteArray().last();
+                if ( listener != null )
+                {
+                    listener.enteredPreviousComponent( componentIndex, componentNode.getByteArray() );
+                }
+            }
+
+            // Go forward, if necessary.
+            while ( index >= componentIndex + componentNode.getByteArray().length() )
+            {
+                componentIndex += componentNode.getByteArray().last();
+                componentNode = componentNode.getNextNode();
+                if ( listener != null )
+                {
+                    listener.enteredNextComponent( componentIndex, componentNode.getByteArray() );
+                }
+            }
+
+            // Update the cursor.
+            int internalComponentIndex = index - componentIndex;
+            if ( componentNode == oldComponentNode )
+            {
+                // Move existing cursor.
+                componentCursor.setIndex( internalComponentIndex );
+            }
+            else
+            {
+                // Create new cursor.
+                componentCursor = componentNode.getByteArray().cursor( internalComponentIndex );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public int getRemaining()
+        {
+            return last() - index + 1;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public boolean hasRemaining()
+        {
+            return getRemaining() > 0;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public byte get()
+        {
+            prepareForAccess( 1 );
+            byte b = componentCursor.get();
+            index += 1;
+            return b;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void put( byte b )
+        {
+            prepareForAccess( 1 );
+            componentCursor.put( b );
+            index += 1;
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void get( IoBuffer bb )
+        {
+            while ( bb.hasRemaining() )
+            {
+                int remainingBefore = bb.remaining();
+                prepareForAccess( remainingBefore );
+                componentCursor.get( bb );
+                int remainingAfter = bb.remaining();
+                // Advance index by actual amount got.
+                int chunkSize = remainingBefore - remainingAfter;
+                index += chunkSize;
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void put( IoBuffer bb )
+        {
+            while ( bb.hasRemaining() )
+            {
+                int remainingBefore = bb.remaining();
+                prepareForAccess( remainingBefore );
+                componentCursor.put( bb );
+                int remainingAfter = bb.remaining();
+                // Advance index by actual amount put.
+                int chunkSize = remainingBefore - remainingAfter;
+                index += chunkSize;
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public short getShort()
+        {
+            prepareForAccess( 2 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                short s = componentCursor.getShort();
+                index += 2;
+                return s;
+            }
+            else
+            {
+                byte b0 = get();
+                byte b1 = get();
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    return ( short ) ( ( b0 << 8 ) | ( b1 << 0 ) );
+                }
+                else
+                {
+                    return ( short ) ( ( b1 << 8 ) | ( b0 << 0 ) );
+                }
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putShort( short s )
+        {
+            prepareForAccess( 2 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                componentCursor.putShort( s );
+                index += 2;
+            }
+            else
+            {
+                byte b0;
+                byte b1;
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    b0 = ( byte ) ( ( s >> 8 ) & 0xff );
+                    b1 = ( byte ) ( ( s >> 0 ) & 0xff );
+                }
+                else
+                {
+                    b0 = ( byte ) ( ( s >> 0 ) & 0xff );
+                    b1 = ( byte ) ( ( s >> 8 ) & 0xff );
+                }
+                put( b0 );
+                put( b1 );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public int getInt()
+        {
+            prepareForAccess( 4 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                int i = componentCursor.getInt();
+                index += 4;
+                return i;
+            }
+            else
+            {
+                byte b0 = get();
+                byte b1 = get();
+                byte b2 = get();
+                byte b3 = get();
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    return ( ( b0 << 24 ) | ( b1 << 16 ) | ( b2 << 8 ) | ( b3 << 0 ) );
+                }
+                else
+                {
+                    return ( ( b3 << 24 ) | ( b2 << 16 ) | ( b1 << 8 ) | ( b0 << 0 ) );
+                }
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putInt( int i )
+        {
+            prepareForAccess( 4 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                componentCursor.putInt( i );
+                index += 4;
+            }
+            else
+            {
+                byte b0;
+                byte b1;
+                byte b2;
+                byte b3;
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    b0 = ( byte ) ( ( i >> 24 ) & 0xff );
+                    b1 = ( byte ) ( ( i >> 16 ) & 0xff );
+                    b2 = ( byte ) ( ( i >> 8 ) & 0xff );
+                    b3 = ( byte ) ( ( i >> 0 ) & 0xff );
+                }
+                else
+                {
+                    b0 = ( byte ) ( ( i >> 0 ) & 0xff );
+                    b1 = ( byte ) ( ( i >> 8 ) & 0xff );
+                    b2 = ( byte ) ( ( i >> 16 ) & 0xff );
+                    b3 = ( byte ) ( ( i >> 24 ) & 0xff );
+                }
+                put( b0 );
+                put( b1 );
+                put( b2 );
+                put( b3 );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public long getLong()
+        {
+            prepareForAccess( 8 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                long l = componentCursor.getLong();
+                index += 8;
+                return l;
+            }
+            else
+            {
+                byte b0 = get();
+                byte b1 = get();
+                byte b2 = get();
+                byte b3 = get();
+                byte b4 = get();
+                byte b5 = get();
+                byte b6 = get();
+                byte b7 = get();
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    return ( ( b0 & 0xffL ) << 56 ) | ( ( b1 & 0xffL ) << 48 ) | ( ( b2 & 0xffL ) << 40 )
+                        | ( ( b3 & 0xffL ) << 32 ) | ( ( b4 & 0xffL ) << 24 ) | ( ( b5 & 0xffL ) << 16 )
+                        | ( ( b6 & 0xffL ) << 8 ) | ( ( b7 & 0xffL ) << 0 );
+                }
+                else
+                {
+                    return ( ( b7 & 0xffL ) << 56 ) | ( ( b6 & 0xffL ) << 48 ) | ( ( b5 & 0xffL ) << 40 )
+                        | ( ( b4 & 0xffL ) << 32 ) | ( ( b3 & 0xffL ) << 24 ) | ( ( b2 & 0xffL ) << 16 )
+                        | ( ( b1 & 0xffL ) << 8 ) | ( ( b0 & 0xffL ) << 0 );
+                }
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putLong( long l )
+        {
+            //TODO: see if there is some optimizing that can be done here
+            prepareForAccess( 8 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                componentCursor.putLong( l );
+                index += 8;
+            }
+            else
+            {
+                byte b0;
+                byte b1;
+                byte b2;
+                byte b3;
+                byte b4;
+                byte b5;
+                byte b6;
+                byte b7;
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    b0 = ( byte ) ( ( l >> 56 ) & 0xff );
+                    b1 = ( byte ) ( ( l >> 48 ) & 0xff );
+                    b2 = ( byte ) ( ( l >> 40 ) & 0xff );
+                    b3 = ( byte ) ( ( l >> 32 ) & 0xff );
+                    b4 = ( byte ) ( ( l >> 24 ) & 0xff );
+                    b5 = ( byte ) ( ( l >> 16 ) & 0xff );
+                    b6 = ( byte ) ( ( l >> 8 ) & 0xff );
+                    b7 = ( byte ) ( ( l >> 0 ) & 0xff );
+                }
+                else
+                {
+                    b0 = ( byte ) ( ( l >> 0 ) & 0xff );
+                    b1 = ( byte ) ( ( l >> 8 ) & 0xff );
+                    b2 = ( byte ) ( ( l >> 16 ) & 0xff );
+                    b3 = ( byte ) ( ( l >> 24 ) & 0xff );
+                    b4 = ( byte ) ( ( l >> 32 ) & 0xff );
+                    b5 = ( byte ) ( ( l >> 40 ) & 0xff );
+                    b6 = ( byte ) ( ( l >> 48 ) & 0xff );
+                    b7 = ( byte ) ( ( l >> 56 ) & 0xff );
+                }
+                put( b0 );
+                put( b1 );
+                put( b2 );
+                put( b3 );
+                put( b4 );
+                put( b5 );
+                put( b6 );
+                put( b7 );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public float getFloat()
+        {
+            prepareForAccess( 4 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                float f = componentCursor.getFloat();
+                index += 4;
+                return f;
+            }
+            else
+            {
+                int i = getInt();
+                return Float.intBitsToFloat( i );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putFloat( float f )
+        {
+            prepareForAccess( 4 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                componentCursor.putFloat( f );
+                index += 4;
+            }
+            else
+            {
+                int i = Float.floatToIntBits( f );
+                putInt( i );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public double getDouble()
+        {
+            prepareForAccess( 8 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                double d = componentCursor.getDouble();
+                index += 8;
+                return d;
+            }
+            else
+            {
+                long l = getLong();
+                return Double.longBitsToDouble( l );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putDouble( double d )
+        {
+            prepareForAccess( 8 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                componentCursor.putDouble( d );
+                index += 8;
+            }
+            else
+            {
+                long l = Double.doubleToLongBits( d );
+                putLong( l );
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public char getChar()
+        {
+            prepareForAccess( 2 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                char c = componentCursor.getChar();
+                index += 2;
+                return c;
+            }
+            else
+            {
+                byte b0 = get();
+                byte b1 = get();
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    return ( char ) ( ( b0 << 8 ) | ( b1 << 0 ) );
+                }
+                else
+                {
+                    return ( char ) ( ( b1 << 8 ) | ( b0 << 0 ) );
+                }
+            }
+        }
+
+
+        /**
+         * @inheritDoc
+         */
+        public void putChar( char c )
+        {
+            prepareForAccess( 2 );
+            if ( componentCursor.getRemaining() >= 4 )
+            {
+                componentCursor.putChar( c );
+                index += 2;
+            }
+            else
+            {
+                byte b0;
+                byte b1;
+                if ( order.equals( ByteOrder.BIG_ENDIAN ) )
+                {
+                    b0 = ( byte ) ( ( c >> 8 ) & 0xff );
+                    b1 = ( byte ) ( ( c >> 0 ) & 0xff );
+                }
+                else
+                {
+                    b0 = ( byte ) ( ( c >> 0 ) & 0xff );
+                    b1 = ( byte ) ( ( c >> 8 ) & 0xff );
+                }
+                put( b0 );
+                put( b1 );
+            }
+        }
+
+    }
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeBase.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeBase.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeBase.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeBase.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,163 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.util.byteaccess.ByteArray.Cursor;
+import org.apache.mina.util.byteaccess.CompositeByteArray.CursorListener;
+
+
+/**
+ * Provides common functionality between the
+ * <code>CompositeByteArrayRelativeReader</code> and
+ * <code>CompositeByteArrayRelativeWriter</code>.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+abstract class CompositeByteArrayRelativeBase
+{
+
+    /**
+     * The underlying <code>CompositeByteArray</code>.
+     */
+    protected final CompositeByteArray cba;
+
+    /**
+     * A cursor of the underlying <code>CompositeByteArray</code>. This
+     * cursor is never moved directly; its position only changes through calls
+     * to relative read or write methods.
+     */
+    protected final Cursor cursor;
+
+    /**
+     * 
+     * Creates a new instance of CompositeByteArrayRelativeBase.
+     *
+     * @param cba
+     *  The {@link CompositeByteArray} that will be the base for this class
+     */
+    public CompositeByteArrayRelativeBase( CompositeByteArray cba )
+    {
+        this.cba = cba;
+        cursor = cba.cursor( cba.first(), new CursorListener()
+        {
+
+            public void enteredFirstComponent( int componentIndex, ByteArray component )
+            {
+                // Do nothing.
+            }
+
+
+            public void enteredLastComponent( int componentIndex, ByteArray component )
+            {
+                assert false;
+            }
+
+
+            public void enteredNextComponent( int componentIndex, ByteArray component )
+            {
+                cursorPassedFirstComponent();
+            }
+
+
+            public void enteredPreviousComponent( int componentIndex, ByteArray component )
+            {
+                assert false;
+            }
+
+        } );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public final int getRemaining()
+    {
+        return cursor.getRemaining();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public final boolean hasRemaining()
+    {
+        return cursor.hasRemaining();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public ByteOrder order()
+    {
+        return cba.order();
+    }
+
+
+    /**
+     * Make a <code>ByteArray</code> available for access at the end of this object.
+     */
+    public final void append( ByteArray ba )
+    {
+        cba.addLast( ba );
+    }
+
+
+    /**
+     * Free all resources associated with this object.
+     */
+    public final void free()
+    {
+        cba.free();
+    }
+
+
+    /**
+     * Get the index that will be used for the next access.
+     */
+    public final int getIndex()
+    {
+        return cursor.getIndex();
+    }
+
+
+    /**
+     * Get the index after the last byte that can be accessed.
+     */
+    public final int last()
+    {
+        return cba.last();
+    }
+
+
+    /**
+     * Called whenever the cursor has passed from the <code>cba</code>'s
+     * first component. As the first component is no longer used, this provides
+     * a good opportunity for subclasses to perform some action on it (such as
+     * freeing it).
+     */
+    protected abstract void cursorPassedFirstComponent();
+
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeReader.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeReader.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeReader.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeReader.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,161 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Provides restricted, relative, read-only access to the bytes in a
+ * <code>CompositeByteArray</code>. Using this interface has the advantage
+ * that it can be automatically determined when a component
+ * <code>ByteArray</code> can no longer be read, and thus components can be
+ * automatically freed. This makes it easier to use pooling for underlying
+ * <code>ByteArray</code>s.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public class CompositeByteArrayRelativeReader extends CompositeByteArrayRelativeBase implements IoRelativeReader
+{
+
+    /**
+     * Whether or not to free component <code>CompositeByteArray</code>s when
+     * the cursor moves past them.
+     */
+    private final boolean autoFree;
+
+    /**
+     * 
+     * Creates a new instance of CompositeByteArrayRelativeReader.
+     *
+     * @param cba
+     *  The backing ByteArray
+     * @param autoFree
+     *  If data should be freed once it has been passed in the list
+     */
+    public CompositeByteArrayRelativeReader( CompositeByteArray cba, boolean autoFree )
+    {
+        super( cba );
+        this.autoFree = autoFree;
+    }
+
+
+    @Override
+    protected void cursorPassedFirstComponent()
+    {
+        if ( autoFree )
+        {
+            cba.removeFirst().free();
+        }
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void skip( int length )
+    {
+        cursor.skip( length );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public ByteArray slice( int length )
+    {
+        return cursor.slice( length );
+    }
+
+    /**
+     * Returns the byte at the current position in the buffer
+     * 
+     */
+    public byte get()
+    {
+        return cursor.get();
+    }
+
+    /**
+     * places the data starting at current position into the
+     * supplied {@link IoBuffer}
+     */
+    public void get( IoBuffer bb )
+    {
+        cursor.get( bb );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public short getShort()
+    {
+        return cursor.getShort();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public int getInt()
+    {
+        return cursor.getInt();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public long getLong()
+    {
+        return cursor.getLong();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public float getFloat()
+    {
+        return cursor.getFloat();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public double getDouble()
+    {
+        return cursor.getDouble();
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public char getChar()
+    {
+        return cursor.getChar();
+    }
+
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeWriter.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeWriter.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeWriter.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/CompositeByteArrayRelativeWriter.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,274 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Provides restricted, relative, write-only access to the bytes in a
+ * <code>CompositeByteArray</code>.
+ *
+ * Using this interface has the advantage that it can be automatically
+ * determined when a component <code>ByteArray</code> can no longer be written
+ * to, and thus components can be automatically flushed. This makes it easier to
+ * use pooling for underlying <code>ByteArray</code>s.
+ *
+ * By providing an appropriate <code>Expander</code> it is also possible to
+ * automatically add more backing storage as more data is written.
+ *<br/><br/>
+ * TODO: Get flushing working.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public class CompositeByteArrayRelativeWriter extends CompositeByteArrayRelativeBase implements IoRelativeWriter
+{
+
+    /**
+     * An object that knows how to expand a <code>CompositeByteArray</code>.
+     */
+    public interface Expander
+    {
+        void expand( CompositeByteArray cba, int minSize );
+    }
+
+    /**
+     * No-op expander.  The overridden method does nothing.
+     * 
+     */
+    public static class NopExpander implements Expander
+    {
+        public void expand( CompositeByteArray cba, int minSize )
+        {
+            // Do nothing.
+        }
+    }
+
+    /**
+     * Expands the supplied {@link CompositeByteArray} by the number of
+     * bytes provided in the constructor
+     * 
+     */
+    public static class ChunkedExpander implements Expander
+    {
+
+        private final ByteArrayFactory baf;
+
+        private final int newComponentSize;
+
+
+        public ChunkedExpander( ByteArrayFactory baf, int newComponentSize )
+        {
+            this.baf = baf;
+            this.newComponentSize = newComponentSize;
+        }
+
+
+        public void expand( CompositeByteArray cba, int minSize )
+        {
+            int remaining = minSize;
+            while ( remaining > 0 )
+            {
+                ByteArray component = baf.create( newComponentSize );
+                cba.addLast( component );
+                remaining -= newComponentSize;
+            }
+        }
+
+    }
+
+    /**
+     * An object that knows how to flush a <code>ByteArray</code>.
+     */
+    public interface Flusher
+    {
+        // document free() behaviour
+        void flush( ByteArray ba );
+    }
+
+    /**
+     * The expander to use when the array underflows.
+     */
+    private final Expander expander;
+
+    /**
+     * The flusher to use when flushing component <code>ByteArray</code>s.
+     */
+    private final Flusher flusher;
+
+    /**
+     * Whether or not to automatically flush a component once the cursor moves
+     * past it.
+     */
+    private final boolean autoFlush;
+
+
+    /**
+     * 
+     * Creates a new instance of CompositeByteArrayRelativeWriter.
+     *
+     * @param cba
+     *  The CompositeByteArray to use to back this class
+     * @param expander
+     *  The expander.  Will increase the size of the internal ByteArray
+     * @param flusher
+     *  Flushed the ByteArray when necessary
+     * @param autoFlush
+     *  Should this class automatically flush?
+     */
+    public CompositeByteArrayRelativeWriter( CompositeByteArray cba, Expander expander, Flusher flusher,
+        boolean autoFlush )
+    {
+        super( cba );
+        this.expander = expander;
+        this.flusher = flusher;
+        this.autoFlush = autoFlush;
+    }
+
+
+    private void prepareForAccess( int size )
+    {
+        int underflow = cursor.getIndex() + size - last();
+        if ( underflow > 0 )
+        {
+            expander.expand( cba, underflow );
+        }
+    }
+
+
+    /**
+     * Flush to the current index.
+     */
+    public void flush()
+    {
+        flushTo( cursor.getIndex() );
+    }
+
+
+    /**
+     * Flush to the given index.
+     */
+    public void flushTo( int index )
+    {
+        ByteArray removed = cba.removeTo( index );
+        flusher.flush( removed );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void skip( int length )
+    {
+        cursor.skip( length );
+    }
+
+
+    @Override
+    protected void cursorPassedFirstComponent()
+    {
+        if ( autoFlush )
+        {
+            flushTo( cba.first() + cba.getFirst().length() );
+        }
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void put( byte b )
+    {
+        prepareForAccess( 1 );
+        cursor.put( b );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void put( IoBuffer bb )
+    {
+        prepareForAccess( bb.remaining() );
+        cursor.put( bb );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putShort( short s )
+    {
+        prepareForAccess( 2 );
+        cursor.putShort( s );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putInt( int i )
+    {
+        prepareForAccess( 4 );
+        cursor.putInt( i );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putLong( long l )
+    {
+        prepareForAccess( 8 );
+        cursor.putLong( l );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putFloat( float f )
+    {
+        prepareForAccess( 4 );
+        cursor.putFloat( f );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putDouble( double d )
+    {
+        prepareForAccess( 8 );
+        cursor.putDouble( d );
+    }
+
+
+    /**
+     * @inheritDoc
+     */
+    public void putChar( char c )
+    {
+        prepareForAccess( 2 );
+        cursor.putChar( c );
+    }
+}

Added: mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteReader.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteReader.java?rev=685367&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteReader.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/util/byteaccess/IoAbsoluteReader.java Tue Aug 12 16:24:26 2008
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF 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.apache.mina.util.byteaccess;
+
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+
+
+/**
+ * Provides absolute read access to a sequence of bytes.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ */
+public interface IoAbsoluteReader
+{
+
+    /**
+     * Get the index of the first byte that can be accessed.
+     */
+    int first();
+
+
+    /**
+     * Gets the index after the last byte that can be accessed.
+     */
+    int last();
+
+
+    /**
+     * Gets the total number of bytes that can be accessed.
+     */
+    int length();
+
+
+    /**
+     * Creates an array with a view of part of this array.
+     */
+    ByteArray slice( int index, int length );
+
+
+    /**
+     * Gets the order of the bytes.
+     */
+    ByteOrder order();
+
+
+    /**
+     * Gets a <code>byte</code> from the given index.
+     */
+    byte get( int index );
+
+
+    /**
+     * Gets enough bytes to fill the <code>IoBuffer</code> from the given index.
+     */
+    public void get( int index, IoBuffer bb );
+
+
+    /**
+     * Gets a <code>short</code> from the given index.
+     */
+    short getShort( int index );
+
+
+    /**
+     * Gets an <code>int</code> from the given index.
+     */
+    int getInt( int index );
+
+
+    /**
+     * Gets a <code>long</code> from the given index.
+     */
+    long getLong( int index );
+
+
+    /**
+     * Gets a <code>float</code> from the given index.
+     */
+    float getFloat( int index );
+
+
+    /**
+     * Gets a <code>double</code> from the given index.
+     */
+    double getDouble( int index );
+
+
+    /**
+     * Gets a <code>char</code> from the given index.
+     */
+    char getChar( int index );
+}