1 /* 2 * Copyright (c) 1994, 2017, 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 this.out = out; 71 } 72 73 /** 74 * Writes the specified <code>byte</code> to this output stream. 75 * <p> 76 * The <code>write</code> method of <code>FilterOutputStream</code> 77 * calls the <code>write</code> method of its underlying output stream, 78 * that is, it performs {@code out.write(b)}. 79 * <p> 80 * Implements the abstract {@code write} method of {@code OutputStream}. 81 * 82 * @param b the <code>byte</code>. 83 * @exception IOException if an I/O error occurs. 84 */ 85 @Override 86 public void write(int b) throws IOException { 87 out.write(b); 88 } 89 90 /** 91 * Writes <code>b.length</code> bytes to this output stream. 92 * <p> 93 * The <code>write</code> method of <code>FilterOutputStream</code> 94 * calls its <code>write</code> method of three arguments with the 95 * arguments <code>b</code>, <code>0</code>, and 96 * <code>b.length</code>. 97 * <p> 98 * Note that this method does not call the one-argument 99 * <code>write</code> method of its underlying output stream with 100 * the single argument <code>b</code>. 101 * 102 * @param b the data to be written. 103 * @exception IOException if an I/O error occurs. 104 * @see java.io.FilterOutputStream#write(byte[], int, int) 105 */ 106 @Override 107 public void write(byte b[]) throws IOException { 108 write(b, 0, b.length); 109 } 110 111 /** 112 * Writes <code>len</code> bytes from the specified 113 * <code>byte</code> array starting at offset <code>off</code> to 114 * this output stream. 115 * <p> 116 * The <code>write</code> method of <code>FilterOutputStream</code> 117 * calls the <code>write</code> method of one argument on each 118 * <code>byte</code> to output. 119 * <p> 120 * Note that this method does not call the <code>write</code> method 121 * of its underlying output stream with the same arguments. Subclasses 122 * of <code>FilterOutputStream</code> should provide a more efficient 123 * implementation of this method. 124 * 125 * @param b the data. 126 * @param off the start offset in the data. 127 * @param len the number of bytes to write. 128 * @exception IOException if an I/O error occurs. 129 * @see java.io.FilterOutputStream#write(int) 130 */ 131 @Override 132 public void write(byte b[], int off, int len) throws IOException { 133 if ((off | len | (b.length - (len + off)) | (off + len)) < 0) 134 throw new IndexOutOfBoundsException(); 135 136 for (int i = 0 ; i < len ; i++) { 137 write(b[off + i]); 138 } 139 } 140 141 /** 142 * Flushes this output stream and forces any buffered output bytes 143 * to be written out to the stream. 144 * <p> 145 * The <code>flush</code> method of <code>FilterOutputStream</code> 146 * calls the <code>flush</code> method of its underlying output stream. 147 * 148 * @exception IOException if an I/O error occurs. 149 * @see java.io.FilterOutputStream#out 150 */ 151 @Override 152 public void flush() throws IOException { 153 out.flush(); 154 } 155 156 /** 157 * Closes this output stream and releases any system resources 158 * associated with the stream. 159 * <p> 160 * When not already closed, the {@code close} method of {@code 161 * FilterOutputStream} calls its {@code flush} method, and then 162 * calls the {@code close} method of its underlying output stream. 163 * 164 * @exception IOException if an I/O error occurs. 165 * @see java.io.FilterOutputStream#flush() 166 * @see java.io.FilterOutputStream#out 167 */ 168 @Override 169 public void close() throws IOException { 170 if (closed) { 171 return; 172 } 173 synchronized (closeLock) { 174 if (closed) { 175 return; 176 } 177 closed = true; 178 } 179 180 Throwable flushException = null; 181 try { 182 flush(); 183 } catch (Throwable e) { 184 flushException = e; 185 throw e; 186 } finally { 187 if (flushException == null) { 188 out.close(); 189 } else { 190 try { 191 out.close(); 192 } catch (Throwable closeException) { 193 // evaluate possible precedence of flushException over closeException 194 if ((flushException instanceof ThreadDeath) && 195 !(closeException instanceof ThreadDeath)) { 196 flushException.addSuppressed(closeException); 197 throw (ThreadDeath) flushException; 198 } 199 200 if (flushException != closeException) { 201 closeException.addSuppressed(flushException); 202 } 203 204 throw closeException; 205 } 206 } 207 } 208 } 209 }