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 1307461 2012-03-30 15:12:29Z ggregory $
035     * @since 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}.
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    }