/*
 * Written by Dawid Kurzyniec and released to the public domain, as explained
 * at http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.util.io;

import java.io.*;


/**
 * Buffered input stream that behaves correctly under asynchronous close.
 *
 * @author Dawid Kurzyniec
 */

public class ThreadSafeBufferedInputStream extends BufferedInputStream {
    final boolean tainted;
    public ThreadSafeBufferedInputStream(InputStream in) {
        super(in);
        tainted = (in.getClass() == BufferedInputStream.class);
    }
    public synchronized int read(byte[] buf, int off, int len) throws IOException {
        if (tainted) {
            try {
                return super.read(buf, off, len);
            }
            catch (NullPointerException e) {
                throw new IOException("Stream closed");
            }
        }
        else {
            return super.read(buf, off, len);
        }
    }
    public void close() throws IOException {
        // make sure that read, if in progress, is immediately interrupted
        // and monitor held by read is released. Note that it itself does not
        // solve the problem if in is itself BufferedInputStream; hence,
        // the "tainted" field
        in.close();
        // synchronization here excludes the situation where the reference to
        // "in" is cleared out while read is in progress, resulting in
        // NullPointerExceptions.
        synchronized (this) {
            super.close();
        }
    }
}
