Home | History | Annotate | Download | only in io
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.io;
     19 
     20 /**
     21  * Places information on a communications pipe. When two threads want to pass
     22  * data back and forth, one creates a piped output stream and the other one
     23  * creates a piped input stream.
     24  *
     25  * @see PipedInputStream
     26  */
     27 public class PipedOutputStream extends OutputStream {
     28 
     29     /**
     30      * The destination PipedInputStream
     31      */
     32     private PipedInputStream target;
     33 
     34     /**
     35      * Constructs a new unconnected {@code PipedOutputStream}. The resulting
     36      * stream must be connected to a {@link PipedInputStream} before data can be
     37      * written to it.
     38      */
     39     public PipedOutputStream() {
     40     }
     41 
     42     /**
     43      * Constructs a new {@code PipedOutputStream} connected to the
     44      * {@link PipedInputStream} {@code target}. Any data written to this stream
     45      * can be read from the target stream.
     46      *
     47      * @param target
     48      *            the piped input stream to connect to.
     49      * @throws IOException
     50      *             if this stream or {@code target} are already connected.
     51      */
     52     public PipedOutputStream(PipedInputStream target) throws IOException {
     53         connect(target);
     54     }
     55 
     56     /**
     57      * Closes this stream. If this stream is connected to an input stream, the
     58      * input stream is closed and the pipe is disconnected.
     59      *
     60      * @throws IOException
     61      *             if an error occurs while closing this stream.
     62      */
     63     @Override
     64     public void close() throws IOException {
     65         // Is the pipe connected?
     66         PipedInputStream stream = target;
     67         if (stream != null) {
     68             stream.done();
     69             target = null;
     70         }
     71     }
     72 
     73     /**
     74      * Connects this stream to a {@link PipedInputStream}. Any data written to
     75      * this output stream becomes readable in the input stream.
     76      *
     77      * @param stream
     78      *            the piped input stream to connect to.
     79      * @throws IOException
     80      *             if either stream is already connected.
     81      */
     82     public void connect(PipedInputStream stream) throws IOException {
     83         if (stream == null) {
     84             throw new NullPointerException();
     85         }
     86         synchronized (stream) {
     87             if (this.target != null) {
     88                 throw new IOException("Already connected");
     89             }
     90             if (stream.isConnected) {
     91                 throw new IOException("Pipe already connected");
     92             }
     93             stream.establishConnection();
     94             this.target = stream;
     95         }
     96     }
     97 
     98     /**
     99      * Notifies the readers of this {@link PipedInputStream} that bytes can be
    100      * read. This method does nothing if this stream is not connected.
    101      *
    102      * @throws IOException
    103      *             if an I/O error occurs while flushing this stream.
    104      */
    105     @Override
    106     public void flush() throws IOException {
    107         PipedInputStream stream = target;
    108         if (stream == null) {
    109             return;
    110         }
    111 
    112         synchronized (stream) {
    113             stream.notifyAll();
    114         }
    115     }
    116 
    117     /**
    118      * Writes {@code count} bytes from the byte array {@code buffer} starting at
    119      * {@code offset} to this stream. The written data can then be read from the
    120      * connected input stream.
    121      * <p>
    122      * Separate threads should be used to write to a {@code PipedOutputStream}
    123      * and to read from the connected {@link PipedInputStream}. If the same
    124      * thread is used, a deadlock may occur.
    125      *
    126      * @param buffer
    127      *            the buffer to write.
    128      * @param offset
    129      *            the index of the first byte in {@code buffer} to write.
    130      * @param count
    131      *            the number of bytes from {@code buffer} to write to this
    132      *            stream.
    133      * @throws IndexOutOfBoundsException
    134      *             if {@code offset < 0} or {@code count < 0}, or if {@code
    135      *             offset + count} is bigger than the length of {@code buffer}.
    136      * @throws InterruptedIOException
    137      *             if the pipe is full and the current thread is interrupted
    138      *             waiting for space to write data. This case is not currently
    139      *             handled correctly.
    140      * @throws IOException
    141      *             if this stream is not connected, if the target stream is
    142      *             closed or if the thread reading from the target stream is no
    143      *             longer alive. This case is currently not handled correctly.
    144      */
    145     @Override
    146     public void write(byte[] buffer, int offset, int count) throws IOException {
    147         super.write(buffer, offset, count);
    148     }
    149 
    150     /**
    151      * Writes a single byte to this stream. Only the least significant byte of
    152      * the integer {@code oneByte} is written. The written byte can then be read
    153      * from the connected input stream.
    154      * <p>
    155      * Separate threads should be used to write to a {@code PipedOutputStream}
    156      * and to read from the connected {@link PipedInputStream}. If the same
    157      * thread is used, a deadlock may occur.
    158      *
    159      * @param oneByte
    160      *            the byte to write.
    161      * @throws InterruptedIOException
    162      *             if the pipe is full and the current thread is interrupted
    163      *             waiting for space to write data. This case is not currently
    164      *             handled correctly.
    165      * @throws IOException
    166      *             if this stream is not connected, if the target stream is
    167      *             closed or if the thread reading from the target stream is no
    168      *             longer alive. This case is currently not handled correctly.
    169      */
    170     @Override
    171     public void write(int oneByte) throws IOException {
    172         PipedInputStream stream = target;
    173         if (stream == null) {
    174             throw new IOException("Pipe not connected");
    175         }
    176         stream.receive(oneByte);
    177     }
    178 }
    179