View Javadoc

    1   /***
    2    *
    3    * Copyright 2004 Hiram Chirino
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
    6    * use this file except in compliance with the License. You may obtain a copy of
    7    * the License at
    8    *
    9    * http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    14   * License for the specific language governing permissions and limitations under
    15   * the License.
    16   */
    17  package org.activeio.packet;
    18
    19  import java.io.DataOutput;
    20  import java.io.IOException;
    21  import java.io.OutputStream;
    22  import java.lang.reflect.Constructor;
    23  import java.nio.ByteBuffer;
    24
    25  import org.activeio.Packet;
    26
    27  /***
    28   * Provides a Packet implementation that is backed by a {@see java.nio.ByteBuffer}
    29   *
    30   * @version $Revision$
    31   */
    32  final public class ByteBufferPacket implements Packet {
    33
    34  	public static final int DEFAULT_BUFFER_SIZE = Integer.parseInt(System.getProperty("org.activeio.DefaultByteBufferSize", ""+(64*1024)));
    35  	public static final int DEFAULT_DIRECT_BUFFER_SIZE = Integer.parseInt(System.getProperty("org.activeio.DefaultDirectByteBufferSize", ""+(8*1024)));
    36
    37      private final ByteBuffer buffer;
    38      private static final int TEMP_BUFFER_SIZE = 64*1024;
    39
    40      public ByteBufferPacket(ByteBuffer buffer) {
    41          this.buffer = buffer;
    42          clear();
    43      }
    44
    45      public ByteBuffer getByteBuffer() {
    46          return buffer;
    47      }
    48
    49      public static ByteBufferPacket createDefaultBuffer(boolean direct) {
    50      	if( direct )
    51      		return new ByteBufferPacket( ByteBuffer.allocateDirect(DEFAULT_DIRECT_BUFFER_SIZE) );
    52      	return new ByteBufferPacket( ByteBuffer.allocate(DEFAULT_BUFFER_SIZE)  );
    53      }
    54
    55      public void writeTo(OutputStream out) throws IOException {
    56          if( buffer.hasArray() ) {
    57
    58              // If the buffer is backed by an array.. then use it directly.
    59              out.write(buffer.array(), position(), remaining());
    60              position(limit());
    61
    62          } else {
    63
    64              // It's not backed by a buffer.. We can only dump it to a OutputStream via a byte[] so,
    65              // create a temp buffer that we can use to chunk it out.
    66              byte temp[] = new byte[TEMP_BUFFER_SIZE];
    67              while( buffer.hasRemaining() ) {
    68                  int maxWrite = buffer.remaining() > temp.length ? temp.length : buffer.remaining();
    69  	            buffer.get(temp, 0, maxWrite);
    70  	            out.write(temp,0, maxWrite);
    71              }
    72
    73          }
    74      }
    75
    76      public void writeTo(DataOutput out) throws IOException {
    77          if( buffer.hasArray() ) {
    78
    79              // If the buffer is backed by an array.. then use it directly.
    80              out.write(buffer.array(), position(), remaining());
    81              position(limit());
    82
    83          } else {
    84
    85              // It's not backed by a buffer.. We can only dump it to a OutputStream via a byte[] so,
    86              // create a temp buffer that we can use to chunk it out.
    87              byte temp[] = new byte[TEMP_BUFFER_SIZE];
    88              while( buffer.hasRemaining() ) {
    89                  int maxWrite = buffer.remaining() > temp.length ? temp.length : buffer.remaining();
    90                  buffer.get(temp, 0, maxWrite);
    91                  out.write(temp,0, maxWrite);
    92              }
    93
    94          }
    95      }
    96
    97      public int capacity() {
    98          return buffer.capacity();
    99      }
    100
    101     public void clear() {
    102         buffer.clear();
    103     }
    104
    105     public Packet compact() {
    106         buffer.compact();
    107         return this;
    108     }
    109
    110     public void flip() {
    111         buffer.flip();
    112     }
    113
    114     public boolean hasRemaining() {
    115         return buffer.hasRemaining();
    116     }
    117
    118     public boolean isDirect() {
    119         return buffer.isDirect();
    120     }
    121
    122     public boolean isReadOnly() {
    123         return buffer.isReadOnly();
    124     }
    125
    126     public int limit() {
    127         return buffer.limit();
    128     }
    129
    130     public void limit(int arg0) {
    131         buffer.limit(arg0);
    132     }
    133
    134     public Packet mark() {
    135         buffer.mark();
    136         return this;
    137     }
    138
    139     public int position() {
    140         return buffer.position();
    141     }
    142
    143     public void position(int arg0) {
    144         buffer.position(arg0);
    145     }
    146
    147     public int remaining() {
    148         return buffer.remaining();
    149     }
    150
    151     public void rewind() {
    152         buffer.rewind();
    153     }
    154
    155     public Packet slice() {
    156         return new ByteBufferPacket(buffer.slice());
    157     }
    158
    159     public Packet duplicate() {
    160         return new ByteBufferPacket(buffer.duplicate());
    161     }
    162
    163     public Object duplicate(ClassLoader cl) throws IOException {
    164         try {
    165             Class clazz = cl.loadClass(ByteBufferPacket.class.getName());
    166             Constructor constructor = clazz.getConstructor(new Class[]{ByteBuffer.class});
    167             return constructor.newInstance(new Object[]{buffer.duplicate()});
    168         } catch (Throwable e) {
    169             throw (IOException)new IOException("Could not duplicate packet in a different classloader: "+e).initCause(e);
    170         }
    171
    172     }
    173
    174
    175     /***
    176      * @see org.activeio.Packet#read()
    177      */
    178     public int read() {
    179         if( !buffer.hasRemaining() )
    180             return -1;
    181         return buffer.get() & 0xff;
    182     }
    183
    184     /***
    185      * @see org.activeio.Packet#read(byte[], int, int)
    186      */
    187     public int read(byte[] data, int offset, int length) {
    188         if( !hasRemaining() )
    189             return -1;
    190
    191         int copyLength = Math.min(length, remaining());
    192         buffer.get(data, offset, copyLength);
    193         return copyLength;
    194     }
    195
    196     /***
    197      * @see org.activeio.Packet#write(int)
    198      */
    199     public boolean write(int data) {
    200         if( !buffer.hasRemaining() )
    201             return false;
    202         buffer.put((byte)data);
    203         return true;
    204     }
    205
    206     /***
    207      * @see org.activeio.Packet#write(byte[], int, int)
    208      */
    209     public int write(byte[] data, int offset, int length) {
    210         if( !hasRemaining() )
    211             return -1;
    212
    213         int copyLength = Math.min(length, remaining());
    214         buffer.put(data, offset, copyLength);
    215         return copyLength;
    216     }
    217
    218     /***
    219      * @see org.activeio.Packet#asByteSequence()
    220      */
    221     public ByteSequence asByteSequence() {
    222         if( buffer.hasArray() ) {
    223             byte[] bs = buffer.array();
    224             return new ByteSequence(bs, buffer.position(), buffer.remaining());
    225         }
    226         // TODO: implement the direct case.
    227         return null;
    228     }
    229
    230     /***
    231      * @see org.activeio.Packet#sliceAsBytes()
    232      */
    233     public byte[] sliceAsBytes() {
    234         // TODO Auto-generated method stub
    235         return null;
    236     }
    237
    238     /***
    239      * @param dest
    240      * @return the number of bytes read into the dest.
    241      */
    242     public int read(Packet dest) {
    243
    244 	    int rc = Math.min(dest.remaining(), remaining());
    245 		if( rc > 0 ) {
    246
    247 	        if( dest.getClass() == ByteBufferPacket.class ) {
    248
    249 			    // Adjust our limit so that we don't overflow the dest buffer.
    250 				int limit = limit();
    251 				limit(position()+rc);
    252
    253 	            ((ByteBufferPacket)dest).buffer.put(buffer);
    254
    255 	            // restore the limit.
    256 				limit(limit);
    257
    258 	            return 0;
    259 	        } else {
    260 	            ByteSequence sequence = dest.asByteSequence();
    261 	            rc = read(sequence.getData(), sequence.getOffset(), sequence.getLength());
    262 	            dest.position(dest.position()+rc);
    263 	        }
    264 		}
    265 		return rc;
    266     }
    267
    268     public String toString() {
    269         return "{position="+position()+",limit="+limit()+",capacity="+capacity()+"}";
    270     }
    271
    272     public Object narrow(Class target) {
    273         if( target.isAssignableFrom(getClass()) ) {
    274             return this;
    275         }
    276         return null;
    277     }
    278
    279     public void dispose() {
    280     }
    281 }