/* * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.io; import java.io.*; /** {@collect.stats} * {@description.open} * A piped output stream can be connected to a piped input stream * to create a communications pipe. The piped output stream is the * sending end of the pipe. Typically, data is written to a * <code>PipedOutputStream</code> object by one thread and data is * read from the connected <code>PipedInputStream</code> by some * other thread. * {@description.close} * {@property.open runtime formal:java.io.PipedStream_SingleThread} * Attempting to use both objects from a single thread * is not recommended as it may deadlock the thread. * {@property.close} * {@description.open} * The pipe is said to be <a name=BROKEN> <i>broken</i> </a> if a * thread that was reading data bytes from the connected piped input * stream is no longer alive. * {@description.close} * * @author James Gosling * @see java.io.PipedInputStream * @since JDK1.0 */ public class PipedOutputStream extends OutputStream { /* REMIND: identification of the read and write sides needs to be more sophisticated. Either using thread groups (but what about pipes within a thread?) or using finalization (but it may be a long time until the next GC). */ private PipedInputStream sink; /** {@collect.stats} * {@description.open} * Creates a piped output stream connected to the specified piped * input stream. Data bytes written to this stream will then be * available as input from <code>snk</code>. * {@description.close} * * @param snk The piped input stream to connect to. * @exception IOException if an I/O error occurs. */ public PipedOutputStream(PipedInputStream snk) throws IOException { connect(snk); } /** {@collect.stats} * {@description.open} * Creates a piped output stream that is not yet connected to a * piped input stream. It must be connected to a piped input stream, * either by the receiver or the sender, before being used. * {@description.close} * * @see java.io.PipedInputStream#connect(java.io.PipedOutputStream) * @see java.io.PipedOutputStream#connect(java.io.PipedInputStream) */ public PipedOutputStream() { } /** {@collect.stats} * {@description.open} * Connects this piped output stream to a receiver. If this object * is already connected to some other piped input stream, an * <code>IOException</code> is thrown. * <p> * If <code>snk</code> is an unconnected piped input stream and * <code>src</code> is an unconnected piped output stream, they may * be connected by either the call: * <blockquote><pre> * src.connect(snk)</pre></blockquote> * or the call: * <blockquote><pre> * snk.connect(src)</pre></blockquote> * The two calls have the same effect. * {@description.close} * * @param snk the piped input stream to connect to. * @exception IOException if an I/O error occurs. */ public synchronized void connect(PipedInputStream snk) throws IOException { if (snk == null) { throw new NullPointerException(); } else if (sink != null || snk.connected) { throw new IOException("Already connected"); } sink = snk; snk.in = -1; snk.out = 0; snk.connected = true; } /** {@collect.stats} * {@description.open} * Writes the specified <code>byte</code> to the piped output stream. * <p> * Implements the <code>write</code> method of <code>OutputStream</code>. * {@description.close} * * @param b the <code>byte</code> to be written. * @exception IOException if the pipe is <a href=#BROKEN> broken</a>, * {@link #connect(java.io.PipedInputStream) unconnected}, * closed, or if an I/O error occurs. */ public void write(int b) throws IOException { if (sink == null) { throw new IOException("Pipe not connected"); } sink.receive(b); } /** {@collect.stats} * {@description.open} * Writes <code>len</code> bytes from the specified byte array * starting at offset <code>off</code> to this piped output stream. * {@description.close} * {@description.open blocking} * This method blocks until all the bytes are written to the output * stream. * {@description.close} * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @exception IOException if the pipe is <a href=#BROKEN> broken</a>, * {@link #connect(java.io.PipedInputStream) unconnected}, * closed, or if an I/O error occurs. */ public void write(byte b[], int off, int len) throws IOException { if (sink == null) { throw new IOException("Pipe not connected"); } else if (b == null) { throw new NullPointerException(); } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } sink.receive(b, off, len); } /** {@collect.stats} * {@description.open} * Flushes this output stream and forces any buffered output bytes * to be written out. * This will notify any readers that bytes are waiting in the pipe. * {@description.close} * * @exception IOException if an I/O error occurs. */ public synchronized void flush() throws IOException { if (sink != null) { synchronized (sink) { sink.notifyAll(); } } } /** {@collect.stats} * {@description.open} * Closes this piped output stream and releases any system resources * associated with this stream. * {@description.close} * {@property.open runtime formal:java.io.OutputStream_ManipulateAfterClose} * This stream may no longer be used for * writing bytes. * {@property.close} * * @exception IOException if an I/O error occurs. */ public void close() throws IOException { if (sink != null) { sink.receivedLast(); } } }