//============================================================================== // MultiOutputStream.java //============================================================================== package tribble.io; import java.io.IOException; import java.io.OutputStream; import java.lang.ArrayIndexOutOfBoundsException; import java.lang.String; import java.lang.System; import java.util.ArrayList; /******************************************************************************* * Multiple output stream. * Replicates all output data written to it among one or more output streams. * *

* Data written to this stream are written to all of the underlying output * streams in the order that the streams were added to this object (see the * {@link #addOutput addOutput()} method). * *

* Note that data is written to all of the output streams even if any of them * throw IOExceptions, i.e., the output operation does not stop after * the first exception, but continues until all of the streams have been written * to. If more than one of the output streams throws an IOException, * only the first exception thrown is re-thrown by these methods. * * *

*
Source code:
*
* http://david.tribble.com/src/java/tribble/io/MultiOutputStream.java *
*
Documentation:
*
* http://david.tribble.com/docs/tribble/io/MultiOutputStream.html *
*
* * * @version $Revision: 1.3 $ $Date: 2008/09/26 14:38:30 $ * @since 2008-09-25 * @author David R. Tribble (david@tribble.com) *

* Copyright ©2008 by David R. Tribble, all rights reserved.
* Permission is granted to any person or entity except those designated by * by the United States Department of State as a terrorist, or terrorist * government or agency, to use and distribute this source code provided * that the original copyright notice remains present and unaltered. */ public class MultiOutputStream extends java.io.OutputStream { /** Revision information. */ static final String REV = "@(#)tribble/io/MultiOutputStream.java $Revision: 1.3 $ $Date: 2008/09/26 14:38:30 $\n"; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Static variables /** A multiple output stream which writes output to both System.out * and System.err. */ public static final MultiOutputStream stdouts = new MultiOutputStream(System.out, System.err); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Variables /** Output streams. */ private ArrayList/**/ m_outputs; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constructors /*************************************************************************** * Default constructor. * Constructs a multiple output stream with no underlying output streams. * Data written to this stream is ignored until an underlying output stream * is established by calling {@link #addOutput addOutput()}. * * @since 1.1, 2008-09-25 */ public MultiOutputStream() { } /*************************************************************************** * Constructor. * Contructs a multiple output stream with a single underlying output stream. * * @param out * An output stream, to which all the output of this object is written. * * @see #addOutput addOutput() * * @since 1.1, 2008-09-25 */ public MultiOutputStream(OutputStream out) { addOutput(out); } /*************************************************************************** * Constructor. * Contructs a multiple output stream with two underlying output streams. * * @param out1 * An output stream, to which all the output of this object is written. * * @param out2 * Another output stream, to which all the output of this object is written. * * @see #addOutput addOutput() * * @since 1.2, 2008-09-25 */ public MultiOutputStream(OutputStream out1, OutputStream out2) { addOutput(out1); addOutput(out2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Methods /*************************************************************************** * Add an output stream to this object. * * @param out * An output stream, to which all the output of this object is written. * * @return * The index that the specified output stream (out) has within this * object. Note that the first output stream added has an index of 0. * * @throws NullPointerException (unchecked) * Thrown if out is null. * * @see #getOutput getOutput() * * @since 1.1, 2008-09-25 */ public synchronized int addOutput(OutputStream out) { // Sanity check if (out == null) throw new NullPointerException("Null output stream"); // Add an output stream to the list of outputs if (m_outputs == null) m_outputs = new ArrayList/**/(4); m_outputs.add(out); return m_outputs.size() - 1; } /*************************************************************************** * Retrieve an output stream from this object. * * @param n * Index of the underlying output stream to retrieve. * The index number is the value returned by a previous call to * {@link #addOutput addOutput()}. * * @return * The index that the specified output stream (out) has within this * object. Note that the first output stream added has an index of 0. * * @throws ArrayIndexOutOfBoundsException (unchecked) * Thrown if n does not specify a valid output stream index. * * @see #addOutput addOutput() * * @since 1.2, 2008-09-25 */ public OutputStream getOutput(int n) { // Range check if (m_outputs == null || n < 0 || n >= m_outputs.size()) throw new ArrayIndexOutOfBoundsException( "Bad output stream index: " + n); // Get an output stream from the list of outputs return (OutputStream) m_outputs.get(n); } /*************************************************************************** * Flush all the output streams of this object. * All of the underlying output streams are flushed, forcing any pending * output data to be written. * * @throws IOException * Thrown if flushing any of the underlying output streams causes an * IOException to be thrown. If this happens, the first exception * thrown is re-thrown by this method after all of the underlying streams are * flushed. * * @since 1.2, 2008-09-25 */ public void flush() throws IOException //overrides java.io.OutputStream { IOException err = null; // Sanity check if (m_outputs == null) return; // Flush all the output streams in the list of outputs for (int i = 0; i < m_outputs.size(); i++) { try { OutputStream out; // Flush an underlying output stream out = (OutputStream) m_outputs.get(i); out.flush(); } catch (IOException ex) { if (err == null) err = ex; } } // Handle any caught exceptions if (err != null) throw err; } /*************************************************************************** * Close all the output streams of this object. * All of the underlying output streams are flushed and closed, and then * forgotten, so this object will no longer have any output streams assigned * to it. Any subsequent writes to this object will therefore be ignored. * * @throws IOException * Thrown if closing any of the underlying output streams causes an * IOException to be thrown. If this happens, the first exception * thrown is re-thrown by this method after all of the underlying streams are * closed. * * @since 1.2, 2008-09-25 */ public void close() throws IOException //overrides java.io.OutputStream { IOException err = null; // Sanity check if (m_outputs == null) return; // Close all the output streams in the list of outputs for (int i = 0; i < m_outputs.size(); i++) { try { OutputStream out; // Close an underlying output stream out = (OutputStream) m_outputs.get(i); out.close(); } catch (IOException ex) { if (err == null) err = ex; } } // Discard the list of outputs m_outputs = null; // Handle any caught exceptions if (err != null) throw err; } /*************************************************************************** * Write a byte to the output streams of this object. * * @param b * An output byte. * * @throws IOException * Thrown if any of the underlying output streams throws this exception. * * @since 1.1, 2008-09-25 */ public void write(int b) throws IOException //overrides java.io.OutputStream { IOException err = null; int nOuts; // Sanity check if (m_outputs == null) return; // Write the data byte to all of the output streams nOuts = m_outputs.size(); for (int i = 0; i < nOuts; i++) { try { OutputStream out; // Write the data byte to one of the output streams out = (OutputStream) m_outputs.get(i); out.write(b); } catch (IOException ex) { if (err == null) err = ex; } } // Handle any caught exceptions if (err != null) throw err; } /*************************************************************************** * Write a set of bytes to the output streams of this object. * This is identical to the call: *

    *    {@link #write(byte[], int, int) write}(buf, 0, buf.length)
* * @param buf * An array of bytes to be written. * * @throws IOException * Thrown if any of the underlying output streams throws this exception. * * @since 1.1, 2008-09-25 */ public void write(/*const*/ byte[] buf) throws IOException //overrides java.io.OutputStream { write(buf, 0, buf.length); } /*************************************************************************** * Write a set of bytes to the output streams of this object. * * @param buf * An array of bytes to be written. * * @param off * Index of the first byte in buf to write. * * @param len * Number of bytes in buf to write. * * @throws IOException * Thrown if any of the underlying output streams throws this exception. * * @since 1.1, 2008-09-25 */ public void write(/*const*/ byte[] buf, int off, int len) throws IOException //overrides java.io.OutputStream { IOException err = null; int nOuts; // Sanity check if (m_outputs == null) return; // Write the data bytes to all of the output streams nOuts = m_outputs.size(); for (int i = 0; i < nOuts; i++) { try { OutputStream out; // Write the data bytes to one of the output streams out = (OutputStream) m_outputs.get(i); out.write(buf, off, len); } catch (IOException ex) { if (err == null) err = ex; } } // Handle any caught exceptions if (err != null) throw err; } } // End MultiOutputStream.java