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
59 out.write(buffer.array(), position(), remaining());
60 position(limit());
61
62 } else {
63
64
65
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
80 out.write(buffer.array(), position(), remaining());
81 position(limit());
82
83 } else {
84
85
86
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
227 return null;
228 }
229
230 /***
231 * @see org.activeio.Packet#sliceAsBytes()
232 */
233 public byte[] sliceAsBytes() {
234
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
250 int limit = limit();
251 limit(position()+rc);
252
253 ((ByteBufferPacket)dest).buffer.put(buffer);
254
255
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 }