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 18package 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 */ 27public 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("stream == null"); 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