KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > Ostermiller > util > CircularCharBuffer


1 /*
2  * Circular Character Buffer
3  * Copyright (C) 2002 Stephen Ostermiller
4  * http://ostermiller.org/contact.pl?regarding=Java+Utilities
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * See COPYING.TXT for details.
17  */

18 package com.Ostermiller.util;
19
20 import java.io.Reader JavaDoc;
21 import java.io.Writer JavaDoc;
22 import java.io.IOException JavaDoc;
23
24 /**
25  * Implements the Circular Buffer producer/consumer model for characters.
26  * More information about this class is available from <a target="_top" HREF=
27  * "http://ostermiller.org/utils/CircularCharBuffer.html">ostermiller.org</a>.
28  * <p>
29  * Using this class is a simpler alternative to using a PipedReader
30  * and a PipedWriter. PipedReaders and PipedWriters don't support the
31  * mark operation, don't allow you to control buffer sizes that they use,
32  * and have a more complicated API that requires a instantiating two
33  * classes and connecting them.
34  * <p>
35  * This class is thread safe.
36  *
37  * @see CircularByteBuffer
38  * @see CircularObjectBuffer
39  *
40  * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
41  * @since ostermillerutils 1.00.00
42  */

43 public class CircularCharBuffer {
44
45     /**
46      * The default size for a circular character buffer.
47      *
48      * @since ostermillerutils 1.00.00
49      */

50     private final static int DEFAULT_SIZE = 1024;
51
52     /**
53      * A buffer that will grow as things are added.
54      *
55      * @since ostermillerutils 1.00.00
56      */

57     public final static int INFINITE_SIZE = -1;
58
59     /**
60      * The circular buffer.
61      * <p>
62      * The actual capacity of the buffer is one less than the actual length
63      * of the buffer so that an empty and a full buffer can be
64      * distinguished. An empty buffer will have the markPostion and the
65      * writePosition equal to each other. A full buffer will have
66      * the writePosition one less than the markPostion.
67      * <p>
68      * There are three important indexes into the buffer:
69      * The readPosition, the writePosition, and the markPosition.
70      * If the Reader has never been marked, the readPosition and
71      * the markPosition should always be the same. The characters
72      * available to be read go from the readPosition to the writePosition,
73      * wrapping around the end of the buffer. The space available for writing
74      * goes from the write position to one less than the markPosition,
75      * wrapping around the end of the buffer. The characters that have
76      * been saved to support a reset() of the Reader go from markPosition
77      * to readPosition, wrapping around the end of the buffer.
78      *
79      * @since ostermillerutils 1.00.00
80      */

81     protected char[] buffer;
82     /**
83      * Index of the first character available to be read.
84      *
85      * @since ostermillerutils 1.00.00
86      */

87     protected volatile int readPosition = 0;
88     /**
89      * Index of the first character available to be written.
90      *
91      * @since ostermillerutils 1.00.00
92      */

93     protected volatile int writePosition = 0;
94     /**
95      * Index of the first saved character. (To support stream marking.)
96      *
97      * @since ostermillerutils 1.00.00
98      */

99     protected volatile int markPosition = 0;
100     /**
101      * Number of characters that have to be saved
102      * to support mark() and reset() on the Reader.
103      *
104      * @since ostermillerutils 1.00.00
105      */

106     protected volatile int markSize = 0;
107     /**
108      * If this buffer is infinite (should resize itself when full)
109      *
110      * @since ostermillerutils 1.00.00
111      */

112     protected volatile boolean infinite = false;
113     /**
114      * True if a write to a full buffer should block until the buffer
115      * has room, false if the write method should throw an IOException
116      *
117      * @since ostermillerutils 1.00.00
118      */

119     protected boolean blockingWrite = true;
120     /**
121      * The Reader that can empty this buffer.
122      *
123      * @since ostermillerutils 1.00.00
124      */

125     protected Reader JavaDoc reader = new CircularCharBufferReader();
126     /**
127      * true if the close() method has been called on the Reader
128      *
129      * @since ostermillerutils 1.00.00
130      */

131     protected boolean readerClosed = false;
132     /**
133      * The Writer that can fill this buffer.
134      *
135      * @since ostermillerutils 1.00.00
136      */

137     protected Writer JavaDoc writer = new CircularCharBufferWriter();
138     /**
139      * true if the close() method has been called on the writer
140      *
141      * @since ostermillerutils 1.00.00
142      */

143     protected boolean writerClosed = false;
144
145     /**
146      * Make this buffer ready for reuse. The contents of the buffer
147      * will be cleared and the streams associated with this buffer
148      * will be reopened if they had been closed.
149      *
150      * @since ostermillerutils 1.00.00
151      */

152     public void clear(){
153         synchronized (this){
154             readPosition = 0;
155             writePosition = 0;
156             markPosition = 0;
157             readerClosed = false;
158             writerClosed = false;
159         }
160     }
161
162     /**
163      * Retrieve a Writer that can be used to fill
164      * this buffer.
165      * <p>
166      * Write methods may throw a BufferOverflowException if
167      * the buffer is not large enough. A large enough buffer
168      * size must be chosen so that this does not happen or
169      * the caller must be prepared to catch the exception and
170      * try again once part of the buffer has been consumed.
171      *
172      *
173      * @return the producer for this buffer.
174      *
175      * @since ostermillerutils 1.00.00
176      */

177     public Writer JavaDoc getWriter(){
178         return writer;
179     }
180
181     /**
182      * Retrieve a Reader that can be used to empty
183      * this buffer.
184      * <p>
185      * This Reader supports marks at the expense
186      * of the buffer size.
187      *
188      * @return the consumer for this buffer.
189      *
190      * @since ostermillerutils 1.00.00
191      */

192     public Reader JavaDoc getReader(){
193         return reader;
194     }
195
196     /**
197      * Get number of characters that are available to be read.
198      * <p>
199      * Note that the number of characters available plus
200      * the number of characters free may not add up to the
201      * capacity of this buffer, as the buffer may reserve some
202      * space for other purposes.
203      *
204      * @return the size in characters of this buffer
205      *
206      * @since ostermillerutils 1.00.00
207      */

208     public int getAvailable(){
209         synchronized (this){
210             return available();
211         }
212     }
213
214     /**
215      * Get the number of characters this buffer has free for
216      * writing.
217      * <p>
218      * Note that the number of characters available plus
219      * the number of characters free may not add up to the
220      * capacity of this buffer, as the buffer may reserve some
221      * space for other purposes.
222      *
223      * @return the available space in characters of this buffer
224      *
225      * @since ostermillerutils 1.00.00
226      */

227     public int getSpaceLeft(){
228         synchronized (this){
229             return spaceLeft();
230         }
231     }
232
233     /**
234      * Get the capacity of this buffer.
235      * <p>
236      * Note that the number of characters available plus
237      * the number of characters free may not add up to the
238      * capacity of this buffer, as the buffer may reserve some
239      * space for other purposes.
240      *
241      * @return the size in characters of this buffer
242      *
243      * @since ostermillerutils 1.00.00
244      */

245     public int getSize(){
246         synchronized (this){
247             return buffer.length;
248         }
249     }
250
251     /**
252      * double the size of the buffer
253      *
254      * @since ostermillerutils 1.00.00
255      */

256     private void resize(){
257         char[] newBuffer = new char[buffer.length * 2];
258         int marked = marked();
259         int available = available();
260         if (markPosition <= writePosition){
261             // any space between the mark and
262
// the first write needs to be saved.
263
// In this case it is all in one piece.
264
int length = writePosition - markPosition;
265             System.arraycopy(buffer, markPosition, newBuffer, 0, length);
266         } else {
267             int length1 = buffer.length - markPosition;
268             System.arraycopy(buffer, markPosition, newBuffer, 0, length1);
269             int length2 = writePosition;
270             System.arraycopy(buffer, 0, newBuffer, length1, length2);
271         }
272         buffer = newBuffer;
273         markPosition = 0;
274         readPosition = marked;
275         writePosition = marked + available;
276     }
277
278     /**
279      * Space available in the buffer which can be written.
280      *
281      * @since ostermillerutils 1.00.00
282      */

283     private int spaceLeft(){
284         if (writePosition < markPosition){
285             // any space between the first write and
286
// the mark except one character is available.
287
// In this case it is all in one piece.
288
return (markPosition - writePosition - 1);
289         } else {
290             // space at the beginning and end.
291
return ((buffer.length - 1) - (writePosition - markPosition));
292         }
293     }
294
295     /**
296      * Characters available for reading.
297      *
298      * @since ostermillerutils 1.00.00
299      */

300     private int available(){
301         if (readPosition <= writePosition){
302             // any space between the first read and
303
// the first write is available. In this case i
304
// is all in one piece.
305
return (writePosition - readPosition);
306         } else {
307             // space at the beginning and end.
308
return (buffer.length - (readPosition - writePosition));
309         }
310     }
311
312     /**
313      * Characters saved for supporting marks.
314      *
315      * @since ostermillerutils 1.00.00
316      */

317     private int marked(){
318         if (markPosition <= readPosition){
319             // any space between the markPosition and
320
// the first write is marked. In this case i
321
// is all in one piece.
322
return (readPosition - markPosition);
323         } else {
324             // space at the beginning and end.
325
return (buffer.length - (markPosition - readPosition));
326         }
327     }
328
329     /**
330      * If we have passed the markSize reset the
331      * mark so that the space can be used.
332      *
333      * @since ostermillerutils 1.00.00
334      */

335     private void ensureMark(){
336         if (marked() >= markSize){
337             markPosition = readPosition;
338             markSize = 0;
339         }
340     }
341
342     /**
343      * Create a new buffer with a default capacity.
344      * Writing to a full buffer will block until space
345      * is available rather than throw an exception.
346      *
347      * @since ostermillerutils 1.00.00
348      */

349     public CircularCharBuffer(){
350         this (DEFAULT_SIZE, true);
351     }
352
353     /**
354      * Create a new buffer with given capacity.
355      * Writing to a full buffer will block until space
356      * is available rather than throw an exception.
357      * <p>
358      * Note that the buffer may reserve some characters for
359      * special purposes and capacity number of characters may
360      * not be able to be written to the buffer.
361      * <p>
362      * Note that if the buffer is of INFINITE_SIZE it will
363      * neither block or throw exceptions, but rather grow
364      * without bound.
365      *
366      * @param size desired capacity of the buffer in characters or CircularCharBuffer.INFINITE_SIZE
367      *
368      * @since ostermillerutils 1.00.00
369      */

370     public CircularCharBuffer(int size){
371         this (size, true);
372     }
373
374     /**
375      * Create a new buffer with a default capacity and
376      * given blocking behavior.
377      *
378      * @param blockingWrite true writing to a full buffer should block
379      * until space is available, false if an exception should
380      * be thrown instead.
381      *
382      * @since ostermillerutils 1.00.00
383      */

384     public CircularCharBuffer(boolean blockingWrite){
385         this (DEFAULT_SIZE, blockingWrite);
386     }
387
388     /**
389      * Create a new buffer with the given capacity and
390      * blocking behavior.
391      * <p>
392      * Note that the buffer may reserve some characters for
393      * special purposes and capacity number of characters may
394      * not be able to be written to the buffer.
395      * <p>
396      * Note that if the buffer is of CircularCharBuffer.INFINITE_SIZE it will
397      * neither block or throw exceptions, but rather grow
398      * without bound.
399      *
400      * @param size desired capacity of the buffer in characters or CircularCharBuffer.INFINITE_SIZE
401      * @param blockingWrite true writing to a full buffer should block
402      * until space is available, false if an exception should
403      * be thrown instead.
404      *
405      * @since ostermillerutils 1.00.00
406      */

407     public CircularCharBuffer(int size, boolean blockingWrite){
408         if (size == INFINITE_SIZE){
409             buffer = new char[DEFAULT_SIZE];
410             infinite = true;
411         } else {
412             buffer = new char[size];
413             infinite = false;
414         }
415         this.blockingWrite = blockingWrite;
416     }
417
418     /**
419      * Class for reading from a circular character buffer.
420      *
421      * @since ostermillerutils 1.00.00
422      */

423     protected class CircularCharBufferReader extends Reader JavaDoc {
424
425         /**
426          * Close the stream. Once a stream has been closed, further read(), ready(),
427          * mark(), or reset() invocations will throw an IOException. Closing a
428          * previously-closed stream, however, has no effect.
429          *
430          * @throws IOException never.
431          *
432          * @since ostermillerutils 1.00.00
433          */

434         public void close() throws IOException JavaDoc {
435             synchronized (CircularCharBuffer.this){
436                 readerClosed = true;
437             }
438         }
439
440         /**
441          * Mark the present position in the stream. Subsequent calls to reset() will
442          * attempt to reposition the stream to this point.
443          * <p>
444          * The readAheadLimit must be less than the size of circular buffer.
445          *
446          * @param readAheadLimit Limit on the number of characters that may be read while
447          * still preserving the mark. After reading this many characters, attempting to
448          * reset the stream will fail.
449          * @throws IOException if the stream is closed, or the buffer size is greater
450          * than or equal to the readAheadLimit.
451          *
452          * @since ostermillerutils 1.00.00
453          */

454         public void mark(int readAheadLimit) throws IOException JavaDoc {
455             synchronized (CircularCharBuffer.this){
456                 if (readerClosed) throw new IOException JavaDoc("Reader has been closed; cannot mark a closed Reader.");
457                 if (buffer.length - 1 <= readAheadLimit) throw new IOException JavaDoc("Cannot mark stream, readAheadLimit bigger than buffer size.");
458                 markSize = readAheadLimit;
459                 markPosition = readPosition;
460             }
461         }
462
463         /**
464          * Tell whether this stream supports the mark() operation.
465          *
466          * @return true, mark is supported.
467          *
468          * @since ostermillerutils 1.00.00
469          */

470         public boolean markSupported() {
471             return true;
472         }
473
474         /**
475          * Read a single character.
476          * This method will block until a character is available, an I/O error occurs,
477          * or the end of the stream is reached.
478          *
479          * @return The character read, as an integer in the range 0 to 65535 (0x00-0xffff),
480          * or -1 if the end of the stream has been reached
481          * @throws IOException if the stream is closed.
482          *
483          * @since ostermillerutils 1.00.00
484          */

485         public int read() throws IOException JavaDoc {
486             while (true){
487                 synchronized (CircularCharBuffer.this){
488                     if (readerClosed) throw new IOException JavaDoc("Reader has been closed; cannot read from a closed Reader.");
489                     int available = available();
490                     if (available > 0){
491                         int result = buffer[readPosition] & 0xffff;
492                         readPosition++;
493                         if (readPosition == buffer.length){
494                             readPosition = 0;
495                         }
496                         ensureMark();
497                         return result;
498                     } else if (writerClosed){
499                         return -1;
500                     }
501                 }
502                 try {
503                     Thread.sleep(100);
504                 } catch(Exception JavaDoc x){
505                     throw new IOException JavaDoc("Blocking read operation interrupted.");
506                 }
507             }
508         }
509
510         /**
511          * Read characters into an array.
512          * This method will block until some input is available,
513          * an I/O error occurs, or the end of the stream is reached.
514          *
515          * @param cbuf Destination buffer.
516          * @return The number of characters read, or -1 if the end of
517          * the stream has been reached
518          * @throws IOException if the stream is closed.
519          *
520          * @since ostermillerutils 1.00.00
521          */

522         public int read(char[] cbuf) throws IOException JavaDoc {
523             return read(cbuf, 0, cbuf.length);
524         }
525
526         /**
527          * Read characters into a portion of an array.
528          * This method will block until some input is available,
529          * an I/O error occurs, or the end of the stream is reached.
530          *
531          * @param cbuf Destination buffer.
532          * @param off Offset at which to start storing characters.
533          * @param len Maximum number of characters to read.
534          * @return The number of characters read, or -1 if the end of
535          * the stream has been reached
536          * @throws IOException if the stream is closed.
537          *
538          * @since ostermillerutils 1.00.00
539          */

540         public int read(char[] cbuf, int off, int len) throws IOException JavaDoc {
541             while (true){
542                 synchronized (CircularCharBuffer.this){
543                     if (readerClosed) throw new IOException JavaDoc("Reader has been closed; cannot read from a closed Reader.");
544                     int available = available();
545                     if (available > 0){
546                         int length = Math.min(len, available);
547                         int firstLen = Math.min(length, buffer.length - readPosition);
548                         int secondLen = length - firstLen;
549                         System.arraycopy(buffer, readPosition, cbuf, off, firstLen);
550                         if (secondLen > 0){
551                             System.arraycopy(buffer, 0, cbuf, off+firstLen, secondLen);
552                             readPosition = secondLen;
553                         } else {
554                             readPosition += length;
555                         }
556                         if (readPosition == buffer.length) {
557                             readPosition = 0;
558                         }
559                         ensureMark();
560                         return length;
561                     } else if (writerClosed){
562                         return -1;
563                     }
564                 }
565                 try {
566                     Thread.sleep(100);
567                 } catch(Exception JavaDoc x){
568                     throw new IOException JavaDoc("Blocking read operation interrupted.");
569                 }
570             }
571         }
572
573         /**
574          * Tell whether this stream is ready to be read.
575          *
576          * @return True if the next read() is guaranteed not to block for input,
577          * false otherwise. Note that returning false does not guarantee that
578          * the next read will block.
579          * @throws IOException if the stream is closed.
580          *
581          * @since ostermillerutils 1.00.00
582          */

583         public boolean ready() throws IOException JavaDoc {
584             synchronized (CircularCharBuffer.this){
585                 if (readerClosed) throw new IOException JavaDoc("Reader has been closed, it is not ready.");
586                 return (available() > 0);
587             }
588         }
589
590         /**
591          * Reset the stream.
592          * If the stream has been marked, then attempt to reposition i
593          * at the mark. If the stream has not been marked, or more characters
594          * than the readAheadLimit have been read, this method has no effect.
595          *
596          * @throws IOException if the stream is closed.
597          *
598          * @since ostermillerutils 1.00.00
599          */

600         public void reset() throws IOException JavaDoc {
601             synchronized (CircularCharBuffer.this){
602                 if (readerClosed) throw new IOException JavaDoc("Reader has been closed; cannot reset a closed Reader.");
603                 readPosition = markPosition;
604             }
605         }
606
607         /**
608          * Skip characters.
609          * This method will block until some characters are available,
610          * an I/O error occurs, or the end of the stream is reached.
611          *
612          * @param n The number of characters to skip
613          * @return The number of characters actually skipped
614          * @throws IllegalArgumentException if n is negative.
615          * @throws IOException if the stream is closed.
616          *
617          * @since ostermillerutils 1.00.00
618          */

619         public long skip(long n) throws IOException JavaDoc, IllegalArgumentException JavaDoc {
620             while (true){
621                 synchronized (CircularCharBuffer.this){
622                     if (readerClosed) throw new IOException JavaDoc("Reader has been closed; cannot skip characters on a closed Reader.");
623                     int available = available();
624                     if (available > 0){
625                         int length = Math.min((int)n, available);
626                         int firstLen = Math.min(length, buffer.length - readPosition);
627                         int secondLen = length - firstLen;
628                         if (secondLen > 0){
629                             readPosition = secondLen;
630                         } else {
631                             readPosition += length;
632                         }
633                         if (readPosition == buffer.length) {
634                             readPosition = 0;
635                         }
636                         return length;
637                     } else if (writerClosed){
638                         return 0;
639                     }
640                 }
641                 try {
642                     Thread.sleep(100);
643                 } catch(Exception JavaDoc x){
644                     throw new IOException JavaDoc("Blocking read operation interrupted.");
645                 }
646             }
647         }
648     }
649
650     /**
651      * Class for writing to a circular character buffer.
652      * If the buffer is full, the writes will either block
653      * until there is some space available or throw an IOException
654      * based on the CircularCharBuffer's preference.
655      *
656      * @since ostermillerutils 1.00.00
657      */

658     protected class CircularCharBufferWriter extends Writer JavaDoc {
659
660         /**
661          * Close the stream, flushing it first.
662          * This will cause the reader associated with this circular buffer
663          * to read its last characters once it empties the buffer.
664          * Once a stream has been closed, further write() or flush() invocations
665          * will cause an IOException to be thrown. Closing a previously-closed stream,
666          * however, has no effect.
667          *
668          * @throws IOException never.
669          *
670          * @since ostermillerutils 1.00.00
671          */

672         public void close() throws IOException JavaDoc {
673             synchronized (CircularCharBuffer.this){
674                 if (!writerClosed){
675                     flush();
676                 }
677                 writerClosed = true;
678             }
679         }
680
681         /**
682          * Flush the stream.
683          *
684          * @throws IOException if the stream is closed.
685          *
686          * @since ostermillerutils 1.00.00
687          */

688         public void flush() throws IOException JavaDoc {
689             if (writerClosed) throw new IOException JavaDoc("Writer has been closed; cannot flush a closed Writer.");
690             if (readerClosed) throw new IOException JavaDoc("Buffer closed by Reader; cannot flush.");
691             // this method needs to do nothing
692
}
693
694         /**
695          * Write an array of characters.
696          * If the buffer allows blocking writes, this method will block until
697          * all the data has been written rather than throw an IOException.
698          *
699          * @param cbuf Array of characters to be written
700          * @throws BufferOverflowException if buffer does not allow blocking writes
701          * and the buffer is full. If the exception is thrown, no data
702          * will have been written since the buffer was set to be non-blocking.
703          * @throws IOException if the stream is closed, or the write is interrupted.
704          *
705          * @since ostermillerutils 1.00.00
706          */

707         public void write(char[] cbuf) throws IOException JavaDoc {
708             write(cbuf, 0, cbuf.length);
709         }
710
711         /**
712          * Write a portion of an array of characters.
713          * If the buffer allows blocking writes, this method will block until
714          * all the data has been written rather than throw an IOException.
715          *
716          * @param cbuf Array of characters
717          * @param off Offset from which to start writing characters
718          * @param len - Number of characters to write
719          * @throws BufferOverflowException if buffer does not allow blocking writes
720          * and the buffer is full. If the exception is thrown, no data
721          * will have been written since the buffer was set to be non-blocking.
722          * @throws IOException if the stream is closed, or the write is interrupted.
723          *
724          * @since ostermillerutils 1.00.00
725          */

726         public void write(char[] cbuf, int off, int len) throws IOException JavaDoc {
727             while (len > 0){
728                 synchronized (CircularCharBuffer.this){
729                     if (writerClosed) throw new IOException JavaDoc("Writer has been closed; cannot write to a closed Writer.");
730                     if (readerClosed) throw new IOException JavaDoc("Buffer closed by Reader; cannot write to a closed buffer.");
731                     int spaceLeft = spaceLeft();
732                     while (infinite && spaceLeft < len){
733                         resize();
734                         spaceLeft = spaceLeft();
735                     }
736                     if (!blockingWrite && spaceLeft < len) throw new BufferOverflowException("CircularCharBuffer is full; cannot write " + len + " characters");
737                     int realLen = Math.min(len, spaceLeft);
738                     int firstLen = Math.min(realLen, buffer.length - writePosition);
739                     int secondLen = Math.min(realLen - firstLen, buffer.length - markPosition - 1);
740                     int written = firstLen + secondLen;
741                     if (firstLen > 0){
742                         System.arraycopy(cbuf, off, buffer, writePosition, firstLen);
743                     }
744                     if (secondLen > 0){
745                         System.arraycopy(cbuf, off+firstLen, buffer, 0, secondLen);
746                         writePosition = secondLen;
747                     } else {
748                         writePosition += written;
749                     }
750                     if (writePosition == buffer.length) {
751                         writePosition = 0;
752                     }
753                     off += written;
754                     len -= written;
755                 }
756                 if (len > 0){
757                     try {
758                         Thread.sleep(100);
759                     } catch(Exception JavaDoc x){
760                         throw new IOException JavaDoc("Waiting for available space in buffer interrupted.");
761                     }
762                 }
763             }
764         }
765
766         /**
767          * Write a single character.
768          * The character to be written is contained in the 16 low-order bits of the
769          * given integer value; the 16 high-order bits are ignored.
770          * If the buffer allows blocking writes, this method will block until
771          * all the data has been written rather than throw an IOException.
772          *
773          * @param c int specifying a character to be written.
774          * @throws BufferOverflowException if buffer does not allow blocking writes
775          * and the buffer is full.
776          * @throws IOException if the stream is closed, or the write is interrupted.
777          *
778          * @since ostermillerutils 1.00.00
779          */

780         public void write(int c) throws IOException JavaDoc {
781             boolean written = false;
782             while (!written){
783                 synchronized (CircularCharBuffer.this){
784                     if (writerClosed) throw new IOException JavaDoc("Writer has been closed; cannot write to a closed Writer.");
785                     if (readerClosed) throw new IOException JavaDoc("Buffer closed by Reader; cannot write to a closed buffer.");
786                     int spaceLeft = spaceLeft();
787                     while (infinite && spaceLeft < 1){
788                         resize();
789                         spaceLeft = spaceLeft();
790                     }
791                     if (!blockingWrite && spaceLeft < 1) throw new BufferOverflowException("CircularCharBuffer is full; cannot write 1 character");
792                     if (spaceLeft > 0){
793                         buffer[writePosition] = (char)(c & 0xffff);
794                         writePosition++;
795                         if (writePosition == buffer.length) {
796                             writePosition = 0;
797                         }
798                         written = true;
799                     }
800                 }
801                 if (!written){
802                     try {
803                         Thread.sleep(100);
804                     } catch(Exception JavaDoc x){
805                         throw new IOException JavaDoc("Waiting for available space in buffer interrupted.");
806                     }
807                 }
808             }
809         }
810
811         /**
812          * Write a string.
813          * If the buffer allows blocking writes, this method will block until
814          * all the data has been written rather than throw an IOException.
815          *
816          * @param str String to be written
817          * @throws BufferOverflowException if buffer does not allow blocking writes
818          * and the buffer is full. If the exception is thrown, no data
819          * will have been written since the buffer was set to be non-blocking.
820          * @throws IOException if the stream is closed, or the write is interrupted.
821          *
822          * @since ostermillerutils 1.00.00
823          */

824         public void write(String JavaDoc str) throws IOException JavaDoc {
825             write(str, 0, str.length());
826         }
827
828         /**
829          * Write a portion of a string.
830          * If the buffer allows blocking writes, this method will block until
831          * all the data has been written rather than throw an IOException.
832          *
833          * @param str A String
834          * @param off Offset from which to start writing characters
835          * @param len Number of characters to write
836          * @throws BufferOverflowException if buffer does not allow blocking writes
837          * and the buffer is full. If the exception is thrown, no data
838          * will have been written since the buffer was set to be non-blocking.
839          * @throws IOException if the stream is closed, or the write is interrupted.
840          *
841          * @since ostermillerutils 1.00.00
842          */

843         public void write(String JavaDoc str, int off, int len) throws IOException JavaDoc {
844             while (len > 0){
845                 synchronized (CircularCharBuffer.this){
846                     if (writerClosed) throw new IOException JavaDoc("Writer has been closed; cannot write to a closed Writer.");
847                     if (readerClosed) throw new IOException JavaDoc("Buffer closed by Reader; cannot write to a closed buffer.");
848                     int spaceLeft = spaceLeft();
849                     while (infinite && spaceLeft < len){
850                         resize();
851                         spaceLeft = spaceLeft();
852                     }
853                     if (!blockingWrite && spaceLeft < len) throw new BufferOverflowException("CircularCharBuffer is full; cannot write " + len + " characters");
854                     int realLen = Math.min(len, spaceLeft);
855                     int firstLen = Math.min(realLen, buffer.length - writePosition);
856                     int secondLen = Math.min(realLen - firstLen, buffer.length - markPosition - 1);
857                     int written = firstLen + secondLen;
858                     for (int i=0; i<firstLen; i++){
859                         buffer[writePosition + i] = str.charAt(off+i);
860                     }
861                     if (secondLen > 0){
862                         for (int i=0; i<secondLen; i++){
863                             buffer[i] = str.charAt(off+firstLen+i);
864                         }
865                         writePosition = secondLen;
866                     } else {
867                         writePosition += written;
868                     }
869                     if (writePosition == buffer.length) {
870                         writePosition = 0;
871                     }
872                     off += written;
873                     len -= written;
874                 }
875                 if (len > 0){
876                     try {
877                         Thread.sleep(100);
878                     } catch(Exception JavaDoc x){
879                         throw new IOException JavaDoc("Waiting for available space in buffer interrupted.");
880                     }
881                 }
882             }
883         }
884     }
885 }
886
Popular Tags