View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.buffer;
    17
    18  import java.io.IOException;
    19  import java.io.InputStream;
    20  import java.io.OutputStream;
    21  import java.nio.ByteBuffer;
    22  import java.nio.ByteOrder;
    23  import java.nio.channels.GatheringByteChannel;
    24  import java.nio.channels.ScatteringByteChannel;
    25
    26
    27  /**
    28   * A dynamic capacity buffer which increases its capacity as needed.  It is
    29   * recommended to use {@link ChannelBuffers#dynamicBuffer(int)} instead of
    30   * calling the constructor explicitly.
    31   */
    32  public class DynamicChannelBuffer extends AbstractChannelBuffer {
    33
    34      private final ChannelBufferFactory factory;
    35      private final ByteOrder endianness;
    36      private ChannelBuffer buffer;
    37
    38      public DynamicChannelBuffer(int estimatedLength) {
    39          this(ByteOrder.BIG_ENDIAN, estimatedLength);
    40      }
    41
    42      public DynamicChannelBuffer(ByteOrder endianness, int estimatedLength) {
    43          this(endianness, estimatedLength, HeapChannelBufferFactory.getInstance(endianness));
    44      }
    45
    46      public DynamicChannelBuffer(ByteOrder endianness, int estimatedLength, ChannelBufferFactory factory) {
    47          if (estimatedLength < 0) {
    48              throw new IllegalArgumentException("estimatedLength: " + estimatedLength);
    49          }
    50          if (endianness == null) {
    51              throw new NullPointerException("endianness");
    52          }
    53          if (factory == null) {
    54              throw new NullPointerException("factory");
    55          }
    56          this.factory = factory;
    57          this.endianness = endianness;
    58          buffer = factory.getBuffer(order(), estimatedLength);
    59      }
    60
    61      @Override
    62      public void ensureWritableBytes(int minWritableBytes) {
    63          if (minWritableBytes <= writableBytes()) {
    64              return;
    65          }
    66
    67          int newCapacity;
    68          if (capacity() == 0) {
    69              newCapacity = 1;
    70          } else {
    71              newCapacity = capacity();
    72          }
    73          int minNewCapacity = writerIndex() + minWritableBytes;
    74          while (newCapacity < minNewCapacity) {
    75              newCapacity <<= 1;
    76
    77              // Check if we exceeded the maximum size of 2gb if this is the case then
    78              // newCapacity == 0
    79              //
    80              // https://github.com/netty/netty/issues/258
    81              if (newCapacity == 0) {
    82                  throw new IllegalStateException("Maximum size of 2gb exceeded");
    83              }
    84          }
    85
    86          ChannelBuffer newBuffer = factory().getBuffer(order(), newCapacity);
    87          newBuffer.writeBytes(buffer, 0, writerIndex());
    88          buffer = newBuffer;
    89      }
    90
    91      public ChannelBufferFactory factory() {
    92          return factory;
    93      }
    94
    95      public ByteOrder order() {
    96          return endianness;
    97      }
    98
    99      public boolean isDirect() {
    100         return buffer.isDirect();
    101     }
    102
    103     public int capacity() {
    104         return buffer.capacity();
    105     }
    106
    107     public boolean hasArray() {
    108         return buffer.hasArray();
    109     }
    110
    111     public byte[] array() {
    112         return buffer.array();
    113     }
    114
    115     public int arrayOffset() {
    116         return buffer.arrayOffset();
    117     }
    118
    119     public byte getByte(int index) {
    120         return buffer.getByte(index);
    121     }
    122
    123     public short getShort(int index) {
    124         return buffer.getShort(index);
    125     }
    126
    127     public int getUnsignedMedium(int index) {
    128         return buffer.getUnsignedMedium(index);
    129     }
    130
    131     public int getInt(int index) {
    132         return buffer.getInt(index);
    133     }
    134
    135     public long getLong(int index) {
    136         return buffer.getLong(index);
    137     }
    138
    139     public void getBytes(int index, byte[] dst, int dstIndex, int length) {
    140         buffer.getBytes(index, dst, dstIndex, length);
    141     }
    142
    143     public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
    144         buffer.getBytes(index, dst, dstIndex, length);
    145     }
    146
    147     public void getBytes(int index, ByteBuffer dst) {
    148         buffer.getBytes(index, dst);
    149     }
    150
    151     public int getBytes(int index, GatheringByteChannel out, int length)
    152             throws IOException {
    153         return buffer.getBytes(index, out, length);
    154     }
    155
    156     public void getBytes(int index, OutputStream out, int length)
    157             throws IOException {
    158         buffer.getBytes(index, out, length);
    159     }
    160
    161     public void setByte(int index, int value) {
    162         buffer.setByte(index, value);
    163     }
    164
    165     public void setShort(int index, int value) {
    166         buffer.setShort(index, value);
    167     }
    168
    169     public void setMedium(int index, int value) {
    170         buffer.setMedium(index, value);
    171     }
    172
    173     public void setInt(int index, int value) {
    174         buffer.setInt(index, value);
    175     }
    176
    177     public void setLong(int index, long value) {
    178         buffer.setLong(index, value);
    179     }
    180
    181     public void setBytes(int index, byte[] src, int srcIndex, int length) {
    182         buffer.setBytes(index, src, srcIndex, length);
    183     }
    184
    185     public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
    186         buffer.setBytes(index, src, srcIndex, length);
    187     }
    188
    189     public void setBytes(int index, ByteBuffer src) {
    190         buffer.setBytes(index, src);
    191     }
    192
    193     public int setBytes(int index, InputStream in, int length)
    194             throws IOException {
    195         return buffer.setBytes(index, in, length);
    196     }
    197
    198     public int setBytes(int index, ScatteringByteChannel in, int length)
    199             throws IOException {
    200         return buffer.setBytes(index, in, length);
    201     }
    202
    203     @Override
    204     public void writeByte(int value) {
    205         ensureWritableBytes(1);
    206         super.writeByte(value);
    207     }
    208
    209     @Override
    210     public void writeShort(int value) {
    211         ensureWritableBytes(2);
    212         super.writeShort(value);
    213     }
    214
    215     @Override
    216     public void writeMedium(int value) {
    217         ensureWritableBytes(3);
    218         super.writeMedium(value);
    219     }
    220
    221     @Override
    222     public void writeInt(int value) {
    223         ensureWritableBytes(4);
    224         super.writeInt(value);
    225     }
    226
    227     @Override
    228     public void writeLong(long value) {
    229         ensureWritableBytes(8);
    230         super.writeLong(value);
    231     }
    232
    233     @Override
    234     public void writeBytes(byte[] src, int srcIndex, int length) {
    235         ensureWritableBytes(length);
    236         super.writeBytes(src, srcIndex, length);
    237     }
    238
    239     @Override
    240     public void writeBytes(ChannelBuffer src, int srcIndex, int length) {
    241         ensureWritableBytes(length);
    242         super.writeBytes(src, srcIndex, length);
    243     }
    244
    245     @Override
    246     public void writeBytes(ByteBuffer src) {
    247         ensureWritableBytes(src.remaining());
    248         super.writeBytes(src);
    249     }
    250
    251     @Override
    252     public int writeBytes(InputStream in, int length) throws IOException {
    253         ensureWritableBytes(length);
    254         return super.writeBytes(in, length);
    255     }
    256
    257     @Override
    258     public int writeBytes(ScatteringByteChannel in, int length)
    259             throws IOException {
    260         ensureWritableBytes(length);
    261         return super.writeBytes(in, length);
    262     }
    263
    264     @Override
    265     public void writeZero(int length) {
    266         ensureWritableBytes(length);
    267         super.writeZero(length);
    268     }
    269
    270     public ChannelBuffer duplicate() {
    271         return new DuplicatedChannelBuffer(this);
    272     }
    273
    274     public ChannelBuffer copy(int index, int length) {
    275         DynamicChannelBuffer copiedBuffer = new DynamicChannelBuffer(order(), Math.max(length, 64), factory());
    276         copiedBuffer.buffer = buffer.copy(index, length);
    277         copiedBuffer.setIndex(0, length);
    278         return copiedBuffer;
    279     }
    280
    281     public ChannelBuffer slice(int index, int length) {
    282         if (index == 0) {
    283             if (length == 0) {
    284                 return ChannelBuffers.EMPTY_BUFFER;
    285             }
    286             return new TruncatedChannelBuffer(this, length);
    287         } else {
    288             if (length == 0) {
    289                 return ChannelBuffers.EMPTY_BUFFER;
    290             }
    291             return new SlicedChannelBuffer(this, index, length);
    292         }
    293     }
    294
    295     public ByteBuffer toByteBuffer(int index, int length) {
    296         return buffer.toByteBuffer(index, length);
    297     }
    298 }