commit d76f5b46b5185fd66c61912c53be2c3da736cccd
Author: Walter Oggioni
+ * In {@link SimpleBufferAllocator}, the underlying {@link ByteBuffer} of the {@link IoBuffer} is
+ * reallocated on its capacity change, which means the newly allocated bigger {@link ByteBuffer}
+ * replaces the old small {@link ByteBuffer} . Consequently, the old {@link ByteBuffer} is marked
+ * for garbage collection.
+ *
+ * It's not a problem in most cases as long as the capacity change doesn't happen frequently.
+ * However, once it happens too often, it burdens the VM and the cost of filling the newly allocated
+ * {@link ByteBuffer} with {@code NUL} surpass the cost of accessing the cache. In 2 dual-core
+ * Opteron Italy 270 processors, {@link CachedBufferAllocator} outperformed
+ * {@link SimpleBufferAllocator} in the following situation:
+ *
+ * {@link CachedBufferAllocator} uses {@link ThreadLocal} to store the cached buffer, allocates
+ * buffers whose capacity is power of 2 only and provides performance advantage if
+ * {@link IoBuffer#free()} is called properly.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $
+ */
+public class CachedBufferAllocator implements IoBufferAllocator {
+
+ private static final int DEFAULT_MAX_POOL_SIZE = 8;
+ private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB
+
+ private final int maxPoolSize;
+ private final int maxCachedBufferSize;
+
+ private final ThreadLocal
+ *
+ * You can allocate a new heap buffer.
+ *
+ * decoder
and returns it.
+ *
+ * @param prefixLength the length of the length field (1, 2, or 4)
+ * @param decoder the decoder to use for decoding the string
+ * @return the prefixed string
+ * @throws CharacterCodingException when decoding fails
+ * @throws BufferUnderflowException when there is not enough data available
+ */
+ @Override
+ public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
+ throws CharacterCodingException {
+ if (!prefixedDataAvailable(prefixLength)) {
+ throw new BufferUnderflowException();
+ }
+
+ int fieldSize = 0;
+
+ switch (prefixLength) {
+ case 1:
+ fieldSize = getUnsigned();
+ break;
+ case 2:
+ fieldSize = getUnsignedShort();
+ break;
+ case 4:
+ fieldSize = getInt();
+ break;
+ }
+
+ if (fieldSize == 0) {
+ return "";
+ }
+
+ boolean utf16 = decoder.charset().name().startsWith("UTF-16");
+
+ if (utf16 && (fieldSize & 1) != 0) {
+ throw new BufferDataException("fieldSize is not even for a UTF-16 string.");
+ }
+
+ int oldLimit = limit();
+ int end = position() + fieldSize;
+
+ if (oldLimit < end) {
+ throw new BufferUnderflowException();
+ }
+
+ limit(end);
+ decoder.reset();
+
+ int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
+ CharBuffer out = CharBuffer.allocate(expectedLength);
+ for (;;) {
+ CoderResult cr;
+ if (hasRemaining()) {
+ cr = decoder.decode(buf(), out, true);
+ } else {
+ cr = decoder.flush(out);
+ }
+
+ if (cr.isUnderflow()) {
+ break;
+ }
+
+ if (cr.isOverflow()) {
+ CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
+ out.flip();
+ o.put(out);
+ out = o;
+ continue;
+ }
+
+ cr.throwException();
+ }
+
+ limit(oldLimit);
+ position(end);
+ return out.flip().toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
+ throws CharacterCodingException {
+ return putPrefixedString(in, 2, 0, encoder);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
+ throws CharacterCodingException {
+ return putPrefixedString(in, prefixLength, 0, encoder);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding,
+ CharsetEncoder encoder) throws CharacterCodingException {
+ return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue,
+ CharsetEncoder encoder) throws CharacterCodingException {
+ int maxLength;
+ switch (prefixLength) {
+ case 1:
+ maxLength = 255;
+ break;
+ case 2:
+ maxLength = 65535;
+ break;
+ case 4:
+ maxLength = Integer.MAX_VALUE;
+ break;
+ default:
+ throw new IllegalArgumentException("prefixLength: " + prefixLength);
+ }
+
+ if (val.length() > maxLength) {
+ throw new IllegalArgumentException("The specified string is too long.");
+ }
+ if (val.length() == 0) {
+ switch (prefixLength) {
+ case 1:
+ put((byte) 0);
+ break;
+ case 2:
+ putShort((short) 0);
+ break;
+ case 4:
+ putInt(0);
+ break;
+ }
+ return this;
+ }
+
+ int padMask;
+ switch (padding) {
+ case 0:
+ case 1:
+ padMask = 0;
+ break;
+ case 2:
+ padMask = 1;
+ break;
+ case 4:
+ padMask = 3;
+ break;
+ default:
+ throw new IllegalArgumentException("padding: " + padding);
+ }
+
+ CharBuffer in = CharBuffer.wrap(val);
+ skip(prefixLength); // make a room for the length field
+ int oldPos = position();
+ encoder.reset();
+
+ int expandedState = 0;
+
+ for (;;) {
+ CoderResult cr;
+ if (in.hasRemaining()) {
+ cr = encoder.encode(in, buf(), true);
+ } else {
+ cr = encoder.flush(buf());
+ }
+
+ if (position() - oldPos > maxLength) {
+ throw new IllegalArgumentException("The specified string is too long.");
+ }
+
+ if (cr.isUnderflow()) {
+ break;
+ }
+ if (cr.isOverflow()) {
+ if (isAutoExpand()) {
+ switch (expandedState) {
+ case 0:
+ autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
+ expandedState++;
+ break;
+ case 1:
+ autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
+ expandedState++;
+ break;
+ default:
+ throw new RuntimeException(
+ "Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
+ + " but that wasn't enough for '" + val + "'");
+ }
+ continue;
+ }
+ } else {
+ expandedState = 0;
+ }
+ cr.throwException();
+ }
+
+ // Write the length field
+ fill(padValue, padding - (position() - oldPos & padMask));
+ int length = position() - oldPos;
+ switch (prefixLength) {
+ case 1:
+ put(oldPos - 1, (byte) length);
+ break;
+ case 2:
+ putShort(oldPos - 2, (short) length);
+ break;
+ case 4:
+ putInt(oldPos - 4, length);
+ break;
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object getObject() throws ClassNotFoundException {
+ return getObject(Thread.currentThread().getContextClassLoader());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object getObject(final ClassLoader classLoader) throws ClassNotFoundException {
+ if (!prefixedDataAvailable(4)) {
+ throw new BufferUnderflowException();
+ }
+
+ int length = getInt();
+ if (length <= 4) {
+ throw new BufferDataException("Object length should be greater than 4: " + length);
+ }
+
+ int oldLimit = limit();
+ limit(position() + length);
+ try {
+ ObjectInputStream in = new ObjectInputStream(asInputStream()) {
+ @Override
+ protected ObjectStreamClass readClassDescriptor()
+ throws IOException, ClassNotFoundException {
+ int type = read();
+ if (type < 0) {
+ throw new EOFException();
+ }
+ switch (type) {
+ case 0: // Primitive types
+ return super.readClassDescriptor();
+ case 1: // Non-primitive types
+ String className = readUTF();
+ Class> clazz = Class.forName(className, true, classLoader);
+ return ObjectStreamClass.lookup(clazz);
+ default:
+ throw new StreamCorruptedException("Unexpected class descriptor type: " + type);
+ }
+ }
+
+ @Override
+ protected Class> resolveClass(ObjectStreamClass desc)
+ throws IOException, ClassNotFoundException {
+ String name = desc.getName();
+ try {
+ return Class.forName(name, false, classLoader);
+ } catch (ClassNotFoundException ex) {
+ return super.resolveClass(desc);
+ }
+ }
+ };
+ return in.readObject();
+ } catch (IOException e) {
+ throw new BufferDataException(e);
+ } finally {
+ limit(oldLimit);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer putObject(Object o) {
+ int oldPos = position();
+ skip(4); // Make a room for the length field.
+ try {
+ ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
+ @Override
+ protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
+ if (desc.forClass().isPrimitive()) {
+ write(0);
+ super.writeClassDescriptor(desc);
+ } else {
+ write(1);
+ writeUTF(desc.getName());
+ }
+ }
+ };
+ out.writeObject(o);
+ out.flush();
+ } catch (IOException e) {
+ throw new BufferDataException(e);
+ }
+
+ // Fill the length field
+ int newPos = position();
+ position(oldPos);
+ putInt(newPos - oldPos - 4);
+ position(newPos);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean prefixedDataAvailable(int prefixLength) {
+ return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
+ if (remaining() < prefixLength) {
+ return false;
+ }
+
+ int dataLength;
+ switch (prefixLength) {
+ case 1:
+ dataLength = getUnsigned(position());
+ break;
+ case 2:
+ dataLength = getUnsignedShort(position());
+ break;
+ case 4:
+ dataLength = getInt(position());
+ break;
+ default:
+ throw new IllegalArgumentException("prefixLength: " + prefixLength);
+ }
+
+ if (dataLength < 0 || dataLength > maxDataLength) {
+ throw new BufferDataException("dataLength: " + dataLength);
+ }
+
+ return remaining() - prefixLength >= dataLength;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int indexOf(byte b) {
+ if (hasArray()) {
+ int arrayOffset = arrayOffset();
+ int beginPos = arrayOffset + position();
+ int limit = arrayOffset + limit();
+ byte[] array = array();
+
+ for (int i = beginPos; i < limit; i++) {
+ if (array[i] == b) {
+ return i - arrayOffset;
+ }
+ }
+ } else {
+ int beginPos = position();
+ int limit = limit();
+
+ for (int i = beginPos; i < limit; i++) {
+ if (get(i) == b) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer skip(int size) {
+ autoExpand(size);
+ return position(position() + size);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer fill(byte value, int size) {
+ autoExpand(size);
+ int q = size >>> 3;
+ int r = size & 7;
+
+ if (q > 0) {
+ int intValue = value | value << 8 | value << 16 | value << 24;
+ long longValue = intValue;
+ longValue <<= 32;
+ longValue |= intValue;
+
+ for (int i = q; i > 0; i--) {
+ putLong(longValue);
+ }
+ }
+
+ q = r >>> 2;
+ r = r & 3;
+
+ if (q > 0) {
+ int intValue = value | value << 8 | value << 16 | value << 24;
+ putInt(intValue);
+ }
+
+ q = r >> 1;
+ r = r & 1;
+
+ if (q > 0) {
+ short shortValue = (short) (value | value << 8);
+ putShort(shortValue);
+ }
+
+ if (r > 0) {
+ put(value);
+ }
+
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer fillAndReset(byte value, int size) {
+ autoExpand(size);
+ int pos = position();
+ try {
+ fill(value, size);
+ } finally {
+ position(pos);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer fill(int size) {
+ autoExpand(size);
+ int q = size >>> 3;
+ int r = size & 7;
+
+ for (int i = q; i > 0; i--) {
+ putLong(0L);
+ }
+
+ q = r >>> 2;
+ r = r & 3;
+
+ if (q > 0) {
+ putInt(0);
+ }
+
+ q = r >> 1;
+ r = r & 1;
+
+ if (q > 0) {
+ putShort((short) 0);
+ }
+
+ if (r > 0) {
+ put((byte) 0);
+ }
+
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IoBuffer fillAndReset(int size) {
+ autoExpand(size);
+ int pos = position();
+ try {
+ fill(size);
+ } finally {
+ position(pos);
+ }
+
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public autoExpand
property is
+ * true
.
+ */
+ private IoBuffer autoExpand(int expectedRemaining) {
+ if (isAutoExpand()) {
+ expand(expectedRemaining, true);
+ }
+ return this;
+ }
+
+ /**
+ * This method forwards the call to {@link #expand(int)} only when autoExpand
property is
+ * true
.
+ */
+ private IoBuffer autoExpand(int pos, int expectedRemaining) {
+ if (isAutoExpand()) {
+ expand(pos, expectedRemaining, true);
+ }
+ return this;
+ }
+
+ private static void checkFieldSize(int fieldSize) {
+ if (fieldSize < 0) {
+ throw new IllegalArgumentException("fieldSize cannot be negative: " + fieldSize);
+ }
+ }
+}
diff --git a/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java b/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java
new file mode 100644
index 0000000..fdd6639
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/buffer/BufferDataException.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.google.code.yanf4j.buffer;
+
+/**
+ * A {@link RuntimeException} which is thrown when the data the {@link IoBuffer} contains is
+ * corrupt.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $
+ *
+ */
+public class BufferDataException extends RuntimeException {
+ private static final long serialVersionUID = -4138189188602563502L;
+
+ public BufferDataException() {
+ super();
+ }
+
+ public BufferDataException(String message) {
+ super(message);
+ }
+
+ public BufferDataException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public BufferDataException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java b/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java
new file mode 100644
index 0000000..8655ee8
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/buffer/CachedBufferAllocator.java
@@ -0,0 +1,271 @@
+/*
+ * 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 com.google.code.yanf4j.buffer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import com.google.code.yanf4j.util.CircularQueue;
+
+/**
+ * An {@link IoBufferAllocator} that caches the buffers which are likely to be reused during
+ * auto-expansion of the buffers.
+ *
+ *
+ * Please note the observation above is subject to change in a different environment.
+ * Allocation
+ *
+ * IoBuffer buf = IoBuffer.allocate(1024, false);
+ *
+ *
+ * you can also allocate a new direct buffer:
+ *
+ *
+ * IoBuffer buf = IoBuffer.allocate(1024, true);
+ *
+ *
+ * or you can set the default buffer type.
+ *
+ *
+ * // Allocate heap buffer by default.
+ * IoBuffer.setUseDirectBuffer(false);
+ * // A new heap buffer is returned.
+ * IoBuffer buf = IoBuffer.allocate(1024);
+ *
+ *
+ *
+ * This class provides a few wrap(...)
methods that wraps any NIO buffers and byte arrays.
+ *
+ *
+ * Writing variable-length data using NIO ByteBuffers
is not really easy, and it is because
+ * its size is fixed. {@link IoBuffer} introduces autoExpand
property. If
+ * autoExpand
property is true, you never get {@link BufferOverflowException} or
+ * {@link IndexOutOfBoundsException} (except when index is negative). It automatically expands its
+ * capacity and limit value. For example:
+ *
+ *
+ * String greeting = messageBundle.getMessage("hello"); + * IoBuffer buf = IoBuffer.allocate(16); + * // Turn on autoExpand (it is off by default) + * buf.setAutoExpand(true); + * buf.putString(greeting, utf8encoder); + *+ * + * The underlying {@link ByteBuffer} is reallocated by {@link IoBuffer} behind the scene if the + * encoded data is larger than 16 bytes in the example above. Its capacity will double, and its + * limit will increase to the last position the string is written. + * + * + *
+ * You might also want to decrease the capacity of the buffer when most of the allocated memory area
+ * is not being used. {@link IoBuffer} provides autoShrink
property to take care of this
+ * issue. If autoShrink
is turned on, {@link IoBuffer} halves the capacity of the buffer
+ * when {@link #compact()} is invoked and only 1/4 or less of the current capacity is being used.
+ *
+ * You can also {@link #shrink()} method manually to shrink the capacity of the buffer. + *
+ * The underlying {@link ByteBuffer} is reallocated by {@link IoBuffer} behind the scene, and + * therefore {@link #buf()} will return a different {@link ByteBuffer} instance once capacity + * changes. Please also note {@link #compact()} or {@link #shrink()} will not decrease the capacity + * if the new capacity is less than the {@link #minimumCapacity()} of the buffer. + * + *
+ * Derived buffers are the buffers which were created by {@link #duplicate()}, {@link #slice()}, or
+ * {@link #asReadOnlyBuffer()}. They are useful especially when you broadcast the same messages to
+ * multiple {@link IoSession}s. Please note that the buffer derived from and its derived buffers are
+ * not both auto-expandable neither auto-shrinkable. Trying to call {@link #setAutoExpand(boolean)}
+ * or {@link #setAutoShrink(boolean)} with true
parameter will raise an
+ * {@link IllegalStateException}.
+ *
+ * {@link IoBufferAllocator} interface lets you override the default buffer management behavior. + * There are two allocators provided out-of-the-box: + *
true
if and only if a direct buffer is allocated by default when the type of
+ * the new buffer is not specified. The default value is false
.
+ */
+ public static boolean isUseDirectBuffer() {
+ return useDirectBuffer;
+ }
+
+ /**
+ * Sets if a direct buffer should be allocated by default when the type of the new buffer is not
+ * specified. The default value is false
.
+ */
+ public static void setUseDirectBuffer(boolean useDirectBuffer) {
+ IoBuffer.useDirectBuffer = useDirectBuffer;
+ }
+
+ /**
+ * Returns the direct or heap buffer which is capable to store the specified amount of bytes.
+ *
+ * @param capacity the capacity of the buffer
+ *
+ * @see #setUseDirectBuffer(boolean)
+ */
+ public static IoBuffer allocate(int capacity) {
+ return allocate(capacity, useDirectBuffer);
+ }
+
+ /**
+ * Returns the buffer which is capable of the specified size.
+ *
+ * @param capacity the capacity of the buffer
+ * @param direct true
to get a direct buffer, false
to get a heap buffer.
+ */
+ public static IoBuffer allocate(int capacity, boolean direct) {
+ if (capacity < 0) {
+ throw new IllegalArgumentException("capacity: " + capacity);
+ }
+
+ return allocator.allocate(capacity, direct);
+ }
+
+ /**
+ * Wraps the specified NIO {@link ByteBuffer} into MINA buffer.
+ */
+ public static IoBuffer wrap(ByteBuffer nioBuffer) {
+ return allocator.wrap(nioBuffer);
+ }
+
+ /**
+ * Wraps the specified byte array into MINA heap buffer.
+ */
+ public static IoBuffer wrap(byte[] byteArray) {
+ return wrap(ByteBuffer.wrap(byteArray));
+ }
+
+ /**
+ * Wraps the specified byte array into MINA heap buffer.
+ */
+ public static IoBuffer wrap(byte[] byteArray, int offset, int length) {
+ return wrap(ByteBuffer.wrap(byteArray, offset, length));
+ }
+
+ /**
+ * Normalizes the specified capacity of the buffer to power of 2, which is often helpful for
+ * optimal memory usage and performance. If it is greater than or equal to
+ * {@link Integer#MAX_VALUE}, it returns {@link Integer#MAX_VALUE}. If it is zero, it returns
+ * zero.
+ */
+ protected static int normalizeCapacity(int requestedCapacity) {
+ switch (requestedCapacity) {
+ case 0:
+ case 1 << 0:
+ case 1 << 1:
+ case 1 << 2:
+ case 1 << 3:
+ case 1 << 4:
+ case 1 << 5:
+ case 1 << 6:
+ case 1 << 7:
+ case 1 << 8:
+ case 1 << 9:
+ case 1 << 10:
+ case 1 << 11:
+ case 1 << 12:
+ case 1 << 13:
+ case 1 << 14:
+ case 1 << 15:
+ case 1 << 16:
+ case 1 << 17:
+ case 1 << 18:
+ case 1 << 19:
+ case 1 << 21:
+ case 1 << 22:
+ case 1 << 23:
+ case 1 << 24:
+ case 1 << 25:
+ case 1 << 26:
+ case 1 << 27:
+ case 1 << 28:
+ case 1 << 29:
+ case 1 << 30:
+ case Integer.MAX_VALUE:
+ return requestedCapacity;
+ }
+
+ int newCapacity = 1;
+ while (newCapacity < requestedCapacity) {
+ newCapacity <<= 1;
+ if (newCapacity < 0) {
+ return Integer.MAX_VALUE;
+ }
+ }
+ return newCapacity;
+ }
+
+ /**
+ * Creates a new instance. This is an empty constructor.
+ */
+ protected IoBuffer() {}
+
+ /**
+ * Declares this buffer and all its derived buffers are not used anymore so that it can be reused
+ * by some {@link IoBufferAllocator} implementations. It is not mandatory to call this method, but
+ * you might want to invoke this method for maximum performance.
+ */
+ public abstract void free();
+
+ /**
+ * Returns the underlying NIO buffer instance.
+ */
+ public abstract ByteBuffer buf();
+
+ /**
+ * @see ByteBuffer#isDirect()
+ */
+ public abstract boolean isDirect();
+
+ /**
+ * returns true
if and only if this buffer is derived from other buffer via
+ * {@link #duplicate()}, {@link #slice()} or {@link #asReadOnlyBuffer()}.
+ */
+ public abstract boolean isDerived();
+
+ /**
+ * @see ByteBuffer#isReadOnly()
+ */
+ public abstract boolean isReadOnly();
+
+ /**
+ * Returns the minimum capacity of this buffer which is used to determine the new capacity of the
+ * buffer shrunk by {@link #compact()} and {@link #shrink()} operation. The default value is the
+ * initial capacity of the buffer.
+ */
+ public abstract int minimumCapacity();
+
+ /**
+ * Sets the minimum capacity of this buffer which is used to determine the new capacity of the
+ * buffer shrunk by {@link #compact()} and {@link #shrink()} operation. The default value is the
+ * initial capacity of the buffer.
+ */
+ public abstract IoBuffer minimumCapacity(int minimumCapacity);
+
+ /**
+ * @see ByteBuffer#capacity()
+ */
+ public abstract int capacity();
+
+ /**
+ * Increases the capacity of this buffer. If the new capacity is less than or equal to the current
+ * capacity, this method returns silently. If the new capacity is greater than the current
+ * capacity, the buffer is reallocated while retaining the position, limit, mark and the content
+ * of the buffer.
+ */
+ public abstract IoBuffer capacity(int newCapacity);
+
+ /**
+ * Returns true
if and only if autoExpand
is turned on.
+ */
+ public abstract boolean isAutoExpand();
+
+ /**
+ * Turns on or off autoExpand
.
+ */
+ public abstract IoBuffer setAutoExpand(boolean autoExpand);
+
+ /**
+ * Returns true
if and only if autoShrink
is turned on.
+ */
+ public abstract boolean isAutoShrink();
+
+ /**
+ * Turns on or off autoShrink
.
+ */
+ public abstract IoBuffer setAutoShrink(boolean autoShrink);
+
+ /**
+ * Changes the capacity and limit of this buffer so this buffer get the specified
+ * expectedRemaining
room from the current position. This method works even if you didn't
+ * set autoExpand
to true
.
+ */
+ public abstract IoBuffer expand(int expectedRemaining);
+
+ /**
+ * Changes the capacity and limit of this buffer so this buffer get the specified
+ * expectedRemaining
room from the specified position
. This method works even if
+ * you didn't set autoExpand
to true
.
+ */
+ public abstract IoBuffer expand(int position, int expectedRemaining);
+
+ /**
+ * Changes the capacity of this buffer so this buffer occupies as less memory as possible while
+ * retaining the position, limit and the buffer content between the position and limit. The
+ * capacity of the buffer never becomes less than {@link #minimumCapacity()}. The mark is
+ * discarded once the capacity changes.
+ */
+ public abstract IoBuffer shrink();
+
+ /**
+ * @see java.nio.Buffer#position()
+ */
+ public abstract int position();
+
+ /**
+ * @see java.nio.Buffer#position(int)
+ */
+ public abstract IoBuffer position(int newPosition);
+
+ /**
+ * @see java.nio.Buffer#limit()
+ */
+ public abstract int limit();
+
+ /**
+ * @see java.nio.Buffer#limit(int)
+ */
+ public abstract IoBuffer limit(int newLimit);
+
+ /**
+ * @see java.nio.Buffer#mark()
+ */
+ public abstract IoBuffer mark();
+
+ /**
+ * Returns the position of the current mark. This method returns -1
if no mark is set.
+ */
+ public abstract int markValue();
+
+ /**
+ * @see java.nio.Buffer#reset()
+ */
+ public abstract IoBuffer reset();
+
+ /**
+ * @see java.nio.Buffer#clear()
+ */
+ public abstract IoBuffer clear();
+
+ /**
+ * Clears this buffer and fills its content with NUL
. The position is set to zero, the
+ * limit is set to the capacity, and the mark is discarded.
+ */
+ public abstract IoBuffer sweep();
+
+ /**
+ * double Clears this buffer and fills its content with value
. The position is set to
+ * zero, the limit is set to the capacity, and the mark is discarded.
+ */
+ public abstract IoBuffer sweep(byte value);
+
+ /**
+ * @see java.nio.Buffer#flip()
+ */
+ public abstract IoBuffer flip();
+
+ /**
+ * @see java.nio.Buffer#rewind()
+ */
+ public abstract IoBuffer rewind();
+
+ /**
+ * @see java.nio.Buffer#remaining()
+ */
+ public abstract int remaining();
+
+ /**
+ * @see java.nio.Buffer#hasRemaining()
+ */
+ public abstract boolean hasRemaining();
+
+ /**
+ * @see ByteBuffer#duplicate()
+ */
+ public abstract IoBuffer duplicate();
+
+ /**
+ * @see ByteBuffer#slice()
+ */
+ public abstract IoBuffer slice();
+
+ /**
+ * @see ByteBuffer#asReadOnlyBuffer()
+ */
+ public abstract IoBuffer asReadOnlyBuffer();
+
+ /**
+ * @see ByteBuffer#hasArray()
+ */
+ public abstract boolean hasArray();
+
+ /**
+ * @see ByteBuffer#array()
+ */
+ public abstract byte[] array();
+
+ /**
+ * @see ByteBuffer#arrayOffset()
+ */
+ public abstract int arrayOffset();
+
+ /**
+ * @see ByteBuffer#get()
+ */
+ public abstract byte get();
+
+ /**
+ * Reads one unsigned byte as a short integer.
+ */
+ public abstract short getUnsigned();
+
+ /**
+ * @see ByteBuffer#put(byte)
+ */
+ public abstract IoBuffer put(byte b);
+
+ /**
+ * @see ByteBuffer#get(int)
+ */
+ public abstract byte get(int index);
+
+ /**
+ * Reads one byte as an unsigned short integer.
+ */
+ public abstract short getUnsigned(int index);
+
+ /**
+ * @see ByteBuffer#put(int, byte)
+ */
+ public abstract IoBuffer put(int index, byte b);
+
+ /**
+ * @see ByteBuffer#get(byte[], int, int)
+ */
+ public abstract IoBuffer get(byte[] dst, int offset, int length);
+
+ /**
+ * @see ByteBuffer#get(byte[])
+ */
+ public abstract IoBuffer get(byte[] dst);
+
+ /**
+ * TODO document me.
+ */
+ public abstract IoBuffer getSlice(int index, int length);
+
+ /**
+ * TODO document me.
+ */
+ public abstract IoBuffer getSlice(int length);
+
+ /**
+ * Writes the content of the specified src
into this buffer.
+ */
+ public abstract IoBuffer put(ByteBuffer src);
+
+ /**
+ * Writes the content of the specified src
into this buffer.
+ */
+ public abstract IoBuffer put(IoBuffer src);
+
+ /**
+ * @see ByteBuffer#put(byte[], int, int)
+ */
+ public abstract IoBuffer put(byte[] src, int offset, int length);
+
+ /**
+ * @see ByteBuffer#put(byte[])
+ */
+ public abstract IoBuffer put(byte[] src);
+
+ /**
+ * @see ByteBuffer#compact()
+ */
+ public abstract IoBuffer compact();
+
+ /**
+ * @see ByteBuffer#order()
+ */
+ public abstract ByteOrder order();
+
+ /**
+ * @see ByteBuffer#order(ByteOrder)
+ */
+ public abstract IoBuffer order(ByteOrder bo);
+
+ /**
+ * @see ByteBuffer#getChar()
+ */
+ public abstract char getChar();
+
+ /**
+ * @see ByteBuffer#putChar(char)
+ */
+ public abstract IoBuffer putChar(char value);
+
+ /**
+ * @see ByteBuffer#getChar(int)
+ */
+ public abstract char getChar(int index);
+
+ /**
+ * @see ByteBuffer#putChar(int, char)
+ */
+ public abstract IoBuffer putChar(int index, char value);
+
+ /**
+ * @see ByteBuffer#asCharBuffer()
+ */
+ public abstract CharBuffer asCharBuffer();
+
+ /**
+ * @see ByteBuffer#getShort()
+ */
+ public abstract short getShort();
+
+ /**
+ * Reads two bytes unsigned integer.
+ */
+ public abstract int getUnsignedShort();
+
+ /**
+ * @see ByteBuffer#putShort(short)
+ */
+ public abstract IoBuffer putShort(short value);
+
+ /**
+ * @see ByteBuffer#getShort()
+ */
+ public abstract short getShort(int index);
+
+ /**
+ * Reads two bytes unsigned integer.
+ */
+ public abstract int getUnsignedShort(int index);
+
+ /**
+ * @see ByteBuffer#putShort(int, short)
+ */
+ public abstract IoBuffer putShort(int index, short value);
+
+ /**
+ * @see ByteBuffer#asShortBuffer()
+ */
+ public abstract ShortBuffer asShortBuffer();
+
+ /**
+ * @see ByteBuffer#getInt()
+ */
+ public abstract int getInt();
+
+ /**
+ * Reads four bytes unsigned integer.
+ */
+ public abstract long getUnsignedInt();
+
+ /**
+ * Relative get method for reading a medium int value.
+ *
+ * + * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order, and then increments the position by three. + *
+ * + * @return The medium int value at the buffer's current position + */ + public abstract int getMediumInt(); + + /** + * Relative get method for reading an unsigned medium int value. + * + *+ * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order, and then increments the position by three. + *
+ * + * @return The unsigned medium int value at the buffer's current position + */ + public abstract int getUnsignedMediumInt(); + + /** + * Absolute get method for reading a medium int value. + * + *+ * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order. + *
+ * + * @param index The index from which the medium int will be read + * @return The medium int value at the given index + * + * @throws IndexOutOfBoundsException Ifindex
is negative or not smaller than the
+ * buffer's limit
+ */
+ public abstract int getMediumInt(int index);
+
+ /**
+ * Absolute get method for reading an unsigned medium int value.
+ *
+ * + * Reads the next three bytes at this buffer's current position, composing them into an int value + * according to the current byte order. + *
+ * + * @param index The index from which the unsigned medium int will be read + * @return The unsigned medium int value at the given index + * + * @throws IndexOutOfBoundsException Ifindex
is negative or not smaller than the
+ * buffer's limit
+ */
+ public abstract int getUnsignedMediumInt(int index);
+
+ /**
+ * Relative put method for writing a medium int value.
+ *
+ * + * Writes three bytes containing the given int value, in the current byte order, into this buffer + * at the current position, and then increments the position by three. + *
+ * + * @param value The medium int value to be written + * + * @return This buffer + * + * @throws BufferOverflowException If there are fewer than three bytes remaining in this buffer + * + * @throws ReadOnlyBufferException If this buffer is read-only + */ + public abstract IoBuffer putMediumInt(int value); + + /** + * Absolute put method for writing a medium int value. + * + *+ * Writes three bytes containing the given int value, in the current byte order, into this buffer + * at the given index. + *
+ * + * @param index The index at which the bytes will be written + * + * @param value The medium int value to be written + * + * @return This buffer + * + * @throws IndexOutOfBoundsException Ifindex
is negative or not smaller than the
+ * buffer's limit, minus three
+ *
+ * @throws ReadOnlyBufferException If this buffer is read-only
+ */
+ public abstract IoBuffer putMediumInt(int index, int value);
+
+ /**
+ * @see ByteBuffer#putInt(int)
+ */
+ public abstract IoBuffer putInt(int value);
+
+ /**
+ * @see ByteBuffer#getInt(int)
+ */
+ public abstract int getInt(int index);
+
+ /**
+ * Reads four bytes unsigned integer.
+ */
+ public abstract long getUnsignedInt(int index);
+
+ /**
+ * @see ByteBuffer#putInt(int, int)
+ */
+ public abstract IoBuffer putInt(int index, int value);
+
+ /**
+ * @see ByteBuffer#asIntBuffer()
+ */
+ public abstract IntBuffer asIntBuffer();
+
+ /**
+ * @see ByteBuffer#getLong()
+ */
+ public abstract long getLong();
+
+ /**
+ * @see ByteBuffer#putLong(int, long)
+ */
+ public abstract IoBuffer putLong(long value);
+
+ /**
+ * @see ByteBuffer#getLong(int)
+ */
+ public abstract long getLong(int index);
+
+ /**
+ * @see ByteBuffer#putLong(int, long)
+ */
+ public abstract IoBuffer putLong(int index, long value);
+
+ /**
+ * @see ByteBuffer#asLongBuffer()
+ */
+ public abstract LongBuffer asLongBuffer();
+
+ /**
+ * @see ByteBuffer#getFloat()
+ */
+ public abstract float getFloat();
+
+ /**
+ * @see ByteBuffer#putFloat(float)
+ */
+ public abstract IoBuffer putFloat(float value);
+
+ /**
+ * @see ByteBuffer#getFloat(int)
+ */
+ public abstract float getFloat(int index);
+
+ /**
+ * @see ByteBuffer#putFloat(int, float)
+ */
+ public abstract IoBuffer putFloat(int index, float value);
+
+ /**
+ * @see ByteBuffer#asFloatBuffer()
+ */
+ public abstract FloatBuffer asFloatBuffer();
+
+ /**
+ * @see ByteBuffer#getDouble()
+ */
+ public abstract double getDouble();
+
+ /**
+ * @see ByteBuffer#putDouble(double)
+ */
+ public abstract IoBuffer putDouble(double value);
+
+ /**
+ * @see ByteBuffer#getDouble(int)
+ */
+ public abstract double getDouble(int index);
+
+ /**
+ * @see ByteBuffer#putDouble(int, double)
+ */
+ public abstract IoBuffer putDouble(int index, double value);
+
+ /**
+ * @see ByteBuffer#asDoubleBuffer()
+ */
+ public abstract DoubleBuffer asDoubleBuffer();
+
+ /**
+ * Returns an {@link InputStream} that reads the data from this buffer. {@link InputStream#read()}
+ * returns -1
if the buffer position reaches to the limit.
+ */
+ public abstract InputStream asInputStream();
+
+ /**
+ * Returns an {@link OutputStream} that appends the data into this buffer. Please note that the
+ * {@link OutputStream#write(int)} will throw a {@link BufferOverflowException} instead of an
+ * {@link IOException} in case of buffer overflow. Please set autoExpand
property by
+ * calling {@link #setAutoExpand(boolean)} to prevent the unexpected runtime exception.
+ */
+ public abstract OutputStream asOutputStream();
+
+ /**
+ * Returns hexdump of this buffer. The data and pointer are not changed as a result of this method
+ * call.
+ *
+ * @return hexidecimal representation of this buffer
+ */
+ public abstract String getHexDump();
+
+ /**
+ * Return hexdump of this buffer with limited length.
+ *
+ * @param lengthLimit The maximum number of bytes to dump from the current buffer position.
+ * @return hexidecimal representation of this buffer
+ */
+ public abstract String getHexDump(int lengthLimit);
+
+ // //////////////////////////////
+ // String getters and putters //
+ // //////////////////////////////
+
+ /**
+ * Reads a NUL
-terminated string from this buffer using the specified
+ * decoder
and returns it. This method reads until the limit of this buffer if no
+ * NUL
is found.
+ */
+ public abstract String getString(CharsetDecoder decoder) throws CharacterCodingException;
+
+ /**
+ * Reads a NUL
-terminated string from this buffer using the specified
+ * decoder
and returns it.
+ *
+ * @param fieldSize the maximum number of bytes to read
+ */
+ public abstract String getString(int fieldSize, CharsetDecoder decoder)
+ throws CharacterCodingException;
+
+ /**
+ * Writes the content of in
into this buffer using the specified encoder
+ * . This method doesn't terminate string with NUL
. You have to do it by yourself.
+ *
+ * @throws BufferOverflowException if the specified string doesn't fit
+ */
+ public abstract IoBuffer putString(CharSequence val, CharsetEncoder encoder)
+ throws CharacterCodingException;
+
+ /**
+ * Writes the content of in
into this buffer as a NUL
-terminated string
+ * using the specified encoder
.
+ *
+ * If the charset name of the encoder is UTF-16, you cannot specify odd fieldSize
,
+ * and this method will append two NUL
s as a terminator.
+ *
+ * Please note that this method doesn't terminate with
+ * Each bit is mapped to a value in the specified enum. The least significant bit maps to the
+ * first entry in the specified enum and each subsequent bit maps to each subsequent bit as mapped
+ * to the subsequent enum value.
+ *
+ * You can think this class like a {@link FilterOutputStream}. All operations are proxied by default
+ * so that you can extend this class and override existing operations selectively. You can introduce
+ * new operations, too.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (Thu, 26 Jun 2008) $
+ */
+public class IoBufferWrapper extends IoBuffer {
+
+ /**
+ * The buffer proxied by this proxy.
+ */
+ private final IoBuffer buf;
+
+ /**
+ * Create a new instance.
+ *
+ * @param buf the buffer to be proxied
+ */
+ protected IoBufferWrapper(IoBuffer buf) {
+ if (buf == null) {
+ throw new NullPointerException("buf");
+ }
+ this.buf = buf;
+ }
+
+ /**
+ * Returns the parent buffer that this buffer wrapped.
+ */
+ public IoBuffer getParentBuffer() {
+ return buf;
+ }
+
+ @Override
+ public boolean isDirect() {
+ return buf.isDirect();
+ }
+
+ @Override
+ public ByteBuffer buf() {
+ return buf.buf();
+ }
+
+ @Override
+ public int capacity() {
+ return buf.capacity();
+ }
+
+ @Override
+ public int position() {
+ return buf.position();
+ }
+
+ @Override
+ public IoBuffer position(int newPosition) {
+ buf.position(newPosition);
+ return this;
+ }
+
+ @Override
+ public int limit() {
+ return buf.limit();
+ }
+
+ @Override
+ public IoBuffer limit(int newLimit) {
+ buf.limit(newLimit);
+ return this;
+ }
+
+ @Override
+ public IoBuffer mark() {
+ buf.mark();
+ return this;
+ }
+
+ @Override
+ public IoBuffer reset() {
+ buf.reset();
+ return this;
+ }
+
+ @Override
+ public IoBuffer clear() {
+ buf.clear();
+ return this;
+ }
+
+ @Override
+ public IoBuffer sweep() {
+ buf.sweep();
+ return this;
+ }
+
+ @Override
+ public IoBuffer sweep(byte value) {
+ buf.sweep(value);
+ return this;
+ }
+
+ @Override
+ public IoBuffer flip() {
+ buf.flip();
+ return this;
+ }
+
+ @Override
+ public IoBuffer rewind() {
+ buf.rewind();
+ return this;
+ }
+
+ @Override
+ public int remaining() {
+ return buf.remaining();
+ }
+
+ @Override
+ public boolean hasRemaining() {
+ return buf.hasRemaining();
+ }
+
+ @Override
+ public byte get() {
+ return buf.get();
+ }
+
+ @Override
+ public short getUnsigned() {
+ return buf.getUnsigned();
+ }
+
+ @Override
+ public IoBuffer put(byte b) {
+ buf.put(b);
+ return this;
+ }
+
+ @Override
+ public byte get(int index) {
+ return buf.get(index);
+ }
+
+ @Override
+ public short getUnsigned(int index) {
+ return buf.getUnsigned(index);
+ }
+
+ @Override
+ public IoBuffer put(int index, byte b) {
+ buf.put(index, b);
+ return this;
+ }
+
+ @Override
+ public IoBuffer get(byte[] dst, int offset, int length) {
+ buf.get(dst, offset, length);
+ return this;
+ }
+
+ @Override
+ public IoBuffer getSlice(int index, int length) {
+ return buf.getSlice(index, length);
+ }
+
+ @Override
+ public IoBuffer getSlice(int length) {
+ return buf.getSlice(length);
+ }
+
+ @Override
+ public IoBuffer get(byte[] dst) {
+ buf.get(dst);
+ return this;
+ }
+
+ @Override
+ public IoBuffer put(IoBuffer src) {
+ buf.put(src);
+ return this;
+ }
+
+ @Override
+ public IoBuffer put(ByteBuffer src) {
+ buf.put(src);
+ return this;
+ }
+
+ @Override
+ public IoBuffer put(byte[] src, int offset, int length) {
+ buf.put(src, offset, length);
+ return this;
+ }
+
+ @Override
+ public IoBuffer put(byte[] src) {
+ buf.put(src);
+ return this;
+ }
+
+ @Override
+ public IoBuffer compact() {
+ buf.compact();
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return buf.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return buf.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object ob) {
+ return buf.equals(ob);
+ }
+
+ public int compareTo(IoBuffer that) {
+ return buf.compareTo(that);
+ }
+
+ @Override
+ public ByteOrder order() {
+ return buf.order();
+ }
+
+ @Override
+ public IoBuffer order(ByteOrder bo) {
+ buf.order(bo);
+ return this;
+ }
+
+ @Override
+ public char getChar() {
+ return buf.getChar();
+ }
+
+ @Override
+ public IoBuffer putChar(char value) {
+ buf.putChar(value);
+ return this;
+ }
+
+ @Override
+ public char getChar(int index) {
+ return buf.getChar(index);
+ }
+
+ @Override
+ public IoBuffer putChar(int index, char value) {
+ buf.putChar(index, value);
+ return this;
+ }
+
+ @Override
+ public CharBuffer asCharBuffer() {
+ return buf.asCharBuffer();
+ }
+
+ @Override
+ public short getShort() {
+ return buf.getShort();
+ }
+
+ @Override
+ public int getUnsignedShort() {
+ return buf.getUnsignedShort();
+ }
+
+ @Override
+ public IoBuffer putShort(short value) {
+ buf.putShort(value);
+ return this;
+ }
+
+ @Override
+ public short getShort(int index) {
+ return buf.getShort(index);
+ }
+
+ @Override
+ public int getUnsignedShort(int index) {
+ return buf.getUnsignedShort(index);
+ }
+
+ @Override
+ public IoBuffer putShort(int index, short value) {
+ buf.putShort(index, value);
+ return this;
+ }
+
+ @Override
+ public ShortBuffer asShortBuffer() {
+ return buf.asShortBuffer();
+ }
+
+ @Override
+ public int getInt() {
+ return buf.getInt();
+ }
+
+ @Override
+ public long getUnsignedInt() {
+ return buf.getUnsignedInt();
+ }
+
+ @Override
+ public IoBuffer putInt(int value) {
+ buf.putInt(value);
+ return this;
+ }
+
+ @Override
+ public int getInt(int index) {
+ return buf.getInt(index);
+ }
+
+ @Override
+ public long getUnsignedInt(int index) {
+ return buf.getUnsignedInt(index);
+ }
+
+ @Override
+ public IoBuffer putInt(int index, int value) {
+ buf.putInt(index, value);
+ return this;
+ }
+
+ @Override
+ public IntBuffer asIntBuffer() {
+ return buf.asIntBuffer();
+ }
+
+ @Override
+ public long getLong() {
+ return buf.getLong();
+ }
+
+ @Override
+ public IoBuffer putLong(long value) {
+ buf.putLong(value);
+ return this;
+ }
+
+ @Override
+ public long getLong(int index) {
+ return buf.getLong(index);
+ }
+
+ @Override
+ public IoBuffer putLong(int index, long value) {
+ buf.putLong(index, value);
+ return this;
+ }
+
+ @Override
+ public LongBuffer asLongBuffer() {
+ return buf.asLongBuffer();
+ }
+
+ @Override
+ public float getFloat() {
+ return buf.getFloat();
+ }
+
+ @Override
+ public IoBuffer putFloat(float value) {
+ buf.putFloat(value);
+ return this;
+ }
+
+ @Override
+ public float getFloat(int index) {
+ return buf.getFloat(index);
+ }
+
+ @Override
+ public IoBuffer putFloat(int index, float value) {
+ buf.putFloat(index, value);
+ return this;
+ }
+
+ @Override
+ public FloatBuffer asFloatBuffer() {
+ return buf.asFloatBuffer();
+ }
+
+ @Override
+ public double getDouble() {
+ return buf.getDouble();
+ }
+
+ @Override
+ public IoBuffer putDouble(double value) {
+ buf.putDouble(value);
+ return this;
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return buf.getDouble(index);
+ }
+
+ @Override
+ public IoBuffer putDouble(int index, double value) {
+ buf.putDouble(index, value);
+ return this;
+ }
+
+ @Override
+ public DoubleBuffer asDoubleBuffer() {
+ return buf.asDoubleBuffer();
+ }
+
+ @Override
+ public String getHexDump() {
+ return buf.getHexDump();
+ }
+
+ @Override
+ public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException {
+ return buf.getString(fieldSize, decoder);
+ }
+
+ @Override
+ public String getString(CharsetDecoder decoder) throws CharacterCodingException {
+ return buf.getString(decoder);
+ }
+
+ @Override
+ public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException {
+ return buf.getPrefixedString(decoder);
+ }
+
+ @Override
+ public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
+ throws CharacterCodingException {
+ return buf.getPrefixedString(prefixLength, decoder);
+ }
+
+ @Override
+ public IoBuffer putString(CharSequence in, int fieldSize, CharsetEncoder encoder)
+ throws CharacterCodingException {
+ buf.putString(in, fieldSize, encoder);
+ return this;
+ }
+
+ @Override
+ public IoBuffer putString(CharSequence in, CharsetEncoder encoder)
+ throws CharacterCodingException {
+ buf.putString(in, encoder);
+ return this;
+ }
+
+ @Override
+ public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
+ throws CharacterCodingException {
+ buf.putPrefixedString(in, encoder);
+ return this;
+ }
+
+ @Override
+ public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
+ throws CharacterCodingException {
+ buf.putPrefixedString(in, prefixLength, encoder);
+ return this;
+ }
+
+ @Override
+ public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding,
+ CharsetEncoder encoder) throws CharacterCodingException {
+ buf.putPrefixedString(in, prefixLength, padding, encoder);
+ return this;
+ }
+
+ @Override
+ public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, byte padValue,
+ CharsetEncoder encoder) throws CharacterCodingException {
+ buf.putPrefixedString(in, prefixLength, padding, padValue, encoder);
+ return this;
+ }
+
+ @Override
+ public IoBuffer skip(int size) {
+ buf.skip(size);
+ return this;
+ }
+
+ @Override
+ public IoBuffer fill(byte value, int size) {
+ buf.fill(value, size);
+ return this;
+ }
+
+ @Override
+ public IoBuffer fillAndReset(byte value, int size) {
+ buf.fillAndReset(value, size);
+ return this;
+ }
+
+ @Override
+ public IoBuffer fill(int size) {
+ buf.fill(size);
+ return this;
+ }
+
+ @Override
+ public IoBuffer fillAndReset(int size) {
+ buf.fillAndReset(size);
+ return this;
+ }
+
+ @Override
+ public boolean isAutoExpand() {
+ return buf.isAutoExpand();
+ }
+
+ @Override
+ public IoBuffer setAutoExpand(boolean autoExpand) {
+ buf.setAutoExpand(autoExpand);
+ return this;
+ }
+
+ @Override
+ public IoBuffer expand(int pos, int expectedRemaining) {
+ buf.expand(pos, expectedRemaining);
+ return this;
+ }
+
+ @Override
+ public IoBuffer expand(int expectedRemaining) {
+ buf.expand(expectedRemaining);
+ return this;
+ }
+
+ @Override
+ public Object getObject() throws ClassNotFoundException {
+ return buf.getObject();
+ }
+
+ @Override
+ public Object getObject(ClassLoader classLoader) throws ClassNotFoundException {
+ return buf.getObject(classLoader);
+ }
+
+ @Override
+ public IoBuffer putObject(Object o) {
+ buf.putObject(o);
+ return this;
+ }
+
+ @Override
+ public InputStream asInputStream() {
+ return buf.asInputStream();
+ }
+
+ @Override
+ public OutputStream asOutputStream() {
+ return buf.asOutputStream();
+ }
+
+ @Override
+ public IoBuffer duplicate() {
+ return buf.duplicate();
+ }
+
+ @Override
+ public IoBuffer slice() {
+ return buf.slice();
+ }
+
+ @Override
+ public IoBuffer asReadOnlyBuffer() {
+ return buf.asReadOnlyBuffer();
+ }
+
+ @Override
+ public byte[] array() {
+ return buf.array();
+ }
+
+ @Override
+ public int arrayOffset() {
+ return buf.arrayOffset();
+ }
+
+ @Override
+ public int minimumCapacity() {
+ return buf.minimumCapacity();
+ }
+
+ @Override
+ public IoBuffer minimumCapacity(int minimumCapacity) {
+ buf.minimumCapacity(minimumCapacity);
+ return this;
+ }
+
+ @Override
+ public IoBuffer capacity(int newCapacity) {
+ buf.capacity(newCapacity);
+ return this;
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return buf.isReadOnly();
+ }
+
+ @Override
+ public int markValue() {
+ return buf.markValue();
+ }
+
+ @Override
+ public boolean hasArray() {
+ return buf.hasArray();
+ }
+
+ @Override
+ public void free() {
+ buf.free();
+ }
+
+ @Override
+ public boolean isDerived() {
+ return buf.isDerived();
+ }
+
+ @Override
+ public boolean isAutoShrink() {
+ return buf.isAutoShrink();
+ }
+
+ @Override
+ public IoBuffer setAutoShrink(boolean autoShrink) {
+ buf.setAutoShrink(autoShrink);
+ return this;
+ }
+
+ @Override
+ public IoBuffer shrink() {
+ buf.shrink();
+ return this;
+ }
+
+ @Override
+ public int getMediumInt() {
+ return buf.getMediumInt();
+ }
+
+ @Override
+ public int getUnsignedMediumInt() {
+ return buf.getUnsignedMediumInt();
+ }
+
+ @Override
+ public int getMediumInt(int index) {
+ return buf.getMediumInt(index);
+ }
+
+ @Override
+ public int getUnsignedMediumInt(int index) {
+ return buf.getUnsignedMediumInt(index);
+ }
+
+ @Override
+ public IoBuffer putMediumInt(int value) {
+ buf.putMediumInt(value);
+ return this;
+ }
+
+ @Override
+ public IoBuffer putMediumInt(int index, int value) {
+ buf.putMediumInt(index, value);
+ return this;
+ }
+
+ @Override
+ public String getHexDump(int lengthLimit) {
+ return buf.getHexDump(lengthLimit);
+ }
+
+ @Override
+ public boolean prefixedDataAvailable(int prefixLength) {
+ return buf.prefixedDataAvailable(prefixLength);
+ }
+
+ @Override
+ public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
+ return buf.prefixedDataAvailable(prefixLength, maxDataLength);
+ }
+
+ @Override
+ public int indexOf(byte b) {
+ return buf.indexOf(b);
+ }
+
+ @Override
+ public
+ * The value of this socket option is a {@code Boolean} that represents whether the option is
+ * enabled or disabled. When the {@code SO_KEEPALIVE} option is enabled the operating system may
+ * use a keep-alive mechanism to periodically probe the other end of a connection when
+ * the connection is otherwise idle. The exact semantics of the keep alive mechanism is system
+ * dependent and therefore unspecified.
+ *
+ *
+ * The initial value of this socket option is {@code FALSE}. The socket option may be enabled or
+ * disabled at any time.
+ *
+ * @see RFC 1122 * Requirements for Internet
+ * Hosts -- Communication Layers< /a>
+ * @see Socket#setKeepAlive
+ */
+ public static final SocketOption
+ * The value of this socket option is an {@code Integer} that is the size of the socket send
+ * buffer in bytes. The socket send buffer is an output buffer used by the networking
+ * implementation. It may need to be increased for high-volume connections. The value of the
+ * socket option is a hint to the implementation to size the buffer and the actual size
+ * may differ. The socket option can be queried to retrieve the actual size.
+ *
+ *
+ * For datagram-oriented sockets, the size of the send buffer may limit the size of the datagrams
+ * that may be sent by the socket. Whether datagrams larger than the buffer size are sent or
+ * discarded is system dependent.
+ *
+ *
+ * The initial/default size of the socket send buffer and the range of allowable values is system
+ * dependent although a negative size is not allowed. An attempt to set the socket send buffer to
+ * larger than its maximum size causes it to be set to its maximum size.
+ *
+ *
+ * An implementation allows this socket option to be set before the socket is bound or connected.
+ * Whether an implementation allows the socket send buffer to be changed after the socket is bound
+ * is system dependent.
+ *
+ * @see Socket#setSendBufferSize
+ */
+ public static final SocketOption
+ * The value of this socket option is an {@code Integer} that is the size of the socket receive
+ * buffer in bytes. The socket receive buffer is an input buffer used by the networking
+ * implementation. It may need to be increased for high-volume connections or decreased to limit
+ * the possible backlog of incoming data. The value of the socket option is a hint to the
+ * implementation to size the buffer and the actual size may differ.
+ *
+ *
+ * For datagram-oriented sockets, the size of the receive buffer may limit the size of the
+ * datagrams that can be received. Whether datagrams larger than the buffer size can be received
+ * is system dependent. Increasing the socket receive buffer may be important for cases where
+ * datagrams arrive in bursts faster than they can be processed.
+ *
+ *
+ * In the case of stream-oriented sockets and the TCP/IP protocol, the size of the socket receive
+ * buffer may be used when advertising the size of the TCP receive window to the remote peer.
+ *
+ *
+ * The initial/default size of the socket receive buffer and the range of allowable values is
+ * system dependent although a negative size is not allowed. An attempt to set the socket receive
+ * buffer to larger than its maximum size causes it to be set to its maximum size.
+ *
+ *
+ * An implementation allows this socket option to be set before the socket is bound or connected.
+ * Whether an implementation allows the socket receive buffer to be changed after the socket is
+ * bound is system dependent.
+ *
+ * @see RFC 1323: TCP * Extensions for High
+ * Performance< /a>
+ * @see Socket#setReceiveBufferSize
+ * @see ServerSocket#setReceiveBufferSize
+ */
+ public static final SocketOption
+ * The value of this socket option is a {@code Boolean} that represents whether the option is
+ * enabled or disabled. The exact semantics of this socket option are socket type and system
+ * dependent.
+ *
+ *
+ * In the case of stream-oriented sockets, this socket option will usually determine whether the
+ * socket can be bound to a socket address when a previous connection involving that socket
+ * address is in the TIME_WAIT state. On implementations where the semantics differ, and
+ * the socket option is not required to be enabled in order to bind the socket when a previous
+ * connection is in this state, then the implementation may choose to ignore this option.
+ *
+ *
+ * For datagram-oriented sockets the socket option is used to allow multiple programs bind to the
+ * same address. This option should be enabled when the socket is to be used for Internet Protocol
+ * (IP) multicasting.
+ *
+ *
+ * An implementation allows this socket option to be set before the socket is bound or connected.
+ * Changing the value of this socket option after the socket is bound has no effect. The default
+ * value of this socket option is system dependent.
+ *
+ * @see RFC 793: * Transmission Control
+ * Protocol< /a>
+ * @see ServerSocket#setReuseAddress
+ */
+ public static final SocketOption
+ * The value of this socket option is an {@code Integer} that controls the action taken when
+ * unsent data is queued on the socket and a method to close the socket is invoked. If the value
+ * of the socket option is zero or greater, then it represents a timeout value, in seconds, known
+ * as the linger interval. The linger interval is the timeout for the {@code close}
+ * method to block while the operating system attempts to transmit the unsent data or it decides
+ * that it is unable to transmit the data. If the value of the socket option is less than zero
+ * then the option is disabled. In that case the {@code close} method does not wait until unsent
+ * data is transmitted; if possible the operating system will transmit any unsent data before the
+ * connection is closed.
+ *
+ *
+ * This socket option is intended for use with sockets that are configured in
+ * {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode only. The behavior of
+ * the {@code close} method when this option is enabled on a non-blocking socket is not defined.
+ *
+ *
+ * The initial value of this socket option is a negative value, meaning that the option is
+ * disabled. The option may be enabled, or the linger interval changed, at any time. The maximum
+ * value of the linger interval is system dependent. Setting the linger interval to a value that
+ * is greater than its maximum value causes the linger interval to be set to its maximum value.
+ *
+ * @see Socket#setSoLinger
+ */
+ public static final SocketOption
+ * The value of this socket option is a {@code Boolean} that represents whether the option is
+ * enabled or disabled. The socket option is specific to stream-oriented sockets using the TCP/IP
+ * protocol. TCP/IP uses an algorithm known as The Nagle Algorithm to coalesce short
+ * segments and improve network efficiency.
+ *
+ *
+ * The default value of this socket option is {@code FALSE}. The socket option should only be
+ * enabled in cases where it is known that the coalescing impacts performance. The socket option
+ * may be enabled at any time. In other words, the Nagle Algorithm can be disabled. Once the
+ * option is enabled, it is system dependent whether it can be subsequently disabled. If it
+ * cannot, then invoking the {@code setOption} method to disable the option has no effect.
+ *
+ * @see RFC 1122: * Requirements for Internet
+ * Hosts -- Communication Layers< /a>
+ * @see Socket#setTcpNoDelay
+ */
+ public static final SocketOption
+ * Beware that, unlike in most collections, the
+ * This class and its iterator implement all of the optional methods of the
+ * {@link Collection} and {@link Iterator} interfaces.
+ *
+ *
+ * Memory consistency effects: As with other concurrent collections, actions in a thread prior to
+ * placing an object into a {@code LinkedTransferQueue}
+ * happen-before actions subsequent to
+ * the access or removal of that element from the {@code LinkedTransferQueue} in another thread.
+ *
+ * @author Doug Lea
+ * @author The Netty Project (netty-dev@lists.jboss.org)
+ * @author Trustin Lee (tlee@redhat.com)
+ *
+ * @param NUL
if the input string is
+ * longer than fieldSize
.
+ *
+ * @param fieldSize the maximum number of bytes to write
+ */
+ public abstract IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder)
+ throws CharacterCodingException;
+
+ /**
+ * Reads a string which has a 16-bit length field before the actual encoded string, using the
+ * specified decoder
and returns it. This method is a shortcut for
+ * getPrefixedString(2, decoder)
.
+ */
+ public abstract String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException;
+
+ /**
+ * Reads a string which has a length field before the actual encoded string, using the specified
+ * decoder
and returns it.
+ *
+ * @param prefixLength the length of the length field (1, 2, or 4)
+ */
+ public abstract String getPrefixedString(int prefixLength, CharsetDecoder decoder)
+ throws CharacterCodingException;
+
+ /**
+ * Writes the content of in
into this buffer as a string which has a 16-bit length
+ * field before the actual encoded string, using the specified encoder
. This method
+ * is a shortcut for putPrefixedString(in, 2, 0, encoder)
.
+ *
+ * @throws BufferOverflowException if the specified string doesn't fit
+ */
+ public abstract IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
+ throws CharacterCodingException;
+
+ /**
+ * Writes the content of in
into this buffer as a string which has a 16-bit length
+ * field before the actual encoded string, using the specified encoder
. This method
+ * is a shortcut for putPrefixedString(in, prefixLength, 0, encoder)
.
+ *
+ * @param prefixLength the length of the length field (1, 2, or 4)
+ *
+ * @throws BufferOverflowException if the specified string doesn't fit
+ */
+ public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength,
+ CharsetEncoder encoder) throws CharacterCodingException;
+
+ /**
+ * Writes the content of in
into this buffer as a string which has a 16-bit length
+ * field before the actual encoded string, using the specified encoder
. This method
+ * is a shortcut for putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)
.
+ *
+ * @param prefixLength the length of the length field (1, 2, or 4)
+ * @param padding the number of padded NUL
s (1 (or 0), 2, or 4)
+ *
+ * @throws BufferOverflowException if the specified string doesn't fit
+ */
+ public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding,
+ CharsetEncoder encoder) throws CharacterCodingException;
+
+ /**
+ * Writes the content of in
into this buffer as a string which has a 16-bit length
+ * field before the actual encoded string, using the specified encoder
.
+ *
+ * @param prefixLength the length of the length field (1, 2, or 4)
+ * @param padding the number of padded bytes (1 (or 0), 2, or 4)
+ * @param padValue the value of padded bytes
+ *
+ * @throws BufferOverflowException if the specified string doesn't fit
+ */
+ public abstract IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding,
+ byte padValue, CharsetEncoder encoder) throws CharacterCodingException;
+
+ /**
+ * Reads a Java object from the buffer using the context {@link ClassLoader} of the current
+ * thread.
+ */
+ public abstract Object getObject() throws ClassNotFoundException;
+
+ /**
+ * Reads a Java object from the buffer using the specified classLoader
.
+ */
+ public abstract Object getObject(final ClassLoader classLoader) throws ClassNotFoundException;
+
+ /**
+ * Writes the specified Java object to the buffer.
+ */
+ public abstract IoBuffer putObject(Object o);
+
+ /**
+ * Returns true
if this buffer contains a data which has a data length as a prefix and
+ * the buffer has remaining data as enough as specified in the data length field. This method is
+ * identical with prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )
. Please not
+ * that using this method can allow DoS (Denial of Service) attack in case the remote peer sends
+ * too big data length value. It is recommended to use {@link #prefixedDataAvailable(int, int)}
+ * instead.
+ *
+ * @param prefixLength the length of the prefix field (1, 2, or 4)
+ *
+ * @throws IllegalArgumentException if prefixLength is wrong
+ * @throws BufferDataException if data length is negative
+ */
+ public abstract boolean prefixedDataAvailable(int prefixLength);
+
+ /**
+ * Returns true
if this buffer contains a data which has a data length as a prefix and
+ * the buffer has remaining data as enough as specified in the data length field.
+ *
+ * @param prefixLength the length of the prefix field (1, 2, or 4)
+ * @param maxDataLength the allowed maximum of the read data length
+ *
+ * @throws IllegalArgumentException if prefixLength is wrong
+ * @throws BufferDataException if data length is negative or greater then maxDataLength
+ */
+ public abstract boolean prefixedDataAvailable(int prefixLength, int maxDataLength);
+
+ // ///////////////////
+ // IndexOf methods //
+ // ///////////////////
+
+ /**
+ * Returns the first occurence position of the specified byte from the current position to the
+ * current limit.
+ *
+ * @return -1
if the specified byte is not found
+ */
+ public abstract int indexOf(byte b);
+
+ // ////////////////////////
+ // Skip or fill methods //
+ // ////////////////////////
+
+ /**
+ * Forwards the position of this buffer as the specified size
bytes.
+ */
+ public abstract IoBuffer skip(int size);
+
+ /**
+ * Fills this buffer with the specified value. This method moves buffer position forward.
+ */
+ public abstract IoBuffer fill(byte value, int size);
+
+ /**
+ * Fills this buffer with the specified value. This method does not change buffer position.
+ */
+ public abstract IoBuffer fillAndReset(byte value, int size);
+
+ /**
+ * Fills this buffer with NUL (0x00)
. This method moves buffer position forward.
+ */
+ public abstract IoBuffer fill(int size);
+
+ /**
+ * Fills this buffer with NUL (0x00)
. This method does not change buffer position.
+ */
+ public abstract IoBuffer fillAndReset(int size);
+
+ // ////////////////////////
+ // Enum methods //
+ // ////////////////////////
+
+ /**
+ * Reads a byte from the buffer and returns the correlating enum constant defined by the specified
+ * enum type.
+ *
+ * @param true
to get a direct buffer, false
to get a heap buffer.
+ */
+ IoBuffer allocate(int capacity, boolean direct);
+
+ /**
+ * Returns the NIO buffer which is capable of the specified size.
+ *
+ * @param capacity the capacity of the buffer
+ * @param direct true
to get a direct buffer, false
to get a heap buffer.
+ */
+ ByteBuffer allocateNioBuffer(int capacity, boolean direct);
+
+ /**
+ * Wraps the specified NIO {@link ByteBuffer} into MINA buffer.
+ */
+ IoBuffer wrap(ByteBuffer nioBuffer);
+
+ /**
+ * Dispose of this allocator.
+ */
+ void dispose();
+}
diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java
new file mode 100644
index 0000000..339b8bb
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferHexDumper.java
@@ -0,0 +1,105 @@
+/*
+ * 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 com.google.code.yanf4j.buffer;
+
+/**
+ * Provides utility methods to dump an {@link IoBuffer} into a hex formatted string.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev: 686598 $, $Date: 2008-08-17 12:58:23 +0200 (Sun, 17 Aug 2008) $
+ */
+class IoBufferHexDumper {
+
+ /**
+ * The high digits lookup table.
+ */
+ private static final byte[] highDigits;
+
+ /**
+ * The low digits lookup table.
+ */
+ private static final byte[] lowDigits;
+
+ /**
+ * Initialize lookup tables.
+ */
+ static {
+ final byte[] digits =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ int i;
+ byte[] high = new byte[256];
+ byte[] low = new byte[256];
+
+ for (i = 0; i < 256; i++) {
+ high[i] = digits[i >>> 4];
+ low[i] = digits[i & 0x0F];
+ }
+
+ highDigits = high;
+ lowDigits = low;
+ }
+
+ /**
+ * Dumps an {@link IoBuffer} to a hex formatted string.
+ *
+ * @param in the buffer to dump
+ * @param lengthLimit the limit at which hex dumping will stop
+ * @return a hex formatted string representation of the in {@link Iobuffer}.
+ */
+ public static String getHexdump(IoBuffer in, int lengthLimit) {
+ if (lengthLimit == 0) {
+ throw new IllegalArgumentException("lengthLimit: " + lengthLimit + " (expected: 1+)");
+ }
+
+ boolean truncate = in.remaining() > lengthLimit;
+ int size;
+ if (truncate) {
+ size = lengthLimit;
+ } else {
+ size = in.remaining();
+ }
+
+ if (size == 0) {
+ return "empty";
+ }
+
+ StringBuilder out = new StringBuilder(in.remaining() * 3 - 1);
+
+ int mark = in.position();
+
+ // fill the first
+ int byteValue = in.get() & 0xFF;
+ out.append((char) highDigits[byteValue]);
+ out.append((char) lowDigits[byteValue]);
+ size--;
+
+ // and the others, too
+ for (; size > 0; size--) {
+ out.append(' ');
+ byteValue = in.get() & 0xFF;
+ out.append((char) highDigits[byteValue]);
+ out.append((char) lowDigits[byteValue]);
+ }
+
+ in.position(mark);
+
+ if (truncate) {
+ out.append("...");
+ }
+
+ return out.toString();
+ }
+}
diff --git a/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java b/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java
new file mode 100644
index 0000000..ed3d0da
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/buffer/IoBufferWrapper.java
@@ -0,0 +1,891 @@
+/*
+ * 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 com.google.code.yanf4j.buffer;
+
+import java.io.FilterOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * A {@link IoBuffer} that wraps a buffer and proxies any operations to it.
+ * IoBuffer from mina
+
+
\ No newline at end of file
diff --git a/src/main/java/com/google/code/yanf4j/config/Configuration.java b/src/main/java/com/google/code/yanf4j/config/Configuration.java
new file mode 100644
index 0000000..eb797e9
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/config/Configuration.java
@@ -0,0 +1,191 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang] Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
+ * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
+ * for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.config;
+
+import net.rubyeye.xmemcached.impl.ReconnectRequest;
+import java.util.concurrent.DelayQueue;
+import com.google.code.yanf4j.util.SystemUtils;
+
+/**
+ * Networking configuration
+ *
+ * @author dennis
+ *
+ */
+public class Configuration {
+
+ public static final String XMEMCACHED_SELECTOR_POOL_SIZE = "xmemcached.selector.pool.size";
+
+ /**
+ * Read buffer size per connection
+ */
+ private int sessionReadBufferSize = 32 * 1024;
+
+ /**
+ * Socket SO_TIMEOUT option
+ */
+ private int soTimeout = 0;
+
+ /**
+ * Thread count for processing WRITABLE event
+ */
+ private int writeThreadCount = 0;
+
+ /**
+ * Whether to enable statistics
+ */
+ private boolean statisticsServer = false;
+
+ /**
+ * Whether to handle read write concurrently,default is true
+ */
+ private boolean handleReadWriteConcurrently = true;
+
+ /**
+ * Thread coount for processing message dispatching
+ */
+ private int dispatchMessageThreadCount = 0;
+
+ /**
+ * THread count for processing READABLE event
+ */
+ private int readThreadCount = 1;
+
+ private int selectorPoolSize =
+ System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE) == null ? SystemUtils.getSystemThreadCount()
+ : Integer.parseInt(System.getProperty(XMEMCACHED_SELECTOR_POOL_SIZE));
+
+ /**
+ * Increasing buffer size per time
+ */
+ public static final int DEFAULT_INCREASE_BUFF_SIZE = 32 * 1024;
+
+ /**
+ * Max read buffer size for connection
+ */
+ public final static int MAX_READ_BUFFER_SIZE = 128 * 1024;
+
+ /**
+ * check session idle interval
+ */
+ private long checkSessionTimeoutInterval = 1000L;
+
+ public final int getWriteThreadCount() {
+ return this.writeThreadCount;
+ }
+
+ public final int getDispatchMessageThreadCount() {
+ return this.dispatchMessageThreadCount;
+ }
+
+ public final void setDispatchMessageThreadCount(int dispatchMessageThreadCount) {
+ this.dispatchMessageThreadCount = dispatchMessageThreadCount;
+ }
+
+ public final void setWriteThreadCount(int writeThreadCount) {
+ this.writeThreadCount = writeThreadCount;
+ }
+
+ private long sessionIdleTimeout = 5000L;
+
+ /**
+ * @see setSessionIdleTimeout
+ * @return
+ */
+ public final long getSessionIdleTimeout() {
+ return this.sessionIdleTimeout;
+ }
+
+ public final void setSessionIdleTimeout(long sessionIdleTimeout) {
+ this.sessionIdleTimeout = sessionIdleTimeout;
+ }
+
+ /**
+ * @see setSessionReadBufferSize
+ * @return
+ */
+ public final int getSessionReadBufferSize() {
+ return this.sessionReadBufferSize;
+ }
+
+ public final boolean isHandleReadWriteConcurrently() {
+ return this.handleReadWriteConcurrently;
+ }
+
+ public final int getSoTimeout() {
+ return this.soTimeout;
+ }
+
+ protected long statisticsInterval = 5 * 60 * 1000L;
+
+ public final long getStatisticsInterval() {
+ return this.statisticsInterval;
+ }
+
+ public final void setStatisticsInterval(long statisticsInterval) {
+ this.statisticsInterval = statisticsInterval;
+ }
+
+ public final void setSoTimeout(int soTimeout) {
+ if (soTimeout < 0) {
+ throw new IllegalArgumentException("soTimeout<0");
+ }
+ this.soTimeout = soTimeout;
+ }
+
+ public final void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently) {
+ this.handleReadWriteConcurrently = handleReadWriteConcurrently;
+ }
+
+ public final void setSessionReadBufferSize(int tcpHandlerReadBufferSize) {
+ if (tcpHandlerReadBufferSize <= 0) {
+ throw new IllegalArgumentException("tcpHandlerReadBufferSize<=0");
+ }
+ this.sessionReadBufferSize = tcpHandlerReadBufferSize;
+ }
+
+ public final boolean isStatisticsServer() {
+ return this.statisticsServer;
+ }
+
+ public final void setStatisticsServer(boolean statisticsServer) {
+ this.statisticsServer = statisticsServer;
+ }
+
+ /**
+ * @see setReadThreadCount
+ * @return
+ */
+ public final int getReadThreadCount() {
+ return this.readThreadCount;
+ }
+
+ public final void setReadThreadCount(int readThreadCount) {
+ if (readThreadCount < 0) {
+ throw new IllegalArgumentException("readThreadCount<0");
+ }
+ this.readThreadCount = readThreadCount;
+ }
+
+ public void setCheckSessionTimeoutInterval(long checkSessionTimeoutInterval) {
+ this.checkSessionTimeoutInterval = checkSessionTimeoutInterval;
+ }
+
+ public long getCheckSessionTimeoutInterval() {
+ return this.checkSessionTimeoutInterval;
+ }
+
+ public void setSelectorPoolSize(int selectorPoolSize) {
+ this.selectorPoolSize = selectorPoolSize;
+ }
+
+ public int getSelectorPoolSize() {
+ return selectorPoolSize;
+ }
+}
diff --git a/src/main/java/com/google/code/yanf4j/config/package.html b/src/main/java/com/google/code/yanf4j/config/package.html
new file mode 100644
index 0000000..89574a3
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/config/package.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Networking configuration
+
+
\ No newline at end of file
diff --git a/src/main/java/com/google/code/yanf4j/core/CodecFactory.java b/src/main/java/com/google/code/yanf4j/core/CodecFactory.java
new file mode 100644
index 0000000..d15a0b0
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/core/CodecFactory.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.core;
+
+import com.google.code.yanf4j.buffer.IoBuffer;
+
+/**
+ *
+ *
+ * Codec factory
+ *
+ * @author boyan
+ *
+ */
+public interface CodecFactory {
+
+ public interface Encoder {
+ public IoBuffer encode(Object message, Session session);
+ }
+
+ public interface Decoder {
+ public Object decode(IoBuffer buff, Session session);
+ }
+
+ public Encoder getEncoder();
+
+ public Decoder getDecoder();
+}
diff --git a/src/main/java/com/google/code/yanf4j/core/Controller.java b/src/main/java/com/google/code/yanf4j/core/Controller.java
new file mode 100644
index 0000000..d2c8ba6
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/core/Controller.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.core;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import com.google.code.yanf4j.statistics.Statistics;
+
+/**
+ * Networking Controller
+ *
+ *
+ * @author boyan
+ *
+ */
+public interface Controller {
+
+ public abstract long getSessionTimeout();
+
+ public long getSessionIdleTimeout();
+
+ public void setSessionIdleTimeout(long sessionIdleTimeout);
+
+ public abstract void setSessionTimeout(long sessionTimeout);
+
+ public abstract int getSoTimeout();
+
+ public abstract void setSoTimeout(int timeout);
+
+ public abstract void addStateListener(ControllerStateListener listener);
+
+ public void removeStateListener(ControllerStateListener listener);
+
+ public abstract boolean isHandleReadWriteConcurrently();
+
+ public abstract void setHandleReadWriteConcurrently(boolean handleReadWriteConcurrently);
+
+ public abstract int getReadThreadCount();
+
+ public abstract void setReadThreadCount(int readThreadCount);
+
+ public abstract Handler getHandler();
+
+ public abstract void setHandler(Handler handler);
+
+ public abstract int getPort();
+
+ public abstract void start() throws IOException;
+
+ public abstract boolean isStarted();
+
+ public abstract Statistics getStatistics();
+
+ public abstract CodecFactory getCodecFactory();
+
+ public abstract void setCodecFactory(CodecFactory codecFactory);
+
+ public abstract void stop() throws IOException;
+
+ public void setReceiveThroughputLimit(double receivePacketRate);
+
+ public double getReceiveThroughputLimit();
+
+ public double getSendThroughputLimit();
+
+ public void setSendThroughputLimit(double sendThroughputLimit);
+
+ public InetSocketAddress getLocalSocketAddress();
+
+ public void setLocalSocketAddress(InetSocketAddress inetAddress);
+
+ public int getDispatchMessageThreadCount();
+
+ public void setDispatchMessageThreadCount(int dispatchMessageThreadPoolSize);
+
+ public int getWriteThreadCount();
+
+ public void setWriteThreadCount(int writeThreadCount);
+
+ public Networking core package
+
+
\ No newline at end of file
diff --git a/src/main/java/com/google/code/yanf4j/nio/NioSession.java b/src/main/java/com/google/code/yanf4j/nio/NioSession.java
new file mode 100644
index 0000000..4799375
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/nio/NioSession.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang] Licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
+ * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
+ * for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.nio;
+
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.Selector;
+import com.google.code.yanf4j.core.EventType;
+import com.google.code.yanf4j.core.Session;
+
+/**
+ * Nio connection
+ *
+ * @author dennis
+ *
+ */
+public interface NioSession extends Session {
+ /**
+ * When io event occured
+ *
+ * @param event
+ * @param selector
+ */
+ public void onEvent(EventType event, Selector selector);
+
+ /**
+ * Enable read event
+ *
+ * @param selector
+ */
+ public void enableRead(Selector selector);
+
+ /**
+ * Enable write event
+ *
+ * @param selector
+ */
+ public void enableWrite(Selector selector);
+
+ /**
+ * return the channel for this connection
+ *
+ * @return
+ */
+
+ public SelectableChannel channel();
+}
diff --git a/src/main/java/com/google/code/yanf4j/nio/NioSessionConfig.java b/src/main/java/com/google/code/yanf4j/nio/NioSessionConfig.java
new file mode 100644
index 0000000..ccaa81d
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/nio/NioSessionConfig.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.nio;
+
+import java.nio.channels.SelectableChannel;
+import java.util.Queue;
+import com.google.code.yanf4j.core.CodecFactory;
+import com.google.code.yanf4j.core.Dispatcher;
+import com.google.code.yanf4j.core.Handler;
+import com.google.code.yanf4j.core.SessionConfig;
+import com.google.code.yanf4j.core.WriteMessage;
+import com.google.code.yanf4j.nio.impl.SelectorManager;
+import com.google.code.yanf4j.statistics.Statistics;
+
+/**
+ * Nio session configuration
+ *
+ * @author dennis
+ *
+ */
+public class NioSessionConfig extends SessionConfig {
+
+ public final SelectableChannel selectableChannel;
+ public final SelectorManager selectorManager;
+
+ public NioSessionConfig(SelectableChannel sc, Handler handler, SelectorManager reactor,
+ CodecFactory codecFactory, Statistics statistics, QueueNio implementation
+
+
\ No newline at end of file
diff --git a/src/main/java/com/google/code/yanf4j/statistics/Statistics.java b/src/main/java/com/google/code/yanf4j/statistics/Statistics.java
new file mode 100644
index 0000000..099cff2
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/statistics/Statistics.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.statistics;
+
+/**
+ * Statistics
+ *
+ * @author dennis
+ *
+ */
+public interface Statistics {
+
+ public void start();
+
+ public void stop();
+
+ public double getReceiveBytesPerSecond();
+
+ public double getSendBytesPerSecond();
+
+ public abstract void statisticsProcess(long n);
+
+ public abstract long getProcessedMessageCount();
+
+ public abstract double getProcessedMessageAverageTime();
+
+ public abstract void statisticsRead(long n);
+
+ public abstract void statisticsWrite(long n);
+
+ public abstract long getRecvMessageCount();
+
+ public abstract long getRecvMessageTotalSize();
+
+ public abstract long getRecvMessageAverageSize();
+
+ public abstract long getWriteMessageTotalSize();
+
+ public abstract long getWriteMessageCount();
+
+ public abstract long getWriteMessageAverageSize();
+
+ public abstract double getRecvMessageCountPerSecond();
+
+ public abstract double getWriteMessageCountPerSecond();
+
+ public void statisticsAccept();
+
+ public double getAcceptCountPerSecond();
+
+ public long getStartedTime();
+
+ public void reset();
+
+ public void restart();
+
+ public boolean isStatistics();
+
+ public void setReceiveThroughputLimit(double receiveThroughputLimit);
+
+ /**
+ * Check session if receive bytes per second is over flow controll
+ *
+ * @return
+ */
+ public boolean isReceiveOverFlow();
+
+ /**
+ * Check session if receive bytes per second is over flow controll
+ *
+ * @return
+ */
+ public boolean isSendOverFlow();
+
+ public double getSendThroughputLimit();
+
+ public void setSendThroughputLimit(double sendThroughputLimit);
+
+ public double getReceiveThroughputLimit();
+
+}
diff --git a/src/main/java/com/google/code/yanf4j/statistics/impl/DefaultStatistics.java b/src/main/java/com/google/code/yanf4j/statistics/impl/DefaultStatistics.java
new file mode 100644
index 0000000..4701ddb
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/statistics/impl/DefaultStatistics.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.statistics.impl;
+
+import com.google.code.yanf4j.statistics.Statistics;
+
+/**
+ * Default statistics implementation
+ *
+ * @author dennis
+ *
+ */
+public class DefaultStatistics implements Statistics {
+ public void start() {
+
+ }
+
+ public double getSendBytesPerSecond() {
+ return 0;
+ }
+
+ public double getReceiveBytesPerSecond() {
+ return 0;
+ }
+
+ public boolean isStatistics() {
+ return false;
+ }
+
+ public long getStartedTime() {
+ return 0;
+ }
+
+ public void reset() {
+
+ }
+
+ public void restart() {
+
+ }
+
+ public double getProcessedMessageAverageTime() {
+ return 0;
+ }
+
+ public long getProcessedMessageCount() {
+ return 0;
+ }
+
+ public void statisticsProcess(long n) {
+
+ }
+
+ public void stop() {
+
+ }
+
+ public long getRecvMessageCount() {
+
+ return 0;
+ }
+
+ public long getRecvMessageTotalSize() {
+
+ return 0;
+ }
+
+ public long getRecvMessageAverageSize() {
+
+ return 0;
+ }
+
+ public double getRecvMessageCountPerSecond() {
+
+ return 0;
+ }
+
+ public long getWriteMessageCount() {
+
+ return 0;
+ }
+
+ public long getWriteMessageTotalSize() {
+
+ return 0;
+ }
+
+ public long getWriteMessageAverageSize() {
+
+ return 0;
+ }
+
+ public void statisticsRead(long n) {
+
+ }
+
+ public void statisticsWrite(long n) {
+
+ }
+
+ public double getWriteMessageCountPerSecond() {
+
+ return 0;
+ }
+
+ public double getAcceptCountPerSecond() {
+ return 0;
+ }
+
+ public void statisticsAccept() {
+
+ }
+
+ public void setReceiveThroughputLimit(double receivePacketRate) {}
+
+ public boolean isReceiveOverFlow() {
+ return false;
+ }
+
+ public boolean isSendOverFlow() {
+ return false;
+ }
+
+ public double getSendThroughputLimit() {
+ return -1.0;
+ }
+
+ public void setSendThroughputLimit(double sendThroughputLimit) {}
+
+ public final double getReceiveThroughputLimit() {
+ return -1.0;
+ }
+
+}
diff --git a/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java b/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java
new file mode 100644
index 0000000..bd5ad80
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/statistics/impl/SimpleStatistics.java
@@ -0,0 +1,237 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.statistics.impl;
+
+import java.util.concurrent.atomic.AtomicLong;
+import com.google.code.yanf4j.statistics.Statistics;
+
+/**
+ * A simple statistics implementation
+ *
+ * @author dennis
+ *
+ */
+public class SimpleStatistics implements Statistics {
+ private boolean started = false;
+
+ public boolean isStatistics() {
+ return this.started;
+ }
+
+ public synchronized void reset() {
+ if (this.started) {
+ throw new IllegalStateException();
+ }
+ this.startTime = this.stopTime = -1;
+ this.recvMessageCount.set(0);
+ this.recvMessageTotalSize.set(0);
+ this.writeMessageCount.set(0);
+ this.writeMessageTotalSize.set(0);
+ this.processMessageCount.set(0);
+ this.processMessageTotalTime.set(0);
+ this.acceptCount.set(0);
+ }
+
+ private double receiveThroughputLimit = -1.0; // receive bytes per second
+ private double sendThroughputLimit = -1.0; // send bytes per second
+
+ public void setReceiveThroughputLimit(double receivePacketRate) {
+ this.receiveThroughputLimit = receivePacketRate;
+ }
+
+ /**
+ * Check session if receive bytes per second is over flow controll
+ *
+ * @return
+ */
+ public boolean isReceiveOverFlow() {
+ if (getReceiveThroughputLimit() < 0.0000f) {
+ return false;
+ }
+ return getReceiveBytesPerSecond() > getReceiveThroughputLimit();
+ }
+
+ /**
+ * Check session if receive bytes per second is over flow controll
+ *
+ * @return
+ */
+ public boolean isSendOverFlow() {
+ if (getSendThroughputLimit() < 0.0000f) {
+ return false;
+ }
+ return getSendBytesPerSecond() > getSendThroughputLimit();
+ }
+
+ public double getSendThroughputLimit() {
+ return this.sendThroughputLimit;
+ }
+
+ public void setSendThroughputLimit(double sendThroughputLimit) {
+ this.sendThroughputLimit = sendThroughputLimit;
+ }
+
+ public final double getReceiveThroughputLimit() {
+ return this.receiveThroughputLimit;
+ }
+
+ public synchronized void restart() {
+ stop();
+ reset();
+ start();
+ }
+
+ private long startTime, stopTime = -1;
+
+ private AtomicLong recvMessageCount = new AtomicLong();
+
+ private AtomicLong recvMessageTotalSize = new AtomicLong();
+
+ private AtomicLong writeMessageCount = new AtomicLong();
+
+ private AtomicLong writeMessageTotalSize = new AtomicLong();
+
+ private AtomicLong processMessageCount = new AtomicLong();
+
+ private AtomicLong acceptCount = new AtomicLong();
+
+ private AtomicLong processMessageTotalTime = new AtomicLong();
+
+ public long getStartedTime() {
+ return this.startTime;
+ }
+
+ public double getProcessedMessageAverageTime() {
+ return this.processMessageCount.get() == 0 ? 0
+ : (double) this.processMessageTotalTime.get() / this.processMessageCount.get();
+ }
+
+ public long getProcessedMessageCount() {
+ return this.processMessageCount.get();
+ }
+
+ public void statisticsProcess(long n) {
+ if (!this.started) {
+ return;
+ }
+ if (n < 0) {
+ return;
+ }
+ this.processMessageTotalTime.addAndGet(n);
+ this.processMessageCount.incrementAndGet();
+ }
+
+ public SimpleStatistics() {
+
+ }
+
+ public synchronized void start() {
+ this.startTime = System.currentTimeMillis();
+ this.started = true;
+ }
+
+ public synchronized void stop() {
+ this.stopTime = System.currentTimeMillis();
+ this.started = false;
+ }
+
+ public void statisticsRead(long n) {
+ if (!this.started) {
+ return;
+ }
+ if (n <= 0) {
+ return;
+ }
+ this.recvMessageCount.incrementAndGet();
+ this.recvMessageTotalSize.addAndGet(n);
+ }
+
+ public long getRecvMessageCount() {
+ return this.recvMessageCount.get();
+ }
+
+ public long getRecvMessageTotalSize() {
+ return this.recvMessageTotalSize.get();
+ }
+
+ public long getWriteMessageCount() {
+ return this.writeMessageCount.get();
+ }
+
+ public long getWriteMessageTotalSize() {
+ return this.writeMessageTotalSize.get();
+ }
+
+ public void statisticsWrite(long n) {
+ if (!this.started) {
+ return;
+ }
+ if (n <= 0) {
+ return;
+ }
+ this.writeMessageCount.incrementAndGet();
+ this.writeMessageTotalSize.addAndGet(n);
+ }
+
+ public long getRecvMessageAverageSize() {
+ return this.recvMessageCount.get() == 0 ? 0
+ : this.recvMessageTotalSize.get() / this.recvMessageCount.get();
+ }
+
+ public double getRecvMessageCountPerSecond() {
+ long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime)
+ : (this.stopTime - this.startTime);
+ return duration == 0 ? 0 : (double) this.recvMessageCount.get() * 1000 / duration;
+ }
+
+ public double getWriteMessageCountPerSecond() {
+ long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime)
+ : (this.stopTime - this.startTime);
+ return duration == 0 ? 0 : (double) this.writeMessageCount.get() * 1000 / duration;
+ }
+
+ public long getWriteMessageAverageSize() {
+ return this.writeMessageCount.get() == 0 ? 0
+ : this.writeMessageTotalSize.get() / this.writeMessageCount.get();
+ }
+
+ public double getAcceptCountPerSecond() {
+ long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime)
+ : (this.stopTime - this.startTime);
+ return duration == 0 ? 0 : (double) this.acceptCount.get() * 1000 / duration;
+ }
+
+ public double getReceiveBytesPerSecond() {
+ long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime)
+ : (this.stopTime - this.startTime);
+ return duration == 0 ? 0 : (double) this.recvMessageTotalSize.get() * 1000 / duration;
+ }
+
+ public double getSendBytesPerSecond() {
+ long duration = (this.stopTime == -1) ? (System.currentTimeMillis() - this.startTime)
+ : (this.stopTime - this.startTime);
+ return duration == 0 ? 0 : (double) this.writeMessageTotalSize.get() * 1000 / duration;
+ }
+
+ public void statisticsAccept() {
+ if (!this.started) {
+ return;
+ }
+ this.acceptCount.incrementAndGet();
+ }
+
+}
diff --git a/src/main/java/com/google/code/yanf4j/statistics/package.html b/src/main/java/com/google/code/yanf4j/statistics/package.html
new file mode 100644
index 0000000..3604b72
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/statistics/package.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Networking statistics
+
+
\ No newline at end of file
diff --git a/src/main/java/com/google/code/yanf4j/util/ByteBufferMatcher.java b/src/main/java/com/google/code/yanf4j/util/ByteBufferMatcher.java
new file mode 100644
index 0000000..74705b1
--- /dev/null
+++ b/src/main/java/com/google/code/yanf4j/util/ByteBufferMatcher.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+/**
+ * Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)] Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You
+ * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+ * applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
+ * the License for the specific language governing permissions and limitations under the License
+ */
+package com.google.code.yanf4j.util;
+
+import java.util.List;
+import com.google.code.yanf4j.buffer.IoBuffer;
+
+/**
+ * ByteBuffer matcher
+ *
+ * @author dennis
+ *
+ */
+public interface ByteBufferMatcher {
+
+ public int matchFirst(IoBuffer buffer);
+
+ public ListTransferQueue
based on linked nodes. This queue orders elements FIFO
+ * (first-in-first-out) with respect to any given producer. The head of the queue is that
+ * element that has been on the queue the longest time for some producer. The tail of the
+ * queue is that element that has been on the queue the shortest time for some producer.
+ *
+ * size
method is NOT a constant-time
+ * operation. Because of the asynchronous nature of these queues, determining the current number of
+ * elements requires a traversal of the elements.
+ *
+ *