📄 bytebuffer.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */package org.apache.mina.common;import java.io.IOException;import java.io.InputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamClass;import java.io.OutputStream;import java.nio.BufferOverflowException;import java.nio.BufferUnderflowException;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.nio.charset.CoderResult;import org.apache.mina.common.support.ByteBufferHexDumper;import org.apache.mina.filter.codec.ProtocolEncoderOutput;/** * A byte buffer used by MINA applications. * <p> * This is a replacement for {@link java.nio.ByteBuffer}. Please refer to * {@link java.nio.ByteBuffer} and {@link java.nio.Buffer} documentation for * usage. MINA does not use NIO {@link java.nio.ByteBuffer} directly for two * reasons: * <ul> * <li>It doesn't provide useful getters and putters such as * <code>fill</code>, <code>get/putString</code>, and * <code>get/putAsciiInt()</code> enough.</li> * <li>It is hard to distinguish if the buffer is created from MINA buffer * pool or not. MINA have to return used buffers back to pool.</li> * <li>It is difficult to write variable-length data due to its fixed * capacity</li> * </ul> * </p> * * <h2>Allocation</h2> * <p> * You can get a heap buffer from buffer pool: * <pre> * ByteBuffer buf = ByteBuffer.allocate(1024, false); * </pre> * you can also get a direct buffer from buffer pool: * <pre> * ByteBuffer buf = ByteBuffer.allocate(1024, true); * </pre> * or you can let MINA choose: * <pre> * ByteBuffer buf = ByteBuffer.allocate(1024); * </pre> * </p> * * <h2>Acquire/Release</h2> * <p> * <b>Please note that you never need to release the allocated buffer</b> * because MINA will release it automatically when: * <ul> * <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li> * <li>You pass the buffer by calling {@link IoFilter.NextFilter#filterWrite(IoSession,IoFilter.WriteRequest)}.</li> * <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li> * </ul> * And, you don't need to release any {@link ByteBuffer} which is passed as a parameter * of {@link IoHandler#messageReceived(IoSession, Object)} method. They are released * automatically when the method returns. * <p> * You have to release buffers manually by calling {@link #release()} when: * <ul> * <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li> * <li>You called {@link #acquire()} to prevent the buffer from being released.</li> * </ul> * </p> * * <h2>Wrapping existing NIO buffers and arrays</h2> * <p> * This class provides a few <tt>wrap(...)</tt> methods that wraps * any NIO buffers and byte arrays. Wrapped MINA buffers are not returned * to the buffer pool by default to prevent unexpected memory leakage by default. * In case you want to make it pooled, you can call {@link #setPooled(boolean)} * with <tt>true</tt> flag to enable pooling. * * <h2>AutoExpand</h2> * <p> * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really * easy, and it is because its size is fixed. MINA <tt>ByteBuffer</tt> * introduces <tt>autoExpand</tt> property. If <tt>autoExpand</tt> 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: * <pre> * String greeting = messageBundle.getMessage( "hello" ); * ByteBuffer buf = ByteBuffer.allocate( 16 ); * // Turn on autoExpand (it is off by default) * buf.setAutoExpand( true ); * buf.putString( greeting, utf8encoder ); * </pre> * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind * the scene if the encoded data is larger than 16 bytes. Its capacity will * increase by two times, and its limit will increase to the last position * the string is written. * </p> * * <h2>Derived Buffers</h2> * <p> * 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 derived buffers are * neither pooled nor auto-expandable. Trying to expand a derived buffer will * raise {@link IllegalStateException}. * </p> * * <h2>Changing Buffer Allocation and Management Policy</h2> * <p> * MINA provides a {@link ByteBufferAllocator} interface to let you override * the default buffer management behavior. There are two allocators provided * out-of-the-box: * <ul> * <li>{@link PooledByteBufferAllocator} (Default)</li> * <li>{@link SimpleByteBufferAllocator}</li> * </ul> * You can change the allocator by calling {@link #setAllocator(ByteBufferAllocator)}. * </p> * * @author The Apache Directory Project (mina-dev@directory.apache.org) * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13 7월 2007) $ * @noinspection StaticNonFinalField * @see ByteBufferAllocator */public abstract class ByteBuffer implements Comparable<ByteBuffer> { private static ByteBufferAllocator allocator = new PooledByteBufferAllocator(); private static boolean useDirectBuffers = true; /** * Returns the current allocator which manages the allocated buffers. */ public static ByteBufferAllocator getAllocator() { return allocator; } /** * Changes the current allocator with the specified one to manage * the allocated buffers from now. */ public static void setAllocator(ByteBufferAllocator newAllocator) { if (newAllocator == null) { throw new NullPointerException("allocator"); } ByteBufferAllocator oldAllocator = allocator; allocator = newAllocator; if (null != oldAllocator) { oldAllocator.dispose(); } } public static boolean isUseDirectBuffers() { return useDirectBuffers; } public static void setUseDirectBuffers(boolean useDirectBuffers) { ByteBuffer.useDirectBuffers = useDirectBuffers; } /** * Returns the direct or heap buffer which is capable of the specified * size. This method tries to allocate direct buffer first, and then * tries heap buffer if direct buffer memory is exhausted. Please use * {@link #allocate(int, boolean)} to allocate buffers of specific type. * * @param capacity the capacity of the buffer */ public static ByteBuffer allocate(int capacity) { if (useDirectBuffers) { try { // first try to allocate direct buffer return allocate(capacity, true); } catch (OutOfMemoryError e) { // fall through to heap buffer } } return allocate(capacity, false); } /** * Returns the buffer which is capable of the specified size. * * @param capacity the capacity of the buffer * @param direct <tt>true</tt> to get a direct buffer, * <tt>false</tt> to get a heap buffer. */ public static ByteBuffer allocate(int capacity, boolean direct) { return allocator.allocate(capacity, direct); } /** * Wraps the specified NIO {@link java.nio.ByteBuffer} into MINA buffer. */ public static ByteBuffer wrap(java.nio.ByteBuffer nioBuffer) { return allocator.wrap(nioBuffer); } /** * Wraps the specified byte array into MINA heap buffer. */ public static ByteBuffer wrap(byte[] byteArray) { return wrap(java.nio.ByteBuffer.wrap(byteArray)); } /** * Wraps the specified byte array into MINA heap buffer. * Please note that MINA buffers are going to be pooled, and * therefore there can be waste of memory if you wrap * your byte array specifying <tt>offset</tt> and <tt>length</tt>. */ public static ByteBuffer wrap(byte[] byteArray, int offset, int length) { return wrap(java.nio.ByteBuffer.wrap(byteArray, offset, length)); } protected ByteBuffer() { } /** * Increases the internal reference count of this buffer to defer * automatic release. You have to invoke {@link #release()} as many * as you invoked this method to release this buffer. * * @throws IllegalStateException if you attempt to acquire already * released buffer. */ public abstract void acquire(); /** * Releases the specified buffer to buffer pool. * * @throws IllegalStateException if you attempt to release already * released buffer. */ public abstract void release(); /** * Returns the underlying NIO buffer instance. */ public abstract java.nio.ByteBuffer buf(); /** * @see java.nio.ByteBuffer#isDirect() */ public abstract boolean isDirect(); /** * @see java.nio.ByteBuffer#isReadOnly() */ public abstract boolean isReadOnly(); /** * @see java.nio.ByteBuffer#capacity() */ public abstract int capacity(); /** * Changes the capacity of this buffer. */ public abstract ByteBuffer capacity(int newCapacity); /** * Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on. */ public abstract boolean isAutoExpand(); /** * Turns on or off <tt>autoExpand</tt>. */ public abstract ByteBuffer setAutoExpand(boolean autoExpand); /** * Changes the capacity and limit of this buffer so this buffer get * the specified <tt>expectedRemaining</tt> room from the current position. * This method works even if you didn't set <tt>autoExpand</tt> to * <tt>true</tt>. */ public ByteBuffer expand(int expectedRemaining) { return expand(position(), expectedRemaining); } /** * Changes the capacity and limit of this buffer so this buffer get * the specified <tt>expectedRemaining</tt> room from the specified * <tt>pos</tt>. * This method works even if you didn't set <tt>autoExpand</tt> to * <tt>true</tt>. */ public abstract ByteBuffer expand(int pos, int expectedRemaining); /** * Returns <tt>true</tt> if and only if this buffer is returned back * to the buffer pool when released. * <p> * The default value of this property is <tt>true</tt> if and only if you * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)}, * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)}, * and {@link #wrap(java.nio.ByteBuffer)}) */ public abstract boolean isPooled(); /** * Sets whether this buffer is returned back to the buffer pool when released. * <p> * The default value of this property is <tt>true</tt> if and only if you * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)}, * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)}, * and {@link #wrap(java.nio.ByteBuffer)}) */ public abstract void setPooled(boolean pooled); /** * @see java.nio.Buffer#position() */ public abstract int position(); /** * @see java.nio.Buffer#position(int) */ public abstract ByteBuffer position(int newPosition); /** * @see java.nio.Buffer#limit() */ public abstract int limit(); /** * @see java.nio.Buffer#limit(int) */ public abstract ByteBuffer limit(int newLimit); /** * @see java.nio.Buffer#mark() */ public abstract ByteBuffer mark(); /** * Returns the position of the current mark. This method returns <tt>-1</tt> if no * mark is set. */ public abstract int markValue(); /** * @see java.nio.Buffer#reset() */ public abstract ByteBuffer reset(); /** * @see java.nio.Buffer#clear() */ public abstract ByteBuffer clear(); /** * Clears this buffer and fills its content with <tt>NUL</tt>. * The position is set to zero, the limit is set to the capacity, * and the mark is discarded. */ public ByteBuffer sweep() { clear(); return fillAndReset(remaining()); } /** * Clears this buffer and fills its content with <tt>value</tt>. * The position is set to zero, the limit is set to the capacity, * and the mark is discarded. */ public ByteBuffer sweep(byte value) { clear(); return fillAndReset(value, remaining()); } /** * @see java.nio.Buffer#flip() */ public abstract ByteBuffer flip(); /** * @see java.nio.Buffer#rewind() */ public abstract ByteBuffer rewind(); /** * @see java.nio.Buffer#remaining() */ public int remaining() { return limit() - position(); } /** * @see java.nio.Buffer#hasRemaining() */ public boolean hasRemaining() { return remaining() > 0; } /** * @see java.nio.ByteBuffer#duplicate() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -