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

org.ow2.easywsdl.wsdl.util.InputStreamForker Maven / Gradle / Ivy

There is a newer version: 2.8.0
Show newest version
/**
 * PETALS - PETALS Services Platform.
 * Copyright (c) 2008 OW2 Consortium, http://www.ow2.org/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * -------------------------------------------------------------------------
 * $Id$
 * -------------------------------------------------------------------------
 */

package org.ow2.easywsdl.wsdl.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * Initial developer(s): Christophe DENEUX
 * 
 * @author cdeneux - Capgemini Sud
 * 
 */
public class InputStreamForker {

    private InputStream originalInputStream;

    private final ForkedInputStream is1;

    private final ForkedInputStream is2;

    /**
     * true if the close() method has been called on two forked input
     * streams
     */
    protected boolean originalInputStreamClosed = false;

    public InputStreamForker(final InputStream originalInputStream) {
        this.originalInputStream = originalInputStream;

        this.is1 = new ForkedInputStream();
        this.is2 = new ForkedInputStream();
        
        this.is1.setOtherForkedInputStream(this.is2);
        this.is2.setOtherForkedInputStream(this.is1);

    }
    
    public InputStream getInputStreamOne() {
        return this.is1;
    }

    public InputStream getInputStreamTwo() {
        return this.is2;
    }

    protected class ForkedInputStream extends InputStream {

        final private LinkedList bufferList;
        
        private boolean isClosed = false;
        
        /**
         * The other forked input stream.
         */
        private ForkedInputStream otherForkedInputStream;

        /**
         * A reference on the other branch of inputstream to improve
         * performances (avoid to call {@link ForkedInputStream#getBufferList()}
         * on {@link #otherForkedInputStream}).
         */
        private LinkedList otherBufferList;

        public ForkedInputStream() {
            this.bufferList = new LinkedList();;
        }
        
        public void setOtherForkedInputStream(final ForkedInputStream otherForkedInputStream) {
            this.otherForkedInputStream = otherForkedInputStream;
            this.otherBufferList = this.otherForkedInputStream.getBufferList();
        }
        
        public LinkedList getBufferList() {
            return this.bufferList;
        }
        public boolean isClosed() {
            return this.isClosed;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public int available() throws IOException {
            synchronized (InputStreamForker.this) {

                int available = 0;

                final Iterator iterator = this.bufferList.iterator();
                while (iterator.hasNext()) {
                    available += iterator.next().length;
                }

                if (!InputStreamForker.this.originalInputStreamClosed && !this.isClosed) {
                    available += InputStreamForker.this.originalInputStream
                            .available();
                }

                return available;
            }
        }

        /**
         * 

{@inheritDoc}

*

If both forked input streams are closed, the original input stream is closed.

*

If the forked stream has already been closed, this method has no effect.

*/ @Override public void close() throws IOException { if (!this.isClosed) { synchronized (InputStreamForker.this) { this.isClosed = true; // Note: It's not needed to check if the original input // stream is closed because it is closed when closing one of // two forked input streams. So, as the current forked input // stream is not closed, the original input stream is not // closed. if (this.otherForkedInputStream.isClosed) { // The other forked input stream is closed, we close the // original input stream InputStreamForker.this.originalInputStream.close(); InputStreamForker.this.originalInputStreamClosed = true; } } } } @Override public boolean markSupported() { return false; } /** *

* Reads the next byte of data from the input stream. The value byte is * returned as an int in the range 0 to * 255. If no byte is available because the end of the * stream has been reached, the value -1 is returned. * This method blocks until input data is available, the end of the * stream is detected, or an exception is thrown. *

*

* The byte is read in the internal buffer. If no data is available in * the internal buffer, the byte is read from the original input stream. *

* * @return the next byte of data, or -1 if the end of the * stream is reached. * @exception IOException * if an I/O error occurs. */ @Override public int read() throws IOException { byte[] buffer = new byte[1]; int nbByteRead = this.read(buffer); if (nbByteRead != 1) { throw new IOException("No byte read."); } return buffer[0]; } @Override public int read(final byte[] cbuf) throws IOException { return this.read(cbuf, 0, cbuf.length); } @Override public int read(final byte[] cbuf, final int off, final int len) throws IOException { return this.localRead(cbuf, off, len, false); } @Override public long skip(long n) throws IOException, IllegalArgumentException { if (n > Long.MAX_VALUE) { throw new IllegalArgumentException("Only value lesser " + Integer.MAX_VALUE + "are accepted."); } return this.localRead(null, 0, (int) n, true); } private int localRead(final byte[] cbuf, final int off, final int len, final boolean skip) throws IOException { int remainingLen = len; int offset = off; int byteRead; // Original input stream reading and buffer list management must // be synchronized. Otherwise, inversions can occur. synchronized (InputStreamForker.this) { // First we read from the internal buffers int nbBuffers = this.bufferList.size(); while (nbBuffers > 0 && remainingLen != 0) { final byte[] buffer = this.bufferList.getFirst(); if (remainingLen >= buffer.length) { // Full copy needed if (!skip) { System.arraycopy(buffer, 0, cbuf, offset, buffer.length); } this.bufferList.removeFirst(); remainingLen -= buffer.length; if (remainingLen == 0) { // No more bytes must be read return len; } offset += buffer.length; nbBuffers--; } else { // Partial copy needed because the buffer len to read is // reached if (!skip) { System.arraycopy(buffer, 0, cbuf, offset, remainingLen); } // Replace byte buffer by a buffer containing remaining // bytes final byte[] newBuffer = new byte[buffer.length - remainingLen]; System.arraycopy(buffer, remainingLen, newBuffer, 0, buffer.length - remainingLen); this.bufferList.removeFirst(); this.bufferList.addFirst(newBuffer); return len; } } // Next, we read missing bytes from the original input stream if (InputStreamForker.this.originalInputStreamClosed) { throw new IOException( "The original InputStream has been closed; cannot read from a closed InputStream."); } byte[] buffer = new byte[remainingLen]; byteRead = InputStreamForker.this.originalInputStream.read( buffer, 0, remainingLen); if (byteRead != -1) { // We add the read bytes into the other branch, only if it is not closed. if (!this.otherForkedInputStream.isClosed()) { if (byteRead == remainingLen) { // We can add the buffer as is because of its length is // right. this.otherBufferList.addLast(buffer); } else { final byte[] newBuffer = new byte[byteRead]; System.arraycopy(buffer, 0, newBuffer, 0, byteRead); this.otherBufferList.addLast(newBuffer); } } if (!skip) { System.arraycopy(buffer, 0, cbuf, offset, remainingLen); } return len - remainingLen + byteRead; } else { // EOF of the originial input stream is reached, we must // return -1 (EOF) if no bytes have been read from the // buffer list. if (len == remainingLen) { // no bytes have been read from the buffer list. return -1; } else { // bytes have been read from the buffer list. return len - remainingLen; } } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy