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