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 */
017package org.apache.commons.io.output;
018
019import java.io.IOException;
020import java.io.OutputStream;
021
022/**
023 * Classic splitter of {@link OutputStream}. Named after the Unix 'tee' command. It allows a stream to be branched off so there
024 * are now two streams.
025 */
026public class TeeOutputStream extends ProxyOutputStream {
027
028    /** the second OutputStream to write to */
029    protected OutputStream branch; //TODO consider making this private
030
031    /**
032     * Constructs a TeeOutputStream.
033     * @param out the main OutputStream
034     * @param branch the second OutputStream
035     */
036    public TeeOutputStream(final OutputStream out, final OutputStream branch) {
037        super(out);
038        this.branch = branch;
039    }
040
041    /**
042     * Write the bytes to both streams.
043     * @param b the bytes to write
044     * @throws IOException if an I/O error occurs
045     */
046    @Override
047    public synchronized void write(final byte[] b) throws IOException {
048        super.write(b);
049        this.branch.write(b);
050    }
051
052    /**
053     * Write the specified bytes to both streams.
054     * @param b the bytes to write
055     * @param off The start offset
056     * @param len The number of bytes to write
057     * @throws IOException if an I/O error occurs
058     */
059    @Override
060    public synchronized void write(final byte[] b, final int off, final int len) throws IOException {
061        super.write(b, off, len);
062        this.branch.write(b, off, len);
063    }
064
065    /**
066     * Write a byte to both streams.
067     * @param b the byte to write
068     * @throws IOException if an I/O error occurs
069     */
070    @Override
071    public synchronized void write(final int b) throws IOException {
072        super.write(b);
073        this.branch.write(b);
074    }
075
076    /**
077     * Flushes both streams.
078     * @throws IOException if an I/O error occurs
079     */
080    @Override
081    public void flush() throws IOException {
082        super.flush();
083        this.branch.flush();
084    }
085
086    /**
087     * Closes both output streams.
088     *
089     * If closing the main output stream throws an exception, attempt to close the branch output stream.
090     *
091     * If closing the main and branch output streams both throw exceptions, which exceptions is thrown by this method is
092     * currently unspecified and subject to change.
093     *
094     * @throws IOException
095     *             if an I/O error occurs
096     */
097    @Override
098    public void close() throws IOException {
099        try {
100            super.close();
101        } finally {
102            this.branch.close();
103        }
104    }
105
106}