All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ml.alternet.io.InputStreamAggregator Maven / Gradle / Ivy

Go to download

Alternet Tools include discovery service tools, concurrent and locking tools, and more

The newest version!
package ml.alternet.io;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * InputStreamAggregator aggregates several InputStreams into a single
 * one.
 *
 * @see java.io.InputStream
 *
 * @author Philippe Poulard
 */
public class InputStreamAggregator extends InputStream {

    private static final Logger LOGGER = Logger.getLogger(InputStreamAggregator.class.getName());

    // An iterator on the input streams.
    private Iterator it = null;
    // The current InputStream.
    private InputStream current = null;
    // True if this close() method has been called.
    private boolean closed = false;

    /**
     * Create a new InputStream aggregator.
     *
     * @param input
     *            A non-{@code null} list (possibly empty) of InputStreams.
     */
    public InputStreamAggregator(List input) {
        this.it = input.iterator();
        next();
    }

    /**
     * Create a new InputStream aggregator.
     *
     * @param input
     *            A non-{@code null} iterator (possibly empty) on InputStreams.
     */
    public InputStreamAggregator(Iterator input) {
        this.it = input;
        next();
    }

    /**
     * Create a new InputStream aggregator.
     *
     * @param input
     *            The InputStream to read.
     */
    public InputStreamAggregator(InputStream... input) {
        this.it = Arrays.asList(input).iterator();
        next();
    }

    /**
     * Advance to the next input.
     */
    private void next() {
        if (this.current != null) {
            try {
                this.current.close();
            } catch (IOException e) {
                LOGGER.log(Level.INFO, e.getMessage(), e);
            }
        }
        if (this.it.hasNext()) {
            this.current = this.it.next();
        } else {
            this.current = null;
        }
    }

    /**
     * Read a single byte. This method will block until a byte is available, an
     * I/O error occurs, or the end of all underlying streams are reached.
     *
     * @return The byte read, as an integer in the range 0 to 255, or -1 if the
     *         end of the stream has been reached.
     *
     * @throws IOException
     *             If an I/O error occurs
     */
    @Override
    public int read() throws IOException {
        if (this.closed) {
            throw new IOException("InputStream closed");
        }
        int r = -1;
        if (this.current != null) {
            r = this.current.read();
            if (r == -1) {
                next();
                r = read();
            }
        }
        return r;
    }

    /**
     * Read bytes into an array. This method will block until some input is
     * available, an I/O error occurs, or the end of all underlying streams are
     * reached.
     *
     * @param bytes
     *            The destination buffer.
     * @return The number of bytes read, or -1 if the end of the stream has been
     *         reached.
     *
     * @throws IOException
     *             If an I/O error occurs
     * @throws NullPointerException
     *             If cbuf is null.
     */
    @Override
    public int read(byte[] bytes) throws IOException {
        return read(bytes, 0, bytes.length);
    }

    /**
     * Read bytes into a portion of an array. This method will block until some
     * input is available, an I/O error occurs, or the end of all underlying
     * streams are reached.
     *
     * @param bytes
     *            The destination buffer.
     * @param off
     *            The offset at which to start storing bytes.
     * @param len
     *            The maximum number of bytes to read.
     * @return The number of bytes read, or -1 if the end of the stream has been
     *         reached.
     *
     * @throws IOException
     *             If an I/O error occurs
     * @throws NullPointerException
     *             If "bytes" is null.
     * @throws IndexOutOfBoundsException
     *             If len or offset are out of the boundaries of the buffer.
     */
    @Override
    public int read(byte[] bytes, int off, int len) throws IOException {
        if (off < 0 || len < 0 || off + len > bytes.length) {
            throw new IndexOutOfBoundsException();
        }
        if (this.closed) {
            throw new IOException("InputStream closed");
        }
        int r = -1;
        if (this.current != null) {
            r = this.current.read(bytes, off, len);
            if (r == -1) {
                next();
                r = read(bytes, off, len);
            } else if (r < len) {
                next();
                int next = read(bytes, off + r, len - r);
                if (next != -1) {
                    r += next;
                }
            }
        }
        return r;
    }

    /**
     * Skip bytes. This method will block until some bytes are available, an I/O
     * error occurs, or the end of the stream is reached.
     *
     * @param n
     *            The number of bytes to skip.
     * @return The number of bytes actually skipped.
     *
     * @throws IllegalArgumentException
     *             If n is negative.
     * @throws IOException
     *             If an I/O error occurs
     */
    @Override
    public long skip(long n) throws IOException {
        if (this.closed) {
            throw new IOException("InputStream closed");
        }
        if (n < 0) {
            throw new IllegalArgumentException("Can't skip " + n + " bytes");
        }
        if (n == 0 || this.current == null) {
            return 0;
        }
        long s = this.current.skip(n);
        if (s < n) {
            next();
            s += skip(n - s);
        }
        return s;
    }

    /**
     * Returns the number of bytes that can be read from this input stream
     * without blocking.
     * 

* The available method of InputStreamAggregator * returns the sum of the the number of bytes remaining to be read in the * current buffer (count - pos) and the result of calling * the available method of the underlying input stream. * * @return The number of bytes that can be read from this input stream * without blocking. * @exception IOException * if an I/O error occurs. * @see java.io.FilterInputStream */ @Override public synchronized int available() throws IOException { if (this.closed) { throw new IOException("InputStream closed"); } if (this.current == null) { return 0; } return this.current.available(); } /** * Close the stream and any underlying streams. Once a stream has been * closed, further read(), ready(), mark(), or reset() invocations will * throw an IOException. Closing a previously-closed stream, however, has no * effect. * * @throws IOException * If an I/O error occurs */ @Override public void close() throws IOException { if (closed) { return; } while (this.current != null) { this.current.close(); next(); } closed = true; } /** * Mark not supported. * * @param readlimit * Not used. */ @Override public void mark(int readlimit) { } /** * Reset not supported. * * @throws IOException * Always thrown. */ @Override public void reset() throws IOException { throw new IOException("Reset not supported"); } /** * Mark not supported. * * @return false. */ @Override public boolean markSupported() { return false; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy