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.channels.ClosedChannelException;
23  import java.nio.channels.GatheringByteChannel;
24  import java.nio.channels.ScatteringByteChannel;
25  
26  /**
27   * A skeletal implementation for Java heap buffers.
28   */
29  public abstract class HeapChannelBuffer extends AbstractChannelBuffer {
30  
31      /**
32       * The underlying heap byte array that this buffer is wrapping.
33       */
34      protected final byte[] array;
35  
36      /**
37       * Creates a new heap buffer with a newly allocated byte array.
38       *
39       * @param length the length of the new byte array
40       */
41      protected HeapChannelBuffer(int length) {
42          this(new byte[length], 0, 0);
43      }
44  
45      /**
46       * Creates a new heap buffer with an existing byte array.
47       *
48       * @param array the byte array to wrap
49       */
50      protected HeapChannelBuffer(byte[] array) {
51          this(array, 0, array.length);
52      }
53  
54      /**
55       * Creates a new heap buffer with an existing byte array.
56       *
57       * @param array        the byte array to wrap
58       * @param readerIndex  the initial reader index of this buffer
59       * @param writerIndex  the initial writer index of this buffer
60       */
61      protected HeapChannelBuffer(byte[] array, int readerIndex, int writerIndex) {
62          if (array == null) {
63              throw new NullPointerException("array");
64          }
65          this.array = array;
66          setIndex(readerIndex, writerIndex);
67      }
68  
69      public boolean isDirect() {
70          return false;
71      }
72  
73      public int capacity() {
74          return array.length;
75      }
76  
77      public boolean hasArray() {
78          return true;
79      }
80  
81      public byte[] array() {
82          return array;
83      }
84  
85      public int arrayOffset() {
86          return 0;
87      }
88  
89      public byte getByte(int index) {
90          return array[index];
91      }
92  
93      public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
94          if (dst instanceof HeapChannelBuffer) {
95              getBytes(index, ((HeapChannelBuffer) dst).array, dstIndex, length);
96          } else {
97              dst.setBytes(dstIndex, array, index, length);
98          }
99      }
100 
101     public void getBytes(int index, byte[] dst, int dstIndex, int length) {
102         System.arraycopy(array, index, dst, dstIndex, length);
103     }
104 
105     public void getBytes(int index, ByteBuffer dst) {
106         dst.put(array, index, Math.min(capacity() - index, dst.remaining()));
107     }
108 
109     public void getBytes(int index, OutputStream out, int length)
110             throws IOException {
111         out.write(array, index, length);
112     }
113 
114     public int getBytes(int index, GatheringByteChannel out, int length)
115             throws IOException {
116         return out.write(ByteBuffer.wrap(array, index, length));
117     }
118 
119     public void setByte(int index, int value) {
120         array[index] = (byte) value;
121     }
122 
123     public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
124         if (src instanceof HeapChannelBuffer) {
125             setBytes(index, ((HeapChannelBuffer) src).array, srcIndex, length);
126         } else {
127             src.getBytes(srcIndex, array, index, length);
128         }
129     }
130 
131     public void setBytes(int index, byte[] src, int srcIndex, int length) {
132         System.arraycopy(src, srcIndex, array, index, length);
133     }
134 
135     public void setBytes(int index, ByteBuffer src) {
136         src.get(array, index, src.remaining());
137     }
138 
139     public int setBytes(int index, InputStream in, int length) throws IOException {
140         int readBytes = 0;
141         do {
142             int localReadBytes = in.read(array, index, length);
143             if (localReadBytes < 0) {
144                 if (readBytes == 0) {
145                     return -1;
146                 } else {
147                     break;
148                 }
149             }
150             readBytes += localReadBytes;
151             index += localReadBytes;
152             length -= localReadBytes;
153         } while (length > 0);
154 
155         return readBytes;
156     }
157 
158     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
159         ByteBuffer buf = ByteBuffer.wrap(array, index, length);
160         int readBytes = 0;
161 
162         do {
163             int localReadBytes;
164             try {
165                 localReadBytes = in.read(buf);
166             } catch (ClosedChannelException e) {
167                 localReadBytes = -1;
168             }
169             if (localReadBytes < 0) {
170                 if (readBytes == 0) {
171                     return -1;
172                 } else {
173                     break;
174                 }
175             }
176             if (localReadBytes == 0) {
177                 break;
178             }
179             readBytes += localReadBytes;
180         } while (readBytes < length);
181 
182         return readBytes;
183     }
184 
185     public ChannelBuffer slice(int index, int length) {
186         if (index == 0) {
187             if (length == 0) {
188                 return ChannelBuffers.EMPTY_BUFFER;
189             }
190             if (length == array.length) {
191                 ChannelBuffer slice = duplicate();
192                 slice.setIndex(0, length);
193                 return slice;
194             } else {
195                 return new TruncatedChannelBuffer(this, length);
196             }
197         } else {
198             if (length == 0) {
199                 return ChannelBuffers.EMPTY_BUFFER;
200             }
201             return new SlicedChannelBuffer(this, index, length);
202         }
203     }
204 
205     public ByteBuffer toByteBuffer(int index, int length) {
206         return ByteBuffer.wrap(array, index, length).order(order());
207     }
208 }