Package org.xlightweb

Source Code of org.xlightweb.BlockingBodyDataSource$PartHandler

/*
*  Copyright (c) xlightweb.org, 2008 - 2010. All rights reserved.
*
*  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
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xlightweb.org/
*/
package org.xlightweb;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Closeable;
import java.net.SocketTimeoutException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.xsocket.DataConverter;
import org.xsocket.IDataSource;
import org.xsocket.MaxReadSizeExceededException;



/**
*
* I/O resource capable of providing body data in a blocking way. Read operations will be suspended,
* if not enough data is available.
*
* The BlockingBodyDataSource wraps a {@link NonBlockingBodyDataSource}
*  
* @author grro@xlightweb.org
*
*/
public final class BlockingBodyDataSource implements IDataSource, ReadableByteChannel, Closeable {
 
  private static final Logger LOG = Logger.getLogger(BlockingBodyDataSource.class.getName());
 
  public static final int DEFAULT_RECEIVE_TIMEOUT = Integer.MAX_VALUE;

 
  private final ReadNotificationHandler handler = new ReadNotificationHandler();
  private final Object readGuard = new Object();
 
  private final NonBlockingBodyDataSource delegate;
  private int receiveTimeoutSec = DEFAULT_RECEIVE_TIMEOUT;

  // part support
  private PartHandler partHandler = null;
 
 
 
  /**
   * constructor
   *
   * @param delegate the underlying non NonBlockingBodyDataSource
   */
  BlockingBodyDataSource(NonBlockingBodyDataSource delegate) throws IOException {
    this.delegate = delegate;
    delegate.setDataHandler(handler);
  }
 
 
  IHeader getHeader() {
    return delegate.getHeader();
  }
 
    String getEncoding() {
        return delegate.getEncoding();
    }
  
 
  /**
   * returns the underlying tcp connection
   * @return the underlying tcp connection
   */
  NonBlockingBodyDataSource getUnderliyingBodyDataSource() {
    return delegate;
  }


 
  /**
   * sets the receive time out by reading data 
   *  
   * @param timeout  the receive timeout
   */
  public void setReceiveTimeoutSec(int timeout)  {
    this.receiveTimeoutSec = timeout;
  }


  /**
   * gets receive time out by reading data 
   * @return the receive timeout
   */
  public int getReceiveTimeoutSec()  {
    return receiveTimeoutSec;
 
 


  /**
   * returns, if the connection is open.
   *
   * @return true if the connection is open
   */
  public boolean isOpen() {
    return delegate.isOpen();
  }
   

    /**
     * return true if the body is a mulipart
     * @return true, if the body is a mulipart
     */
    public final boolean isMultipart() {
      return delegate.isMultipart();
    }
 
  /**
   * {@inheritDoc}
   */
  public void close() throws IOException {
    delegate.close();
  }

 
  /**
   * get the body size
   *
   * @return  the body size
   * @throws IOException if an exception occurs
   */
  public int size() throws IOException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        if (delegate.isCompleteReceived()) {
          return delegate.available();
        } else {
          waitUntilBodyIsComplete(remainingTime);
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);

    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }

 
     /**
     * Marks the read position in the connection. Subsequent calls to resetToReadMark() will attempt
     * to reposition the connection to this point.
     *
     */
    public void markReadPosition() {
       delegate.markReadPosition();
    }


    /**
     * Resets to the marked read position. If the connection has been marked,
     * then attempt to reposition it at the mark.
     *
     * @return true, if reset was successful
     */
    public boolean resetToReadMark() {
        return delegate.resetToReadMark();
    }


   
    /**
     * remove the read mark
     */
    public void removeReadMark() {
        delegate.removeReadMark();
    }
 
   
    /**
     * read the next part of the mulipart body. {@link BlockingBodyDataSource#isMultipart()} can
     *  be used to verify if the body is a multipart one
     *
     * <pre>
     *  // ...
     *  
     *  BlockingBodyDataSource body = response.getBlockingBody();
     *  if (body.isMultipart()) {
     *      IPart part = body.readPart();
     *      // ...
     *  } else {
     *      // ...
     *  }
     * </pre>
     *
     * @return the next part
   * @throws IOException if an exception occurs
   * @throws NoMultipartTypeException if the body type is not a multipart type
     */
  public IPart readPart() throws NoMultipartTypeException, IOException {
    initPartReader();
   
      long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        try {
          IPart part = delegate.readPart();
          return part;
        } catch (BufferUnderflowException bue) {
          waitUntilBodyIsComplete(remainingTime);
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);

    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");   
  }
 

  /**
   * return all parts of the multipart body. {@link BlockingBodyDataSource#isMultipart()} can
     *  be used to verify if the body is a multipart one
     *
     * <pre>
     *  // ...
     *  
     *  BlockingBodyDataSource body = response.getBlockingBody();
     *  if (body.isMultipart()) {
     *      List<IPart> parts = body.readParts();
     *      // ...
     *  } else {
     *      // ...
     *  }
     * </pre>
   *
   * @return the list of all parts
   * @throws IOException if an exception occurs
   * @throws NoMultipartTypeException if the surrounding body type is not a multipart type
   */
  public List<IPart> readParts() throws NoMultipartTypeException, IOException {
    List<IPart> parts = new ArrayList<IPart>();
   
    while (true) {
      try {
        parts.add(readPart());
      } catch (ClosedChannelException cce) {
        return parts;
      }
    }
  }
 
 
    private synchronized void initPartReader() throws IOException {
      if (partHandler == null) {
        partHandler = new PartHandler();
        delegate.setBodyPartHandler(partHandler);
      }
    }
 
 
  
  private final class PartHandler implements IPartHandler, IUnsynchronized {
   
    public PartHandler() {
    }
 
    public void onPart(NonBlockingBodyDataSource dataSource) throws IOException, BadMessageException {
      onReadDataInserted();
    }
  }

   
  
 
  /**
   * read the body
   *
   * @return the body as byte buffer
   * 
   * @throws IOException if an exception occurs
   */
  public ByteBuffer[] readByteBuffer() throws IOException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        if (delegate.isCompleteReceived()) {
          return readByteBufferByLength(delegate.available());
        } else {
          waitUntilBodyIsComplete(remainingTime);
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);

    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 

 
   
  /**
   * read the body
   *
   * @return the body as bytes
   * 
   * @throws IOException if an exception occurs
   */
  public byte[] readBytes() throws IOException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        if (delegate.isCompleteReceived()) {
          return readBytesByLength(delegate.available());
        } else {
          waitUntilBodyIsComplete(remainingTime);
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);

    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 
 
 
  /**
   * read the body
   *
   * @return the body as string
   * 
   * @throws IOException if an exception occurs
   */
  public String readString() throws IOException {
      return readString(delegate.getEncoding());
  }


 
    /**
     * read the body
     *
     * @param encoding  the encoding
     * @return the body as string
     * 
     * @throws IOException if an exception occurs
     */
    public String readString(String encoding) throws IOException {
        long start = System.currentTimeMillis();
        long remainingTime = receiveTimeoutSec;

        do {
            synchronized (readGuard) {
                if (delegate.isCompleteReceived()) {
                    delegate.removeLeadingBOM();
                    return readStringByLength(delegate.available(), encoding);
                } else {
                    waitUntilBodyIsComplete(remainingTime);
                }
            }

            remainingTime = computeRemainingTime(start, receiveTimeoutSec);
        } while (remainingTime > 0);

        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
        }

        throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
   
 
 
  private void waitUntilBodyIsComplete(long remainingTime) throws IOException {
      
    if (delegate.isMoreInputDataExpected()) {  // is not complete AND not terminated
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("waiting until body is complete received (guard: " + readGuard + ")");
            }

      waitingForData(readGuard, remainingTime);
     
    } else {
       
        // if not complete throw exeption
      if (!delegate.isCompleteReceived()) {
          DetailedClosedChannelException cce = new DetailedClosedChannelException("insufficient data received (data received: " + delegate.getSizeDataReceived() + ")");
                if (LOG.isLoggable(Level.FINE)) {
                    LOG.fine(cce.getMessage());
                }
        throw cce;
       
      } else {
          if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("complete body received (guard: " + readGuard + ")");
            }     
      }
    } 
  }


 
 
  /**
   * {@inheritDoc}.
   */
  public int read(ByteBuffer buffer) throws IOException {
    int size = buffer.remaining();
    if (size < 1) {
      return 0;
    }

    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    synchronized (readGuard) {
      do {
        int availableSize = delegate.available();

        // if at least one byte is available -> read and return
        if (availableSize > 0) {
          int read = delegate.read(buffer);
          if (read > 0) {
            return read;
          }
        }
       
        if (availableSize == -1) {
                    // check if channel is closed by reading with length 0
                    // is closed a ClosedChannelException will be thrown
                    delegate.read(ByteBuffer.allocate(0));
        }
   
        // no data available
        if (isOpen()) {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("waiting for at least 1 byte (guard: " + readGuard + ")");
            }
          waitingForData(readGuard, remainingTime);
         
        } else {
          return -1;
        }
       
        remainingTime = computeRemainingTime(start, receiveTimeoutSec);
      } while (remainingTime > 0);
    }

    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 
 
 
  /**
   * {@inheritDoc}
   */
  public byte readByte() throws IOException, BufferUnderflowException, SocketTimeoutException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        try {
          return delegate.readByte();
        } catch (BufferUnderflowException bue) {
          if (!delegate.isCompleteReceived()) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("waiting for 1 byte (guard: " + readGuard + ")");
              }

            waitingForData(readGuard, remainingTime);
           
          } else {
            throw new ClosedChannelException();
          }
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);

    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 
 

  /**
   * {@inheritDoc}
   */
  public short readShort() throws IOException, BufferUnderflowException, SocketTimeoutException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        try {
          return delegate.readShort();
        } catch (BufferUnderflowException bue) {
          if (!delegate.isCompleteReceived()) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("waiting for " + (2 - delegate.size()) + "bytes (guard: " + readGuard + ")");
              }

            waitingForData(readGuard, remainingTime);               
          } else {
            throw new ClosedChannelException();
          }
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);
   

    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 
 
  /**
   * {@inheritDoc}
   */
  public int readInt() throws IOException, BufferUnderflowException, SocketTimeoutException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;
 
    do {
      synchronized (readGuard) {
        try {
          return delegate.readInt();
        } catch (BufferUnderflowException bue) {
          if (!delegate.isCompleteReceived()) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("waiting for " + (4 - delegate.size()) + "bytes (guard: " + readGuard + ")");
              }

            waitingForData(readGuard, remainingTime);               
          } else {
            throw new ClosedChannelException();
          }
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);


    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 
 
  /**
   * {@inheritDoc}
   */
  public long readLong() throws IOException, BufferUnderflowException, SocketTimeoutException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        try {
          return delegate.readLong();
        } catch (BufferUnderflowException bue) {
          if (!delegate.isCompleteReceived()) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("waiting for " + (8 - delegate.size()) + "bytes (guard: " + readGuard + ")");
              }

            waitingForData(readGuard, remainingTime);               
          } else {
            throw new ClosedChannelException();
          }
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);


    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }

 
  /**
   * {@inheritDoc}
   */
  public double readDouble() throws IOException, BufferUnderflowException, SocketTimeoutException {
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        try {
          return delegate.readDouble();
        } catch (BufferUnderflowException bue) {
          if (!delegate.isCompleteReceived()) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("waiting for " + (8 - delegate.size()) + "bytes (guard: " + readGuard + ")");
              }

            waitingForData(readGuard, remainingTime);               
          } else {
            throw new ClosedChannelException();
          }
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);


    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 
 
  /**
   * {@inheritDoc}
   */
  public ByteBuffer[] readByteBufferByDelimiter(String delimiter) throws IOException, BufferUnderflowException, SocketTimeoutException {
    return readByteBufferByDelimiter(delimiter, Integer.MAX_VALUE);
  }
 
 

  /**
   * {@inheritDoc}
   */
  public ByteBuffer[] readByteBufferByDelimiter(String delimiter, int maxLength) throws IOException, BufferUnderflowException, MaxReadSizeExceededException, SocketTimeoutException {

    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

   
    do {
      synchronized (readGuard) {
        try {
          return delegate.readByteBufferByDelimiter(delimiter, maxLength);
           
        } catch (MaxReadSizeExceededException mre) {
          throw mre;

        } catch (BufferUnderflowException bue) {
          if (!delegate.isCompleteReceived()) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("waiting for more reveived data (guard: " + readGuard + ")");
              }

            waitingForData(readGuard, remainingTime);               
          } else {
            throw new ClosedChannelException();
          }
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);
 
    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
 
 
  /**
   * {@inheritDoc}
   */
  public ByteBuffer[] readByteBufferByLength(int length) throws IOException, BufferUnderflowException, SocketTimeoutException {
    if (length <= 0) {
      return new ByteBuffer[0];
    }

    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {
      synchronized (readGuard) {
        try {
          return delegate.readByteBufferByLength(length);
        } catch (BufferUnderflowException bue) {
          if (!delegate.isCompleteReceived()) {
              if (LOG.isLoggable(Level.FINE)) {
                  LOG.fine("waiting for " + (length - delegate.size()) + "bytes (guard: " + readGuard + ")");
              }

            waitingForData(readGuard, remainingTime);
          } else {
            throw new ClosedChannelException();
          }
        }
      }

      remainingTime = computeRemainingTime(start, receiveTimeoutSec);
    } while (remainingTime > 0);
   
       
    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }

 
 
  private long computeRemainingTime(long start, int receiveTimeoutSec) {
    return (start + ((long) receiveTimeoutSec * 1000)) - System.currentTimeMillis();
  }

 

 
  /**
   * {@inheritDoc}
   */
  public byte[] readBytesByDelimiter(String delimiter) throws IOException, BufferUnderflowException, SocketTimeoutException {
    return readBytesByDelimiter(delimiter, Integer.MAX_VALUE);
  }
 
  /**
   * {@inheritDoc}
   */
  public byte[] readBytesByDelimiter(String delimiter, int maxLength) throws IOException, BufferUnderflowException, MaxReadSizeExceededException, SocketTimeoutException {
    return DataConverter.toBytes(readByteBufferByDelimiter(delimiter, maxLength));
  }
 
 
  /**
   * {@inheritDoc}
   */
  public byte[] readBytesByLength(int length) throws IOException, BufferUnderflowException, SocketTimeoutException {
    return DataConverter.toBytes(readByteBufferByLength(length));
  }
 
  /**
   * {@inheritDoc}
   */
  public String readStringByDelimiter(String delimiter) throws IOException, BufferUnderflowException, UnsupportedEncodingException, SocketTimeoutException {
      return readStringByDelimiter(delimiter, delegate.getEncoding());
  }


    /**
     * read a string by using a delimiter
     *
     * @param delimiter   the delimiter
     * @param encoding    encoding
     * @return the string
     * @throws IOException If some other I/O error occurs
     * @throws UnsupportedEncodingException if the default encoding is not supported
     * @throws BufferUnderflowException if not enough data is available
     * @throws SocketTimeoutException if a timeout occurs
     */
  public String readStringByDelimiter(String delimiter, String encoding) throws IOException, BufferUnderflowException, UnsupportedEncodingException, SocketTimeoutException {
        delegate.removeLeadingBOM();
        return DataConverter.toString(readByteBufferByDelimiter(delimiter), encoding);
    }
 
  /**
   * {@inheritDoc}
   */
  public String readStringByDelimiter(String delimiter, int maxLength) throws IOException, BufferUnderflowException, UnsupportedEncodingException, MaxReadSizeExceededException, SocketTimeoutException {
      return readStringByDelimiter(delimiter, maxLength, delegate.getEncoding());
  }
 
 
  /**
     * read a string by using a delimiter
     *
     * @param delimiter   the delimiter
     * @param maxLength   the max length of bytes that should be read. If the limit is exceeded a MaxReadSizeExceededException will been thrown
     * @param encoding    the encoding
     * @return the string
     * @throws MaxReadSizeExceededException If the max read length has been exceeded and the delimiter hasn�t been found    
     * @throws IOException If some other I/O error occurs
     * @throws UnsupportedEncodingException If the given encoding is not supported
     * @throws BufferUnderflowException if not enough data is available
     * @throws SocketTimeoutException if the timout is reached
     */
    public String readStringByDelimiter(String delimiter, int maxLength, String encoding) throws IOException, BufferUnderflowException, UnsupportedEncodingException, MaxReadSizeExceededException, SocketTimeoutException {
        delegate.removeLeadingBOM();
        return DataConverter.toString(readByteBufferByDelimiter(delimiter, maxLength), encoding);
    }
 
  /**
   * {@inheritDoc}
   */
  public String readStringByLength(int length) throws IOException, BufferUnderflowException, UnsupportedEncodingException, SocketTimeoutException {
      return readStringByLength(length, delegate.getEncoding());
  }
 
 

   
    /**
     * read a string by using a length definition
     *
     * @param length    the amount of bytes to read
     * @param encoding  the encoding
     * @return the string
     * @throws IOException If some other I/O error occurs
     * @throws SocketTimeoutException if the timeout is reached
     * @throws BufferUnderflowException if not enough data is available
     */
    public String readStringByLength(int length, String encoding) throws IOException, BufferUnderflowException, UnsupportedEncodingException, SocketTimeoutException {
       delegate.removeLeadingBOM();
        return DataConverter.toString(readByteBufferByLength(length), encoding);
    }
   
 
  /**
   * {@inheritDoc}
   */
  public long transferTo(WritableByteChannel target, int length) throws IOException, BufferUnderflowException, SocketTimeoutException {
    long written = 0;
   
    ByteBuffer[] buffers = readByteBufferByLength(length);
    for (ByteBuffer buffer : buffers) {
      written += target.write(buffer);
    }
   
    return written;
  }
   
 

  /**
   * transfers the content to the given channel
   *
   * @param target                the target channel
   * @return the number of transfered bytes
   * @return the number of transfered bytes
   * @throws ClosedChannelException If either this channel or the target channel is closed
   * @throws IOException If some other I/O error occurs
   */
  public long transferTo(WritableByteChannel target) throws IOException, BufferUnderflowException, SocketTimeoutException {
    long written = 0;
   
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {

      int available = delegate.available();
     
      if (available > 0) {
        written += transferTo(target, available);
       
      } else if (available == -1) {
        return written;
      }
     
      synchronized (readGuard) {
        if (delegate.available() == 0) {
            if (LOG.isLoggable(Level.FINE)) {
                        LOG.fine("waiting for al least 1 bytes (guard: " + readGuard + ")");
                    }
           
          waitingForData(readGuard, remainingTime);
        }
      }
     
      remainingTime = computeRemainingTime(start, receiveTimeoutSec);

    } while (remainingTime > 0);

   
    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");
  }
   

 
  /**
   * transfer the available data of the this source channel to the given data sink
   *
   * @param dataSink   the data sink
   *
   * @return the number of transfered bytes
   * @throws ClosedChannelException If either this channel or the target channel is closed
   * @throws IOException If some other I/O error occurs
    * @throws BufferUnderflowException if not enough data is available
   */
  public long transferTo(BodyDataSink dataSink) throws ProtocolException, IOException, ClosedChannelException,BufferUnderflowException {
    return transferTo(dataSink, size());
  }
 
 
  /**
     * transfer the available data of the this source channel to the given data sink
     *
     * @param dataSink   the data sink
     *
     * @return the number of transfered bytes
     * @throws ClosedChannelException If either this channel or the target channel is closed
     * @throws IOException If some other I/O error occurs
     * @throws BufferUnderflowException if not enough data is available
     */
    public long transferTo(OutputStream dataSink) throws ProtocolException, IOException, ClosedChannelException,BufferUnderflowException {
        return transferTo(Channels.newChannel(dataSink));
    }
   
 

  /**
   * transfer the data of the this source channel to the given data sink
   *
   * @param dataSink            the data sink
   * @param length              the size to transfer
   *
   * @return the number of transfered bytes
   * @throws ClosedChannelException If either this channel or the target channel is closed
   * @throws IOException If some other I/O error occurs
    * @throws BufferUnderflowException if not enough data is available
   */ 
  public long transferTo(BodyDataSink dataSink, final int length) throws ProtocolException, IOException, ClosedChannelException,BufferUnderflowException {   
   
    long written = 0;
   
    long start = System.currentTimeMillis();
    long remainingTime = receiveTimeoutSec;

    do {

      int available = delegate.available();
     
      if (available >= length) {
        written += delegate.transferTo(dataSink, length);
       
      } else if (available == -1) {
        return written;
      }
     
      synchronized (readGuard) {
        if (delegate.available() < length) {
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.fine("waiting for " + (length - delegate.size()) + " bytes (guard: " + readGuard + ")");
                    }
                   
          waitingForData(readGuard, remainingTime);
        }
      }
     
      remainingTime = computeRemainingTime(start, receiveTimeoutSec);

    } while (remainingTime > 0);

   
    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("receive timeout " + receiveTimeoutSec + " sec reached. throwing timeout exception");
    }

    throw new SocketTimeoutException("timeout " + receiveTimeoutSec + " sec reached");   

  }
 
 
  /**
   * returns this {@link ReadableByteChannel} as {@link InputStream}
   * @return the input stream
   */
  public InputStream toInputStream() {
      return Channels.newInputStream(this);
  }
 
 
  /**
     * returns this {@link ReadableByteChannel} as {@link Reader}
     * @return the input stream
     */
    public Reader toReader() {
        return Channels.newReader(this, getEncoding());
    }
 
  private void waitingForData(Object readGuard, long maxWaittime) {
    try {
      readGuard.wait(maxWaittime);
    } catch (InterruptedException ie) {
      // Restore the interrupted status
      Thread.currentThread().interrupt();
    }
  }
 


  private void onReadDataInserted() { 
      if (LOG.isLoggable(Level.FINE)) {
          try {
              LOG.fine("notifying waiting threads isCompleteReceived=" + delegate.isCompleteReceived() +
                       " available=" + delegate.size() +
                       " moreDataExpected=" + delegate.isMoreInputDataExpected() +
                       " (guard: " + readGuard + ")");
          } catch (IOException ioe) {
              LOG.fine("logging error occured " + ioe.toString());
          }
      }
     
    synchronized (readGuard) {
      readGuard.notifyAll();
    }
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
      long start = System.currentTimeMillis();
      long remainingTime = receiveTimeoutSec;

      try {
          do {
              synchronized (readGuard) {
                  if (delegate.isCompleteReceived()) {
                      return delegate.toString();
                  } else {
                      if (!delegate.isCompleteReceived()) {
                          if (LOG.isLoggable(Level.FINE)) {
                              LOG.fine("waiting for all bytes (guard: " + readGuard + ")");
                          }
                         
                          waitingForData(readGuard, remainingTime);
                      }
                  }
              }
   
              remainingTime = computeRemainingTime(start, receiveTimeoutSec);
          } while (remainingTime > 0);
         
          return "timeout error occured within toString method";
         
      } catch (IOException ioe) {
          return "error occured by performing toString: " + ioe.toString();
      }
  }
 
 
 
  private final class ReadNotificationHandler implements IBodyDataHandler, IUnsynchronized {

    public boolean onData(NonBlockingBodyDataSource bodyDataSource) {
      onReadDataInserted();
      return true;
    }   
  }
}
TOP

Related Classes of org.xlightweb.BlockingBodyDataSource$PartHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.