You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by jv...@apache.org on 2013/04/25 13:47:32 UTC
[1/4] git commit: make protocol decoding exception runtimes
Updated Branches:
refs/heads/trunk 6c811bc08 -> 94da8200b
make protocol decoding exception runtimes
Project: http://git-wip-us.apache.org/repos/asf/mina/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina/commit/6e056d81
Tree: http://git-wip-us.apache.org/repos/asf/mina/tree/6e056d81
Diff: http://git-wip-us.apache.org/repos/asf/mina/diff/6e056d81
Branch: refs/heads/trunk
Commit: 6e056d81b61ee5ec2ebcf44678d73e61a73602d3
Parents: 6c811bc
Author: jvermillard <jv...@apache.org>
Authored: Thu Apr 25 13:43:51 2013 +0200
Committer: jvermillard <jv...@apache.org>
Committed: Thu Apr 25 13:43:51 2013 +0200
----------------------------------------------------------------------
.../mina/codec/ProtocolDecoderException.java | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina/blob/6e056d81/codec/src/main/java/org/apache/mina/codec/ProtocolDecoderException.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/ProtocolDecoderException.java b/codec/src/main/java/org/apache/mina/codec/ProtocolDecoderException.java
index e098b27..b0ab412 100644
--- a/codec/src/main/java/org/apache/mina/codec/ProtocolDecoderException.java
+++ b/codec/src/main/java/org/apache/mina/codec/ProtocolDecoderException.java
@@ -25,7 +25,7 @@ package org.apache.mina.codec;
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
@SuppressWarnings("serial")
-public class ProtocolDecoderException extends Exception {
+public class ProtocolDecoderException extends RuntimeException {
public ProtocolDecoderException() {
super();
[4/4] git commit: removed reference to IoBuffer
Posted by jv...@apache.org.
removed reference to IoBuffer
Project: http://git-wip-us.apache.org/repos/asf/mina/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina/commit/94da8200
Tree: http://git-wip-us.apache.org/repos/asf/mina/tree/94da8200
Diff: http://git-wip-us.apache.org/repos/asf/mina/diff/94da8200
Branch: refs/heads/trunk
Commit: 94da8200b3ef16fff3a06d80c9ac299fb65d1e03
Parents: 8096739
Author: jvermillard <jv...@apache.org>
Authored: Thu Apr 25 13:46:27 2013 +0200
Committer: jvermillard <jv...@apache.org>
Committed: Thu Apr 25 13:46:27 2013 +0200
----------------------------------------------------------------------
.../org/apache/mina/util/ByteBufferDumper.java | 41 ++------------
1 files changed, 6 insertions(+), 35 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina/blob/94da8200/core/src/main/java/org/apache/mina/util/ByteBufferDumper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mina/util/ByteBufferDumper.java b/core/src/main/java/org/apache/mina/util/ByteBufferDumper.java
index 47127ad..0d6981b 100644
--- a/core/src/main/java/org/apache/mina/util/ByteBufferDumper.java
+++ b/core/src/main/java/org/apache/mina/util/ByteBufferDumper.java
@@ -22,45 +22,17 @@ import java.nio.ByteBuffer;
/**
* Utility class for smart dumping {@link ByteBuffer}
- *
+ *
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
public class ByteBufferDumper {
/** Hex chars */
private static final byte[] HEX_CHAR = new byte[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
- 'C', 'D', 'E', 'F' };
-
- /**
- * Dump the content of a IoBuffer
- *
- * @param buffer The IoBuffer to dump
- * @return A string representing the IoBuffer content
- */
- public static String dump(IoBuffer buffer) {
- StringBuilder sb = new StringBuilder();
-
- boolean isFirst = true;
-
- for (int i = 0; i < buffer.limit(); i++) {
- byte byteValue = buffer.get(i);
-
- if (isFirst) {
- isFirst = false;
- } else {
- sb.append(' ');
- }
-
- sb.append(new String(new byte[] { '0', 'x', HEX_CHAR[(byteValue & 0x00F0) >> 4],
- HEX_CHAR[byteValue & 0x000F] }));
- }
-
- return sb.toString();
- }
+ 'C', 'D', 'E', 'F' };
/**
- * Dump the content of the given ByteBuffer, up to a number of bytes. If the
- * toAscii flag is set to <code>true</code>, this method will try to convert
- * the bytes to a String
+ * Dump the content of the given ByteBuffer, up to a number of bytes. If the toAscii flag is set to
+ * <code>true</code>, this method will try to convert the bytes to a String
*
* @param buffer The buffer to dump
* @param nbBytes The number of bytes to dump (-1 for all of them)
@@ -105,7 +77,7 @@ public class ByteBufferDumper {
byteValue = data[i] & 0xFF;
out.append(new String(new byte[] { '0', 'x', HEX_CHAR[(byteValue & 0x00F0) >> 4],
- HEX_CHAR[byteValue & 0x000F] }));
+ HEX_CHAR[byteValue & 0x000F] }));
}
out.append("']");
@@ -122,8 +94,7 @@ public class ByteBufferDumper {
}
/**
- * Dumps the given buffer. If the buffer contains only ascii, it will write
- * the buffer content as a String.
+ * Dumps the given buffer. If the buffer contains only ascii, it will write the buffer content as a String.
*
* @param buffer The buffer to dump
* @return A string representing the buffer content
[3/4] git commit: moved IoBuffer to codec project because it's
usefull only for decoder implementation
Posted by jv...@apache.org.
moved IoBuffer to codec project because it's usefull only for decoder implementation
Project: http://git-wip-us.apache.org/repos/asf/mina/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina/commit/80967391
Tree: http://git-wip-us.apache.org/repos/asf/mina/tree/80967391
Diff: http://git-wip-us.apache.org/repos/asf/mina/diff/80967391
Branch: refs/heads/trunk
Commit: 809673918572c3c5e0674385fed0773341521e89
Parents: 6e056d8
Author: jvermillard <jv...@apache.org>
Authored: Thu Apr 25 13:45:17 2013 +0200
Committer: jvermillard <jv...@apache.org>
Committed: Thu Apr 25 13:45:17 2013 +0200
----------------------------------------------------------------------
.../main/java/org/apache/mina/codec/IoBuffer.java | 995 ++++++++++++++
.../java/org/apache/mina/codec/IoBufferTest.java | 797 ++++++++++++
.../main/java/org/apache/mina/util/IoBuffer.java | 1008 ---------------
.../java/org/apache/mina/util/IoBufferTest.java | 796 ------------
4 files changed, 1792 insertions(+), 1804 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina/blob/80967391/codec/src/main/java/org/apache/mina/codec/IoBuffer.java
----------------------------------------------------------------------
diff --git a/codec/src/main/java/org/apache/mina/codec/IoBuffer.java b/codec/src/main/java/org/apache/mina/codec/IoBuffer.java
new file mode 100644
index 0000000..3ce26ff
--- /dev/null
+++ b/codec/src/main/java/org/apache/mina/codec/IoBuffer.java
@@ -0,0 +1,995 @@
+/**
+ * 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.codec;
+
+import java.nio.Buffer;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.InvalidMarkException;
+import java.nio.ReadOnlyBufferException;
+
+/**
+ * A proxy class used to manage ByteBuffers as if they were just a big ByteBuffer. We can add as many buffers as needed,
+ * when accumulating data. From the user PoV, the methods are the very same than what we can get from ByteBuffer. <br/>
+ * IoBuffer instances are *not* thread safe.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class IoBuffer {
+ /** The list of ByteBuffers were we store the data */
+ private BufferList buffers = new BufferList();
+
+ /** The maximal position in the IoBuffer */
+ private int limit;
+
+ /** The current position in the buffer */
+ private int position;
+
+ /** The marked position, for the next reset() */
+ private int mark;
+
+ /** Tells if the stored buffers are direct or heap */
+ private BufferType type;
+
+ /** Tells if the IoBuffer is readonly */
+ private boolean readOnly;
+
+ /** The bytes order (BIG_INDIAN or LITTLE_INDIAN) */
+ private ByteOrder order = ByteOrder.BIG_ENDIAN;
+
+ /** The two types of buffer we handle */
+ public enum BufferType {
+ HEAP, DIRECT;
+ }
+
+ /** A empty bytes array */
+ private final static byte[] EMPTY_BYTES = new byte[] {};
+
+ /** <code>UNSET_MARK</code> means the mark has not been set. */
+ private final static int UNSET_MARK = -1;
+
+ /**
+ * Construct a IoBuffer, with no buffer in it
+ */
+ public IoBuffer() {
+ position = 0;
+ mark = 0;
+ limit = 0;
+ type = null;
+ order = null;
+ }
+
+ /**
+ * Construct an empty IoBuffer with a defined type (either HEAP or DIRECT)
+ *
+ * @param bufferType the type of buffer to use : BufferType.HEAP or BufferType.DIRECT
+ */
+ public IoBuffer(BufferType bufferType) {
+ position = 0;
+ mark = 0;
+ limit = 0;
+ type = bufferType;
+ }
+
+ /**
+ * Construct a IoBuffer with some ByteBuffers. The IoBuffer type will be selected from the first ByteBuffer type, so
+ * will the order.
+ *
+ * @param byteBuffers the ByteBuffers added to the IoBuffer list
+ */
+ public IoBuffer(ByteBuffer... byteBuffers) {
+ if ((byteBuffers == null) || (byteBuffers.length == 0)) {
+ position = 0;
+ mark = 0;
+ limit = 0;
+ type = null;
+ order = null;
+ } else {
+ for (ByteBuffer byteBuffer : byteBuffers) {
+ if (type == null) {
+ type = byteBuffer.isDirect() ? BufferType.DIRECT : BufferType.HEAP;
+ }
+
+ if (byteBuffer.limit() > 0) {
+ buffers.add(byteBuffer);
+ }
+ }
+ }
+ }
+
+ /**
+ * Construct a IoBuffer from an existing IoBuffer.
+ *
+ * @param ioBuffer the IoBuffer we want to copy
+ */
+ public IoBuffer(IoBuffer ioBuffer) {
+ // Find the position to start with
+ BufferNode node = ioBuffer.buffers.getFirst();
+ int pos = 0;
+
+ while (node != null) {
+ if (node.offset + node.buffer.limit() < position) {
+ node = buffers.getNext();
+ pos = node.offset + node.buffer.limit();
+ } else {
+ buffers.add(node.buffer);
+ }
+ }
+
+ position = position - pos;
+ mark = 0;
+ limit = ioBuffer.limit() - pos;
+ type = ioBuffer.type;
+ order = ioBuffer.order();
+ }
+
+ /**
+ * Adds a new ByteBuffer at the end of the list of buffers.
+ *
+ * @param byteBuffer The added ByteBuffer
+ * @return The modified IoBuffer
+ */
+ public IoBuffer add(ByteBuffer... byteBuffers) {
+ for (ByteBuffer byteBuffer : byteBuffers) {
+ if (byteBuffer.limit() > 0) {
+ buffers.add(byteBuffer);
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Allocate a Heap IoBuffer with a defined capacity
+ *
+ * @param capacity The number of bytes to store
+ * @return The allocated IoBuffer
+ */
+ public static IoBuffer allocate(int capacity) {
+ if (capacity >= 0) {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(capacity);
+
+ return new IoBuffer(byteBuffer);
+ } else {
+ throw new IllegalArgumentException("Cannot allocate an IoBuffer with a negative value : " + capacity);
+ }
+ }
+
+ /**
+ * Allocate a Direct IoBuffer with a defined capacity
+ *
+ * @param capacity The number of bytes to store
+ * @return The allocated IoBuffer
+ */
+ public static IoBuffer allocateDirect(int capacity) {
+ if (capacity >= 0) {
+ ByteBuffer byteBuffer = ByteBuffer.allocateDirect(capacity);
+
+ return new IoBuffer(byteBuffer);
+ } else {
+ throw new IllegalArgumentException("Cannot allocate an IoBuffer with a negative value : " + capacity);
+ }
+ }
+
+ /**
+ * @see ByteBuffer#array() Returns the byte array which this IoBuffer is based on, up to the sum of each contained
+ * ByteBuffer's limit().<br/>
+ * This array can be modified, but this won't modify the content of the underlying ByteBuffer instances,
+ * contrary to the ByteBuffer.array() method.
+ *
+ * @return the byte array which this IoBuffer is based on.
+ * @exception ReadOnlyBufferException if this IoBuffer is based on a read-only array.
+ * @exception UnsupportedOperationException if this IoBuffer is not based on an array.
+ */
+ public byte[] array() {
+ if (isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+
+ if (buffers.size == 0) {
+ return EMPTY_BYTES;
+ }
+
+ byte[] array = new byte[buffers.length];
+ BufferNode node = buffers.getFirst();
+ int pos = 0;
+
+ while (node != null) {
+ ByteBuffer buffer = node.buffer;
+ byte[] src = buffer.array();
+ int length = buffer.limit();
+
+ System.arraycopy(src, 0, array, pos, length);
+ pos += length;
+
+ node = buffers.getNext();
+ }
+
+ return array;
+ }
+
+ /**
+ * @see ByteBuffer#arrayOffset() Returns the offset of the byte array which this IoBuffer is based on, if there is
+ * one.
+ * <p>
+ * The offset is the index of the array which corresponds to the zero position of the IoBuffer.
+ *
+ * @return the offset of the byte array which this IoBuffer is based on.
+ * @exception ReadOnlyBufferException if this IoBuffer is based on a read-only array.
+ * @exception UnsupportedOperationException if this IoBuffer is not based on an array.
+ */
+ public int arrayOffset() {
+ if (isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+
+ // The offset is always 0
+ return 0;
+ }
+
+ /**
+ * @see ByteBuffer#asReadOnlyBuffer()
+ */
+ public IoBuffer asReadOnlyBuffer() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @return the IoBuffer total capacity
+ */
+ public int capacity() {
+ return limit;
+ }
+
+ /**
+ * @see Buffer#clear() Clears this IoBuffer.
+ * <p>
+ * the following internal changes take place:
+ * <ul>
+ * <li>the current position is reset back to the start of the buffer</li>
+ * <li>the value of the buffer limit is made equal to the capacity</li>
+ * <li>and mark is cleared</li>
+ * </ul>
+ * Note that the resulting IoBuffer might be wider than the original one, simply because we will extent the
+ * ByteBuffers limit to their capacity.
+ *
+ * @return this buffer.
+ */
+ public IoBuffer clear() {
+ position = 0;
+ mark = UNSET_MARK;
+
+ BufferNode node = buffers.head;
+ int offset = 0;
+
+ while (node != null) {
+ node.buffer.clear();
+ node.offset = offset;
+ offset += node.buffer.limit();
+ node = node.next;
+ }
+
+ limit = offset;
+ buffers.length = 0;
+ buffers.current = buffers.head;
+
+ return this;
+ }
+
+ /**
+ * @see ByteBuffer#compact()
+ */
+ public IoBuffer compact() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#compareTo(ByteBuffer)
+ */
+ public int compareTo(IoBuffer buffer) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#duplicate()
+ */
+ public IoBuffer duplicate() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#equals(Object)
+ */
+ @Override
+ public boolean equals(Object object) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see Buffer#flip() Flips this buffer.
+ * <p>
+ * The limit is set to the current position, then the position is set to zero, and the mark is cleared.
+ * <p>
+ * The content of this IoBuffer is not changed.
+ *
+ * @return this IoBuffer.
+ */
+ public IoBuffer flip() {
+ limit = position;
+ position = 0;
+ mark = UNSET_MARK;
+
+ return this;
+ }
+
+ /**
+ * Get a single byte for the IoBuffer at the current position. Increment the current position.
+ *
+ * @return The byte found a the current position.
+ */
+ public byte get() {
+ if (position >= limit) {
+ // No more byte to read
+ throw new BufferUnderflowException();
+ }
+
+ // find the byte from the current buffer now
+ BufferNode currentNode = buffers.getCurrent();
+
+ // If the position is within the current buffer, then get the data from it
+ int bufferPosition = position - currentNode.offset;
+
+ if (bufferPosition < currentNode.buffer.limit()) {
+ position++;
+
+ return currentNode.buffer.get();
+ } else {
+ // We have exhausted the current buffer, let's see if we have one more
+ currentNode = buffers.getNext();
+
+ if (currentNode == null) {
+ // No more buffers
+ throw new BufferUnderflowException();
+ } else {
+ position++;
+ currentNode.buffer.position(0);
+
+ return currentNode.buffer.get();
+ }
+ }
+ }
+
+ /**
+ * @see ByteBuffer#get(byte[]) Reads bytes from the current position into the specified byte array and increases the
+ * position by the number of bytes read.
+ * <p>
+ * Calling this method has the same effect as {@code get(dest, 0, dest.length)}.
+ *
+ * @param dest the destination byte array.
+ * @return this IoBuffer.
+ * @exception BufferUnderflowException if {@code dest.length} is greater than {@code remaining()}.
+ */
+ public IoBuffer get(byte[] dst) {
+ if (dst.length > remaining()) {
+ throw new BufferUnderflowException();
+ }
+
+ int size = dst.length;
+ int destPos = 0;
+ BufferNode node = buffers.current;
+
+ while (size > 0) {
+ int length = node.buffer.limit() - node.buffer.position();
+ System.arraycopy(node.buffer.array(), node.buffer.position(), dst, destPos, length);
+ destPos += length;
+ node = buffers.getNext();
+ }
+
+ return this;
+ }
+
+ /**
+ * @see ByteBuffer#get(byte[],int,int)
+ */
+ public IoBuffer get(byte[] dst, int offset, int length) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#get(int) Returns the byte at the specified index and does not change the position.
+ *
+ * @param index the index, must not be negative and less than limit.
+ * @return the byte at the specified index.
+ * @exception IndexOutOfBoundsException if index is invalid.
+ */
+ public byte get(int index) {
+ if ((index < 0) || (index >= limit)) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ BufferNode currentNode = buffers.current;
+ BufferNode node = buffers.getFirst();
+
+ while (node != null) {
+ if (node.offset + node.buffer.limit() > index) {
+ byte result = node.buffer.get(index - node.offset);
+
+ // Reset the initial position before returning
+ buffers.current = currentNode;
+
+ return result;
+ } else {
+ node = buffers.getNext();
+ }
+ }
+
+ // Reset the initial position before returning
+ buffers.current = currentNode;
+
+ // Unlikely to happen
+ throw new IndexOutOfBoundsException();
+ }
+
+ /**
+ * @see ByteBuffer#getChar()
+ */
+ public IoBuffer getChar() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getChar(int)
+ */
+ public IoBuffer getChar(int index) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getDouble()
+ */
+ public IoBuffer getDouble() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getDouble(int)
+ */
+ public IoBuffer getDouble(int index) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getFloat()
+ */
+ public IoBuffer getFloat() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getFloat(int)
+ */
+ public IoBuffer getFloat(int index) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getInt() Returns the int at the current position and increases the position by 4.
+ * <p>
+ * The 4 bytes starting at the current position are composed into a int according to the current byte order and
+ * returned.
+ *
+ * @return the int at the current position.
+ * @exception BufferUnderflowException if the position is greater than {@code limit - 4}.
+ */
+ public int getInt() {
+ int newPosition = position + 4;
+
+ if (newPosition > limit) {
+ throw new BufferUnderflowException();
+ }
+
+ int result = loadInt(position);
+ position = newPosition;
+
+ return result;
+ }
+
+ /**
+ * Load an int from the underlying byteBuffers, taking the order into account.
+ */
+ private final int loadInt(int index) {
+ int bytes = 0;
+
+ if (order == ByteOrder.BIG_ENDIAN) {
+ for (int i = 0; i < 4; i++) {
+ bytes = bytes << 8;
+ bytes = bytes | (get() & 0xFF);
+ }
+ } else {
+ for (int i = 0; i < 4; i++) {
+ int val = get() & 0xFF;
+ bytes = bytes | (val << (i << 3));
+ }
+ }
+
+ return bytes;
+ }
+
+ /**
+ * @see ByteBuffer#getInt(int)
+ */
+ public IoBuffer getInt(int index) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getLong()
+ */
+ public IoBuffer getLong() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getLong(int)
+ */
+ public IoBuffer getLong(int index) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getShort()
+ */
+ public IoBuffer getShort() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#getShort(int)
+ */
+ public IoBuffer getShort(int index) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see Buffer#hasRemaining() Indicates if there are elements remaining in this IoBuffer, that is if
+ * {@code position < limit}.
+ *
+ * @return {@code true} if there are elements remaining in this IoBuffer, {@code false} otherwise.
+ */
+ public boolean hasRemaining() {
+ return position < limit;
+ }
+
+ /**
+ * @see ByteBuffer#isDirect() Tells if the stored ByteBuffers are Direct buffers or Heap Buffers
+ * @return <code>true</code> if we are storing Direct buffers, <code>false</code> otherwise.
+ */
+ public boolean isDirect() {
+ return type == BufferType.DIRECT;
+ }
+
+ /**
+ * @see Buffer#isReadOnly() Indicates whether this IoBuffer is read-only.
+ *
+ * @return {@code true} if this IoBuffer is read-only, {@code false} otherwise.
+ */
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * @return the IoBuffer limit
+ */
+ public int limit() {
+ return limit;
+ }
+
+ /**
+ * @see Buffer#mark() Marks the current position, so that the position may return to this point later by calling
+ * <code>reset()</code>.
+ *
+ * @return this IoBuffer.
+ */
+ public IoBuffer mark() {
+ mark = position;
+
+ return this;
+ }
+
+ /**
+ * @see ByteBuffer#order() Returns the byte order used by this Iouffer when converting bytes from/to other primitive
+ * types.
+ * <p>
+ * The default byte order of byte buffer is always {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN}
+ *
+ * @return the byte order used by this IoBuffer when converting bytes from/to other primitive types.
+ */
+ public ByteOrder order() {
+ return order;
+ }
+
+ /**
+ * @see ByteBuffer#order(ByteOrder) Sets the byte order of this IoBuffer.
+ *
+ * @param byteOrder the byte order to set. If {@code null} then the order will be {@link ByteOrder#LITTLE_ENDIAN
+ * LITTLE_ENDIAN}.
+ * @return this IoBuffer.
+ * @see ByteOrder
+ */
+ public IoBuffer order(ByteOrder bo) {
+ if (bo == null) {
+ order = ByteOrder.LITTLE_ENDIAN;
+ } else {
+ order = bo;
+ }
+
+ return this;
+ }
+
+ /**
+ * @see Buffer#position()
+ * @return The current position across all the ByteBuffers contained in the IoBuffer
+ */
+ public int position() {
+ return position;
+ }
+
+ /**
+ * @see Buffer#position(int) Sets the position in the IoBuffer.
+ * <p>
+ * If the mark is set and it is greater than the new position, then it is cleared.
+ *
+ * @param newPosition the new position, must be not negative and not greater than limit.
+ * @return this IoBuffer.
+ * @exception IllegalArgumentException if <code>newPosition</code> is invalid.
+ */
+ public IoBuffer position(int newPosition) {
+ if (newPosition < 0) {
+ throw new IllegalArgumentException("The new position(" + newPosition + ") is negative");
+ }
+
+ if (newPosition >= limit) {
+ throw new IllegalArgumentException("The new position(" + newPosition
+ + ") is larger than this buffer limit (" + limit());
+ }
+
+ if (buffers.head == null) {
+ throw new IllegalArgumentException("Cannot set a position over an empty buffer");
+ }
+
+ // Find the right current buffer
+ BufferNode currentNode = buffers.getCurrent();
+
+ // The new position might not be on the current buffer.
+ if ((newPosition < currentNode.offset) || (newPosition >= currentNode.offset + currentNode.buffer.limit())) {
+ // Ok, we aren't on the current buffer. Find the new current buffer
+ BufferNode node = buffers.head;
+ int counter = 0;
+
+ while (node != null) {
+ int limit = node.buffer.limit();
+ counter += limit;
+
+ if (counter >= newPosition) {
+ // Found
+ currentNode = node;
+ break;
+ } else {
+ node = node.next;
+ }
+ }
+ }
+
+ position = newPosition;
+ currentNode.buffer.position(position - currentNode.offset);
+ buffers.current = currentNode;
+
+ return this;
+ }
+
+ /**
+ * @see Buffer#remaining() Returns the number of remaining elements in this IoBuffer, that is
+ * {@code limit - position}.
+ *
+ * @return the number of remaining elements in this IoBuffer.
+ */
+ public int remaining() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see Buffer#reset() Resets the position of this IoBuffer to the <code>mark</code>.
+ *
+ * @return this IoBuffer.
+ * @exception InvalidMarkException if the mark is not set.
+ */
+ public IoBuffer reset() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see Buffer#rewind() Rewinds this IoBuffer.
+ * <p>
+ * The position is set to zero, and the mark is cleared. The content of this IoBuffer is not changed.
+ *
+ * @return this IoBuffer.
+ */
+ public IoBuffer rewind() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#slice()
+ */
+ public IoBuffer slice() {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#wrap(byte[])
+ */
+ public IoBuffer wrap(byte[] array) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @see ByteBuffer#wrap(byte[], int, int)
+ */
+ public IoBuffer wrap(byte[] array, int offset, int length) {
+ // TODO code me !
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns a string representing the IoBuffer.
+ *
+ * @return a String representation of the IoBuffer
+ */
+ @Override
+ public String toString() {
+ return "IoBuffer[pos=" + position + " lim=" + limit + " mrk=" + mark + "]";
+ }
+
+ // ------------------------------------------------------------------------------------------------
+ // private inner data structure
+ // ------------------------------------------------------------------------------------------------
+ /**
+ * A container for ByterBuffers stored in the buffers list
+ */
+ private class BufferNode {
+ /** The stored buffer */
+ private ByteBuffer buffer;
+
+ /** The next buffer in the list */
+ private BufferNode next;
+
+ /** The position of this buffer in the IoBuffer list of bytes */
+ private int offset;
+
+ /**
+ * Creates a new entry in the list
+ *
+ * @param entry The added ByteBuffer
+ */
+ private BufferNode(ByteBuffer byteBuffer) {
+ this.buffer = byteBuffer;
+ }
+
+ @Override
+ public String toString() {
+ return buffer.toString() + ", Offset:" + offset + (next != null ? " --> \n " : "");
+ }
+ }
+
+ /**
+ * A LinkedList storing all the ByteBuffers. It can only be browsed forward.
+ */
+ private class BufferList {
+ /** The first ByteBuffer in the list */
+ private BufferNode head;
+
+ /** The last ByteBuffer in the list */
+ private BufferNode tail;
+
+ /** The current ByteBuffer in the list */
+ private BufferNode current;
+
+ /** The number of nodes in the list */
+ private int size;
+
+ /** The number of bytes in the list */
+ private int length;
+
+ /** A flag used to indicate that we already have navigated past the tail of the list. */
+ private boolean pastTail;
+
+ /**
+ * Creates an empty list
+ */
+ private BufferList() {
+ head = tail = current = null;
+ size = 0;
+ length = 0;
+ pastTail = false;
+ }
+
+ /**
+ * Creates a list with one ByteBuffer
+ *
+ * @param byteBuffer The added ByteBuffer
+ */
+ private BufferList(ByteBuffer byteBuffer) {
+ BufferNode node = new BufferNode(byteBuffer);
+ head = tail = current = node;
+ size = 1;
+ length = byteBuffer.limit();
+ pastTail = false;
+ }
+
+ /**
+ * Adds a new ByteBuffer in the list
+ *
+ * @param byteBuffer The added ByteBuffer
+ */
+ private void add(ByteBuffer byteBuffer) {
+ assert (byteBuffer != null);
+
+ // Check the buffer type
+ if (type == null) {
+ if (byteBuffer.isDirect()) {
+ type = BufferType.DIRECT;
+ } else {
+ type = BufferType.HEAP;
+ }
+ } else {
+ if (isDirect() != byteBuffer.isDirect()) {
+ throw new RuntimeException();
+ }
+ }
+
+ // Check the ByteOrder
+ if (size == 0) {
+ order = byteBuffer.order();
+ } else if (order != byteBuffer.order()) {
+ throw new RuntimeException();
+ }
+
+ BufferNode newNode = new BufferNode(byteBuffer);
+ newNode.offset = length;
+
+ if (size == 0) {
+ head = tail = current = newNode;
+ } else {
+ tail.next = newNode;
+ tail = newNode;
+ }
+
+ size++;
+ length += byteBuffer.limit();
+ limit = length;
+ pastTail = false;
+ }
+
+ /**
+ * Get the first BufferNode in the list. The current pointer will move forward, after having be reset to the
+ * beginning of the list
+ *
+ * @return The first BufferNode in the list
+ */
+ private BufferNode getFirst() {
+ if (head == null) {
+ return null;
+ }
+
+ current = head.next;
+ pastTail = false;
+
+ return head;
+ }
+
+ /**
+ * Get the next BufferNode from the list. If this is the first time this method is called, it will return the
+ * same value than a getFirst().
+ *
+ * @return The next BufferNode in the list, moving forward in the list at the same time
+ */
+ private BufferNode getNext() {
+ if (current == null) {
+ return null;
+ }
+
+ if (current == tail) {
+ if (pastTail) {
+ return null;
+ } else {
+ pastTail = true;
+
+ return current;
+ }
+ } else {
+ current = current.next;
+
+ return current;
+ }
+ }
+
+ /**
+ * Gets the current BufferNode from the list, if we aren't already past the tail.
+ *
+ * @return The current BufferNode
+ */
+ private BufferNode getCurrent() {
+ if (pastTail) {
+ return null;
+ }
+
+ return current;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ BufferNode node = head;
+
+ while (node != null) {
+ if (node == current) {
+ sb.append("**");
+ }
+
+ sb.append(node);
+ node = node.next;
+ }
+
+ return sb.toString();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina/blob/80967391/codec/src/test/java/org/apache/mina/codec/IoBufferTest.java
----------------------------------------------------------------------
diff --git a/codec/src/test/java/org/apache/mina/codec/IoBufferTest.java b/codec/src/test/java/org/apache/mina/codec/IoBufferTest.java
new file mode 100644
index 0000000..7349eb8
--- /dev/null
+++ b/codec/src/test/java/org/apache/mina/codec/IoBufferTest.java
@@ -0,0 +1,797 @@
+/**
+ * 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.codec;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+import org.apache.mina.codec.IoBuffer;
+import org.junit.Test;
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class IoBufferTest {
+ /**
+ * Test the addition of 3 heap buffers with data
+ */
+ @Test
+ public void testAddHeapBuffers() {
+ ByteBuffer bb1 = ByteBuffer.allocate(5);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(5);
+ bb2.put("345".getBytes());
+ bb2.flip();
+
+ ByteBuffer bb3 = ByteBuffer.allocate(5);
+ bb3.put("6789".getBytes());
+ bb3.flip();
+
+ IoBuffer ioBuffer = new IoBuffer();
+ ioBuffer.add(bb1, bb2).add(bb3);
+
+ assertEquals(0, ioBuffer.position());
+ assertEquals(10, ioBuffer.limit());
+ assertEquals(10, ioBuffer.capacity());
+ assertTrue(ioBuffer.hasRemaining());
+
+ for (int i = 0; i < 10; i++) {
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals("0123456789".charAt(i), ioBuffer.get());
+ }
+
+ try {
+ assertFalse(ioBuffer.hasRemaining());
+ ioBuffer.get();
+ fail();
+ } catch (BufferUnderflowException bufe) {
+ assertTrue(true);
+ }
+ }
+
+ /**
+ * Test the addition of 3 heap buffers, one being empty
+ */
+ @Test
+ public void testAddHeapBuffersOneEmpty() {
+ ByteBuffer bb1 = ByteBuffer.allocate(5);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(0);
+
+ ByteBuffer bb3 = ByteBuffer.allocate(5);
+ bb3.put("3456".getBytes());
+ bb3.flip();
+
+ IoBuffer ioBuffer = new IoBuffer();
+ ioBuffer.add(bb1, bb2).add(bb3);
+
+ assertEquals(0, ioBuffer.position());
+ assertEquals(7, ioBuffer.limit());
+ assertEquals(7, ioBuffer.capacity());
+
+ for (int i = 0; i < 7; i++) {
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals("0123456".charAt(i), ioBuffer.get());
+ }
+
+ try {
+ ioBuffer.get();
+ fail();
+ } catch (BufferUnderflowException bufe) {
+ assertTrue(true);
+ }
+ }
+
+ /**
+ * Test the addition of mixed type buffers
+ */
+ @Test(expected = RuntimeException.class)
+ public void testAddMixedTypeBuffers() {
+ ByteBuffer bb1 = ByteBuffer.allocate(5);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocateDirect(5);
+ bb2.put("3456".getBytes());
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer();
+ ioBuffer.add(bb1, bb2);
+ }
+
+ /**
+ * Test the addition of mixed order buffers
+ */
+ @Test(expected = RuntimeException.class)
+ public void testAddMixedOrderBuffers() {
+ ByteBuffer bb1 = ByteBuffer.allocate(5);
+ bb1.order(ByteOrder.LITTLE_ENDIAN);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocateDirect(5);
+ bb1.order(ByteOrder.BIG_ENDIAN);
+ bb2.put("3456".getBytes());
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer();
+ ioBuffer.add(bb1, bb2);
+ }
+
+ //-------------------------------------------------------------------------
+ // Test the allocate(int) method
+ // 1) allocation with a negative value
+ // 2) allocation with a 0 length
+ // 3) allocation with a 1024 value
+ //-------------------------------------------------------------------------
+ /**
+ * Test the allocation of a new heap IoBuffer with a negative value
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testAllocateNegative() {
+ IoBuffer.allocate(-1);
+ }
+
+ /**
+ * Test the allocation of a new heap IoBuffer with no byte in it
+ */
+ @Test
+ public void testAllocate0() {
+ IoBuffer ioBuffer = IoBuffer.allocate(0);
+
+ assertFalse(ioBuffer.isDirect());
+ assertEquals(0, ioBuffer.capacity());
+ assertEquals(0, ioBuffer.limit());
+ assertEquals(0, ioBuffer.position());
+ assertFalse(ioBuffer.hasRemaining());
+ }
+
+ /**
+ * Test the allocation of a new heap IoBuffer with 1024 bytes
+ */
+ @Test
+ public void testAllocate1024() {
+ IoBuffer ioBuffer = IoBuffer.allocate(1024);
+
+ assertFalse(ioBuffer.isDirect());
+ assertEquals(1024, ioBuffer.capacity());
+ assertEquals(1024, ioBuffer.limit());
+ assertEquals(0, ioBuffer.position());
+ assertTrue(ioBuffer.hasRemaining());
+ }
+
+ //-------------------------------------------------------------------------
+ // Test the allocateDirect(int) method. We check :
+ // 1) allocation with a negative value
+ // 2) allocation with a 0 length
+ // 3) allocation with a 1024 value
+ //-------------------------------------------------------------------------
+ /**
+ * Test the allocation of a new heap IoBuffer with a negative value
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testAllocateDirectNegative() {
+ IoBuffer.allocate(-1);
+ }
+
+ /**
+ * Test the allocation of a new direct IoBuffer with no byte in it
+ */
+ @Test
+ public void testAllocateDirect0() {
+ IoBuffer ioBuffer = IoBuffer.allocateDirect(0);
+
+ assertTrue(ioBuffer.isDirect());
+ assertEquals(0, ioBuffer.capacity());
+ assertEquals(0, ioBuffer.limit());
+ assertEquals(0, ioBuffer.position());
+ assertFalse(ioBuffer.hasRemaining());
+ }
+
+ /**
+ * Test the allocation of a new direct IoBuffer with 1024 bytes
+ */
+ @Test
+ public void testAllocateDirect1024() {
+ IoBuffer ioBuffer = IoBuffer.allocateDirect(1024);
+
+ assertTrue(ioBuffer.isDirect());
+ assertEquals(1024, ioBuffer.capacity());
+ assertEquals(1024, ioBuffer.limit());
+ assertEquals(0, ioBuffer.position());
+ assertTrue(ioBuffer.hasRemaining());
+ }
+
+ /**
+ * Test the get() method on a IoBuffer containing one ByteBuffer with 3 bytes
+ */
+ @Test
+ public void testGetOneBuffer3Bytes() {
+ ByteBuffer bb = ByteBuffer.allocate(5);
+ bb.put("012".getBytes());
+ bb.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb);
+ assertEquals(0, ioBuffer.position());
+ assertEquals(3, ioBuffer.limit());
+
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('0', ioBuffer.get());
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('1', ioBuffer.get());
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('2', ioBuffer.get());
+
+ try {
+ assertFalse(ioBuffer.hasRemaining());
+ ioBuffer.get();
+ fail();
+ } catch (BufferUnderflowException bufe) {
+ // expected
+ assertEquals(3, ioBuffer.position());
+ }
+ }
+
+ /**
+ * Test the get() method on a IoBuffer containing one ByteBuffer with 0 bytes
+ */
+ @Test
+ public void testGetOneBuffer0Bytes() {
+ ByteBuffer bb = ByteBuffer.allocate(0);
+
+ IoBuffer ioBuffer = new IoBuffer(bb);
+ assertEquals(0, ioBuffer.position());
+ assertEquals(0, ioBuffer.limit());
+
+ try {
+ assertFalse(ioBuffer.hasRemaining());
+ ioBuffer.get();
+ fail();
+ } catch (BufferUnderflowException bufe) {
+ // expected
+ assertEquals(0, ioBuffer.position());
+ }
+ }
+
+ /**
+ * Test the get() method on a IoBuffer containing two ByteBuffer with 3 bytes
+ */
+ @Test
+ public void testGetTwoBuffer3Bytes() {
+ ByteBuffer bb1 = ByteBuffer.allocate(5);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(5);
+ bb2.put("345".getBytes());
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ assertEquals(0, ioBuffer.position());
+ assertEquals(6, ioBuffer.limit());
+ assertTrue(ioBuffer.hasRemaining());
+
+ assertEquals('0', ioBuffer.get());
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('1', ioBuffer.get());
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('2', ioBuffer.get());
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('3', ioBuffer.get());
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('4', ioBuffer.get());
+ assertTrue(ioBuffer.hasRemaining());
+ assertEquals('5', ioBuffer.get());
+
+ try {
+ assertFalse(ioBuffer.hasRemaining());
+ ioBuffer.get();
+ fail();
+ } catch (BufferUnderflowException bufe) {
+ // expected
+ assertEquals(6, ioBuffer.position());
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // Test the array() method. We will check those cases :
+ // 1) array over an empty buffer: we should get an empty byte array
+ // 2) array over a buffer with one single empty ByteBuffer
+ // 3) array over a buffer with one single ByteBuffer with data
+ // 4) array over a buffer containing many ByteBuffers
+ //-------------------------------------------------------------------------
+ /**
+ * Test the array method for a IoBuffer containing one empty ByteBuffer
+ */
+ @Test
+ public void testArrayEmptyByteBuffer() {
+ IoBuffer ioBuffer = new IoBuffer();
+
+ byte[] array = ioBuffer.array();
+ assertNotNull(array);
+ assertEquals(0, array.length);
+ assertTrue(Arrays.equals(new byte[] {}, array));
+ }
+
+ /**
+ * Test the array method for a IoBuffer containing one ByteBuffer (cases 2 and 3)
+ */
+ @Test
+ public void testArrayOneByteBuffer() {
+ ByteBuffer bb1 = ByteBuffer.allocate(5);
+ IoBuffer ioBuffer = new IoBuffer(bb1);
+
+ // Empty buffer first
+ byte[] array = ioBuffer.array();
+ assertNotNull(array);
+ assertEquals(5, array.length);
+ assertTrue(Arrays.equals(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 }, array));
+
+ // Buffer with data
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ioBuffer = new IoBuffer(bb1);
+
+ array = ioBuffer.array();
+ assertNotNull(array);
+ assertEquals(3, array.length);
+ assertTrue(Arrays.equals(new byte[] { '0', '1', '2' }, array));
+ }
+
+ /**
+ * Test the array method for a IoBuffer containing one ByteBuffer not initialized
+ */
+ @Test
+ public void testArrayByteBufferNotInitialized() {
+ ByteBuffer bb = ByteBuffer.allocate(3);
+ IoBuffer ioBuffer = new IoBuffer(bb);
+
+ byte[] array = ioBuffer.array();
+ assertNotNull(array);
+ assertEquals(3, array.length);
+ assertTrue(Arrays.equals(new byte[] { 0x00, 0x00, 0x00 }, array));
+ }
+
+ /**
+ * Test the array method for a IoBuffer containing three ByteBuffers
+ */
+ @Test
+ public void testArrayThreeByteBuffers() {
+ ByteBuffer bb1 = ByteBuffer.allocate(5);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(0);
+
+ ByteBuffer bb3 = ByteBuffer.allocate(5);
+ bb3.put("3456".getBytes());
+ bb3.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
+
+ byte[] array = ioBuffer.array();
+ assertNotNull(array);
+ assertEquals(7, array.length);
+ assertTrue(Arrays.equals(new byte[] { '0', '1', '2', '3', '4', '5', '6' }, array));
+ }
+
+ /**
+ * Test the getInt() method, on a buffer containing 2 ints in one ByteBuffer
+ */
+ @Test
+ public void testGetInt2IntsOneBB() {
+ ByteBuffer bb = ByteBuffer.allocate(8);
+ bb.putInt(12345);
+ bb.putInt(67890);
+ bb.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb);
+ assertEquals(12345, ioBuffer.getInt());
+ assertEquals(67890, ioBuffer.getInt());
+ }
+
+ /**
+ * Test the getInt() method, on a buffer containing 2 ints in two ByteBuffers
+ */
+ @Test
+ public void testGetInt2Ints2BBs() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.putInt(12345);
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.putInt(67890);
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ assertEquals(12345, ioBuffer.getInt());
+ assertEquals(67890, ioBuffer.getInt());
+ }
+
+ /**
+ * Test the getInt() method, on a buffer containing 2 ints in two ByteBuffers
+ * with LittleInidan order
+ */
+ @Test
+ public void testGetInt2Ints2BBsLittleIndian() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.order(ByteOrder.LITTLE_ENDIAN);
+ bb1.putInt(12345);
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.order(ByteOrder.LITTLE_ENDIAN);
+ bb2.putInt(67890);
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ assertEquals(12345, ioBuffer.getInt());
+ assertEquals(67890, ioBuffer.getInt());
+ }
+
+ /**
+ * Test the getInt() method, on a buffer containing 1 int spread in two ByteBuffers
+ */
+ @Test
+ public void testGetInt1Int2BBs() {
+ ByteBuffer bb1 = ByteBuffer.allocate(1);
+ bb1.put((byte) 0x01);
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(3);
+ bb2.put(new byte[] { 0x02, 0x03, 0x04 });
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ assertEquals(0x01020304, ioBuffer.getInt());
+ }
+
+ /**
+ * Test the getInt() method, on a buffer containing 1 incomplet int spread in two ByteBuffers
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void testGetIntIncompletInt2BBs() {
+ ByteBuffer bb1 = ByteBuffer.allocate(1);
+ bb1.put((byte) 0x01);
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(2);
+ bb2.put(new byte[] { 0x02, 0x03 });
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ ioBuffer.getInt();
+ }
+
+ /**
+ * test the get(int) method on one buffer
+ */
+ @Test
+ public void testGetIntOneBuffer() {
+ ByteBuffer bb = ByteBuffer.allocate(4);
+ bb.put("0123".getBytes());
+ bb.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb);
+
+ assertEquals('0', ioBuffer.get());
+ assertEquals('1', ioBuffer.get());
+ assertEquals('0', ioBuffer.get(0));
+ assertEquals('3', ioBuffer.get(3));
+ assertEquals('1', ioBuffer.get(1));
+ assertEquals('2', ioBuffer.get(2));
+ assertEquals('2', ioBuffer.get());
+
+ try {
+ ioBuffer.get(4);
+ fail();
+ } catch (IndexOutOfBoundsException ioobe) {
+ // expected
+ assertTrue(true);
+ }
+ }
+
+ /**
+ * test the get(int) method on two buffers
+ */
+ @Test
+ public void testGetIntTwoBuffer() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.put("0123".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.put("4567".getBytes());
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ assertEquals('0', ioBuffer.get());
+ assertEquals('1', ioBuffer.get());
+ assertEquals('0', ioBuffer.get(0));
+ assertEquals('4', ioBuffer.get(4));
+ assertEquals('7', ioBuffer.get(7));
+ assertEquals('2', ioBuffer.get(2));
+ assertEquals('2', ioBuffer.get());
+ assertEquals('3', ioBuffer.get());
+ assertEquals('4', ioBuffer.get());
+
+ try {
+ ioBuffer.get(8);
+ fail();
+ } catch (IndexOutOfBoundsException ioobe) {
+ // expected
+ assertTrue(true);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // The the clear method. It will erase all the data in all the inner
+ // ByteBuffer, thus the buffer size might increase.
+ // We will check those case :
+ // 1) clear an empty buffer
+ // 2) clear a buffer with one ByteBuffer
+ // 3) clear a buffer with numerous ByteBuffers
+ //-------------------------------------------------------------------------
+ /**
+ * Test the clear() method
+ */
+ @Test
+ public void testClearEmptyBuffer() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.put("345".getBytes());
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ assertEquals(6, ioBuffer.limit());
+
+ // Move forward a bit
+ ioBuffer.get();
+ ioBuffer.get();
+
+ // Clear
+ ioBuffer.clear();
+
+ // We should be back to the origin
+ assertEquals(0, ioBuffer.position());
+
+ // The limit must have grown
+ assertEquals(8, ioBuffer.limit());
+ }
+
+ /**
+ * Test the flip() method
+ */
+ @Test
+ public void testFlip() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.put("0123".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.put("4567".getBytes());
+ bb2.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
+
+ // Move forward a bit
+ ioBuffer.get();
+ ioBuffer.get();
+
+ // Clear
+ ioBuffer.clear();
+
+ // We should be back to the origin
+ assertEquals(0, ioBuffer.position());
+ assertEquals(8, ioBuffer.limit());
+ }
+
+ //-------------------------------------------------------------------------
+ // Test the position() method
+ // We will test that the position() metho returns the correct result in
+ // those cases :
+ // 1) the buffer is empty : must return 0
+ // 2) must return a value between 0 and limit()
+ //-------------------------------------------------------------------------
+ /**
+ * Test the position method over an emptyIoBuffer
+ */
+ @Test
+ public void testPositionEmptyBuffer() {
+ IoBuffer ioBuffer = new IoBuffer();
+
+ assertEquals(0, ioBuffer.position());
+ }
+
+ /**
+ * Test the position method over a buffer
+ */
+ @Test
+ public void testPositionBuffer() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.put("3456".getBytes());
+ bb2.flip();
+
+ ByteBuffer bb3 = ByteBuffer.allocate(4);
+ bb3.put("789".getBytes());
+ bb3.flip();
+
+ // The resulting buffer will be seen as "0123456789"
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
+
+ // Iterate and check the position
+ for (int i = 0; i < ioBuffer.limit(); i++) {
+ assertEquals(i, ioBuffer.position());
+ ioBuffer.get();
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // Test the position(int) method
+ // We will test many different cases
+ // 1) a position() in an empty buffer
+ // 2) a position() with a negative value
+ // 3) a position() with a value above the limit
+ // 4) a position() within the current buffer
+ // 4-1) at the beginning of the current buffer
+ // 4-2) at the end of the current buffer
+ // 4-3) in the middle of the current buffer
+ // 5) a position() before the current buffer
+ // 6) a position() after the current buffer
+ //-------------------------------------------------------------------------
+ /**
+ * Test the position method over an emptyIoBuffer
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testPositionIntEmptyBuffer() {
+ IoBuffer ioBuffer = new IoBuffer();
+
+ ioBuffer.position(0);
+ }
+
+ /**
+ * Test the position method with a negative value
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testPositionNegativeValue() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.put("0123".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.put("4567".getBytes());
+ bb2.flip();
+
+ ByteBuffer bb3 = ByteBuffer.allocate(4);
+ bb3.put("89".getBytes());
+ bb3.flip();
+
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
+
+ ioBuffer.position(-1);
+ }
+
+ /**
+ * Test the position method with a value above the buffer size
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testPositionAboveValue() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.put("3456".getBytes());
+ bb2.flip();
+
+ ByteBuffer bb3 = ByteBuffer.allocate(4);
+ bb3.put("789".getBytes());
+ bb3.flip();
+
+ // The resulting buffer will be seen as "0123456789"
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
+
+ ioBuffer.position(10);
+ }
+
+ /**
+ * Test the position method in the current buffer
+ */
+ @Test
+ public void testPositionCurrentBuffer() {
+ ByteBuffer bb1 = ByteBuffer.allocate(4);
+ bb1.put("012".getBytes());
+ bb1.flip();
+
+ ByteBuffer bb2 = ByteBuffer.allocate(4);
+ bb2.put("3456".getBytes());
+ bb2.flip();
+
+ ByteBuffer bb3 = ByteBuffer.allocate(4);
+ bb3.put("789".getBytes());
+ bb3.flip();
+
+ // The resulting buffer will be seen as "0123456789"
+ IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
+
+ // Set the position in the middle of bb2 (4-3)
+ ioBuffer.position(5);
+
+ assertEquals('5', ioBuffer.get());
+
+ // Set the position at the beginning of bb2 (4-1)
+ ioBuffer.position(3);
+
+ assertEquals('3', ioBuffer.get());
+
+ // Set the position at the end of bb2 (4-2)
+ ioBuffer.position(6);
+
+ assertEquals('6', ioBuffer.get());
+
+ // Set a position before the current buffer (5)
+ ioBuffer.position(2);
+ assertEquals('2', ioBuffer.get());
+
+ // Set a position after the current buffer (6)
+ ioBuffer.position(7);
+ assertEquals('7', ioBuffer.get());
+
+ // Now, let's see if we can get all the elements correctly
+ // if we set the position from 0 to end
+ for (int i = 0; i < ioBuffer.limit(); i++) {
+ ioBuffer.position(i);
+ assertEquals('0' + i, ioBuffer.get());
+ }
+
+ // Same, in revert order
+ for (int i = ioBuffer.limit() - 1; i >= 0; i--) {
+ ioBuffer.position(i);
+ assertEquals('0' + i, ioBuffer.get());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina/blob/80967391/core/src/main/java/org/apache/mina/util/IoBuffer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mina/util/IoBuffer.java b/core/src/main/java/org/apache/mina/util/IoBuffer.java
deleted file mode 100644
index aac97b6..0000000
--- a/core/src/main/java/org/apache/mina/util/IoBuffer.java
+++ /dev/null
@@ -1,1008 +0,0 @@
-/**
- * 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;
-
-import java.nio.Buffer;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.InvalidMarkException;
-import java.nio.ReadOnlyBufferException;
-
-/**
- * A proxy class used to manage ByteBuffers as if they were just a big ByteBuffer. We can
- * add as many buffers as needed, when accumulating data. From the user PoV, the methods
- * are the very same than what we can get from ByteBuffer.
- * <br/>
- * IoBuffer instances are *not* thred safe.
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public class IoBuffer {
- /** The list of ByteBuffers were we store the data */
- private BufferList buffers = new BufferList();
-
- /** The maximal position in the IoBuffer */
- private int limit;
-
- /** The current position in the buffer */
- private int position;
-
- /** The marked position, for the next reset() */
- private int mark;
-
- /** Tells if the stored buffers are direct or heap */
- private BufferType type;
-
- /** Tells if the IoBuffer is readonly */
- private boolean readOnly;
-
- /** The bytes order (BIG_INDIAN or LITTLE_INDIAN) */
- private ByteOrder order = ByteOrder.BIG_ENDIAN;
-
- /** The two types of buffer we handle */
- public enum BufferType {
- HEAP, DIRECT;
- }
-
- /** A empty bytes array */
- private final static byte[] EMPTY_BYTES = new byte[] {};
-
- /** <code>UNSET_MARK</code> means the mark has not been set. */
- private final static int UNSET_MARK = -1;
-
- /**
- * Construct a IoBuffer, with no buffer in it
- */
- public IoBuffer() {
- position = 0;
- mark = 0;
- limit = 0;
- type = null;
- order = null;
- }
-
- /**
- * Construct an empty IoBuffer with a defined type (either HEAP or DIRECT)
- *
- * @param bufferType the type of buffer to use : BufferType.HEAP or BufferType.DIRECT
- */
- public IoBuffer(BufferType bufferType) {
- position = 0;
- mark = 0;
- limit = 0;
- type = bufferType;
- }
-
- /**
- * Construct a IoBuffer with some ByteBuffers. The IoBuffer type will be selected
- * from the first ByteBuffer type, so will the order.
- * @param byteBuffers the ByteBuffers added to the IoBuffer list
- */
- public IoBuffer(ByteBuffer... byteBuffers) {
- if ((byteBuffers == null) || (byteBuffers.length == 0)) {
- position = 0;
- mark = 0;
- limit = 0;
- type = null;
- order = null;
- } else {
- for (ByteBuffer byteBuffer : byteBuffers) {
- if (type == null) {
- type = byteBuffer.isDirect() ? BufferType.DIRECT : BufferType.HEAP;
- }
-
- if (byteBuffer.limit() > 0) {
- buffers.add(byteBuffer);
- }
- }
- }
- }
-
- /**
- * Construct a IoBuffer from an existing IoBuffer.
- * @param ioBuffer the IoBuffer we want to copy
- */
- public IoBuffer(IoBuffer ioBuffer) {
- // Find the position to start with
- BufferNode node = ioBuffer.buffers.getFirst();
- int pos = 0;
-
- while (node != null) {
- if (node.offset + node.buffer.limit() < position) {
- node = buffers.getNext();
- pos = node.offset + node.buffer.limit();
- } else {
- buffers.add(node.buffer);
- }
- }
-
- position = position - pos;
- mark = 0;
- limit = ioBuffer.limit() - pos;
- type = ioBuffer.type;
- order = ioBuffer.order();
- }
-
- /**
- * Adds a new ByteBuffer at the end of the list of buffers.
- *
- * @param byteBuffer The added ByteBuffer
- * @return The modified IoBuffer
- */
- public IoBuffer add(ByteBuffer... byteBuffers) {
- for (ByteBuffer byteBuffer : byteBuffers) {
- if (byteBuffer.limit() > 0) {
- buffers.add(byteBuffer);
- }
- }
-
- return this;
- }
-
- /**
- * Allocate a Heap IoBuffer with a defined capacity
- * @param capacity The number of bytes to store
- * @return The allocated IoBuffer
- */
- public static IoBuffer allocate(int capacity) {
- if (capacity >= 0) {
- ByteBuffer byteBuffer = ByteBuffer.allocate(capacity);
-
- return new IoBuffer(byteBuffer);
- } else {
- throw new IllegalArgumentException("Cannot allocate an IoBuffer with a negative value : " + capacity);
- }
- }
-
- /**
- * Allocate a Direct IoBuffer with a defined capacity
- * @param capacity The number of bytes to store
- * @return The allocated IoBuffer
- */
- public static IoBuffer allocateDirect(int capacity) {
- if (capacity >= 0) {
- ByteBuffer byteBuffer = ByteBuffer.allocateDirect(capacity);
-
- return new IoBuffer(byteBuffer);
- } else {
- throw new IllegalArgumentException("Cannot allocate an IoBuffer with a negative value : " + capacity);
- }
- }
-
- /**
- * @see ByteBuffer#array()
- * Returns the byte array which this IoBuffer is based on, up to the sum of each
- * contained ByteBuffer's limit().<br/>
- * This array can be modified, but this won't modify the content of the underlying
- * ByteBuffer instances, contrary to the ByteBuffer.array() method.
- *
- * @return the byte array which this IoBuffer is based on.
- * @exception ReadOnlyBufferException if this IoBuffer is based on a read-only array.
- * @exception UnsupportedOperationException if this IoBuffer is not based on an array.
- */
- public byte[] array() {
- if (isReadOnly()) {
- throw new ReadOnlyBufferException();
- }
-
- if (buffers.size == 0) {
- return EMPTY_BYTES;
- }
-
- byte[] array = new byte[buffers.length];
- BufferNode node = buffers.getFirst();
- int pos = 0;
-
- while (node != null) {
- ByteBuffer buffer = node.buffer;
- byte[] src = buffer.array();
- int length = buffer.limit();
-
- System.arraycopy(src, 0, array, pos, length);
- pos += length;
-
- node = buffers.getNext();
- }
-
- return array;
- }
-
- /**
- * @see ByteBuffer#arrayOffset()
- * Returns the offset of the byte array which this IoBuffer is based on, if
- * there is one.
- * <p>
- * The offset is the index of the array which corresponds to the zero
- * position of the IoBuffer.
- *
- * @return the offset of the byte array which this IoBuffer is based on.
- * @exception ReadOnlyBufferException if this IoBuffer is based on a read-only array.
- * @exception UnsupportedOperationException if this IoBuffer is not based on an array.
- */
- public int arrayOffset() {
- if (isReadOnly()) {
- throw new ReadOnlyBufferException();
- }
-
- // The offset is always 0
- return 0;
- }
-
- /**
- * @see ByteBuffer#asReadOnlyBuffer()
- */
- public IoBuffer asReadOnlyBuffer() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @return the IoBuffer total capacity
- */
- public int capacity() {
- return limit;
- }
-
- /**
- * @see Buffer#clear()
- * Clears this IoBuffer.
- * <p>
- * the following internal changes take place:
- * <ul>
- * <li>the current position is reset back to the start of the buffer</li>
- * <li>the value of the buffer limit is made equal to the capacity</li>
- * <li>and mark is cleared</li>
- * </ul>
- * Note that the resulting IoBuffer might be wider than the original one, simply
- * because we will extent the ByteBuffers limit to their capacity.
- *
- * @return this buffer.
- */
- public IoBuffer clear() {
- position = 0;
- mark = UNSET_MARK;
-
- BufferNode node = buffers.head;
- int offset = 0;
-
- while (node != null) {
- node.buffer.clear();
- node.offset = offset;
- offset += node.buffer.limit();
- node = node.next;
- }
-
- limit = offset;
- buffers.length = 0;
- buffers.current = buffers.head;
-
- return this;
- }
-
- /**
- * @see ByteBuffer#compact()
- */
- public IoBuffer compact() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#compareTo(ByteBuffer)
- */
- public int compareTo(IoBuffer buffer) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#duplicate()
- */
- public IoBuffer duplicate() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#equals(Object)
- */
- public boolean equals(Object object) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see Buffer#flip()
- * Flips this buffer.
- * <p>
- * The limit is set to the current position, then the position is set to
- * zero, and the mark is cleared.
- * <p>
- * The content of this IoBuffer is not changed.
- *
- * @return this IoBuffer.
- */
- public IoBuffer flip() {
- limit = position;
- position = 0;
- mark = UNSET_MARK;
-
- return this;
- }
-
- /**
- * Get a single byte for the IoBuffer at the current position. Increment the current position.
- * @return The byte found a the current position.
- */
- public byte get() {
- if (position >= limit) {
- // No more byte to read
- throw new BufferUnderflowException();
- }
-
- // find the byte from the current buffer now
- BufferNode currentNode = buffers.getCurrent();
-
- // If the position is within the current buffer, then get the data from it
- int bufferPosition = position - currentNode.offset;
-
- if (bufferPosition < currentNode.buffer.limit()) {
- position++;
-
- return currentNode.buffer.get();
- } else {
- // We have exhausted the current buffer, let's see if we have one more
- currentNode = buffers.getNext();
-
- if (currentNode == null) {
- // No more buffers
- throw new BufferUnderflowException();
- } else {
- position++;
- currentNode.buffer.position(0);
-
- return currentNode.buffer.get();
- }
- }
- }
-
- /**
- * @see ByteBuffer#get(byte[])
- * Reads bytes from the current position into the specified byte array and
- * increases the position by the number of bytes read.
- * <p>
- * Calling this method has the same effect as
- * {@code get(dest, 0, dest.length)}.
- *
- * @param dest the destination byte array.
- * @return this IoBuffer.
- * @exception BufferUnderflowException if {@code dest.length} is greater than {@code remaining()}.
- */
- public IoBuffer get(byte[] dst) {
- if (dst.length > remaining()) {
- throw new BufferUnderflowException();
- }
-
- int size = dst.length;
- int destPos = 0;
- BufferNode node = buffers.current;
-
- while (size > 0) {
- int length = node.buffer.limit() - node.buffer.position();
- System.arraycopy(node.buffer.array(), node.buffer.position(), dst, destPos, length);
- destPos += length;
- node = buffers.getNext();
- }
-
- return this;
- }
-
- /**
- * @see ByteBuffer#get(byte[],int,int)
- */
- public IoBuffer get(byte[] dst, int offset, int length) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#get(int)
- * Returns the byte at the specified index and does not change the position.
- *
- * @param index the index, must not be negative and less than limit.
- * @return the byte at the specified index.
- * @exception IndexOutOfBoundsException if index is invalid.
- */
- public byte get(int index) {
- if ((index < 0) || (index >= limit)) {
- throw new IndexOutOfBoundsException();
- }
-
- BufferNode currentNode = buffers.current;
- BufferNode node = buffers.getFirst();
-
- while (node != null) {
- if (node.offset + node.buffer.limit() > index) {
- byte result = node.buffer.get(index - node.offset);
-
- // Reset the initial position before returning
- buffers.current = currentNode;
-
- return result;
- } else {
- node = buffers.getNext();
- }
- }
-
- // Reset the initial position before returning
- buffers.current = currentNode;
-
- // Unlikely to happen
- throw new IndexOutOfBoundsException();
- }
-
- /**
- * @see ByteBuffer#getChar()
- */
- public IoBuffer getChar() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getChar(int)
- */
- public IoBuffer getChar(int index) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getDouble()
- */
- public IoBuffer getDouble() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getDouble(int)
- */
- public IoBuffer getDouble(int index) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getFloat()
- */
- public IoBuffer getFloat() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getFloat(int)
- */
- public IoBuffer getFloat(int index) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getInt()
- * Returns the int at the current position and increases the position by 4.
- * <p>
- * The 4 bytes starting at the current position are composed into a int
- * according to the current byte order and returned.
- *
- * @return the int at the current position.
- * @exception BufferUnderflowException if the position is greater than {@code limit - 4}.
- */
- public int getInt() {
- int newPosition = position + 4;
-
- if (newPosition > limit) {
- throw new BufferUnderflowException();
- }
-
- int result = loadInt(position);
- position = newPosition;
-
- return result;
- }
-
- /**
- * Load an int from the underlying byteBuffers, taking the order into account.
- */
- private final int loadInt(int index) {
- int bytes = 0;
-
- if (order == ByteOrder.BIG_ENDIAN) {
- for (int i = 0; i < 4; i++) {
- bytes = bytes << 8;
- bytes = bytes | (get() & 0xFF);
- }
- } else {
- for (int i = 0; i < 4; i++) {
- int val = get() & 0xFF;
- bytes = bytes | (val << (i << 3));
- }
- }
-
- return bytes;
- }
-
- /**
- * @see ByteBuffer#getInt(int)
- */
- public IoBuffer getInt(int index) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getLong()
- */
- public IoBuffer getLong() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getLong(int)
- */
- public IoBuffer getLong(int index) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getShort()
- */
- public IoBuffer getShort() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#getShort(int)
- */
- public IoBuffer getShort(int index) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#hashCode()
- */
- public int hashCode() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see Buffer#hasRemaining()
- * Indicates if there are elements remaining in this IoBuffer, that is if
- * {@code position < limit}.
- *
- * @return {@code true} if there are elements remaining in this IoBuffer,
- * {@code false} otherwise.
- */
- public boolean hasRemaining() {
- return position < limit;
- }
-
- /**
- * @see ByteBuffer#isDirect()
- * Tells if the stored ByteBuffers are Direct buffers or Heap Buffers
- * @return <code>true</code> if we are storing Direct buffers, <code>false</code> otherwise.
- */
- public boolean isDirect() {
- return type == BufferType.DIRECT;
- }
-
- /**
- * @see Buffer#isReadOnly()
- * Indicates whether this IoBuffer is read-only.
- *
- * @return {@code true} if this IoBuffer is read-only, {@code false}
- * otherwise.
- */
- public boolean isReadOnly() {
- return readOnly;
- }
-
- /**
- * @return the IoBuffer limit
- */
- public int limit() {
- return limit;
- }
-
- /**
- * @see Buffer#mark()
- * Marks the current position, so that the position may return to this point
- * later by calling <code>reset()</code>.
- *
- * @return this IoBuffer.
- */
- public IoBuffer mark() {
- mark = position;
-
- return this;
- }
-
- /**
- * @see ByteBuffer#order()
- * Returns the byte order used by this Iouffer when converting bytes from/to
- * other primitive types.
- * <p>
- * The default byte order of byte buffer is always
- * {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN}
- *
- * @return the byte order used by this IoBuffer when converting bytes from/to
- * other primitive types.
-
- */
- public ByteOrder order() {
- return order;
- }
-
- /**
- * @see ByteBuffer#order(ByteOrder)
- * Sets the byte order of this IoBuffer.
- *
- * @param byteOrder the byte order to set. If {@code null} then the order
- * will be {@link ByteOrder#LITTLE_ENDIAN LITTLE_ENDIAN}.
- * @return this IoBuffer.
- * @see ByteOrder
- */
- public IoBuffer order(ByteOrder bo) {
- if (bo == null) {
- order = ByteOrder.LITTLE_ENDIAN;
- } else {
- order = bo;
- }
-
- return this;
- }
-
- /**
- * @see Buffer#position()
- * @return The current position across all the ByteBuffers contained in the IoBuffer
- */
- public int position() {
- return position;
- }
-
- /**
- * @see Buffer#position(int)
- * Sets the position in the IoBuffer.
- * <p>
- * If the mark is set and it is greater than the new position, then it is
- * cleared.
- *
- * @param newPosition the new position, must be not negative and not greater than
- * limit.
- * @return this IoBuffer.
- * @exception IllegalArgumentException if <code>newPosition</code> is invalid.
- */
- public IoBuffer position(int newPosition) {
- if (newPosition < 0) {
- throw new IllegalArgumentException("The new position(" + newPosition + ") is negative");
- }
-
- if (newPosition >= limit) {
- throw new IllegalArgumentException("The new position(" + newPosition
- + ") is larger than this buffer limit (" + limit());
- }
-
- if (buffers.head == null) {
- throw new IllegalArgumentException("Cannot set a position over an empty buffer");
- }
-
- // Find the right current buffer
- BufferNode currentNode = buffers.getCurrent();
-
- // The new position might not be on the current buffer.
- if ((newPosition < currentNode.offset) || (newPosition >= currentNode.offset + currentNode.buffer.limit())) {
- // Ok, we aren't on the current buffer. Find the new current buffer
- BufferNode node = buffers.head;
- int counter = 0;
-
- while (node != null) {
- int limit = node.buffer.limit();
- counter += limit;
-
- if (counter >= newPosition) {
- // Found
- currentNode = node;
- break;
- } else {
- node = node.next;
- }
- }
- }
-
- position = newPosition;
- currentNode.buffer.position(position - currentNode.offset);
- buffers.current = currentNode;
-
- return this;
- }
-
- /**
- * @see Buffer#remaining()
- * Returns the number of remaining elements in this IoBuffer, that is
- * {@code limit - position}.
- *
- * @return the number of remaining elements in this IoBuffer.
- */
- public int remaining() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see Buffer#reset()
- * Resets the position of this IoBuffer to the <code>mark</code>.
- *
- * @return this IoBuffer.
- * @exception InvalidMarkException if the mark is not set.
- */
- public IoBuffer reset() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see Buffer#rewind()
- * Rewinds this IoBuffer.
- * <p>
- * The position is set to zero, and the mark is cleared. The content of this
- * IoBuffer is not changed.
- *
- * @return this IoBuffer.
- */
- public IoBuffer rewind() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#slice()
- */
- public IoBuffer slice() {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#wrap(byte[])
- */
- public IoBuffer wrap(byte[] array) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * @see ByteBuffer#wrap(byte[], int, int)
- */
- public IoBuffer wrap(byte[] array, int offset, int length) {
- // TODO code me !
- throw new UnsupportedOperationException();
- }
-
- /**
- * Returns a string representing the IoBuffer.
- * @return a String representation of the IoBuffer
- */
- public String toString() {
- return "IoBuffer[pos=" + position + " lim=" + limit + " mrk=" + mark + "]";
- }
-
- //------------------------------------------------------------------------------------------------
- // private inner data structure
- //------------------------------------------------------------------------------------------------
- /**
- * A container for ByterBuffers stored in the buffers list
- */
- private class BufferNode {
- /** The stored buffer */
- private ByteBuffer buffer;
-
- /** The next buffer in the list */
- private BufferNode next;
-
- /** The position of this buffer in the IoBuffer list of bytes */
- private int offset;
-
- /**
- * Creates a new entry in the list
- * @param entry The added ByteBuffer
- */
- private BufferNode(ByteBuffer byteBuffer) {
- this.buffer = byteBuffer;
- }
-
- public String toString() {
- return buffer.toString() + ", Offset:" + offset + (next != null ? " --> \n " : "");
- }
- }
-
- /**
- * A LinkedList storing all the ByteBuffers. It can only be browsed forward.
- */
- private class BufferList {
- /** The first ByteBuffer in the list */
- private BufferNode head;
-
- /** The last ByteBuffer in the list */
- private BufferNode tail;
-
- /** The current ByteBuffer in the list */
- private BufferNode current;
-
- /** The number of nodes in the list */
- private int size;
-
- /** The number of bytes in the list */
- private int length;
-
- /** A flag used to indicate that we already have navigated past the tail of the list. */
- private boolean pastTail;
-
- /**
- * Creates an empty list
- */
- private BufferList() {
- head = tail = current = null;
- size = 0;
- length = 0;
- pastTail = false;
- }
-
- /**
- * Creates a list with one ByteBuffer
- * @param byteBuffer The added ByteBuffer
- */
- private BufferList(ByteBuffer byteBuffer) {
- BufferNode node = new BufferNode(byteBuffer);
- head = tail = current = node;
- size = 1;
- length = byteBuffer.limit();
- pastTail = false;
- }
-
- /**
- * Adds a new ByteBuffer in the list
- * @param byteBuffer The added ByteBuffer
- */
- private void add(ByteBuffer byteBuffer) {
- assert (byteBuffer != null);
-
- // Check the buffer type
- if (type == null) {
- if (byteBuffer.isDirect()) {
- type = BufferType.DIRECT;
- } else {
- type = BufferType.HEAP;
- }
- } else {
- if (isDirect() != byteBuffer.isDirect()) {
- throw new RuntimeException();
- }
- }
-
- // Check the ByteOrder
- if (size == 0) {
- order = byteBuffer.order();
- } else if (order != byteBuffer.order()) {
- throw new RuntimeException();
- }
-
- BufferNode newNode = new BufferNode(byteBuffer);
- newNode.offset = length;
-
- if (size == 0) {
- head = tail = current = newNode;
- } else {
- tail.next = newNode;
- tail = newNode;
- }
-
- size++;
- length += byteBuffer.limit();
- limit = length;
- pastTail = false;
- }
-
- /**
- * Get the first BufferNode in the list. The current pointer will move
- * forward, after having be reset to the beginning of the list
- * @return The first BufferNode in the list
- */
- private BufferNode getFirst() {
- if (head == null) {
- return null;
- }
-
- current = head.next;
- pastTail = false;
-
- return head;
- }
-
- /**
- * Get the next BufferNode from the list. If this is the first time this method
- * is called, it will return the same value than a getFirst().
- * @return The next BufferNode in the list, moving forward in the list at the same time
- */
- private BufferNode getNext() {
- if (current == null) {
- return null;
- }
-
- if (current == tail) {
- if (pastTail) {
- return null;
- } else {
- pastTail = true;
-
- return current;
- }
- } else {
- current = current.next;
-
- return current;
- }
- }
-
- /**
- * Gets the current BufferNode from the list, if we aren't already past the tail.
- * @return The current BufferNode
- */
- private BufferNode getCurrent() {
- if (pastTail) {
- return null;
- }
-
- return current;
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- BufferNode node = head;
-
- while (node != null) {
- if (node == current) {
- sb.append("**");
- }
-
- sb.append(node);
- node = node.next;
- }
-
- return sb.toString();
- }
- }
-}
[2/4] moved IoBuffer to codec project because it's usefull only for
decoder implementation
Posted by jv...@apache.org.
http://git-wip-us.apache.org/repos/asf/mina/blob/80967391/core/src/test/java/org/apache/mina/util/IoBufferTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/mina/util/IoBufferTest.java b/core/src/test/java/org/apache/mina/util/IoBufferTest.java
deleted file mode 100644
index b9dada6..0000000
--- a/core/src/test/java/org/apache/mina/util/IoBufferTest.java
+++ /dev/null
@@ -1,796 +0,0 @@
-/**
- * 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;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-
-import org.junit.Test;
-
-/**
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public class IoBufferTest {
- /**
- * Test the addition of 3 heap buffers with data
- */
- @Test
- public void testAddHeapBuffers() {
- ByteBuffer bb1 = ByteBuffer.allocate(5);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(5);
- bb2.put("345".getBytes());
- bb2.flip();
-
- ByteBuffer bb3 = ByteBuffer.allocate(5);
- bb3.put("6789".getBytes());
- bb3.flip();
-
- IoBuffer ioBuffer = new IoBuffer();
- ioBuffer.add(bb1, bb2).add(bb3);
-
- assertEquals(0, ioBuffer.position());
- assertEquals(10, ioBuffer.limit());
- assertEquals(10, ioBuffer.capacity());
- assertTrue(ioBuffer.hasRemaining());
-
- for (int i = 0; i < 10; i++) {
- assertTrue(ioBuffer.hasRemaining());
- assertEquals("0123456789".charAt(i), ioBuffer.get());
- }
-
- try {
- assertFalse(ioBuffer.hasRemaining());
- ioBuffer.get();
- fail();
- } catch (BufferUnderflowException bufe) {
- assertTrue(true);
- }
- }
-
- /**
- * Test the addition of 3 heap buffers, one being empty
- */
- @Test
- public void testAddHeapBuffersOneEmpty() {
- ByteBuffer bb1 = ByteBuffer.allocate(5);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(0);
-
- ByteBuffer bb3 = ByteBuffer.allocate(5);
- bb3.put("3456".getBytes());
- bb3.flip();
-
- IoBuffer ioBuffer = new IoBuffer();
- ioBuffer.add(bb1, bb2).add(bb3);
-
- assertEquals(0, ioBuffer.position());
- assertEquals(7, ioBuffer.limit());
- assertEquals(7, ioBuffer.capacity());
-
- for (int i = 0; i < 7; i++) {
- assertTrue(ioBuffer.hasRemaining());
- assertEquals("0123456".charAt(i), ioBuffer.get());
- }
-
- try {
- ioBuffer.get();
- fail();
- } catch (BufferUnderflowException bufe) {
- assertTrue(true);
- }
- }
-
- /**
- * Test the addition of mixed type buffers
- */
- @Test(expected = RuntimeException.class)
- public void testAddMixedTypeBuffers() {
- ByteBuffer bb1 = ByteBuffer.allocate(5);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocateDirect(5);
- bb2.put("3456".getBytes());
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer();
- ioBuffer.add(bb1, bb2);
- }
-
- /**
- * Test the addition of mixed order buffers
- */
- @Test(expected = RuntimeException.class)
- public void testAddMixedOrderBuffers() {
- ByteBuffer bb1 = ByteBuffer.allocate(5);
- bb1.order(ByteOrder.LITTLE_ENDIAN);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocateDirect(5);
- bb1.order(ByteOrder.BIG_ENDIAN);
- bb2.put("3456".getBytes());
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer();
- ioBuffer.add(bb1, bb2);
- }
-
- //-------------------------------------------------------------------------
- // Test the allocate(int) method
- // 1) allocation with a negative value
- // 2) allocation with a 0 length
- // 3) allocation with a 1024 value
- //-------------------------------------------------------------------------
- /**
- * Test the allocation of a new heap IoBuffer with a negative value
- */
- @Test(expected = IllegalArgumentException.class)
- public void testAllocateNegative() {
- IoBuffer.allocate(-1);
- }
-
- /**
- * Test the allocation of a new heap IoBuffer with no byte in it
- */
- @Test
- public void testAllocate0() {
- IoBuffer ioBuffer = IoBuffer.allocate(0);
-
- assertFalse(ioBuffer.isDirect());
- assertEquals(0, ioBuffer.capacity());
- assertEquals(0, ioBuffer.limit());
- assertEquals(0, ioBuffer.position());
- assertFalse(ioBuffer.hasRemaining());
- }
-
- /**
- * Test the allocation of a new heap IoBuffer with 1024 bytes
- */
- @Test
- public void testAllocate1024() {
- IoBuffer ioBuffer = IoBuffer.allocate(1024);
-
- assertFalse(ioBuffer.isDirect());
- assertEquals(1024, ioBuffer.capacity());
- assertEquals(1024, ioBuffer.limit());
- assertEquals(0, ioBuffer.position());
- assertTrue(ioBuffer.hasRemaining());
- }
-
- //-------------------------------------------------------------------------
- // Test the allocateDirect(int) method. We check :
- // 1) allocation with a negative value
- // 2) allocation with a 0 length
- // 3) allocation with a 1024 value
- //-------------------------------------------------------------------------
- /**
- * Test the allocation of a new heap IoBuffer with a negative value
- */
- @Test(expected = IllegalArgumentException.class)
- public void testAllocateDirectNegative() {
- IoBuffer.allocate(-1);
- }
-
- /**
- * Test the allocation of a new direct IoBuffer with no byte in it
- */
- @Test
- public void testAllocateDirect0() {
- IoBuffer ioBuffer = IoBuffer.allocateDirect(0);
-
- assertTrue(ioBuffer.isDirect());
- assertEquals(0, ioBuffer.capacity());
- assertEquals(0, ioBuffer.limit());
- assertEquals(0, ioBuffer.position());
- assertFalse(ioBuffer.hasRemaining());
- }
-
- /**
- * Test the allocation of a new direct IoBuffer with 1024 bytes
- */
- @Test
- public void testAllocateDirect1024() {
- IoBuffer ioBuffer = IoBuffer.allocateDirect(1024);
-
- assertTrue(ioBuffer.isDirect());
- assertEquals(1024, ioBuffer.capacity());
- assertEquals(1024, ioBuffer.limit());
- assertEquals(0, ioBuffer.position());
- assertTrue(ioBuffer.hasRemaining());
- }
-
- /**
- * Test the get() method on a IoBuffer containing one ByteBuffer with 3 bytes
- */
- @Test
- public void testGetOneBuffer3Bytes() {
- ByteBuffer bb = ByteBuffer.allocate(5);
- bb.put("012".getBytes());
- bb.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb);
- assertEquals(0, ioBuffer.position());
- assertEquals(3, ioBuffer.limit());
-
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('0', ioBuffer.get());
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('1', ioBuffer.get());
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('2', ioBuffer.get());
-
- try {
- assertFalse(ioBuffer.hasRemaining());
- ioBuffer.get();
- fail();
- } catch (BufferUnderflowException bufe) {
- // expected
- assertEquals(3, ioBuffer.position());
- }
- }
-
- /**
- * Test the get() method on a IoBuffer containing one ByteBuffer with 0 bytes
- */
- @Test
- public void testGetOneBuffer0Bytes() {
- ByteBuffer bb = ByteBuffer.allocate(0);
-
- IoBuffer ioBuffer = new IoBuffer(bb);
- assertEquals(0, ioBuffer.position());
- assertEquals(0, ioBuffer.limit());
-
- try {
- assertFalse(ioBuffer.hasRemaining());
- ioBuffer.get();
- fail();
- } catch (BufferUnderflowException bufe) {
- // expected
- assertEquals(0, ioBuffer.position());
- }
- }
-
- /**
- * Test the get() method on a IoBuffer containing two ByteBuffer with 3 bytes
- */
- @Test
- public void testGetTwoBuffer3Bytes() {
- ByteBuffer bb1 = ByteBuffer.allocate(5);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(5);
- bb2.put("345".getBytes());
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- assertEquals(0, ioBuffer.position());
- assertEquals(6, ioBuffer.limit());
- assertTrue(ioBuffer.hasRemaining());
-
- assertEquals('0', ioBuffer.get());
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('1', ioBuffer.get());
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('2', ioBuffer.get());
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('3', ioBuffer.get());
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('4', ioBuffer.get());
- assertTrue(ioBuffer.hasRemaining());
- assertEquals('5', ioBuffer.get());
-
- try {
- assertFalse(ioBuffer.hasRemaining());
- ioBuffer.get();
- fail();
- } catch (BufferUnderflowException bufe) {
- // expected
- assertEquals(6, ioBuffer.position());
- }
- }
-
- //-------------------------------------------------------------------------
- // Test the array() method. We will check those cases :
- // 1) array over an empty buffer: we should get an empty byte array
- // 2) array over a buffer with one single empty ByteBuffer
- // 3) array over a buffer with one single ByteBuffer with data
- // 4) array over a buffer containing many ByteBuffers
- //-------------------------------------------------------------------------
- /**
- * Test the array method for a IoBuffer containing one empty ByteBuffer
- */
- @Test
- public void testArrayEmptyByteBuffer() {
- IoBuffer ioBuffer = new IoBuffer();
-
- byte[] array = ioBuffer.array();
- assertNotNull(array);
- assertEquals(0, array.length);
- assertTrue(Arrays.equals(new byte[] {}, array));
- }
-
- /**
- * Test the array method for a IoBuffer containing one ByteBuffer (cases 2 and 3)
- */
- @Test
- public void testArrayOneByteBuffer() {
- ByteBuffer bb1 = ByteBuffer.allocate(5);
- IoBuffer ioBuffer = new IoBuffer(bb1);
-
- // Empty buffer first
- byte[] array = ioBuffer.array();
- assertNotNull(array);
- assertEquals(5, array.length);
- assertTrue(Arrays.equals(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 }, array));
-
- // Buffer with data
- bb1.put("012".getBytes());
- bb1.flip();
-
- ioBuffer = new IoBuffer(bb1);
-
- array = ioBuffer.array();
- assertNotNull(array);
- assertEquals(3, array.length);
- assertTrue(Arrays.equals(new byte[] { '0', '1', '2' }, array));
- }
-
- /**
- * Test the array method for a IoBuffer containing one ByteBuffer not initialized
- */
- @Test
- public void testArrayByteBufferNotInitialized() {
- ByteBuffer bb = ByteBuffer.allocate(3);
- IoBuffer ioBuffer = new IoBuffer(bb);
-
- byte[] array = ioBuffer.array();
- assertNotNull(array);
- assertEquals(3, array.length);
- assertTrue(Arrays.equals(new byte[] { 0x00, 0x00, 0x00 }, array));
- }
-
- /**
- * Test the array method for a IoBuffer containing three ByteBuffers
- */
- @Test
- public void testArrayThreeByteBuffers() {
- ByteBuffer bb1 = ByteBuffer.allocate(5);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(0);
-
- ByteBuffer bb3 = ByteBuffer.allocate(5);
- bb3.put("3456".getBytes());
- bb3.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
-
- byte[] array = ioBuffer.array();
- assertNotNull(array);
- assertEquals(7, array.length);
- assertTrue(Arrays.equals(new byte[] { '0', '1', '2', '3', '4', '5', '6' }, array));
- }
-
- /**
- * Test the getInt() method, on a buffer containing 2 ints in one ByteBuffer
- */
- @Test
- public void testGetInt2IntsOneBB() {
- ByteBuffer bb = ByteBuffer.allocate(8);
- bb.putInt(12345);
- bb.putInt(67890);
- bb.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb);
- assertEquals(12345, ioBuffer.getInt());
- assertEquals(67890, ioBuffer.getInt());
- }
-
- /**
- * Test the getInt() method, on a buffer containing 2 ints in two ByteBuffers
- */
- @Test
- public void testGetInt2Ints2BBs() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.putInt(12345);
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.putInt(67890);
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- assertEquals(12345, ioBuffer.getInt());
- assertEquals(67890, ioBuffer.getInt());
- }
-
- /**
- * Test the getInt() method, on a buffer containing 2 ints in two ByteBuffers
- * with LittleInidan order
- */
- @Test
- public void testGetInt2Ints2BBsLittleIndian() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.order(ByteOrder.LITTLE_ENDIAN);
- bb1.putInt(12345);
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.order(ByteOrder.LITTLE_ENDIAN);
- bb2.putInt(67890);
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- assertEquals(12345, ioBuffer.getInt());
- assertEquals(67890, ioBuffer.getInt());
- }
-
- /**
- * Test the getInt() method, on a buffer containing 1 int spread in two ByteBuffers
- */
- @Test
- public void testGetInt1Int2BBs() {
- ByteBuffer bb1 = ByteBuffer.allocate(1);
- bb1.put((byte) 0x01);
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(3);
- bb2.put(new byte[] { 0x02, 0x03, 0x04 });
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- assertEquals(0x01020304, ioBuffer.getInt());
- }
-
- /**
- * Test the getInt() method, on a buffer containing 1 incomplet int spread in two ByteBuffers
- */
- @Test(expected = BufferUnderflowException.class)
- public void testGetIntIncompletInt2BBs() {
- ByteBuffer bb1 = ByteBuffer.allocate(1);
- bb1.put((byte) 0x01);
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(2);
- bb2.put(new byte[] { 0x02, 0x03 });
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- ioBuffer.getInt();
- }
-
- /**
- * test the get(int) method on one buffer
- */
- @Test
- public void testGetIntOneBuffer() {
- ByteBuffer bb = ByteBuffer.allocate(4);
- bb.put("0123".getBytes());
- bb.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb);
-
- assertEquals('0', ioBuffer.get());
- assertEquals('1', ioBuffer.get());
- assertEquals('0', ioBuffer.get(0));
- assertEquals('3', ioBuffer.get(3));
- assertEquals('1', ioBuffer.get(1));
- assertEquals('2', ioBuffer.get(2));
- assertEquals('2', ioBuffer.get());
-
- try {
- ioBuffer.get(4);
- fail();
- } catch (IndexOutOfBoundsException ioobe) {
- // expected
- assertTrue(true);
- }
- }
-
- /**
- * test the get(int) method on two buffers
- */
- @Test
- public void testGetIntTwoBuffer() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.put("0123".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.put("4567".getBytes());
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- assertEquals('0', ioBuffer.get());
- assertEquals('1', ioBuffer.get());
- assertEquals('0', ioBuffer.get(0));
- assertEquals('4', ioBuffer.get(4));
- assertEquals('7', ioBuffer.get(7));
- assertEquals('2', ioBuffer.get(2));
- assertEquals('2', ioBuffer.get());
- assertEquals('3', ioBuffer.get());
- assertEquals('4', ioBuffer.get());
-
- try {
- ioBuffer.get(8);
- fail();
- } catch (IndexOutOfBoundsException ioobe) {
- // expected
- assertTrue(true);
- }
- }
-
- //-------------------------------------------------------------------------
- // The the clear method. It will erase all the data in all the inner
- // ByteBuffer, thus the buffer size might increase.
- // We will check those case :
- // 1) clear an empty buffer
- // 2) clear a buffer with one ByteBuffer
- // 3) clear a buffer with numerous ByteBuffers
- //-------------------------------------------------------------------------
- /**
- * Test the clear() method
- */
- @Test
- public void testClearEmptyBuffer() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.put("345".getBytes());
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- assertEquals(6, ioBuffer.limit());
-
- // Move forward a bit
- ioBuffer.get();
- ioBuffer.get();
-
- // Clear
- ioBuffer.clear();
-
- // We should be back to the origin
- assertEquals(0, ioBuffer.position());
-
- // The limit must have grown
- assertEquals(8, ioBuffer.limit());
- }
-
- /**
- * Test the flip() method
- */
- @Test
- public void testFlip() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.put("0123".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.put("4567".getBytes());
- bb2.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2);
-
- // Move forward a bit
- ioBuffer.get();
- ioBuffer.get();
-
- // Clear
- ioBuffer.clear();
-
- // We should be back to the origin
- assertEquals(0, ioBuffer.position());
- assertEquals(8, ioBuffer.limit());
- }
-
- //-------------------------------------------------------------------------
- // Test the position() method
- // We will test that the position() metho returns the correct result in
- // those cases :
- // 1) the buffer is empty : must return 0
- // 2) must return a value between 0 and limit()
- //-------------------------------------------------------------------------
- /**
- * Test the position method over an emptyIoBuffer
- */
- @Test
- public void testPositionEmptyBuffer() {
- IoBuffer ioBuffer = new IoBuffer();
-
- assertEquals(0, ioBuffer.position());
- }
-
- /**
- * Test the position method over a buffer
- */
- @Test
- public void testPositionBuffer() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.put("3456".getBytes());
- bb2.flip();
-
- ByteBuffer bb3 = ByteBuffer.allocate(4);
- bb3.put("789".getBytes());
- bb3.flip();
-
- // The resulting buffer will be seen as "0123456789"
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
-
- // Iterate and check the position
- for (int i = 0; i < ioBuffer.limit(); i++) {
- assertEquals(i, ioBuffer.position());
- ioBuffer.get();
- }
- }
-
- //-------------------------------------------------------------------------
- // Test the position(int) method
- // We will test many different cases
- // 1) a position() in an empty buffer
- // 2) a position() with a negative value
- // 3) a position() with a value above the limit
- // 4) a position() within the current buffer
- // 4-1) at the beginning of the current buffer
- // 4-2) at the end of the current buffer
- // 4-3) in the middle of the current buffer
- // 5) a position() before the current buffer
- // 6) a position() after the current buffer
- //-------------------------------------------------------------------------
- /**
- * Test the position method over an emptyIoBuffer
- */
- @Test(expected = IllegalArgumentException.class)
- public void testPositionIntEmptyBuffer() {
- IoBuffer ioBuffer = new IoBuffer();
-
- ioBuffer.position(0);
- }
-
- /**
- * Test the position method with a negative value
- */
- @Test(expected = IllegalArgumentException.class)
- public void testPositionNegativeValue() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.put("0123".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.put("4567".getBytes());
- bb2.flip();
-
- ByteBuffer bb3 = ByteBuffer.allocate(4);
- bb3.put("89".getBytes());
- bb3.flip();
-
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
-
- ioBuffer.position(-1);
- }
-
- /**
- * Test the position method with a value above the buffer size
- */
- @Test(expected = IllegalArgumentException.class)
- public void testPositionAboveValue() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.put("3456".getBytes());
- bb2.flip();
-
- ByteBuffer bb3 = ByteBuffer.allocate(4);
- bb3.put("789".getBytes());
- bb3.flip();
-
- // The resulting buffer will be seen as "0123456789"
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
-
- ioBuffer.position(10);
- }
-
- /**
- * Test the position method in the current buffer
- */
- @Test
- public void testPositionCurrentBuffer() {
- ByteBuffer bb1 = ByteBuffer.allocate(4);
- bb1.put("012".getBytes());
- bb1.flip();
-
- ByteBuffer bb2 = ByteBuffer.allocate(4);
- bb2.put("3456".getBytes());
- bb2.flip();
-
- ByteBuffer bb3 = ByteBuffer.allocate(4);
- bb3.put("789".getBytes());
- bb3.flip();
-
- // The resulting buffer will be seen as "0123456789"
- IoBuffer ioBuffer = new IoBuffer(bb1, bb2, bb3);
-
- // Set the position in the middle of bb2 (4-3)
- ioBuffer.position(5);
-
- assertEquals('5', ioBuffer.get());
-
- // Set the position at the beginning of bb2 (4-1)
- ioBuffer.position(3);
-
- assertEquals('3', ioBuffer.get());
-
- // Set the position at the end of bb2 (4-2)
- ioBuffer.position(6);
-
- assertEquals('6', ioBuffer.get());
-
- // Set a position before the current buffer (5)
- ioBuffer.position(2);
- assertEquals('2', ioBuffer.get());
-
- // Set a position after the current buffer (6)
- ioBuffer.position(7);
- assertEquals('7', ioBuffer.get());
-
- // Now, let's see if we can get all the elements correctly
- // if we set the position from 0 to end
- for (int i = 0; i < ioBuffer.limit(); i++) {
- ioBuffer.position(i);
- assertEquals('0' + i, ioBuffer.get());
- }
-
- // Same, in revert order
- for (int i = ioBuffer.limit() - 1; i >= 0; i--) {
- ioBuffer.position(i);
- assertEquals('0' + i, ioBuffer.get());
- }
- }
-}