import java.io.*;
import java.util.*;

/** The MulticastOutputStream class is used to provide a single stream
 * that encapsulates arbitrarily many constituent streams such that writing
 * to the one MulticastOutputStream effectively writes to all of the
 * constituent streams.  A simple example of how this could be used would
 * be to arrange to have messages automatically go both to a log file
 * and to the console.
 *
 * <p>Efficiency note: the representation chosen for 
 * MulticastOutputStream was selected based on the
 * assumption that either the number of constituent
 * streams will be small or the remove method will
 * be infrequently used.
 *
 * <p> Written 17 Aug 1996 by
 * <a href="http://www.gac.edu/~max">Max Hailperin</a>
 * <a href="mailto:max@gac.edu">&lt;max@gac.edu&gt;</a>
 */

public class MulticastOutputStream extends OutputStream{
  /** The add method adds another constituent stream
   * to receive all output hencforth sent to the MulticastOutputStream
   * (until the constituent stream is removed).  This is the only
   * way the MulticastOutputStream comes to do anything useful,
   * because when created there are no constituent streams.
   * It is undefined what will happen if a stream that is already
   * one of the constituent streams is added a second time. */
  public synchronized void add(OutputStream newOut){
    streams.addElement(newOut);
  }

  /** The remove method disconnects one of the constituent streams,
   * so that output to the MulticastOutputStream no longer goes there.
   * The removed stream is not closed, however, and thus can still be
   * separately written to or later added back in.  It is undefined
   * what happens if the stream is not one of the constituent streams */
  public synchronized void remove(OutputStream oldOut){
    streams.removeElement(oldOut);
  }

  public synchronized void close()
       throws IOException
  {
    for(int i = 0; i < streams.size(); i++){
      ((OutputStream)streams.elementAt(i)).close();
    }
    streams.removeAllElements();
  }

  public synchronized void flush()
       throws IOException
  {
    for(int i = 0; i < streams.size(); i++){
      ((OutputStream)streams.elementAt(i)).flush();
    }
  }

  public synchronized void write(byte b[])
       throws IOException
  {
    for(int i = 0; i < streams.size(); i++){
      ((OutputStream)streams.elementAt(i)).write(b);
    }
  }

  public synchronized void write(byte b[], int off, int len)
       throws IOException
  {
    for(int i = 0; i < streams.size(); i++){
      ((OutputStream)streams.elementAt(i)).write(b, off, len);
    }
  }

  public synchronized void write(int b)
       throws IOException
  {
    for(int i = 0; i < streams.size(); i++){
      ((OutputStream)streams.elementAt(i)).write(b);
    }
  }

  Vector streams = new Vector();
}