package org.springframework.async.io; import java.io.IOException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.Objects; /** * @author Jon Brisbin <jon@jbrisbin.com> */ public class Buffer implements Comparable<Buffer> { public static int SMALL_BUFFER_SIZE = 1024 * 16; public static int MAX_BUFFER_SIZE = 1024 * 1000; private ByteBuffer buffer; private final boolean dynamic; public Buffer() { dynamic = true; } public Buffer(int atLeast, boolean fixed) { if (fixed) { if (atLeast <= MAX_BUFFER_SIZE) { buffer = ByteBuffer.allocateDirect(atLeast); } else { throw new IllegalArgumentException("Requested buffer size exceeds maximum allowed (" + MAX_BUFFER_SIZE + ")"); } } else { ensureCapacity(atLeast); } dynamic = !fixed; } public Buffer(Buffer bufferToCopy) { this.dynamic = bufferToCopy.dynamic; this.buffer = bufferToCopy.buffer.duplicate(); } public Buffer(ByteBuffer bufferToStartWith) { this.dynamic = true; this.buffer = bufferToStartWith; } public int position() { return (null == buffer ? 0 : buffer.position()); } public int capacity() { return (null == buffer ? SMALL_BUFFER_SIZE : buffer.capacity()); } public int remaining() { return (null == buffer ? SMALL_BUFFER_SIZE : buffer.remaining()); } public Buffer clear() { if (null != buffer) buffer = null; return this; } public Buffer flip() { if (null != buffer) buffer.flip(); return this; } public Buffer rewind() { if (null != buffer) buffer.rewind(); return this; } public byte get() { if (null != buffer) buffer.get(); throw new BufferUnderflowException(); } public Buffer get(byte[] b) { if (null != buffer) buffer.get(b); return this; } public String getAsString() { if (null != buffer) { byte[] b = new byte[buffer.remaining()]; buffer.get(b, 0, b.length); return new String(b); } else { return null; } } public Buffer append(String s) { Objects.requireNonNull(s, "Cannot add null values to a buffer"); ensureCapacity(s.length()); buffer.put(s.getBytes()); return this; } public Buffer append(ByteBuffer b) { Objects.requireNonNull(b, "Cannot add null values to a buffer"); ensureCapacity(b.remaining()); buffer.put(b); return this; } public Buffer append(byte b) { Objects.requireNonNull(b, "Cannot add null values to a buffer"); ensureCapacity(1); buffer.put(b); return this; } public Buffer append(byte[] b) { Objects.requireNonNull(b, "Cannot add null values to a buffer"); ensureCapacity(b.length); buffer.put(b); return this; } public int transferTo(WritableByteChannel channel) throws IOException { return (null != buffer ? channel.write(buffer) : 0); } public ByteBuffer getByteBuffer() { return buffer; } @Override public String toString() { return null != buffer ? buffer.toString() : null; } @Override public int compareTo(Buffer buffer) { return (null != buffer ? this.buffer.compareTo(buffer.buffer) : -1); } private void ensureCapacity(int atLeast) { if (null == buffer) { buffer = ByteBuffer.allocateDirect(SMALL_BUFFER_SIZE); return; } if (dynamic && buffer.remaining() < atLeast) { if (buffer.capacity() + SMALL_BUFFER_SIZE <= MAX_BUFFER_SIZE) { ByteBuffer newBuff = ByteBuffer.allocateDirect(buffer.limit() + SMALL_BUFFER_SIZE); buffer.flip(); newBuff.put(buffer); buffer = newBuff; } else { throw new IllegalStateException("Requested buffer size exceeds maximum allowed (" + MAX_BUFFER_SIZE + ")"); } } } }