//==============================================================================
// 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