001: /*
002: * @(#)PipedWriter.java 1.21 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.io;
029:
030: /**
031: * Piped character-output streams.
032: *
033: * @version 1.13, 00/02/02
034: * @author Mark Reinhold
035: * @since JDK1.1
036: */
037:
038: public class PipedWriter extends Writer {
039:
040: /* Identification of the read and write sides needs to be
041: more sophisticated. Either using thread groups (but what about
042: pipes within a thread?) or using finalization (but it may be a
043: long time until the next GC). */
044: private PipedReader sink;
045:
046: /* This flag records the open status of this particular writer. It
047: * is independent of the status flags defined in PipedReader. It is
048: * used to do a sanity check on connect.
049: */
050: private boolean closed = false;
051:
052: /**
053: * Creates a piped writer connected to the specified piped
054: * reader. Data characters written to this stream will then be
055: * available as input from <code>snk</code>.
056: *
057: * @param snk The piped reader to connect to.
058: * @exception IOException if an I/O error occurs.
059: */
060: public PipedWriter(PipedReader snk) throws IOException {
061: connect(snk);
062: }
063:
064: /**
065: * Creates a piped writer that is not yet connected to a
066: * piped reader. It must be connected to a piped reader,
067: * either by the receiver or the sender, before being used.
068: *
069: * @see java.io.PipedReader#connect(java.io.PipedWriter)
070: * @see java.io.PipedWriter#connect(java.io.PipedReader)
071: */
072: public PipedWriter() {
073: }
074:
075: /**
076: * Connects this piped writer to a receiver. If this object
077: * is already connected to some other piped reader, an
078: * <code>IOException</code> is thrown.
079: * <p>
080: * If <code>snk</code> is an unconnected piped reader and
081: * <code>src</code> is an unconnected piped writer, they may
082: * be connected by either the call:
083: * <blockquote><pre>
084: * src.connect(snk)</pre></blockquote>
085: * or the call:
086: * <blockquote><pre>
087: * snk.connect(src)</pre></blockquote>
088: * The two calls have the same effect.
089: *
090: * @param snk the piped reader to connect to.
091: * @exception IOException if an I/O error occurs.
092: */
093: public synchronized void connect(PipedReader snk)
094: throws IOException {
095: if (snk == null) {
096: throw new NullPointerException();
097: } else if (sink != null || snk.connected) {
098: throw new IOException("Already connected");
099: } else if (snk.closedByReader || closed) {
100: throw new IOException("Pipe closed");
101: }
102:
103: sink = snk;
104: snk.in = -1;
105: snk.out = 0;
106: snk.connected = true;
107: }
108:
109: /**
110: * Writes the specified <code>char</code> to the piped output stream.
111: * If a thread was reading data characters from the connected piped input
112: * stream, but the thread is no longer alive, then an
113: * <code>IOException</code> is thrown.
114: * <p>
115: * Implements the <code>write</code> method of <code>Writer</code>.
116: *
117: * @param c the <code>char</code> to be written.
118: * @exception IOException if an I/O error occurs.
119: */
120: public void write(int c) throws IOException {
121: if (sink == null) {
122: throw new IOException("Pipe not connected");
123: }
124: sink.receive(c);
125: }
126:
127: /**
128: * Writes <code>len</code> characters from the specified character array
129: * starting at offset <code>off</code> to this piped output stream.
130: * If a thread was reading data characters from the connected piped input
131: * stream, but the thread is no longer alive, then an
132: * <code>IOException</code> is thrown.
133: *
134: * @param cbuf the data.
135: * @param off the start offset in the data.
136: * @param len the number of characters to write.
137: * @exception IOException if an I/O error occurs.
138: */
139: public void write(char cbuf[], int off, int len) throws IOException {
140: if (sink == null) {
141: throw new IOException("Pipe not connected");
142: } else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {
143: throw new IndexOutOfBoundsException();
144: }
145: sink.receive(cbuf, off, len);
146: }
147:
148: /**
149: * Flushes this output stream and forces any buffered output characters
150: * to be written out.
151: * This will notify any readers that characters are waiting in the pipe.
152: *
153: * @exception IOException if an I/O error occurs.
154: */
155: public synchronized void flush() throws IOException {
156: if (sink != null) {
157: if (sink.closedByReader || closed) {
158: throw new IOException("Pipe closed");
159: }
160: synchronized (sink) {
161: sink.notifyAll();
162: }
163: }
164: }
165:
166: /**
167: * Closes this piped output stream and releases any system resources
168: * associated with this stream. This stream may no longer be used for
169: * writing characters.
170: *
171: * @exception IOException if an I/O error occurs.
172: */
173: public void close() throws IOException {
174: closed = true;
175: if (sink != null) {
176: sink.receivedLast();
177: }
178: }
179: }
|