    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.io.input;
    018
    019    import java.io.IOException;
    020    import java.io.InputStream;
    021    import java.io.OutputStream;
    022
    023    /**
    024     * InputStream proxy that transparently writes a copy of all bytes read
    025     * from the proxied stream to a given OutputStream. Using {@link #skip(long)}
    026     * or {@link #mark(int)}/{@link #reset()} on the stream will result on some
    027     * bytes from the input stream being skipped or duplicated in the output
    028     * stream.
    029     * <p>
    030     * The proxied input stream is closed when the {@link #close()} method is
    031     * called on this proxy. It is configurable whether the associated output
    032     * stream will also closed.
    033     *
    034     * @version $Id: TeeInputStream.java 659817 2008-05-24 13:23:10Z niallp $
    035     * @since Commons IO 1.4
    036     */
    037    public class TeeInputStream extends ProxyInputStream {
    038
    039        /**
    040         * The output stream that will receive a copy of all bytes read from the
    041         * proxied input stream.
    042         */
    043        private final OutputStream branch;
    044
    045        /**
    046         * Flag for closing also the associated output stream when this
    047         * stream is closed.
    048         */
    049        private final boolean closeBranch;
    050
    051        /**
    052         * Creates a TeeInputStream that proxies the given {@link InputStream}
    053         * and copies all read bytes to the given {@link OutputStream}. The given
    054         * output stream will not be closed when this stream gets closed.
    055         *
    056         * @param input input stream to be proxied
    057         * @param branch output stream that will receive a copy of all bytes read
    058         */
    059        public TeeInputStream(InputStream input, OutputStream branch) {
    060            this(input, branch, false);
    061        }
    062
    063        /**
    064         * Creates a TeeInputStream that proxies the given {@link InputStream}
    065         * and copies all read bytes to the given {@link OutputStream}. The given
    066         * output stream will be closed when this stream gets closed if the
    067         * closeBranch parameter is <code>true</code>.
    068         *
    069         * @param input input stream to be proxied
    070         * @param branch output stream that will receive a copy of all bytes read
    071         * @param closeBranch flag for closing also the output stream when this
    072         *                    stream is closed
    073         */
    074        public TeeInputStream(
    075                InputStream input, OutputStream branch, boolean closeBranch) {
    076            super(input);
    077            this.branch = branch;
    078            this.closeBranch = closeBranch;
    079        }
    080
    081        /**
    082         * Closes the proxied input stream and, if so configured, the associated
    083         * output stream. An exception thrown from one stream will not prevent
    084         * closing of the other stream.
    085         *
    086         * @throws IOException if either of the streams could not be closed
    087         */
    088        @Override
    089        public void close() throws IOException {
    090            try {
    091                super.close();
    092            } finally {
    093                if (closeBranch) {
    094                    branch.close();
    095                }
    096            }
    097        }
    098
    099        /**
    100         * Reads a single byte from the proxied input stream and writes it to
    101         * the associated output stream.
    102         *
    103         * @return next byte from the stream, or -1 if the stream has ended
    104         * @throws IOException if the stream could not be read (or written)
    105         */
    106        @Override
    107        public int read() throws IOException {
    108            int ch = super.read();
    109            if (ch != -1) {
    110                branch.write(ch);
    111            }
    112            return ch;
    113        }
    114
    115        /**
    116         * Reads bytes from the proxied input stream and writes the read bytes
    117         * to the associated output stream.
    118         *
    119         * @param bts byte buffer
    120         * @param st start offset within the buffer
    121         * @param end maximum number of bytes to read
    122         * @return number of bytes read, or -1 if the stream has ended
    123         * @throws IOException if the stream could not be read (or written)
    124         */
    125        @Override
    126        public int read(byte[] bts, int st, int end) throws IOException {
    127            int n = super.read(bts, st, end);
    128            if (n != -1) {
    129                branch.write(bts, st, n);
    130            }
    131            return n;
    132        }
    133
    134        /**
    135         * Reads bytes from the proxied input stream and writes the read bytes
    136         * to the associated output stream.
    137         *
    138         * @param bts byte buffer
    139         * @return number of bytes read, or -1 if the stream has ended
    140         * @throws IOException if the stream could not be read (or written)
    141         */
    142        @Override
    143        public int read(byte[] bts) throws IOException {
    144            int n = super.read(bts);
    145            if (n != -1) {
    146                branch.write(bts, 0, n);
    147            }
    148            return n;
    149        }
    150
    151    }