TimeoutOutputStream.java

package gov.usgs.earthquake.util;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * An output stream that self-closes if the specified timeout elapses between
 * writes.
 */
public class TimeoutOutputStream extends FilterOutputStream implements Runnable {

  /** write timeout in milliseconds. */
  private final long timeout;
  /** thread that enforces timeout. */
  private final Thread timeoutThread;
  /** flag for timeoutThread to terminate. */
  private boolean closed = false;

  /**
   * Create a TimeoutOutputStream.
   *
   * @param out     the wrapped output stream.
   * @param timeout the timeout in milliseconds between writes. If this timeout
   *                completes, the underlying stream will be closed.
   */
  public TimeoutOutputStream(final OutputStream out, final long timeout) {
    super(out);
    this.timeout = timeout;
    this.timeoutThread = new Thread(this);
    this.timeoutThread.start();
  }

  @Override
  public void write(int b) throws IOException {
    // pass directly to underlying stream
    this.out.write(b);
    timeoutThread.interrupt();
  }

  @Override
  public void write(byte[] buf) throws IOException {
    // pass directly to underlying stream
    this.out.write(buf);
    timeoutThread.interrupt();
  }

  @Override
  public void write(byte[] buf, int offset, int length) throws IOException {
    // pass directly to underlying stream
    this.out.write(buf, offset, length);
    timeoutThread.interrupt();
  }

  @Override
  public void close() throws IOException {
    closed = true;
    try {
      super.close();
    } finally {
      // interrupt in case close called from outside timeoutThread
      timeoutThread.interrupt();
    }
  }

  @Override
  public void run() {
    while (!closed) {
      try {
        // wait for timeout milliseconds
        Thread.sleep(timeout);
        // timeout elapsed, close stream
        try {
          close();
        } catch (IOException e) {
        }
      } catch (InterruptedException ie) {
        // a write occured
      }
    }
  }

}