NonBlockingBufferedInputStream.java |
/* * The Apache Software License, Version 1.1 * * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Axis" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.jboss.axis.transport.http; import java.io.IOException; import java.io.InputStream; public class NonBlockingBufferedInputStream extends InputStream { // current stream to be processed private InputStream in; // maximum number of bytes allowed to be returned. private int remainingContent = Integer.MAX_VALUE; // Internal buffer for the input stream private byte[] buffer = new byte[4096]; private int offset = 0; // bytes before this offset have been processed private int numbytes = 0; // number of valid bytes in this buffer /** * set the input stream to be used for subsequent reads * * @param in the InputStream */ public void setInputStream(InputStream in) { this.in = in; numbytes = 0; offset = 0; remainingContent = (in == null) ? 0 : Integer.MAX_VALUE; } /** * set the maximum number of bytes allowed to be read from this input * stream. * * @param value the Content Length */ public void setContentLength(int value) { if (in != null) this.remainingContent = value - (numbytes - offset); } /** * Replenish the buffer with data from the input stream. This is * guaranteed to read atleast one byte or throw an exception. When * possible, it will read up to the length of the buffer * the data is buffered for efficiency. * * @return the byte read */ private void refillBuffer() throws IOException { if (remainingContent <= 0 || in == null) return; // determine number of bytes to read numbytes = in.available(); if (numbytes > remainingContent) numbytes = remainingContent; if (numbytes > buffer.length) numbytes = buffer.length; if (numbytes <= 0) numbytes = 1; // actually attempt to read those bytes numbytes = in.read(buffer, 0, numbytes); // update internal state to reflect this read remainingContent -= numbytes; offset = 0; } /** * Read a byte from the input stream, blocking if necessary. Internally * the data is buffered for efficiency. * * @return the byte read */ public int read() throws IOException { if (in == null) return -1; if (offset >= numbytes) refillBuffer(); if (offset >= numbytes) return -1; return buffer[offset++]; } /** * Read bytes from the input stream. This is guaranteed to return at * least one byte or throw an exception. When possible, it will return * more bytes, up to the length of the array, as long as doing so would * not require waiting on bytes from the input stream. * * @param dest byte array to read into * @return the number of bytes actually read */ public int read(byte[] dest) throws IOException { return read(dest, 0, dest.length); } /** * Read a specified number of bytes from the input stream. This is * guaranteed to return at least one byte or throw an execption. When * possible, it will return more bytes, up to the length specified, * as long as doing so would not require waiting on bytes from the * input stream. * * @param dest byte array to read into * @param off starting offset into the byte array * @param len maximum number of bytes to read * @return the number of bytes actually read */ public int read(byte[] dest, int off, int len) throws IOException { int ready = numbytes - offset; if (ready >= len) { System.arraycopy(buffer, offset, dest, off, len); offset += len; return len; } else if (ready > 0) { System.arraycopy(buffer, offset, dest, off, ready); offset = numbytes; return ready; } else { if (in == null) return -1; refillBuffer(); if (offset >= numbytes) return -1; return read(dest, off, len); } } /** * skip over (and discard) a specified number of bytes in this input * stream * * @param len the number of bytes to be skipped * @return the action number of bytes skipped */ public int skip(int len) throws IOException { int count = 0; while (len-- > 0 && read() >= 0) count++; return count; } /** * return the number of bytes available to be read without blocking * * @return the number of bytes */ public int available() throws IOException { if (in == null) return 0; // return buffered + available from the stream return (numbytes - offset) + in.available(); } /** * disassociate from the underlying input stream */ public void close() throws IOException { setInputStream(null); } /** * Just like read except byte is not removed from the buffer. * the data is buffered for efficiency. * Was added to support multiline http headers. ;-) * * @return the byte read */ public int peek() throws IOException { if (in == null) return -1; if (offset >= numbytes) refillBuffer(); if (offset >= numbytes) return -1; return buffer[offset]; } }
NonBlockingBufferedInputStream.java |