1 /* 2 * Copyright (c) 1994, 2019, 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 /** 29 * This class is the superclass of all classes that filter output 30 * streams. These streams sit on top of an already existing output 31 * stream (the <i>underlying</i> output stream) which it uses as its 32 * basic sink of data, but possibly transforming the data along the 33 * way or providing additional functionality. 34 * <p> 35 * The class <code>FilterOutputStream</code> itself simply overrides 36 * all methods of <code>OutputStream</code> with versions that pass 37 * all requests to the underlying output stream. Subclasses of 38 * <code>FilterOutputStream</code> may further override some of these 39 * methods as well as provide additional methods and fields. 40 * 41 * @author Jonathan Payne 42 * @since 1.0 43 */ 44 public class FilterOutputStream extends OutputStream { 45 /** 46 * The underlying output stream to be filtered. 47 */ 48 protected OutputStream out; 49 50 /** 51 * Whether the stream is closed; implicitly initialized to false. 52 */ 53 private volatile boolean closed; 54 55 /** 56 * Object used to prevent a race on the 'closed' instance variable. 57 */ 58 private final Object closeLock = new Object(); 59 60 /** 61 * Creates an output stream filter built on top of the specified 62 * underlying output stream. 63 * 64 * @param out the underlying output stream to be assigned to 65 * the field {@code this.out} for later use, or 66 * <code>null</code> if this instance is to be 67 * created without an underlying stream. 68 */ 69 public FilterOutputStream(OutputStream out) { 70 if (out == null) { 71 throw new NullPointerException(); 72 } 73 74 this.out = out; 75 } 76 77 /** 78 * Writes the specified <code>byte</code> to this output stream. 79 * <p> 80 * The <code>write</code> method of <code>FilterOutputStream</code> 81 * calls the <code>write</code> method of its underlying output stream, 82 * that is, it performs {@code out.write(b)}. 83 * <p> 84 * Implements the abstract {@code write} method of {@code OutputStream}. 85 * 86 * @param b the <code>byte</code>. 87 * @exception IOException if an I/O error occurs. 88 */ 89 @Override 90 public void write(int b) throws IOException { 91 out.write(b); 92 } 93 94 /** 95 * Writes <code>b.length</code> bytes to this output stream. 96 * <p> 97 * The <code>write</code> method of <code>FilterOutputStream</code> 98 * calls its <code>write</code> method of three arguments with the 99 * arguments <code>b</code>, <code>0</code>, and 100 * <code>b.length</code>. 101 * <p> 102 * Note that this method does not call the one-argument 103 * <code>write</code> method of its underlying output stream with 104 * the single argument <code>b</code>. 105 * 106 * @param b the data to be written. 107 * @exception IOException if an I/O error occurs. 108 * @see java.io.FilterOutputStream#write(byte[], int, int) 109 */ 110 @Override 111 public void write(byte b[]) throws IOException { 112 write(b, 0, b.length); 113 } 114 115 /** 116 * Writes <code>len</code> bytes from the specified 117 * <code>byte</code> array starting at offset <code>off</code> to 118 * this output stream. 119 * <p> 120 * The <code>write</code> method of <code>FilterOutputStream</code> 121 * calls the <code>write</code> method of one argument on each 122 * <code>byte</code> to output. 123 * <p> 124 * Note that this method does not call the <code>write</code> method 125 * of its underlying output stream with the same arguments. Subclasses 126 * of <code>FilterOutputStream</code> should provide a more efficient 127 * implementation of this method. 128 * 129 * @param b the data. 130 * @param off the start offset in the data. 131 * @param len the number of bytes to write. 132 * @exception IOException if an I/O error occurs. 133 * @see java.io.FilterOutputStream#write(int) 134 */ 135 @Override 136 public void write(byte b[], int off, int len) throws IOException { 137 if ((off | len | (b.length - (len + off)) | (off + len)) < 0) 138 throw new IndexOutOfBoundsException(); 139 140 for (int i = 0 ; i < len ; i++) { 141 write(b[off + i]); 142 } 143 } 144 145 /** 146 * Flushes this output stream and forces any buffered output bytes 147 * to be written out to the stream. 148 * <p> 149 * The <code>flush</code> method of <code>FilterOutputStream</code> 150 * calls the <code>flush</code> method of its underlying output stream. 151 * 152 * @exception IOException if an I/O error occurs. 153 * @see java.io.FilterOutputStream#out 154 */ 155 @Override 156 public void flush() throws IOException { 157 out.flush(); 158 } 159 160 /** 161 * Closes this output stream and releases any system resources 162 * associated with the stream. 163 * <p> 164 * When not already closed, the {@code close} method of {@code 165 * FilterOutputStream} calls its {@code flush} method, and then 166 * calls the {@code close} method of its underlying output stream. 167 * 168 * @exception IOException if an I/O error occurs. 169 * @see java.io.FilterOutputStream#flush() 170 * @see java.io.FilterOutputStream#out 171 */ 172 @Override 173 public void close() throws IOException { 174 if (closed) { 175 return; 176 } 177 synchronized (closeLock) { 178 if (closed) { 179 return; 180 } 181 closed = true; 182 } 183 184 Throwable flushException = null; 185 try { 186 flush(); 187 } catch (Throwable e) { 188 flushException = e; 189 throw e; 190 } finally { 191 if (flushException == null) { 192 out.close(); 193 } else { 194 try { 195 out.close(); 196 } catch (Throwable closeException) { 197 // evaluate possible precedence of flushException over closeException 198 if ((flushException instanceof ThreadDeath) && 199 !(closeException instanceof ThreadDeath)) { 200 flushException.addSuppressed(closeException); 201 throw (ThreadDeath) flushException; 202 } 203 204 if (flushException != closeException) { 205 closeException.addSuppressed(flushException); 206 } 207 208 throw closeException; 209 } 210 } 211 } 212 } 213 }