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 }