Source Code Cross Referenced for CircularCharBuffer.java in  » Template-Engine » ostermillerutils » com » Ostermiller » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Template Engine » ostermillerutils » com.Ostermiller.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Circular Character Buffer
003:         * Copyright (C) 2002 Stephen Ostermiller
004:         * http://ostermiller.org/contact.pl?regarding=Java+Utilities
005:         *
006:         * This program is free software; you can redistribute it and/or modify
007:         * it under the terms of the GNU General Public License as published by
008:         * the Free Software Foundation; either version 2 of the License, or
009:         * (at your option) any later version.
010:         *
011:         * This program is distributed in the hope that it will be useful,
012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014:         * GNU General Public License for more details.
015:         *
016:         * See COPYING.TXT for details.
017:         */
018:        package com.Ostermiller.util;
019:
020:        import java.io.*;
021:
022:        /**
023:         * Implements the Circular Buffer producer/consumer model for characters.
024:         * More information about this class is available from <a target="_top" href=
025:         * "http://ostermiller.org/utils/CircularCharBuffer.html">ostermiller.org</a>.
026:         * <p>
027:         * Using this class is a simpler alternative to using a PipedReader
028:         * and a PipedWriter. PipedReaders and PipedWriters don't support the
029:         * mark operation, don't allow you to control buffer sizes that they use,
030:         * and have a more complicated API that requires instantiating two
031:         * classes and connecting them.
032:         * <p>
033:         * This class is thread safe.
034:         *
035:         * @see CircularByteBuffer
036:         * @see CircularObjectBuffer
037:         *
038:         * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
039:         * @since ostermillerutils 1.00.00
040:         */
041:        public class CircularCharBuffer {
042:
043:            /**
044:             * The default size for a circular character buffer.
045:             *
046:             * @since ostermillerutils 1.00.00
047:             */
048:            private final static int DEFAULT_SIZE = 1024;
049:
050:            /**
051:             * A buffer that will grow as things are added.
052:             *
053:             * @since ostermillerutils 1.00.00
054:             */
055:            public final static int INFINITE_SIZE = -1;
056:
057:            /**
058:             * The circular buffer.
059:             * <p>
060:             * The actual capacity of the buffer is one less than the actual length
061:             * of the buffer so that an empty and a full buffer can be
062:             * distinguished.  An empty buffer will have the markPostion and the
063:             * writePosition equal to each other.  A full buffer will have
064:             * the writePosition one less than the markPostion.
065:             * <p>
066:             * There are three important indexes into the buffer:
067:             * The readPosition, the writePosition, and the markPosition.
068:             * If the Reader has never been marked, the readPosition and
069:             * the markPosition should always be the same.  The characters
070:             * available to be read go from the readPosition to the writePosition,
071:             * wrapping around the end of the buffer.  The space available for writing
072:             * goes from the write position to one less than the markPosition,
073:             * wrapping around the end of the buffer.  The characters that have
074:             * been saved to support a reset() of the Reader go from markPosition
075:             * to readPosition, wrapping around the end of the buffer.
076:             *
077:             * @since ostermillerutils 1.00.00
078:             */
079:            protected char[] buffer;
080:            /**
081:             * Index of the first character available to be read.
082:             *
083:             * @since ostermillerutils 1.00.00
084:             */
085:            protected volatile int readPosition = 0;
086:            /**
087:             * Index of the first character available to be written.
088:             *
089:             * @since ostermillerutils 1.00.00
090:             */
091:            protected volatile int writePosition = 0;
092:            /**
093:             * Index of the first saved character. (To support stream marking.)
094:             *
095:             * @since ostermillerutils 1.00.00
096:             */
097:            protected volatile int markPosition = 0;
098:            /**
099:             * Number of characters that have to be saved
100:             * to support mark() and reset() on the Reader.
101:             *
102:             * @since ostermillerutils 1.00.00
103:             */
104:            protected volatile int markSize = 0;
105:            /**
106:             * If this buffer is infinite (should resize itself when full)
107:             *
108:             * @since ostermillerutils 1.00.00
109:             */
110:            protected volatile boolean infinite = false;
111:            /**
112:             * True if a write to a full buffer should block until the buffer
113:             * has room, false if the write method should throw an IOException
114:             *
115:             * @since ostermillerutils 1.00.00
116:             */
117:            protected boolean blockingWrite = true;
118:            /**
119:             * The Reader that can empty this buffer.
120:             *
121:             * @since ostermillerutils 1.00.00
122:             */
123:            protected Reader reader = new CircularCharBufferReader();
124:            /**
125:             * true if the close() method has been called on the Reader
126:             *
127:             * @since ostermillerutils 1.00.00
128:             */
129:            protected boolean readerClosed = false;
130:            /**
131:             * The Writer that can fill this buffer.
132:             *
133:             * @since ostermillerutils 1.00.00
134:             */
135:            protected Writer writer = new CircularCharBufferWriter();
136:            /**
137:             * true if the close() method has been called on the writer
138:             *
139:             * @since ostermillerutils 1.00.00
140:             */
141:            protected boolean writerClosed = false;
142:
143:            /**
144:             * Make this buffer ready for reuse.  The contents of the buffer
145:             * will be cleared and the streams associated with this buffer
146:             * will be reopened if they had been closed.
147:             *
148:             * @since ostermillerutils 1.00.00
149:             */
150:            public void clear() {
151:                synchronized (this ) {
152:                    readPosition = 0;
153:                    writePosition = 0;
154:                    markPosition = 0;
155:                    readerClosed = false;
156:                    writerClosed = false;
157:                }
158:            }
159:
160:            /**
161:             * Retrieve a Writer that can be used to fill
162:             * this buffer.
163:             * <p>
164:             * Write methods may throw a BufferOverflowException if
165:             * the buffer is not large enough.  A large enough buffer
166:             * size must be chosen so that this does not happen or
167:             * the caller must be prepared to catch the exception and
168:             * try again once part of the buffer has been consumed.
169:             *
170:             *
171:             * @return the producer for this buffer.
172:             *
173:             * @since ostermillerutils 1.00.00
174:             */
175:            public Writer getWriter() {
176:                return writer;
177:            }
178:
179:            /**
180:             * Retrieve a Reader that can be used to empty
181:             * this buffer.
182:             * <p>
183:             * This Reader supports marks at the expense
184:             * of the buffer size.
185:             *
186:             * @return the consumer for this buffer.
187:             *
188:             * @since ostermillerutils 1.00.00
189:             */
190:            public Reader getReader() {
191:                return reader;
192:            }
193:
194:            /**
195:             * Get number of characters that are available to be read.
196:             * <p>
197:             * Note that the number of characters available plus
198:             * the number of characters free may not add up to the
199:             * capacity of this buffer, as the buffer may reserve some
200:             * space for other purposes.
201:             *
202:             * @return the size in characters of this buffer
203:             *
204:             * @since ostermillerutils 1.00.00
205:             */
206:            public int getAvailable() {
207:                synchronized (this ) {
208:                    return available();
209:                }
210:            }
211:
212:            /**
213:             * Get the number of characters this buffer has free for
214:             * writing.
215:             * <p>
216:             * Note that the number of characters available plus
217:             * the number of characters free may not add up to the
218:             * capacity of this buffer, as the buffer may reserve some
219:             * space for other purposes.
220:             *
221:             * @return the available space in characters of this buffer
222:             *
223:             * @since ostermillerutils 1.00.00
224:             */
225:            public int getSpaceLeft() {
226:                synchronized (this ) {
227:                    return spaceLeft();
228:                }
229:            }
230:
231:            /**
232:             * Get the capacity of this buffer.
233:             * <p>
234:             * Note that the number of characters available plus
235:             * the number of characters free may not add up to the
236:             * capacity of this buffer, as the buffer may reserve some
237:             * space for other purposes.
238:             *
239:             * @return the size in characters of this buffer
240:             *
241:             * @since ostermillerutils 1.00.00
242:             */
243:            public int getSize() {
244:                synchronized (this ) {
245:                    return buffer.length;
246:                }
247:            }
248:
249:            /**
250:             * double the size of the buffer
251:             *
252:             * @since ostermillerutils 1.00.00
253:             */
254:            private void resize() {
255:                char[] newBuffer = new char[buffer.length * 2];
256:                int marked = marked();
257:                int available = available();
258:                if (markPosition <= writePosition) {
259:                    // any space between the mark and
260:                    // the first write needs to be saved.
261:                    // In this case it is all in one piece.
262:                    int length = writePosition - markPosition;
263:                    System
264:                            .arraycopy(buffer, markPosition, newBuffer, 0,
265:                                    length);
266:                } else {
267:                    int length1 = buffer.length - markPosition;
268:                    System.arraycopy(buffer, markPosition, newBuffer, 0,
269:                            length1);
270:                    int length2 = writePosition;
271:                    System.arraycopy(buffer, 0, newBuffer, length1, length2);
272:                }
273:                buffer = newBuffer;
274:                markPosition = 0;
275:                readPosition = marked;
276:                writePosition = marked + available;
277:            }
278:
279:            /**
280:             * Space available in the buffer which can be written.
281:             *
282:             * @since ostermillerutils 1.00.00
283:             */
284:            private int spaceLeft() {
285:                if (writePosition < markPosition) {
286:                    // any space between the first write and
287:                    // the mark except one character is available.
288:                    // In this case it is all in one piece.
289:                    return (markPosition - writePosition - 1);
290:                }
291:                // space at the beginning and end.
292:                return ((buffer.length - 1) - (writePosition - markPosition));
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:                }
307:                // space at the beginning and end.
308:                return (buffer.length - (readPosition - writePosition));
309:            }
310:
311:            /**
312:             * Characters saved for supporting marks.
313:             *
314:             * @since ostermillerutils 1.00.00
315:             */
316:            private int marked() {
317:                if (markPosition <= readPosition) {
318:                    // any space between the markPosition and
319:                    // the first write is marked.  In this case i
320:                    // is all in one piece.
321:                    return (readPosition - markPosition);
322:                }
323:                // space at the beginning and end.
324:                return (buffer.length - (markPosition - readPosition));
325:            }
326:
327:            /**
328:             * If we have passed the markSize reset the
329:             * mark so that the space can be used.
330:             *
331:             * @since ostermillerutils 1.00.00
332:             */
333:            private void ensureMark() {
334:                if (marked() >= markSize) {
335:                    markPosition = readPosition;
336:                    markSize = 0;
337:                }
338:            }
339:
340:            /**
341:             * Create a new buffer with a default capacity.
342:             * Writing to a full buffer will block until space
343:             * is available rather than throw an exception.
344:             *
345:             * @since ostermillerutils 1.00.00
346:             */
347:            public CircularCharBuffer() {
348:                this (DEFAULT_SIZE, true);
349:            }
350:
351:            /**
352:             * Create a new buffer with given capacity.
353:             * Writing to a full buffer will block until space
354:             * is available rather than throw an exception.
355:             * <p>
356:             * Note that the buffer may reserve some characters for
357:             * special purposes and capacity number of characters may
358:             * not be able to be written to the buffer.
359:             * <p>
360:             * Note that if the buffer is of INFINITE_SIZE it will
361:             * neither block or throw exceptions, but rather grow
362:             * without bound.
363:             *
364:             * @param size desired capacity of the buffer in characters or CircularCharBuffer.INFINITE_SIZE
365:             *
366:             * @since ostermillerutils 1.00.00
367:             */
368:            public CircularCharBuffer(int size) {
369:                this (size, true);
370:            }
371:
372:            /**
373:             * Create a new buffer with a default capacity and
374:             * given blocking behavior.
375:             *
376:             * @param blockingWrite true writing to a full buffer should block
377:             *        until space is available, false if an exception should
378:             *        be thrown instead.
379:             *
380:             * @since ostermillerutils 1.00.00
381:             */
382:            public CircularCharBuffer(boolean blockingWrite) {
383:                this (DEFAULT_SIZE, blockingWrite);
384:            }
385:
386:            /**
387:             * Create a new buffer with the given capacity and
388:             * blocking behavior.
389:             * <p>
390:             * Note that the buffer may reserve some characters for
391:             * special purposes and capacity number of characters may
392:             * not be able to be written to the buffer.
393:             * <p>
394:             * Note that if the buffer is of CircularCharBuffer.INFINITE_SIZE it will
395:             * neither block or throw exceptions, but rather grow
396:             * without bound.
397:             *
398:             * @param size desired capacity of the buffer in characters or CircularCharBuffer.INFINITE_SIZE
399:             * @param blockingWrite true writing to a full buffer should block
400:             *        until space is available, false if an exception should
401:             *        be thrown instead.
402:             *
403:             * @since ostermillerutils 1.00.00
404:             */
405:            public CircularCharBuffer(int size, boolean blockingWrite) {
406:                if (size == INFINITE_SIZE) {
407:                    buffer = new char[DEFAULT_SIZE];
408:                    infinite = true;
409:                } else {
410:                    buffer = new char[size];
411:                    infinite = false;
412:                }
413:                this .blockingWrite = blockingWrite;
414:            }
415:
416:            /**
417:             * Class for reading from a circular character buffer.
418:             *
419:             * @since ostermillerutils 1.00.00
420:             */
421:            protected class CircularCharBufferReader extends Reader {
422:
423:                /**
424:                 * Close the stream. Once a stream has been closed, further read(), ready(),
425:                 * mark(), or reset() invocations will throw an IOException. Closing a
426:                 * previously-closed stream, however, has no effect.
427:                 *
428:                 * @throws IOException never.
429:                 *
430:                 * @since ostermillerutils 1.00.00
431:                 */
432:                @Override
433:                public void close() throws IOException {
434:                    synchronized (CircularCharBuffer.this ) {
435:                        readerClosed = true;
436:                    }
437:                }
438:
439:                /**
440:                 * Mark the present position in the stream. Subsequent calls to reset() will
441:                 * attempt to reposition the stream to this point.
442:                 * <p>
443:                 * The readAheadLimit must be less than the size of circular buffer.
444:                 *
445:                 * @param readAheadLimit Limit on the number of characters that may be read while
446:                 *    still preserving the mark. After reading this many characters, attempting to
447:                 *    reset the stream will fail.
448:                 * @throws IOException if the stream is closed, or the buffer size is greater
449:                 * than or equal to the readAheadLimit.
450:                 *
451:                 * @since ostermillerutils 1.00.00
452:                 */
453:                @Override
454:                public void mark(int readAheadLimit) throws IOException {
455:                    synchronized (CircularCharBuffer.this ) {
456:                        if (readerClosed)
457:                            throw new IOException(
458:                                    "Reader has been closed; cannot mark a closed Reader.");
459:                        if (buffer.length - 1 <= readAheadLimit)
460:                            throw new IOException(
461:                                    "Cannot mark stream, readAheadLimit bigger than buffer size.");
462:                        markSize = readAheadLimit;
463:                        markPosition = readPosition;
464:                    }
465:                }
466:
467:                /**
468:                 * Tell whether this stream supports the mark() operation.
469:                 *
470:                 * @return true, mark is supported.
471:                 *
472:                 * @since ostermillerutils 1.00.00
473:                 */
474:                @Override
475:                public boolean markSupported() {
476:                    return true;
477:                }
478:
479:                /**
480:                 * Read a single character.
481:                 * This method will block until a character is available, an I/O error occurs,
482:                 * or the end of the stream is reached.
483:                 *
484:                 * @return The character read, as an integer in the range 0 to 65535 (0x00-0xffff),
485:                 *     or -1 if the end of the stream has been reached
486:                 * @throws IOException if the stream is closed.
487:                 *
488:                 * @since ostermillerutils 1.00.00
489:                 */
490:                @Override
491:                public int read() throws IOException {
492:                    while (true) {
493:                        synchronized (CircularCharBuffer.this ) {
494:                            if (readerClosed)
495:                                throw new IOException(
496:                                        "Reader has been closed; cannot read from a closed Reader.");
497:                            int available = available();
498:                            if (available > 0) {
499:                                int result = buffer[readPosition] & 0xffff;
500:                                readPosition++;
501:                                if (readPosition == buffer.length) {
502:                                    readPosition = 0;
503:                                }
504:                                ensureMark();
505:                                return result;
506:                            } else if (writerClosed) {
507:                                return -1;
508:                            }
509:                        }
510:                        try {
511:                            Thread.sleep(100);
512:                        } catch (Exception x) {
513:                            throw new IOException(
514:                                    "Blocking read operation interrupted.");
515:                        }
516:                    }
517:                }
518:
519:                /**
520:                 * Read characters into an array.
521:                 * This method will block until some input is available,
522:                 * an I/O error occurs, or the end of the stream is reached.
523:                 *
524:                 * @param cbuf Destination buffer.
525:                 * @return The number of characters read, or -1 if the end of
526:                 *   the stream has been reached
527:                 * @throws IOException if the stream is closed.
528:                 *
529:                 * @since ostermillerutils 1.00.00
530:                 */
531:                @Override
532:                public int read(char[] cbuf) throws IOException {
533:                    return read(cbuf, 0, cbuf.length);
534:                }
535:
536:                /**
537:                 * Read characters into a portion of an array.
538:                 * This method will block until some input is available,
539:                 * an I/O error occurs, or the end of the stream is reached.
540:                 *
541:                 * @param cbuf Destination buffer.
542:                 * @param off Offset at which to start storing characters.
543:                 * @param len Maximum number of characters to read.
544:                 * @return The number of characters read, or -1 if the end of
545:                 *   the stream has been reached
546:                 * @throws IOException if the stream is closed.
547:                 *
548:                 * @since ostermillerutils 1.00.00
549:                 */
550:                @Override
551:                public int read(char[] cbuf, int off, int len)
552:                        throws IOException {
553:                    while (true) {
554:                        synchronized (CircularCharBuffer.this ) {
555:                            if (readerClosed)
556:                                throw new IOException(
557:                                        "Reader has been closed; cannot read from a closed Reader.");
558:                            int available = available();
559:                            if (available > 0) {
560:                                int length = Math.min(len, available);
561:                                int firstLen = Math.min(length, buffer.length
562:                                        - readPosition);
563:                                int secondLen = length - firstLen;
564:                                System.arraycopy(buffer, readPosition, cbuf,
565:                                        off, firstLen);
566:                                if (secondLen > 0) {
567:                                    System.arraycopy(buffer, 0, cbuf, off
568:                                            + firstLen, secondLen);
569:                                    readPosition = secondLen;
570:                                } else {
571:                                    readPosition += length;
572:                                }
573:                                if (readPosition == buffer.length) {
574:                                    readPosition = 0;
575:                                }
576:                                ensureMark();
577:                                return length;
578:                            } else if (writerClosed) {
579:                                return -1;
580:                            }
581:                        }
582:                        try {
583:                            Thread.sleep(100);
584:                        } catch (Exception x) {
585:                            throw new IOException(
586:                                    "Blocking read operation interrupted.");
587:                        }
588:                    }
589:                }
590:
591:                /**
592:                 * Tell whether this stream is ready to be read.
593:                 *
594:                 * @return True if the next read() is guaranteed not to block for input,
595:                 *    false otherwise. Note that returning false does not guarantee that
596:                 *    the next read will block.
597:                 * @throws IOException if the stream is closed.
598:                 *
599:                 * @since ostermillerutils 1.00.00
600:                 */
601:                @Override
602:                public boolean ready() throws IOException {
603:                    synchronized (CircularCharBuffer.this ) {
604:                        if (readerClosed)
605:                            throw new IOException(
606:                                    "Reader has been closed, it is not ready.");
607:                        return (available() > 0);
608:                    }
609:                }
610:
611:                /**
612:                 * Reset the stream.
613:                 * If the stream has been marked, then attempt to reposition i
614:                 * at the mark. If the stream has not been marked, or more characters
615:                 * than the readAheadLimit have been read, this method has no effect.
616:                 *
617:                 * @throws IOException if the stream is closed.
618:                 *
619:                 * @since ostermillerutils 1.00.00
620:                 */
621:                @Override
622:                public void reset() throws IOException {
623:                    synchronized (CircularCharBuffer.this ) {
624:                        if (readerClosed)
625:                            throw new IOException(
626:                                    "Reader has been closed; cannot reset a closed Reader.");
627:                        readPosition = markPosition;
628:                    }
629:                }
630:
631:                /**
632:                 * Skip characters.
633:                 * This method will block until some characters are available,
634:                 * an I/O error occurs, or the end of the stream is reached.
635:                 *
636:                 * @param n The number of characters to skip
637:                 * @return The number of characters actually skipped
638:                 * @throws IllegalArgumentException if n is negative.
639:                 * @throws IOException if the stream is closed.
640:                 *
641:                 * @since ostermillerutils 1.00.00
642:                 */
643:                @Override
644:                public long skip(long n) throws IOException,
645:                        IllegalArgumentException {
646:                    while (true) {
647:                        synchronized (CircularCharBuffer.this ) {
648:                            if (readerClosed)
649:                                throw new IOException(
650:                                        "Reader has been closed; cannot skip characters on a closed Reader.");
651:                            int available = available();
652:                            if (available > 0) {
653:                                int length = Math.min((int) n, available);
654:                                int firstLen = Math.min(length, buffer.length
655:                                        - readPosition);
656:                                int secondLen = length - firstLen;
657:                                if (secondLen > 0) {
658:                                    readPosition = secondLen;
659:                                } else {
660:                                    readPosition += length;
661:                                }
662:                                if (readPosition == buffer.length) {
663:                                    readPosition = 0;
664:                                }
665:                                ensureMark();
666:                                return length;
667:                            } else if (writerClosed) {
668:                                return 0;
669:                            }
670:                        }
671:                        try {
672:                            Thread.sleep(100);
673:                        } catch (Exception x) {
674:                            throw new IOException(
675:                                    "Blocking read operation interrupted.");
676:                        }
677:                    }
678:                }
679:            }
680:
681:            /**
682:             * Class for writing to a circular character buffer.
683:             * If the buffer is full, the writes will either block
684:             * until there is some space available or throw an IOException
685:             * based on the CircularCharBuffer's preference.
686:             *
687:             * @since ostermillerutils 1.00.00
688:             */
689:            protected class CircularCharBufferWriter extends Writer {
690:
691:                /**
692:                 * Close the stream, flushing it first.
693:                 * This will cause the reader associated with this circular buffer
694:                 * to read its last characters once it empties the buffer.
695:                 * Once a stream has been closed, further write() or flush() invocations
696:                 * will cause an IOException to be thrown. Closing a previously-closed stream,
697:                 * however, has no effect.
698:                 *
699:                 * @throws IOException never.
700:                 *
701:                 * @since ostermillerutils 1.00.00
702:                 */
703:                @Override
704:                public void close() throws IOException {
705:                    synchronized (CircularCharBuffer.this ) {
706:                        if (!writerClosed) {
707:                            flush();
708:                        }
709:                        writerClosed = true;
710:                    }
711:                }
712:
713:                /**
714:                 * Flush the stream.
715:                 *
716:                 * @throws IOException if the stream is closed.
717:                 *
718:                 * @since ostermillerutils 1.00.00
719:                 */
720:                @Override
721:                public void flush() throws IOException {
722:                    if (writerClosed)
723:                        throw new IOException(
724:                                "Writer has been closed; cannot flush a closed Writer.");
725:                    if (readerClosed)
726:                        throw new IOException(
727:                                "Buffer closed by Reader; cannot flush.");
728:                    // this method needs to do nothing
729:                }
730:
731:                /**
732:                 * Write an array of characters.
733:                 * If the buffer allows blocking writes, this method will block until
734:                 * all the data has been written rather than throw an IOException.
735:                 *
736:                 * @param cbuf Array of characters to be written
737:                 * @throws BufferOverflowException if buffer does not allow blocking writes
738:                 *   and the buffer is full.  If the exception is thrown, no data
739:                 *   will have been written since the buffer was set to be non-blocking.
740:                 * @throws IOException if the stream is closed, or the write is interrupted.
741:                 *
742:                 * @since ostermillerutils 1.00.00
743:                 */
744:                @Override
745:                public void write(char[] cbuf) throws IOException {
746:                    write(cbuf, 0, cbuf.length);
747:                }
748:
749:                /**
750:                 * Write a portion of an array of characters.
751:                 * If the buffer allows blocking writes, this method will block until
752:                 * all the data has been written rather than throw an IOException.
753:                 *
754:                 * @param cbuf Array of characters
755:                 * @param off Offset from which to start writing characters
756:                 * @param len - Number of characters to write
757:                 * @throws BufferOverflowException if buffer does not allow blocking writes
758:                 *   and the buffer is full.  If the exception is thrown, no data
759:                 *   will have been written since the buffer was set to be non-blocking.
760:                 * @throws IOException if the stream is closed, or the write is interrupted.
761:                 *
762:                 * @since ostermillerutils 1.00.00
763:                 */
764:                @Override
765:                public void write(char[] cbuf, int off, int len)
766:                        throws IOException {
767:                    while (len > 0) {
768:                        synchronized (CircularCharBuffer.this ) {
769:                            if (writerClosed)
770:                                throw new IOException(
771:                                        "Writer has been closed; cannot write to a closed Writer.");
772:                            if (readerClosed)
773:                                throw new IOException(
774:                                        "Buffer closed by Reader; cannot write to a closed buffer.");
775:                            int spaceLeft = spaceLeft();
776:                            while (infinite && spaceLeft < len) {
777:                                resize();
778:                                spaceLeft = spaceLeft();
779:                            }
780:                            if (!blockingWrite && spaceLeft < len)
781:                                throw new BufferOverflowException(
782:                                        "CircularCharBuffer is full; cannot write "
783:                                                + len + " characters");
784:                            int realLen = Math.min(len, spaceLeft);
785:                            int firstLen = Math.min(realLen, buffer.length
786:                                    - writePosition);
787:                            int secondLen = Math.min(realLen - firstLen,
788:                                    buffer.length - markPosition - 1);
789:                            int written = firstLen + secondLen;
790:                            if (firstLen > 0) {
791:                                System.arraycopy(cbuf, off, buffer,
792:                                        writePosition, firstLen);
793:                            }
794:                            if (secondLen > 0) {
795:                                System.arraycopy(cbuf, off + firstLen, buffer,
796:                                        0, secondLen);
797:                                writePosition = secondLen;
798:                            } else {
799:                                writePosition += written;
800:                            }
801:                            if (writePosition == buffer.length) {
802:                                writePosition = 0;
803:                            }
804:                            off += written;
805:                            len -= written;
806:                        }
807:                        if (len > 0) {
808:                            try {
809:                                Thread.sleep(100);
810:                            } catch (Exception x) {
811:                                throw new IOException(
812:                                        "Waiting for available space in buffer interrupted.");
813:                            }
814:                        }
815:                    }
816:                }
817:
818:                /**
819:                 * Write a single character.
820:                 * The character to be written is contained in the 16 low-order bits of the
821:                 * given integer value; the 16 high-order bits are ignored.
822:                 * If the buffer allows blocking writes, this method will block until
823:                 * all the data has been written rather than throw an IOException.
824:                 *
825:                 * @param c number of characters to be written
826:                 * @throws BufferOverflowException if buffer does not allow blocking writes
827:                 *   and the buffer is full.
828:                 * @throws IOException if the stream is closed, or the write is interrupted.
829:                 *
830:                 * @since ostermillerutils 1.00.00
831:                 */
832:                @Override
833:                public void write(int c) throws IOException {
834:                    boolean written = false;
835:                    while (!written) {
836:                        synchronized (CircularCharBuffer.this ) {
837:                            if (writerClosed)
838:                                throw new IOException(
839:                                        "Writer has been closed; cannot write to a closed Writer.");
840:                            if (readerClosed)
841:                                throw new IOException(
842:                                        "Buffer closed by Reader; cannot write to a closed buffer.");
843:                            int spaceLeft = spaceLeft();
844:                            while (infinite && spaceLeft < 1) {
845:                                resize();
846:                                spaceLeft = spaceLeft();
847:                            }
848:                            if (!blockingWrite && spaceLeft < 1)
849:                                throw new BufferOverflowException(
850:                                        "CircularCharBuffer is full; cannot write 1 character");
851:                            if (spaceLeft > 0) {
852:                                buffer[writePosition] = (char) (c & 0xffff);
853:                                writePosition++;
854:                                if (writePosition == buffer.length) {
855:                                    writePosition = 0;
856:                                }
857:                                written = true;
858:                            }
859:                        }
860:                        if (!written) {
861:                            try {
862:                                Thread.sleep(100);
863:                            } catch (Exception x) {
864:                                throw new IOException(
865:                                        "Waiting for available space in buffer interrupted.");
866:                            }
867:                        }
868:                    }
869:                }
870:
871:                /**
872:                 * Write a string.
873:                 * If the buffer allows blocking writes, this method will block until
874:                 * all the data has been written rather than throw an IOException.
875:                 *
876:                 * @param str String to be written
877:                 * @throws BufferOverflowException if buffer does not allow blocking writes
878:                 *   and the buffer is full.  If the exception is thrown, no data
879:                 *   will have been written since the buffer was set to be non-blocking.
880:                 * @throws IOException if the stream is closed, or the write is interrupted.
881:                 *
882:                 * @since ostermillerutils 1.00.00
883:                 */
884:                @Override
885:                public void write(String str) throws IOException {
886:                    write(str, 0, str.length());
887:                }
888:
889:                /**
890:                 * Write a portion of a string.
891:                 * If the buffer allows blocking writes, this method will block until
892:                 * all the data has been written rather than throw an IOException.
893:                 *
894:                 * @param str A String
895:                 * @param off Offset from which to start writing characters
896:                 * @param len Number of characters to write
897:                 * @throws BufferOverflowException if buffer does not allow blocking writes
898:                 *   and the buffer is full.  If the exception is thrown, no data
899:                 *   will have been written since the buffer was set to be non-blocking.
900:                 * @throws IOException if the stream is closed, or the write is interrupted.
901:                 *
902:                 * @since ostermillerutils 1.00.00
903:                 */
904:                @Override
905:                public void write(String str, int off, int len)
906:                        throws IOException {
907:                    while (len > 0) {
908:                        synchronized (CircularCharBuffer.this ) {
909:                            if (writerClosed)
910:                                throw new IOException(
911:                                        "Writer has been closed; cannot write to a closed Writer.");
912:                            if (readerClosed)
913:                                throw new IOException(
914:                                        "Buffer closed by Reader; cannot write to a closed buffer.");
915:                            int spaceLeft = spaceLeft();
916:                            while (infinite && spaceLeft < len) {
917:                                resize();
918:                                spaceLeft = spaceLeft();
919:                            }
920:                            if (!blockingWrite && spaceLeft < len)
921:                                throw new BufferOverflowException(
922:                                        "CircularCharBuffer is full; cannot write "
923:                                                + len + " characters");
924:                            int realLen = Math.min(len, spaceLeft);
925:                            int firstLen = Math.min(realLen, buffer.length
926:                                    - writePosition);
927:                            int secondLen = Math.min(realLen - firstLen,
928:                                    buffer.length - markPosition - 1);
929:                            int written = firstLen + secondLen;
930:                            for (int i = 0; i < firstLen; i++) {
931:                                buffer[writePosition + i] = str.charAt(off + i);
932:                            }
933:                            if (secondLen > 0) {
934:                                for (int i = 0; i < secondLen; i++) {
935:                                    buffer[i] = str.charAt(off + firstLen + i);
936:                                }
937:                                writePosition = secondLen;
938:                            } else {
939:                                writePosition += written;
940:                            }
941:                            if (writePosition == buffer.length) {
942:                                writePosition = 0;
943:                            }
944:                            off += written;
945:                            len -= written;
946:                        }
947:                        if (len > 0) {
948:                            try {
949:                                Thread.sleep(100);
950:                            } catch (Exception x) {
951:                                throw new IOException(
952:                                        "Waiting for available space in buffer interrupted.");
953:                            }
954:                        }
955:                    }
956:                }
957:            }
958:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.