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.ByteOrder;
    23  import java.nio.channels.ClosedChannelException;
    24  import java.nio.channels.GatheringByteChannel;
    25  import java.nio.channels.ScatteringByteChannel;
    26
    27  /**
    28   * A NIO {@link ByteBuffer} based buffer.  It is recommended to use {@link ChannelBuffers#directBuffer(int)}
    29   * and {@link ChannelBuffers#wrappedBuffer(ByteBuffer)} instead of calling the
    30   * constructor explicitly.
    31   *
    32   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
    33   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
    34   *
    35   * @version $Rev: 2309 $, $Date: 2010-06-21 16:00:03 +0900 (Mon, 21 Jun 2010) $
    36   *
    37   */
    38  public class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer {
    39
    40      private final ByteBuffer buffer;
    41      private final ByteOrder order;
    42      private final int capacity;
    43
    44      /**
    45       * Creates a new buffer which wraps the specified buffer's slice.
    46       */
    47      public ByteBufferBackedChannelBuffer(ByteBuffer buffer) {
    48          if (buffer == null) {
    49              throw new NullPointerException("buffer");
    50          }
    51
    52          order = buffer.order();
    53          this.buffer = buffer.slice().order(order);
    54          capacity = buffer.remaining();
    55          writerIndex(capacity);
    56      }
    57
    58      private ByteBufferBackedChannelBuffer(ByteBufferBackedChannelBuffer buffer) {
    59          this.buffer = buffer.buffer;
    60          order = buffer.order;
    61          capacity = buffer.capacity;
    62          setIndex(buffer.readerIndex(), buffer.writerIndex());
    63      }
    64
    65      public ChannelBufferFactory factory() {
    66          if (buffer.isDirect()) {
    67              return DirectChannelBufferFactory.getInstance(order());
    68          } else {
    69              return HeapChannelBufferFactory.getInstance(order());
    70          }
    71      }
    72
    73      public boolean isDirect() {
    74          return buffer.isDirect();
    75      }
    76
    77      public ByteOrder order() {
    78          return order;
    79      }
    80
    81      public int capacity() {
    82          return capacity;
    83      }
    84
    85      public boolean hasArray() {
    86          return buffer.hasArray();
    87      }
    88
    89      public byte[] array() {
    90          return buffer.array();
    91      }
    92
    93      public int arrayOffset() {
    94          return buffer.arrayOffset();
    95      }
    96
    97      public byte getByte(int index) {
    98          return buffer.get(index);
    99      }
    100
    101     public short getShort(int index) {
    102         return buffer.getShort(index);
    103     }
    104
    105     public int getUnsignedMedium(int index) {
    106         return  (getByte(index)   & 0xff) << 16 |
    107                 (getByte(index+1) & 0xff) <<  8 |
    108                 (getByte(index+2) & 0xff) <<  0;
    109     }
    110
    111     public int getInt(int index) {
    112         return buffer.getInt(index);
    113     }
    114
    115     public long getLong(int index) {
    116         return buffer.getLong(index);
    117     }
    118
    119     public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
    120         if (dst instanceof ByteBufferBackedChannelBuffer) {
    121             ByteBufferBackedChannelBuffer bbdst = (ByteBufferBackedChannelBuffer) dst;
    122             ByteBuffer data = bbdst.buffer.duplicate();
    123
    124             data.limit(dstIndex + length).position(dstIndex);
    125             getBytes(index, data);
    126         } else if (buffer.hasArray()) {
    127             dst.setBytes(dstIndex, buffer.array(), index + buffer.arrayOffset(), length);
    128         } else {
    129             dst.setBytes(dstIndex, this, index, length);
    130         }
    131     }
    132
    133     public void getBytes(int index, byte[] dst, int dstIndex, int length) {
    134         ByteBuffer data = buffer.duplicate();
    135         try {
    136             data.limit(index + length).position(index);
    137         } catch (IllegalArgumentException e) {
    138             throw new IndexOutOfBoundsException();
    139         }
    140         data.get(dst, dstIndex, length);
    141     }
    142
    143     public void getBytes(int index, ByteBuffer dst) {
    144         ByteBuffer data = buffer.duplicate();
    145         int bytesToCopy = Math.min(capacity() - index, dst.remaining());
    146         try {
    147             data.limit(index + bytesToCopy).position(index);
    148         } catch (IllegalArgumentException e) {
    149             throw new IndexOutOfBoundsException();
    150         }
    151         dst.put(data);
    152     }
    153
    154     public void setByte(int index, int value) {
    155         buffer.put(index, (byte) value);
    156     }
    157
    158     public void setShort(int index, int value) {
    159         buffer.putShort(index, (short) value);
    160     }
    161
    162     public void setMedium(int index, int   value) {
    163         setByte(index,   (byte) (value >>> 16));
    164         setByte(index+1, (byte) (value >>>  8));
    165         setByte(index+2, (byte) (value >>>  0));
    166     }
    167
    168     public void setInt(int index, int   value) {
    169         buffer.putInt(index, value);
    170     }
    171
    172     public void setLong(int index, long  value) {
    173         buffer.putLong(index, value);
    174     }
    175
    176     public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
    177         if (src instanceof ByteBufferBackedChannelBuffer) {
    178             ByteBufferBackedChannelBuffer bbsrc = (ByteBufferBackedChannelBuffer) src;
    179             ByteBuffer data = bbsrc.buffer.duplicate();
    180
    181             data.limit(srcIndex + length).position(srcIndex);
    182             setBytes(index, data);
    183         } else if (buffer.hasArray()) {
    184             src.getBytes(srcIndex, buffer.array(), index + buffer.arrayOffset(), length);
    185         } else {
    186             src.getBytes(srcIndex, this, index, length);
    187         }
    188     }
    189
    190     public void setBytes(int index, byte[] src, int srcIndex, int length) {
    191         ByteBuffer data = buffer.duplicate();
    192         data.limit(index + length).position(index);
    193         data.put(src, srcIndex, length);
    194     }
    195
    196     public void setBytes(int index, ByteBuffer src) {
    197         ByteBuffer data = buffer.duplicate();
    198         data.limit(index + src.remaining()).position(index);
    199         data.put(src);
    200     }
    201
    202     public void getBytes(int index, OutputStream out, int length) throws IOException {
    203         if (length == 0) {
    204             return;
    205         }
    206
    207         if (buffer.hasArray()) {
    208             out.write(
    209                     buffer.array(),
    210                     index + buffer.arrayOffset(),
    211                     length);
    212         } else {
    213             byte[] tmp = new byte[length];
    214             ((ByteBuffer) buffer.duplicate().position(index)).get(tmp);
    215             out.write(tmp);
    216         }
    217     }
    218
    219     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
    220         if (length == 0) {
    221             return 0;
    222         }
    223
    224         return out.write((ByteBuffer) buffer.duplicate().position(index).limit(index + length));
    225     }
    226
    227     public int setBytes(int index, InputStream in, int length)
    228             throws IOException {
    229
    230         int readBytes = 0;
    231
    232         if (buffer.hasArray()) {
    233             index += buffer.arrayOffset();
    234             do {
    235                 int localReadBytes = in.read(buffer.array(), index, length);
    236                 if (localReadBytes < 0) {
    237                     if (readBytes == 0) {
    238                         return -1;
    239                     } else {
    240                         break;
    241                     }
    242                 }
    243                 readBytes += localReadBytes;
    244                 index += localReadBytes;
    245                 length -= localReadBytes;
    246             } while (length > 0);
    247         } else {
    248             byte[] tmp = new byte[length];
    249             int i = 0;
    250             do {
    251                 int localReadBytes = in.read(tmp, i, tmp.length - i);
    252                 if (localReadBytes < 0) {
    253                     if (readBytes == 0) {
    254                         return -1;
    255                     } else {
    256                         break;
    257                     }
    258                 }
    259                 readBytes += localReadBytes;
    260                 i += readBytes;
    261             } while (i < tmp.length);
    262             ((ByteBuffer) buffer.duplicate().position(index)).put(tmp);
    263         }
    264
    265         return readBytes;
    266     }
    267
    268     public int setBytes(int index, ScatteringByteChannel in, int length)
    269             throws IOException {
    270
    271         ByteBuffer slice = (ByteBuffer) buffer.duplicate().limit(index + length).position(index);
    272         int readBytes = 0;
    273
    274         while (readBytes < length) {
    275             int localReadBytes;
    276             try {
    277                 localReadBytes = in.read(slice);
    278             } catch (ClosedChannelException e) {
    279                 localReadBytes = -1;
    280             }
    281             if (localReadBytes < 0) {
    282                 if (readBytes == 0) {
    283                     return -1;
    284                 } else {
    285                     return readBytes;
    286                 }
    287             } else if (localReadBytes == 0) {
    288                 break;
    289             }
    290             readBytes += localReadBytes;
    291         }
    292
    293         return readBytes;
    294     }
    295
    296     public ByteBuffer toByteBuffer(int index, int length) {
    297         if (index == 0 && length == capacity()) {
    298             return buffer.duplicate().order(order());
    299         } else {
    300             return ((ByteBuffer) buffer.duplicate().position(
    301                     index).limit(index + length)).slice().order(order());
    302         }
    303     }
    304
    305     public ChannelBuffer slice(int index, int length) {
    306         if (index == 0 && length == capacity()) {
    307             ChannelBuffer slice = duplicate();
    308             slice.setIndex(0, length);
    309             return slice;
    310         } else {
    311             if (index >= 0 && length == 0) {
    312                 return ChannelBuffers.EMPTY_BUFFER;
    313             }
    314             return new ByteBufferBackedChannelBuffer(
    315                     ((ByteBuffer) buffer.duplicate().position(
    316                             index).limit(index + length)).order(order()));
    317         }
    318     }
    319
    320     public ChannelBuffer duplicate() {
    321         return new ByteBufferBackedChannelBuffer(this);
    322     }
    323
    324     public ChannelBuffer copy(int index, int length) {
    325         ByteBuffer src;
    326         try {
    327             src = (ByteBuffer) buffer.duplicate().position(index).limit(index + length);
    328         } catch (IllegalArgumentException e) {
    329             throw new IndexOutOfBoundsException();
    330         }
    331
    332         ByteBuffer dst = buffer.isDirect() ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);
    333         dst.put(src);
    334         dst.order(order());
    335         dst.clear();
    336         return new ByteBufferBackedChannelBuffer(dst);
    337     }
    338 }