Home | History | Annotate | Download | only in io
      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      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    174     public void close()  throws IOException {
    175         if (sink != null) {
    176             sink.receivedLast();
    177         }
    178     }
    179 }
    180