1 /*
2  * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.io;
27 
28 import java.io.*;
29 
30 /**
31  * A piped output stream can be connected to a piped input stream
32  * to create a communications pipe. The piped output stream is the
33  * sending end of the pipe. Typically, data is written to a
34  * <code>PipedOutputStream</code> object by one thread and data is
35  * read from the connected <code>PipedInputStream</code> by some
36  * other thread. Attempting to use both objects from a single thread
37  * is not recommended as it may deadlock the thread.
38  * The pipe is said to be <a name=BROKEN> <i>broken</i> </a> if a
39  * thread that was reading data bytes from the connected piped input
40  * stream is no longer alive.
41  *
42  * @author  James Gosling
43  * @see     java.io.PipedInputStream
44  * @since   JDK1.0
45  */
46 public
47 class PipedOutputStream extends OutputStream {
48 
49         /* REMIND: identification of the read and write sides needs to be
50            more sophisticated.  Either using thread groups (but what about
51            pipes within a thread?) or using finalization (but it may be a
52            long time until the next GC). */
53     private PipedInputStream sink;
54 
55     /**
56      * Creates a piped output stream connected to the specified piped
57      * input stream. Data bytes written to this stream will then be
58      * available as input from <code>snk</code>.
59      *
60      * @param      snk   The piped input stream to connect to.
61      * @exception  IOException  if an I/O error occurs.
62      */
PipedOutputStream(PipedInputStream snk)63     public PipedOutputStream(PipedInputStream snk)  throws IOException {
64         connect(snk);
65     }
66 
67     /**
68      * Creates a piped output stream that is not yet connected to a
69      * piped input stream. It must be connected to a piped input stream,
70      * either by the receiver or the sender, before being used.
71      *
72      * @see     java.io.PipedInputStream#connect(java.io.PipedOutputStream)
73      * @see     java.io.PipedOutputStream#connect(java.io.PipedInputStream)
74      */
PipedOutputStream()75     public PipedOutputStream() {
76     }
77 
78     /**
79      * Connects this piped output stream to a receiver. If this object
80      * is already connected to some other piped input stream, an
81      * <code>IOException</code> is thrown.
82      * <p>
83      * If <code>snk</code> is an unconnected piped input stream and
84      * <code>src</code> is an unconnected piped output stream, they may
85      * be connected by either the call:
86      * <blockquote><pre>
87      * src.connect(snk)</pre></blockquote>
88      * or the call:
89      * <blockquote><pre>
90      * snk.connect(src)</pre></blockquote>
91      * The two calls have the same effect.
92      *
93      * @param      snk   the piped input stream to connect to.
94      * @exception  IOException  if an I/O error occurs.
95      */
connect(PipedInputStream snk)96     public synchronized void connect(PipedInputStream snk) throws IOException {
97         if (snk == null) {
98             throw new NullPointerException();
99         } else if (sink != null || snk.connected) {
100             throw new IOException("Already connected");
101         }
102         sink = snk;
103         snk.in = -1;
104         snk.out = 0;
105         snk.connected = true;
106     }
107 
108     /**
109      * Writes the specified <code>byte</code> to the piped output stream.
110      * <p>
111      * Implements the <code>write</code> method of <code>OutputStream</code>.
112      *
113      * @param      b   the <code>byte</code> to be written.
114      * @exception IOException if the pipe is <a href=#BROKEN> broken</a>,
115      *          {@link #connect(java.io.PipedInputStream) unconnected},
116      *          closed, or if an I/O error occurs.
117      */
write(int b)118     public void write(int b)  throws IOException {
119         if (sink == null) {
120             throw new IOException("Pipe not connected");
121         }
122         sink.receive(b);
123     }
124 
125     /**
126      * Writes <code>len</code> bytes from the specified byte array
127      * starting at offset <code>off</code> to this piped output stream.
128      * This method blocks until all the bytes are written to the output
129      * stream.
130      *
131      * @param      b     the data.
132      * @param      off   the start offset in the data.
133      * @param      len   the number of bytes to write.
134      * @exception IOException if the pipe is <a href=#BROKEN> broken</a>,
135      *          {@link #connect(java.io.PipedInputStream) unconnected},
136      *          closed, or if an I/O error occurs.
137      */
write(byte b[], int off, int len)138     public void write(byte b[], int off, int len) throws IOException {
139         if (sink == null) {
140             throw new IOException("Pipe not connected");
141         } else if (b == null) {
142             throw new NullPointerException();
143         } else if ((off < 0) || (off > b.length) || (len < 0) ||
144                    ((off + len) > b.length) || ((off + len) < 0)) {
145             throw new IndexOutOfBoundsException();
146         } else if (len == 0) {
147             return;
148         }
149         sink.receive(b, off, len);
150     }
151 
152     /**
153      * Flushes this output stream and forces any buffered output bytes
154      * to be written out.
155      * This will notify any readers that bytes are waiting in the pipe.
156      *
157      * @exception IOException if an I/O error occurs.
158      */
flush()159     public synchronized void flush() throws IOException {
160         if (sink != null) {
161             synchronized (sink) {
162                 sink.notifyAll();
163             }
164         }
165     }
166 
167     /**
168      * Closes this piped output stream and releases any system resources
169      * associated with this stream. This stream may no longer be used for
170      * writing bytes.
171      *
172      * @exception  IOException  if an I/O error occurs.
173      */
close()174     public void close()  throws IOException {
175         if (sink != null) {
176             sink.receivedLast();
177         }
178     }
179 }
180