KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > io > PipedReader


1 /*
2  * @(#)PipedReader.java 1.15 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.io;
9
10
11 /**
12  * Piped character-input streams.
13  *
14  * @version 1.15, 03/12/19
15  * @author Mark Reinhold
16  * @since JDK1.1
17  */

18
19 public class PipedReader extends Reader JavaDoc {
20     boolean closedByWriter = false;
21     boolean closedByReader = false;
22     boolean connected = false;
23
24     /* REMIND: identification of the read and write sides needs to be
25        more sophisticated. Either using thread groups (but what about
26        pipes within a thread?) or using finalization (but it may be a
27        long time until the next GC). */

28     Thread JavaDoc readSide;
29     Thread JavaDoc writeSide;
30
31     /**
32      * The size of the pipe's circular input buffer.
33      */

34     static final int PIPE_SIZE = 1024;
35
36     /**
37      * The circular buffer into which incoming data is placed.
38      */

39     char buffer[] = new char[PIPE_SIZE];
40
41     /**
42      * The index of the position in the circular buffer at which the
43      * next character of data will be stored when received from the connected
44      * piped writer. <code>in&lt;0</code> implies the buffer is empty,
45      * <code>in==out</code> implies the buffer is full
46      */

47     int in = -1;
48
49     /**
50      * The index of the position in the circular buffer at which the next
51      * character of data will be read by this piped reader.
52      */

53     int out = 0;
54
55     /**
56      * Creates a <code>PipedReader</code> so
57      * that it is connected to the piped writer
58      * <code>src</code>. Data written to <code>src</code>
59      * will then be available as input from this stream.
60      *
61      * @param src the stream to connect to.
62      * @exception IOException if an I/O error occurs.
63      */

64     public PipedReader(PipedWriter JavaDoc src) throws IOException JavaDoc {
65     connect(src);
66     }
67
68     /**
69      * Creates a <code>PipedReader</code> so
70      * that it is not yet connected. It must be
71      * connected to a <code>PipedWriter</code>
72      * before being used.
73      *
74      * @see java.io.PipedReader#connect(java.io.PipedWriter)
75      * @see java.io.PipedWriter#connect(java.io.PipedReader)
76      */

77     public PipedReader() {
78     }
79
80     /**
81      * Causes this piped reader to be connected
82      * to the piped writer <code>src</code>.
83      * If this object is already connected to some
84      * other piped writer, an <code>IOException</code>
85      * is thrown.
86      * <p>
87      * If <code>src</code> is an
88      * unconnected piped writer and <code>snk</code>
89      * is an unconnected piped reader, they
90      * may be connected by either the call:
91      * <p>
92      * <pre><code>snk.connect(src)</code> </pre>
93      * <p>
94      * or the call:
95      * <p>
96      * <pre><code>src.connect(snk)</code> </pre>
97      * <p>
98      * The two
99      * calls have the same effect.
100      *
101      * @param src The piped writer to connect to.
102      * @exception IOException if an I/O error occurs.
103      */

104     public void connect(PipedWriter JavaDoc src) throws IOException JavaDoc {
105     src.connect(this);
106     }
107     
108     /**
109      * Receives a char of data. This method will block if no input is
110      * available.
111      */

112     synchronized void receive(int c) throws IOException JavaDoc {
113         if (!connected) {
114             throw new IOException JavaDoc("Pipe not connected");
115         } else if (closedByWriter || closedByReader) {
116         throw new IOException JavaDoc("Pipe closed");
117     } else if (readSide != null && !readSide.isAlive()) {
118             throw new IOException JavaDoc("Read end dead");
119         }
120
121     writeSide = Thread.currentThread();
122     while (in == out) {
123         if ((readSide != null) && !readSide.isAlive()) {
124         throw new IOException JavaDoc("Pipe broken");
125         }
126         /* full: kick any waiting readers */
127         notifyAll();
128         try {
129             wait(1000);
130         } catch (InterruptedException JavaDoc ex) {
131         throw new java.io.InterruptedIOException JavaDoc();
132         }
133     }
134     if (in < 0) {
135         in = 0;
136         out = 0;
137     }
138     buffer[in++] = (char) c;
139     if (in >= buffer.length) {
140         in = 0;
141     }
142     }
143
144     /**
145      * Receives data into an array of characters. This method will
146      * block until some input is available.
147      */

148     synchronized void receive(char c[], int off, int len) throws IOException JavaDoc {
149     while (--len >= 0) {
150         receive(c[off++]);
151     }
152     }
153
154     /**
155      * Notifies all waiting threads that the last character of data has been
156      * received.
157      */

158     synchronized void receivedLast() {
159     closedByWriter = true;
160     notifyAll();
161     }
162
163     /**
164      * Reads the next character of data from this piped stream.
165      * If no character is available because the end of the stream
166      * has been reached, the value <code>-1</code> is returned.
167      * This method blocks until input data is available, the end of
168      * the stream is detected, or an exception is thrown.
169      *
170      * If a thread was providing data characters
171      * to the connected piped writer, but
172      * the thread is no longer alive, then an
173      * <code>IOException</code> is thrown.
174      *
175      * @return the next character of data, or <code>-1</code> if the end of the
176      * stream is reached.
177      * @exception IOException if the pipe is broken.
178      */

179     public synchronized int read() throws IOException JavaDoc {
180         if (!connected) {
181             throw new IOException JavaDoc("Pipe not connected");
182         } else if (closedByReader) {
183         throw new IOException JavaDoc("Pipe closed");
184     } else if (writeSide != null && !writeSide.isAlive()
185                    && !closedByWriter && (in < 0)) {
186             throw new IOException JavaDoc("Write end dead");
187         }
188
189         readSide = Thread.currentThread();
190     int trials = 2;
191     while (in < 0) {
192         if (closedByWriter) {
193         /* closed by writer, return EOF */
194         return -1;
195         }
196         if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
197         throw new IOException JavaDoc("Pipe broken");
198         }
199             /* might be a writer waiting */
200         notifyAll();
201         try {
202             wait(1000);
203         } catch (InterruptedException JavaDoc ex) {
204         throw new java.io.InterruptedIOException JavaDoc();
205         }
206     }
207     int ret = buffer[out++];
208     if (out >= buffer.length) {
209         out = 0;
210     }
211     if (in == out) {
212             /* now empty */
213         in = -1;
214     }
215     return ret;
216     }
217
218     /**
219      * Reads up to <code>len</code> characters of data from this piped
220      * stream into an array of characters. Less than <code>len</code> characters
221      * will be read if the end of the data stream is reached. This method
222      * blocks until at least one character of input is available.
223      * If a thread was providing data characters to the connected piped output,
224      * but the thread is no longer alive, then an <code>IOException</code>
225      * is thrown.
226      *
227      * @param cbuf the buffer into which the data is read.
228      * @param off the start offset of the data.
229      * @param len the maximum number of characters read.
230      * @return the total number of characters read into the buffer, or
231      * <code>-1</code> if there is no more data because the end of
232      * the stream has been reached.
233      * @exception IOException if an I/O error occurs.
234      */

235     public synchronized int read(char cbuf[], int off, int len) throws IOException JavaDoc {
236         if (!connected) {
237             throw new IOException JavaDoc("Pipe not connected");
238         } else if (closedByReader) {
239         throw new IOException JavaDoc("Pipe closed");
240     } else if (writeSide != null && !writeSide.isAlive()
241                    && !closedByWriter && (in < 0)) {
242             throw new IOException JavaDoc("Write end dead");
243         }
244
245         if ((off < 0) || (off > cbuf.length) || (len < 0) ||
246             ((off + len) > cbuf.length) || ((off + len) < 0)) {
247         throw new IndexOutOfBoundsException JavaDoc();
248     } else if (len == 0) {
249         return 0;
250     }
251
252         /* possibly wait on the first character */
253     int c = read();
254     if (c < 0) {
255         return -1;
256     }
257     cbuf[off] = (char)c;
258     int rlen = 1;
259     while ((in >= 0) && (--len > 0)) {
260         cbuf[off + rlen] = buffer[out++];
261         rlen++;
262         if (out >= buffer.length) {
263         out = 0;
264         }
265         if (in == out) {
266                 /* now empty */
267         in = -1;
268         }
269     }
270     return rlen;
271     }
272
273     /**
274      * Tell whether this stream is ready to be read. A piped character
275      * stream is ready if the circular buffer is not empty.
276      *
277      * @exception IOException If an I/O error occurs
278      */

279     public synchronized boolean ready() throws IOException JavaDoc {
280         if (!connected) {
281             throw new IOException JavaDoc("Pipe not connected");
282         } else if (closedByReader) {
283         throw new IOException JavaDoc("Pipe closed");
284     } else if (writeSide != null && !writeSide.isAlive()
285                    && !closedByWriter && (in < 0)) {
286             throw new IOException JavaDoc("Write end dead");
287         }
288         if (in < 0) {
289             return false;
290         } else {
291             return true;
292         }
293     }
294  
295     /**
296      * Closes this piped stream and releases any system resources
297      * associated with the stream.
298      *
299      * @exception IOException if an I/O error occurs.
300      */

301     public void close() throws IOException JavaDoc {
302     in = -1;
303     closedByReader = true;
304     }
305 }
306
Popular Tags