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 }