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 587913 2007-10-24 15:47:30Z 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        public void close() throws IOException {
089            try {
090                super.close();
091            } finally {
092                if (closeBranch) {
093                    branch.close();
094                }
095            }
096        }
097    
098        /**
099         * Reads a single byte from the proxied input stream and writes it to
100         * the associated output stream.
101         *
102         * @return next byte from the stream, or -1 if the stream has ended
103         * @throws IOException if the stream could not be read (or written) 
104         */
105        public int read() throws IOException {
106            int ch = super.read();
107            if (ch != -1) {
108                branch.write(ch);
109            }
110            return ch;
111        }
112    
113        /**
114         * Reads bytes from the proxied input stream and writes the read bytes
115         * to the associated output stream.
116         *
117         * @param bts byte buffer
118         * @param st start offset within the buffer
119         * @param end maximum number of bytes to read
120         * @return number of bytes read, or -1 if the stream has ended
121         * @throws IOException if the stream could not be read (or written) 
122         */
123        public int read(byte[] bts, int st, int end) throws IOException {
124            int n = super.read(bts, st, end);
125            if (n != -1) {
126                branch.write(bts, st, n);
127            }
128            return n;
129        }
130    
131        /**
132         * Reads bytes from the proxied input stream and writes the read bytes
133         * to the associated output stream.
134         *
135         * @param bts byte buffer
136         * @return number of bytes read, or -1 if the stream has ended
137         * @throws IOException if the stream could not be read (or written) 
138         */
139        public int read(byte[] bts) throws IOException {
140            int n = super.read(bts);
141            if (n != -1) {
142                branch.write(bts, 0, n);
143            }
144            return n;
145        }
146    
147    }