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