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 );
+}