content: /*
   * 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.activemq.artemis.api.core;
  
  import java.io.DataInput;
  import java.nio.ByteBuffer;
  
  import io.netty.buffer.ByteBuf;
  
  /**
   * An ActiveMQBuffer wraps a Netty's ChannelBuffer and is used throughout ActiveMQ Artemis code base.
   * <p>
   * Instances of it can be obtained from {@link ActiveMQBuffers} factory.
   * <p>
   * Much of it derived from Netty ChannelBuffer by Trustin Lee
   *
   * @see ActiveMQBuffers
   */
  public interface ActiveMQBuffer extends DataInput {
  
     /**
      * {@return the underlying Netty's ByteBuf}
      */
     ByteBuf byteBuf();
  
     /**
      * {@return the number of bytes this buffer can contain}
      */
     int capacity();
  
     /**
      * {@return the {@code readerIndex} of this buffer.}
      */
     int readerIndex();
  
     /**
      * Sets the {@code readerIndex} of this buffer.
      *
      * @param readerIndex The reader's index
      * @throws IndexOutOfBoundsException if the specified {@code readerIndex} is less than {@code 0} or greater than
      *                                   {@code this.writerIndex}
      */
     void readerIndex(int readerIndex);
  
     /**
      * {@return the {@code writerIndex} of this buffer.}
      */
     int writerIndex();
  
     /**
      * Sets the {@code writerIndex} of this buffer.
      *
      * @param writerIndex The writer's index
      * @throws IndexOutOfBoundsException if the specified {@code writerIndex} is less than {@code this.readerIndex} or
      *                                   greater than {@code this.capacity}
      */
     void writerIndex(int writerIndex);
  
     /**
      * Sets the {@code readerIndex} and {@code writerIndex} of this buffer in one shot.  This method is useful when you
      * have to worry about the invocation order of {@link #readerIndex(int)} and {@link #writerIndex(int)} methods.  For
      * example, the following code will fail:
      *
      * <pre>
      * // Create a buffer whose readerIndex, writerIndex and capacity are
      * // 0, 0 and 8 respectively.
      * ChannelBuffer buf = ChannelBuffers.buffer(8);
      *
      * // IndexOutOfBoundsException is thrown because the specified
      * // readerIndex (2) cannot be greater than the current writerIndex (0).
      * buf.readerIndex(2);
      * buf.writerIndex(4);
      * </pre>
      * <p>
      * The following code will also fail:
      *
      * <pre>
      * // Create a buffer whose readerIndex, writerIndex and capacity are
      * // 0, 8 and 8 respectively.
      * ChannelBuffer buf = ChannelBuffers.wrappedBuffer(new byte[8]);
      *
      * // readerIndex becomes 8.
      * buf.readLong();
      *
      * // IndexOutOfBoundsException is thrown because the specified
      * // writerIndex (4) cannot be less than the current readerIndex (8).
      * buf.writerIndex(4);
      * buf.readerIndex(2);
      * </pre>
      * <p>
      * By contrast, {@link #setIndex(int, int)} guarantees that it never throws an {@link IndexOutOfBoundsException} as
      * long as the specified indexes meet basic constraints, regardless what the current index values of the buffer are:
      *
      * <pre>
      * // No matter what the current state of the buffer is, the following
      * // call always succeeds as long as the capacity of the buffer is not
      * // less than 4.
      * buf.setIndex(2, 4);
      * </pre>
      *
      * @param readerIndex The reader's index
      * @param writerIndex The writer's index
      * @throws IndexOutOfBoundsException if the specified {@code readerIndex} is less than 0, if the specified
      *                                   {@code writerIndex} is less than the specified {@code readerIndex} or if the
      *                                   specified {@code writerIndex} is greater than {@code this.capacity}
      */
     void setIndex(int readerIndex, int writerIndex);
  
     /**
      * {@return the number of readable bytes which is equal to {@code (this.writerIndex - this.readerIndex)}}
      */
     int readableBytes();
  
     /**
      * {@return the number of writable bytes which is equal to {@code (this.capacity - this.writerIndex)}}
      */
     int writableBytes();
  
     /**
      * {@return {@code true} if and only if {@code (this.writerIndex - this.readerIndex)} is greater than {@code 0}}
      */
     boolean readable();
  
     /**
      * {@return {@code true}if and only if {@code (this.capacity - this.writerIndex)} is greater than {@code 0}}
      */
     boolean writable();
  
     /**
      * Sets the {@code readerIndex} and {@code writerIndex} of this buffer to {@code 0}. This method is identical to
      * {@link #setIndex(int, int) setIndex(0, 0)}.
      * <p>
      * Please note that the behavior of this method is different from that of NIO buffer, which sets the {@code limit} to
      * the {@code capacity} of the buffer.
      */
     void clear();
  
     /**
      * Marks the current {@code readerIndex} in this buffer.  You can reposition the current {@code readerIndex} to the
      * marked {@code readerIndex} by calling {@link #resetReaderIndex()}. The initial value of the marked
      * {@code readerIndex} is {@code 0}.
      */
     void markReaderIndex();
  
     /**
      * Repositions the current {@code readerIndex} to the marked {@code readerIndex} in this buffer.
      *
      * @throws IndexOutOfBoundsException if the current {@code writerIndex} is less than the marked {@code readerIndex}
      */
     void resetReaderIndex();
  
     /**
      * Marks the current {@code writerIndex} in this buffer.  You can reposition the current {@code writerIndex} to the
      * marked {@code writerIndex} by calling {@link #resetWriterIndex()}. The initial value of the marked
      * {@code writerIndex} is {@code 0}.
      */
     void markWriterIndex();
  
     /**
      * Repositions the current {@code writerIndex} to the marked {@code writerIndex} in this buffer.
      *
      * @throws IndexOutOfBoundsException if the current {@code readerIndex} is greater than the marked
      *                                   {@code writerIndex}
      */
     void resetWriterIndex();
  
     /**
      * Discards the bytes between the 0th index and {@code readerIndex}. It moves the bytes between {@code readerIndex}
      * and {@code writerIndex} to the 0th index, and sets {@code readerIndex} and {@code writerIndex} to {@code 0} and
      * {@code oldWriterIndex - oldReaderIndex} respectively.
      * <p>
      * Please refer to the class documentation for more detailed explanation.
      */
     void discardReadBytes();
  
     /**
      * Gets a byte at the specified absolute {@code index} in this buffer. This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return The byte at the specified index
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 1} is
      *                                   greater than {@code this.capacity}
      */
     byte getByte(int index);
  
     /**
      * Gets an unsigned byte at the specified absolute {@code index} in this buffer.  This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return an unsigned byte at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 1} is
      *                                   greater than {@code this.capacity}
      */
     short getUnsignedByte(int index);
  
     /**
      * Gets a 16-bit short integer at the specified absolute {@code index} in this buffer.  This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return a 16-bit short integer at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 2} is
      *                                   greater than {@code this.capacity}
      */
     short getShort(int index);
  
     /**
      * Gets an unsigned 16-bit short integer at the specified absolute {@code index} in this buffer.  This method does
      * not modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return an unsigned 16-bit short integer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 2} is
      *                                   greater than {@code this.capacity}
      */
     int getUnsignedShort(int index);
  
     /**
      * Gets a 32-bit integer at the specified absolute {@code index} in this buffer.  This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return a 32-bit integer at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 4} is
      *                                   greater than {@code this.capacity}
      */
     int getInt(int index);
  
     /**
      * Gets an unsigned 32-bit integer at the specified absolute {@code index} in this buffer.  This method does not
      * modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index The index into this buffer
      * @return an unsigned 32-bit integer at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 4} is
      *                                   greater than {@code this.capacity}
      */
     long getUnsignedInt(int index);
  
     /**
      * Gets a 64-bit long integer at the specified absolute {@code index} in this buffer.  This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return a 64-bit long integer at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 8} is
      *                                   greater than {@code this.capacity}
      */
     long getLong(int index);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the specified absolute {@code index} until
      * the destination becomes non-writable.  This method is basically same with
      * {@link #getBytes(int, ActiveMQBuffer, int, int)}, except that this method increases the {@code writerIndex} of the
      * destination by the number of the transferred bytes while {@link #getBytes(int, ActiveMQBuffer, int, int)} does
      * not. This method does not modify {@code readerIndex} or {@code writerIndex} of the source buffer (i.e.
      * {@code this}).
      *
      * @param index Index into the buffer
      * @param dst   The destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or if
      *                                   {@code index + dst.writableBytes} is greater than {@code this.capacity}
      */
     void getBytes(int index, ActiveMQBuffer dst);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the specified absolute {@code index}.  This
      * method is basically same with {@link #getBytes(int, ActiveMQBuffer, int, int)}, except that this method increases
      * the {@code writerIndex} of the destination by the number of the transferred bytes while
      * {@link #getBytes(int, ActiveMQBuffer, int, int)} does not. This method does not modify {@code readerIndex} or
      * {@code writerIndex} of the source buffer (i.e. {@code this}).
      *
      * @param length the number of bytes to transfer
      * @param index  Index into the buffer
      * @param dst    The destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, if {@code index + length}
      *                                   is greater than {@code this.capacity}, or if {@code length} is greater than
      *                                   {@code dst.writableBytes}
      */
     void getBytes(int index, ActiveMQBuffer dst, int length);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the specified absolute {@code index}. This
      * method does not modify {@code readerIndex} or {@code writerIndex} of both the source (i.e. {@code this}) and the
      * destination.
      *
      * @param dst      The destination bufferIndex the first index of the destination
      * @param length   The number of bytes to transfer
      * @param index    Index into the buffer
      * @param dstIndex The index into the destination bufferThe destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, if the specified
      *                                   {@code dstIndex} is less than {@code 0}, if {@code index + length} is greater
      *                                   than {@code this.capacity}, or if {@code dstIndex + length} is greater than
      *                                   {@code dst.capacity}
      */
     void getBytes(int index, ActiveMQBuffer dst, int dstIndex, int length);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the specified absolute {@code index}. This
      * method does not modify {@code readerIndex} or {@code writerIndex} of this buffer
      *
      * @param index Index into the buffer
      * @param dst   The destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or if
      *                                   {@code index + dst.length} is greater than {@code this.capacity}
      */
     void getBytes(int index, byte[] dst);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the specified absolute {@code index}. This
      * method does not modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param dstIndex The first index of the destination
      * @param length   The number of bytes to transfer
      * @param index    Index into the buffer
      * @param dst      The destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, if the specified
      *                                   {@code dstIndex} is less than {@code 0}, if {@code index + length} is greater
      *                                   than {@code this.capacity}, or if {@code dstIndex + length} is greater than
      *                                   {@code dst.length}
      */
     void getBytes(int index, byte[] dst, int dstIndex, int length);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the specified absolute {@code index} until
      * the destination's position reaches its limit. This method does not modify {@code readerIndex} or
      * {@code writerIndex} of this buffer while the destination's {@code position} will be increased.
      *
      * @param index Index into the buffer
      * @param dst   The destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or if
      *                                   {@code index + dst.remaining()} is greater than {@code this.capacity}
      */
     void getBytes(int index, ByteBuffer dst);
  
     /**
      * Gets a char at the specified absolute {@code index} in this buffer.  This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return a char at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 2} is
      *                                   greater than {@code this.capacity}
      */
     char getChar(int index);
  
     /**
      * Gets a float at the specified absolute {@code index} in this buffer.  This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return a float at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 4} is
      *                                   greater than {@code this.capacity}
      */
     float getFloat(int index);
  
     /**
      * Gets a double at the specified absolute {@code index} in this buffer.  This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @return a double at the specified absolute {@code index}
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 8} is
      *                                   greater than {@code this.capacity}
      */
     double getDouble(int index);
  
     /**
      * Sets the specified byte at the specified absolute {@code index} in this buffer. This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param value The specified byte
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 1} is
      *                                   greater than {@code this.capacity}
      */
     void setByte(int index, byte value);
  
     /**
      * Sets the specified 16-bit short integer at the specified absolute {@code index} in this buffer. This method does
      * not modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param value The specified 16-bit short integer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 2} is
      *                                   greater than {@code this.capacity}
      */
     void setShort(int index, short value);
  
     /**
      * Sets the specified 32-bit integer at the specified absolute {@code index} in this buffer. This method does not
      * modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param value The specified 32-bit integer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 4} is
      *                                   greater than {@code this.capacity}
      */
     void setInt(int index, int value);
  
     /**
      * Sets the specified 64-bit long integer at the specified absolute {@code index} in this buffer. This method does
      * not modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param value The specified 64-bit long integer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 8} is
      *                                   greater than {@code this.capacity}
      */
     void setLong(int index, long value);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the specified absolute {@code index} until
      * the destination becomes unreadable.  This method is basically same with
      * {@link #setBytes(int, ActiveMQBuffer, int, int)}, except that this method increases the {@code readerIndex} of the
      * source buffer by the number of the transferred bytes while {@link #getBytes(int, ActiveMQBuffer, int, int)} does
      * not. This method does not modify {@code readerIndex} or {@code writerIndex} of the source buffer (i.e.
      * {@code this}).
      *
      * @param index Index into the buffer
      * @param src   The source buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or if
      *                                   {@code index + src.readableBytes} is greater than {@code this.capacity}
      */
     void setBytes(int index, ActiveMQBuffer src);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the specified absolute {@code index}. This
      * method is basically same with {@link #setBytes(int, ActiveMQBuffer, int, int)}, except that this method increases
      * the {@code readerIndex} of the source buffer by the number of the transferred bytes while
      * {@link #getBytes(int, ActiveMQBuffer, int, int)} does not. This method does not modify {@code readerIndex} or
      * {@code writerIndex} of the source buffer (i.e. {@code this}).
      *
      * @param length the number of bytes to transfer
      * @param index  Index into the buffer
      * @param src    The source buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, if {@code index + length}
      *                                   is greater than {@code this.capacity}, or if {@code length} is greater than
      *                                   {@code src.readableBytes}
      */
     void setBytes(int index, ActiveMQBuffer src, int length);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the specified absolute {@code index}. This
      * method does not modify {@code readerIndex} or {@code writerIndex} of both the source (i.e. {@code this}) and the
      * destination.
      *
      * @param src      The source bufferIndex the first index of the source
      * @param length   The number of bytes to transfer
      * @param index    Index into the buffer
      * @param srcIndex The source buffer index
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, if the specified
      *                                   {@code srcIndex} is less than {@code 0}, if {@code index + length} is greater
      *                                   than {@code this.capacity}, or if {@code srcIndex + length} is greater than
      *                                   {@code src.capacity}
      */
     void setBytes(int index, ActiveMQBuffer src, int srcIndex, int length);
  
     /**
      * Transfers the specified source array's data to this buffer starting at the specified absolute {@code index}. This
      * method does not modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param src   The source buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or if
      *                                   {@code index + src.length} is greater than {@code this.capacity}
      */
     void setBytes(int index, byte[] src);
  
     /**
      * Transfers the specified source array's data to this buffer starting at the specified absolute {@code index}. This
      * method does not modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index    Index into the buffer
      * @param src      The source buffer
      * @param srcIndex The source buffer index
      * @param length   The number of bytes to transfer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0}, if the specified
      *                                   {@code srcIndex} is less than {@code 0}, if {@code index + length} is greater
      *                                   than {@code this.capacity}, or if {@code srcIndex + length} is greater than
      *                                   {@code src.length}
      */
     void setBytes(int index, byte[] src, int srcIndex, int length);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the specified absolute {@code index} until
      * the source buffer's position reaches its limit. This method does not modify {@code readerIndex} or
      * {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param src   The source buffer
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or if
      *                                   {@code index + src.remaining()} is greater than {@code this.capacity}
      */
     void setBytes(int index, ByteBuffer src);
  
     /**
      * Sets the specified char at the specified absolute {@code index} in this buffer. This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param value The specified char
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 2} is
      *                                   greater than {@code this.capacity}
      */
     void setChar(int index, char value);
  
     /**
      * Sets the specified float at the specified absolute {@code index} in this buffer. This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param value The specified float
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 4} is
      *                                   greater than {@code this.capacity}
      */
     void setFloat(int index, float value);
  
     /**
      * Sets the specified double at the specified absolute {@code index} in this buffer. This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index Index into the buffer
      * @param value The specified double
      * @throws IndexOutOfBoundsException if the specified {@code index} is less than {@code 0} or {@code index + 8} is
      *                                   greater than {@code this.capacity}
      */
     void setDouble(int index, double value);
  
     /**
      * Gets a byte at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 1} in this buffer.
      *
      * @return a byte at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 1}
      */
     @Override
     byte readByte();
  
     /**
      * Gets an unsigned byte at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 1} in
      * this buffer.
      *
      * @return an unsigned byte at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 1}
      */
     @Override
     int readUnsignedByte();
  
     /**
      * Gets a 16-bit short integer at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 2}
      * in this buffer.
      *
      * @return a 16-bit short integer at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 2}
      */
     @Override
     short readShort();
  
     /**
      * Gets an unsigned 16-bit short integer at the current {@code readerIndex} and increases the {@code readerIndex} by
      * {@code 2} in this buffer.
      *
      * @return an unsigned 16-bit short integer at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 2}
      */
     @Override
     int readUnsignedShort();
  
     /**
      * Gets a 32-bit integer at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 4} in
      * this buffer.
      *
      * @return a 32-bit integer at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 4}
      */
     @Override
     int readInt();
  
     /**
      * Gets a (potentially {@code null}) 32-bit integer at the current {@code readerIndex} and increases the
      * {@code readerIndex} by {@code 4} in this buffer.
      *
      * @return a (potentially {@code null}) 32-bit integer at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 4}
      */
     Integer readNullableInt();
  
     /**
      * Gets an unsigned 32-bit integer at the current {@code readerIndex} and increases the {@code readerIndex} by
      * {@code 4} in this buffer.
      *
      * @return an unsigned 32-bit integer at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 4}
      */
     long readUnsignedInt();
  
     /**
      * Gets a 64-bit integer at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 8} in
      * this buffer.
      *
      * @return a 64-bit integer at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 8}
      */
     @Override
     long readLong();
  
     /**
      * Gets a (potentially {@code null}) 64-bit integer at the current {@code readerIndex} and increases the
      * {@code readerIndex} by {@code 8} in this buffer.
      *
      * @return a (potentially {@code null}) 64-bit integer at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 8}
      */
     Long readNullableLong();
  
     /**
      * Gets a char at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 2} in this buffer.
      *
      * @return a char at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 2}
      */
     @Override
     char readChar();
  
     /**
      * Gets a float at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 4} in this
      * buffer.
      *
      * @return a float at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 4}
      */
     @Override
     float readFloat();
  
     /**
      * Gets a double at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 8} in this
      * buffer.
      *
      * @return a double at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 8}
      */
     @Override
     double readDouble();
  
     /**
      * Gets a boolean at the current {@code readerIndex} and increases the {@code readerIndex} by {@code 1} in this
      * buffer.
      *
      * @return a boolean at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 1}
      */
     @Override
     boolean readBoolean();
  
     /**
      * Gets a (potentially {@code null}) boolean at the current {@code readerIndex} and increases the {@code readerIndex}
      * by {@code 1} in this buffer.
      *
      * @return a (potentially {@code null}) boolean at the current {@code readerIndex}
      * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less than {@code 1}
      */
     Boolean readNullableBoolean();
  
     /**
      * Gets a SimpleString (potentially {@code null}) at the current {@code readerIndex}
      *
      * @return a SimpleString (potentially {@code null}) at the current {@code readerIndex}
      */
     SimpleString readNullableSimpleString();
  
     /**
      * Gets a String (potentially {@code null}) at the current {@code readerIndex}
      *
      * @return a String (potentially {@code null}) at the current {@code readerIndex}
      */
     String readNullableString();
  
     /**
      * Gets a non-null SimpleString at the current {@code readerIndex}
      *
      * @return a non-null SimpleString at the current {@code readerIndex}
      */
     SimpleString readSimpleString();
  
     /**
      * Gets a non-null String at the current {@code readerIndex}
      *
      * @return a non-null String at the current {@code readerIndex}
      */
     String readString();
  
     /**
      * Gets a UTF-8 String at the current {@code readerIndex}
      *
      * @return a UTF-8 String at the current {@code readerIndex}
      */
     @Override
     String readUTF();
  
     /**
      * Returns a new slice of this buffer's sub-region starting at the current {@code readerIndex} and increases the
      * {@code readerIndex} by the size of the new slice (= {@code length}).
      *
      * @param length the size of the new slice
      * @return the newly created slice
      * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.readableBytes}
      */
     ActiveMQBuffer readSlice(int length);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the current {@code readerIndex} until the
      * destination becomes non-writable, and increases the {@code readerIndex} by the number of the transferred bytes.
      * This method is basically same with {@link #readBytes(ActiveMQBuffer, int, int)}, except that this method increases
      * the {@code writerIndex} of the destination by the number of the transferred bytes while
      * {@link #readBytes(ActiveMQBuffer, int, int)} does not.
      *
      * @param dst The destination buffer
      * @throws IndexOutOfBoundsException if {@code dst.writableBytes} is greater than {@code this.readableBytes}
      */
     void readBytes(ActiveMQBuffer dst);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the current {@code readerIndex} and
      * increases the {@code readerIndex} by the number of the transferred bytes (= {@code length}).  This method is
      * basically same with {@link #readBytes(ActiveMQBuffer, int, int)}, except that this method increases the
      * {@code writerIndex} of the destination by the number of the transferred bytes (= {@code length}) while
      * {@link #readBytes(ActiveMQBuffer, int, int)} does not.
      *
      * @param dst    The destination buffer
      * @param length The number of bytes to transfer
      * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.readableBytes} or if
      *                                   {@code length} is greater than {@code dst.writableBytes}
      */
     void readBytes(ActiveMQBuffer dst, int length);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the current {@code readerIndex} and
      * increases the {@code readerIndex} by the number of the transferred bytes (= {@code length}).
      *
      * @param dstIndex The destination buffer index
      * @param length   the number of bytes to transfer
      * @param dst      The destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code dstIndex} is less than {@code 0}, if {@code length} is
      *                                   greater than {@code this.readableBytes}, or if {@code dstIndex + length} is
      *                                   greater than {@code dst.capacity}
      */
     void readBytes(ActiveMQBuffer dst, int dstIndex, int length);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the current {@code readerIndex} and
      * increases the {@code readerIndex} by the number of the transferred bytes (= {@code dst.length}).
      *
      * @param dst The destination buffer
      * @throws IndexOutOfBoundsException if {@code dst.length} is greater than {@code this.readableBytes}
      */
     void readBytes(byte[] dst);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the current {@code readerIndex} and
      * increases the {@code readerIndex} by the number of the transferred bytes (= {@code length}).
      *
      * @param dstIndex The destination bufferIndex
      * @param length   the number of bytes to transfer
      * @param dst      The destination buffer
      * @throws IndexOutOfBoundsException if the specified {@code dstIndex} is less than {@code 0}, if {@code length} is
      *                                   greater than {@code this.readableBytes}, or if {@code dstIndex + length} is
      *                                   greater than {@code dst.length}
      */
     void readBytes(byte[] dst, int dstIndex, int length);
  
     /**
      * Transfers this buffer's data to the specified destination starting at the current {@code readerIndex} until the
      * destination's position reaches its limit, and increases the {@code readerIndex} by the number of the transferred
      * bytes.
      *
      * @param dst The destination buffer
      * @throws IndexOutOfBoundsException if {@code dst.remaining()} is greater than {@code this.readableBytes}
      */
     void readBytes(ByteBuffer dst);
  
     /**
      * Increases the current {@code readerIndex} by the specified {@code length} in this buffer.
      *
      * @param length The number of bytes to skip
      * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.readableBytes}
      */
     @Override
     int skipBytes(int length);
  
     /**
      * Sets the specified byte at the current {@code writerIndex} and increases the {@code writerIndex} by {@code 1} in
      * this buffer.
      *
      * @param value The specified byte
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 1}
      */
     void writeByte(byte value);
  
     /**
      * Sets the specified 16-bit short integer at the current {@code writerIndex} and increases the {@code writerIndex}
      * by {@code 2} in this buffer.
      *
      * @param value The specified 16-bit short integer
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 2}
      */
     void writeShort(short value);
  
     /**
      * Sets the specified 32-bit integer at the current {@code writerIndex} and increases the {@code writerIndex} by
      * {@code 4} in this buffer.
      *
      * @param value The specified 32-bit integer
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 4}
      */
     void writeInt(int value);
  
     /**
      * Sets the specified (potentially {@code null}) 32-bit integer at the current {@code writerIndex} and increases the
      * {@code writerIndex} by {@code 4} in this buffer.
      *
      * @param value The specified (potentially {@code null}) 32-bit integer
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 4}
      */
     void writeNullableInt(Integer value);
  
     /**
      * Sets the specified 64-bit long integer at the current {@code writerIndex} and increases the {@code writerIndex} by
      * {@code 8} in this buffer.
      *
      * @param value The specified 64-bit long integer
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 8}
      */
     void writeLong(long value);
  
     /**
      * Sets the specified (potentially {@code null}) 64-bit long integer at the current {@code writerIndex} and increases
      * the {@code writerIndex} by {@code 8} in this buffer.
      *
      * @param value The specified (potentially {@code null}) 64-bit long integer
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 8}
      */
     void writeNullableLong(Long value);
  
     /**
      * Sets the specified char at the current {@code writerIndex} and increases the {@code writerIndex} by {@code 2} in
      * this buffer.
      *
      * @param chr The specified char
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 2}
      */
     void writeChar(char chr);
  
     /**
      * Sets the specified float at the current {@code writerIndex} and increases the {@code writerIndex} by {@code 4} in
      * this buffer.
      *
      * @param value The specified float
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 4}
      */
     void writeFloat(float value);
  
     /**
      * Sets the specified double at the current {@code writerIndex} and increases the {@code writerIndex} by {@code 8} in
      * this buffer.
      *
      * @param value The specified double
      * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less than {@code 8}
      */
     void writeDouble(double value);
  
     /**
      * Sets the specified boolean at the current {@code writerIndex}
      *
      * @param val The specified boolean
      */
     void writeBoolean(boolean val);
  
     /**
      * Sets the specified (potentially {@code null}) Boolean at the current {@code writerIndex}
      *
      * @param val The specified boolean
      */
     void writeNullableBoolean(Boolean val);
  
     /**
      * Sets the specified SimpleString (potentially {@code null}) at the current {@code writerIndex}
      *
      * @param val The specified SimpleString
      */
     void writeNullableSimpleString(SimpleString val);
  
     /**
      * Sets the specified String (potentially {@code null}) at the current {@code writerIndex}
      *
      * @param val The specified String
      */
     void writeNullableString(String val);
  
     /**
      * Sets the specified non-null SimpleString at the current {@code writerIndex}
      *
      * @param val The specified non-null SimpleString
      */
     void writeSimpleString(SimpleString val);
  
     /**
      * Sets the specified non-null String at the current {@code writerIndex}
      *
      * @param val The specified non-null String
      */
     void writeString(String val);
  
     /**
      * Sets the specified UTF-8 String at the current {@code writerIndex}
      *
      * @param utf The specified UTF-8 String
      */
  
     void writeUTF(String utf);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the current {@code writerIndex} and
      * increases the {@code writerIndex} by the number of the transferred bytes (= {@code length}).  This method is
      * basically same with {@link #writeBytes(ActiveMQBuffer, int, int)}, except that this method increases the
      * {@code readerIndex} of the source buffer by the number of the transferred bytes (= {@code length}) while
      * {@link #writeBytes(ActiveMQBuffer, int, int)} does not.
      *
      * @param length the number of bytes to transfer
      * @param src    The source buffer
      * @throws IndexOutOfBoundsException if {@code length} is greater than {@code this.writableBytes} or if
      *                                   {@code length} is greater then {@code src.readableBytes}
      */
     void writeBytes(ActiveMQBuffer src, int length);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the current {@code writerIndex} and
      * increases the {@code writerIndex} by the number of the transferred bytes (= {@code length}).
      *
      * @param srcIndex the first index of the source
      * @param length   the number of bytes to transfer
      * @param src      The source buffer
      * @throws IndexOutOfBoundsException if the specified {@code srcIndex} is less than {@code 0}, if
      *                                   {@code srcIndex + length} is greater than {@code src.capacity}, or if
      *                                   {@code length} is greater than {@code this.writableBytes}
      */
     void writeBytes(ActiveMQBuffer src, int srcIndex, int length);
  
     /**
      * Transfers the specified source array's data to this buffer starting at the current {@code writerIndex} and
      * increases the {@code writerIndex} by the number of the transferred bytes (= {@code src.length}).
      *
      * @param src The source buffer
      * @throws IndexOutOfBoundsException if {@code src.length} is greater than {@code this.writableBytes}
      */
     void writeBytes(byte[] src);
  
     /**
      * Transfers the specified source array's data to this buffer starting at the current {@code writerIndex} and
      * increases the {@code writerIndex} by the number of the transferred bytes (= {@code length}).
      *
      * @param srcIndex the first index of the source
      * @param length   the number of bytes to transfer
      * @param src      The source buffer
      * @throws IndexOutOfBoundsException if the specified {@code srcIndex} is less than {@code 0}, if
      *                                   {@code srcIndex + length} is greater than {@code src.length}, or if
      *                                   {@code length} is greater than {@code this.writableBytes}
      */
     void writeBytes(byte[] src, int srcIndex, int length);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the current {@code writerIndex} until the
      * source buffer's position reaches its limit, and increases the {@code writerIndex} by the number of the transferred
      * bytes.
      *
      * @param src The source buffer
      * @throws IndexOutOfBoundsException if {@code src.remaining()} is greater than {@code this.writableBytes}
      */
     void writeBytes(ByteBuffer src);
  
     /**
      * Transfers the specified source buffer's data to this buffer starting at the current {@code writerIndex} until the
      * source buffer's position reaches its limit, and increases the {@code writerIndex} by the number of the transferred
      * bytes.
      *
      * @param src The source buffer
      * @throws IndexOutOfBoundsException if {@code src.remaining()} is greater than {@code this.writableBytes}
      */
     void writeBytes(ByteBuf src, int srcIndex, int length);
  
     /**
      * Returns a copy of this buffer's readable bytes.  Modifying the content of the returned buffer or this buffer does
      * not affect each other at all. This method is identical to
      * {@code buf.copy(buf.readerIndex(), buf.readableBytes())}. This method does not modify {@code readerIndex} or
      * {@code writerIndex} of this buffer.
      *
      * @return a copy of this buffer's readable bytes
      */
     ActiveMQBuffer copy();
  
     /**
      * Returns a copy of this buffer's sub-region.  Modifying the content of the returned buffer or this buffer does not
      * affect each other at all. This method does not modify {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index  Index into the buffer
      * @param length The number of bytes to copy
      * @return a copy of this buffer's readable bytes
      */
     ActiveMQBuffer copy(int index, int length);
  
     /**
      * Returns a slice of this buffer's readable bytes. Modifying the content of the returned buffer or this buffer
      * affects each other's content while they maintain separate indexes and marks.  This method is identical to
      * {@code buf.slice(buf.readerIndex(), buf.readableBytes())}. This method does not modify {@code readerIndex} or
      * {@code writerIndex} of this buffer.
      *
      * @return a slice of this buffer's readable bytes
      */
     ActiveMQBuffer slice();
  
     /**
      * Returns a slice of this buffer's sub-region. Modifying the content of the returned buffer or this buffer affects
      * each other's content while they maintain separate indexes and marks. This method does not modify
      * {@code readerIndex} or {@code writerIndex} of this buffer.
      *
      * @param index  Index into the buffer
      * @param length The number of bytes
      * @return a slice of this buffer's sub-region
      */
     ActiveMQBuffer slice(int index, int length);
  
     /**
      * Returns a buffer which shares the whole region of this buffer. Modifying the content of the returned buffer or
      * this buffer affects each other's content while they maintain separate indexes and marks. This method is identical
      * to {@code buf.slice(0, buf.capacity())}. This method does not modify {@code readerIndex} or {@code writerIndex} of
      * this buffer.
      *
      * @return a buffer which shares the whole region of this buffer
      */
     ActiveMQBuffer duplicate();
  
     /**
      * Converts this buffer's readable bytes into a NIO buffer.  The returned buffer might or might not share the content
      * with this buffer, while they have separate indexes and marks.  This method is identical to
      * {@code buf.toByteBuffer(buf.readerIndex(), buf.readableBytes())}. This method does not modify {@code readerIndex}
      * or {@code writerIndex} of this buffer.
      *
      * @return A converted NIO ByteBuffer
      */
     ByteBuffer toByteBuffer();
  
     /**
      * Converts this buffer's sub-region into a NIO buffer.  The returned buffer might or might not share the content
      * with this buffer, while they have separate indexes and marks. This method does not modify {@code readerIndex} or
      * {@code writerIndex} of this buffer.
      *
      * @param index  Index into the buffer
      * @param length The number of bytes
      * @return A converted NIO Buffer
      */
     ByteBuffer toByteBuffer(int index, int length);
  
     /**
      * Release any underlying resources held by this buffer
      */
     void release();
  
  }
  