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