View Javadoc

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