KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xsocket > ByteBufferQueue


1 // $Id: ByteBufferQueue.java 1383 2007-06-27 08:10:17Z grro $
2
/*
3  * Copyright (c) xsocket.org, 2006 - 2007. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
20  * The latest copy of this software may be found on http://www.xsocket.org/
21  */

22 package org.xsocket;
23
24 import java.nio.BufferUnderflowException JavaDoc;
25 import java.nio.ByteBuffer JavaDoc;
26 import java.util.LinkedList JavaDoc;
27
28
29
30 /**
31  * A ByteBuffer queue for framework-internal usage
32  *
33  *
34  * @author grro@xsocket.org
35  */

36 public final class ByteBufferQueue {
37
38     
39     private static final Integer JavaDoc UNKNOWN = null;
40     
41     private LinkedList JavaDoc<ByteBuffer JavaDoc> buffers = null;
42     private Integer JavaDoc currentSize = UNKNOWN;
43     private int insertVersion = 0;
44     
45     
46
47
48     /**
49      * returns true, if empty
50      *
51      * @return true, if empty
52      */

53     public synchronized boolean isEmpty() {
54         
55         if (buffers == null) {
56             return true;
57             
58         } else {
59             return buffers.isEmpty();
60         }
61     }
62
63
64     /**
65      * return the current size
66      *
67      * @return the current size
68      */

69     public synchronized int getSize() {
70         
71         // performance optimization if size has been already calculated
72
if (currentSize != UNKNOWN) {
73             return currentSize;
74         }
75         
76         
77         if (isEmpty()) {
78             return 0;
79             
80         } else {
81             int size = 0;
82             for (ByteBuffer JavaDoc buffer : buffers) {
83                 size += buffer.remaining();
84             }
85             
86             currentSize = size;
87             return size;
88         }
89     }
90
91     
92     
93     
94
95     /**
96      * get the size of the first ByteBuffer in queue
97      *
98      * @return the size of the first ByteBuffer
99      */

100     public synchronized int getFirstBufferSize() {
101         if (buffers == null) {
102             return 0;
103         }
104
105         if (buffers.isEmpty()) {
106             buffers = null;
107             return 0;
108         }
109
110         ByteBuffer JavaDoc buffer = buffers.getFirst();
111         return buffer.remaining();
112     }
113     
114
115     
116     /**
117      * append a byte buffer to this queue.
118      *
119      * @param data the ByteBuffer to append
120      */

121     public synchronized void append(ByteBuffer JavaDoc data) {
122
123         // is data available?
124
if (data != null) {
125             
126             // really?
127
if (data.hasRemaining()) {
128                 // yes
129
currentSize = UNKNOWN;
130                 insertVersion++;
131
132                 if (buffers == null) {
133                     buffers= new LinkedList JavaDoc<ByteBuffer JavaDoc>();
134                 }
135
136                 buffers.add(data);
137             }
138         }
139     }
140
141
142     /**
143      * append a list of byte buffer to this queue. By adding a list,
144      * the list becomes part of to the buffer, and shouldn't be modified outside the buffer
145      * to avoid side effects
146      *
147      * @param bufs the list of ByteBuffer
148      */

149     public synchronized void append(LinkedList JavaDoc<ByteBuffer JavaDoc> bufs) {
150
151         //is data available?
152
if (bufs != null) {
153             
154             // really?
155
if (bufs.size() > 0) {
156
157                 // yes
158
currentSize = UNKNOWN;
159                 insertVersion++;
160                 
161                 if (buffers == null) {
162                     buffers = bufs;
163                     
164                 } else {
165                     buffers.addAll(bufs);
166                 }
167             }
168         }
169     }
170
171
172     /**
173      * add a byte buffer at the first position
174      *
175      * @param buffer the ByteBuffer to add
176      */

177     public synchronized void addFirst(ByteBuffer JavaDoc buffer) {
178
179         // is data available?
180
if (buffer != null) {
181             
182             // really?
183
if (buffer.hasRemaining()) {
184                 
185                 // yes
186
currentSize = UNKNOWN;
187                 insertVersion++;
188
189                 if (buffers == null) {
190                     buffers= new LinkedList JavaDoc<ByteBuffer JavaDoc>();
191                 }
192
193                 buffers.addFirst(buffer);
194             }
195         }
196     }
197
198     
199     
200
201     /**
202      * add a list of byte buffer to the first position. By adding a list,
203      * the list becomes part of to the buffer, and shouldn't be modified outside the buffer
204      * to avoid side effects.
205      *
206      *
207      * @param bufs the list of ByteBuffer to add
208      */

209     public synchronized void addFirst(LinkedList JavaDoc<ByteBuffer JavaDoc> bufs) {
210
211         // is data available?
212
if (bufs != null) {
213             
214             // really?
215
if (bufs.size() > 0) {
216                 
217                 // yes
218
currentSize = UNKNOWN;
219                 insertVersion++;
220     
221                 if (buffers == null) {
222                     buffers = bufs;
223                     
224                 } else {
225                     bufs.addAll(buffers);
226                     buffers = bufs;
227                 }
228             }
229         }
230     }
231     
232     
233
234     /**
235      * add a list of byte buffer to the first position. By adding a list,
236      * the list becomes part of to the buffer, and shouldn't be modified outside the buffer
237      * to avoid side effects.
238      * Buffers will be added silence, which means the insertVersion will not be modified
239      *
240      *
241      *
242      * @param bufs the list of ByteBuffer to add
243      */

244     public synchronized void addFirstSilence(LinkedList JavaDoc<ByteBuffer JavaDoc> bufs) {
245
246         // is data available?
247
if (bufs != null) {
248             
249             // really?
250
if (bufs.size() > 0) {
251                 
252                 // yes
253
currentSize = UNKNOWN;
254     
255                 if (buffers == null) {
256                     buffers = bufs;
257                     
258                 } else {
259                     bufs.addAll(buffers);
260                     buffers = bufs;
261                 }
262             }
263         }
264     }
265
266
267     /**
268      * drain the queue
269      *
270      * @return the queue content
271      */

272     public synchronized LinkedList JavaDoc<ByteBuffer JavaDoc> drain() {
273         
274         // is data available?
275
if (buffers != null) {
276             
277             // really?
278
if (!buffers.isEmpty()) {
279                 
280                 // yes
281
currentSize = UNKNOWN;
282                 
283                 LinkedList JavaDoc<ByteBuffer JavaDoc> result = buffers;
284                 buffers = null;
285                 
286                 return result;
287                 
288             } else {
289                 // no ... just a empty list
290
buffers = null;
291             }
292         }
293
294         // no... return empty list
295
return new LinkedList JavaDoc<ByteBuffer JavaDoc>();
296     }
297
298
299
300
301     /**
302      * remove the first ByteBuffer
303      * @return the first ByteBuffer
304      */

305     public synchronized ByteBuffer JavaDoc removeFirst() {
306
307         // is data available?
308
if (buffers == null) {
309             return null;
310
311         } else {
312     
313             // really?
314
if (buffers.isEmpty()) {
315                 buffers = null;
316                 return null;
317             
318             } else {
319                 // yes
320
currentSize = UNKNOWN;
321                 return buffers.removeFirst();
322             }
323         }
324     }
325
326     
327
328     /**
329      * return a int, which represent the insert version.
330      * this value will increase with each insert modification
331      *
332      * @return the modify version
333      */

334     public int getInsertVersionVersion() {
335         return insertVersion;
336     }
337
338     /**
339      * read bytes
340      *
341      * @param length the length
342      * @return the read bytes
343      * @throws BufferUnderflowException if the buffer's limit has been reached
344      */

345     public synchronized ByteBuffer JavaDoc read(int length) throws BufferUnderflowException JavaDoc {
346
347         // data available?
348
if (buffers == null) {
349             throw new BufferUnderflowException JavaDoc();
350         }
351
352         // enough bytes available ?
353
if (!isSizeEqualsOrLargerThan(length)) {
354             throw new BufferUnderflowException JavaDoc();
355         }
356
357
358         // get first buffer
359
currentSize = UNKNOWN;
360         ByteBuffer JavaDoc buffer = buffers.removeFirst();
361         int remainingFirst = buffer.remaining();
362
363
364         // remainig of first buffer == required length
365
if (remainingFirst == length) {
366             return buffer;
367
368
369         // remainig of first buffer > required length
370
} else if(remainingFirst > length) {
371             int savedLimit = buffer.limit();
372             int savedPos = buffer.position();
373
374             buffer.limit(buffer.position() + length);
375
376             ByteBuffer JavaDoc resultBuf = buffer.slice();
377
378             buffer.position(savedPos + length);
379             buffer.limit(savedLimit);
380             addFirst(buffer.slice());
381
382             return resultBuf;
383
384
385         // remainig of first buffer < required length
386
} else {
387
388             ByteBuffer JavaDoc result = ByteBuffer.allocate(length);
389             int written = 0;
390
391             while (true) {
392                 // read the buffer
393
while(buffer.hasRemaining()) {
394                     result.put(buffer.get());
395                     written++;
396                     if (written == length) {
397                         if (buffer.position() < buffer.limit()) {
398                             buffers.addFirst(buffer.slice());
399                         }
400                         result.clear();
401                         return result;
402                     }
403                 }
404
405                 buffer = buffers.poll();
406             }
407         }
408     }
409
410
411
412     private boolean isSizeEqualsOrLargerThan(int size) {
413         if (buffers == null) {
414             return false;
415         }
416
417         int l = 0;
418
419         for (ByteBuffer JavaDoc buffer : buffers) {
420             l += buffer.remaining();
421             if (l >= size) {
422                 return true;
423             }
424         }
425
426         return false;
427     }
428
429
430
431     /**
432      * {@inheritDoc}
433      */

434     @Override JavaDoc
435     public String JavaDoc toString() {
436         StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
437         if (buffers != null) {
438             ByteBuffer JavaDoc[] copy = new ByteBuffer JavaDoc[buffers.size()];
439             try {
440                 for (int i = 0; i < copy.length; i++) {
441                     copy[i] = buffers.get(i).duplicate();
442                 }
443                 sb.append(DataConverter.toString(copy, "US-ASCII", Integer.MAX_VALUE));
444             } catch (Exception JavaDoc ignore) {
445                 sb.append(DataConverter.toHexString(copy, Integer.MAX_VALUE));
446             }
447         }
448
449         return sb.toString();
450     }
451 }
452
Popular Tags