FileDocCategorySizeDatePackage
InputBuffer.javaAPI DocApache Tomcat 6.0.1412528Fri Jul 20 04:20:34 BST 2007org.apache.catalina.connector

InputBuffer

public class InputBuffer extends Reader implements CharChunk.CharInputChannel, CharChunk.CharOutputChannel, ByteChunk.ByteInputChannel
The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3 OutputBuffer, adapted to handle input instead of output. This allows complete recycling of the facade objects (the ServletInputStream and the BufferedReader).
author
Remy Maucherat

Fields Summary
public static final String
DEFAULT_ENCODING
public static final int
DEFAULT_BUFFER_SIZE
public final int
INITIAL_STATE
public final int
CHAR_STATE
public final int
BYTE_STATE
private org.apache.tomcat.util.buf.ByteChunk
bb
The byte buffer.
private org.apache.tomcat.util.buf.CharChunk
cb
The chunk buffer.
private int
state
State of the output buffer.
private int
bytesRead
Number of bytes read.
private int
charsRead
Number of chars read.
private boolean
closed
Flag which indicates if the input buffer is closed.
private org.apache.tomcat.util.buf.ByteChunk
inputChunk
Byte chunk used to input bytes.
private String
enc
Encoding to use.
private boolean
gotEnc
Encoder is set.
protected HashMap
encoders
List of encoders.
protected org.apache.tomcat.util.buf.B2CConverter
conv
Current byte to char converter.
private org.apache.coyote.Request
coyoteRequest
Associated Coyote request.
private int
markPos
Buffer position.
private int
size
Buffer size.
Constructors Summary
public InputBuffer()
Default constructor. Allocate the buffer with the default buffer size.



    // ----------------------------------------------------------- Constructors


                   
      

        this(DEFAULT_BUFFER_SIZE);

    
public InputBuffer(int size)
Alternate constructor which allows specifying the initial buffer size.

param
size Buffer size to use


        this.size = size;
        bb = new ByteChunk(size);
        bb.setLimit(size);
        bb.setByteInputChannel(this);
        cb = new CharChunk(size);
        cb.setLimit(size);
        cb.setOptimizedWrite(false);
        cb.setCharInputChannel(this);
        cb.setCharOutputChannel(this);

    
Methods Summary
public intavailable()

        int available = 0;
        if (state == BYTE_STATE) {
            available = bb.getLength();
        } else if (state == CHAR_STATE) {
            available = cb.getLength();
        }
        if (available == 0) {
            coyoteRequest.action(ActionCode.ACTION_AVAILABLE, null);
            available = (coyoteRequest.getAvailable() > 0) ? 1 : 0;
        }
        return available;
    
public voidcheckConverter()


        if (!gotEnc)
            setConverter();

    
public voidclearEncoders()
Clear cached encoders (to save memory for Comet requests).

        encoders.clear();
    
public voidclose()
Close the input buffer.

throws
IOException An underlying IOException occurred

        closed = true;
    
public org.apache.coyote.RequestgetRequest()
Get associated Coyote request.

return
the associated Coyote request

        return this.coyoteRequest;
    
public voidmark(int readAheadLimit)

        if (cb.getLength() <= 0) {
            cb.setOffset(0);
            cb.setEnd(0);
        } else {
            if ((cb.getBuffer().length > (2 * size)) 
                && (cb.getLength()) < (cb.getStart())) {
                System.arraycopy(cb.getBuffer(), cb.getStart(), 
                                 cb.getBuffer(), 0, cb.getLength());
                cb.setEnd(cb.getLength());
                cb.setOffset(0);
            }
        }
        int offset = readAheadLimit;
        if (offset < size) {
            offset = size;
        }
        cb.setLimit(cb.getStart() + offset);
        markPos = cb.getStart();
    
public booleanmarkSupported()

        return true;
    
public intread(byte[] b, int off, int len)

        return bb.substract(b, off, len);
    
public intread()

        return cb.substract();
    
public intread(char[] cbuf)

        return read(cbuf, 0, cbuf.length);
    
public intread(char[] cbuf, int off, int len)

        return cb.substract(cbuf, off, len);
    
public intreadByte()

        return bb.substract();
    
public booleanready()

        return (available() > 0);
    
public intrealReadBytes(byte[] cbuf, int off, int len)
Reads new bytes in the byte chunk.

param
cbuf Byte buffer to be written to the response
param
off Offset
param
len Length
throws
IOException An underlying IOException occurred


        if (closed)
            return -1;
        if (coyoteRequest == null)
            return -1;

        state = BYTE_STATE;

        int result = coyoteRequest.doRead(bb);

        return result;

    
public intrealReadChars(char[] cbuf, int off, int len)


        if (!gotEnc)
            setConverter();

        if (bb.getLength() <= 0) {
            int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
            if (nRead < 0) {
                return -1;
            }
        }

        if (markPos == -1) {
            cb.setOffset(0);
            cb.setEnd(0);
        }

        int limit = bb.getLength()+cb.getStart();
        if( cb.getLimit() < limit ) 
	    cb.setLimit(limit);
        conv.convert(bb, cb);
        bb.setOffset(bb.getEnd());
        state = CHAR_STATE;

        return cb.getLength();

    
public voidrealWriteChars(char[] c, int off, int len)
Since the converter will use append, it is possible to get chars to be removed from the buffer for "writing". Since the chars have already been read before, they are ignored. If a mark was set, then the mark is lost.

        markPos = -1;
    
public voidrecycle()
Recycle the output buffer.

        
        state = INITIAL_STATE;
        bytesRead = 0;
        charsRead = 0;
        
        // If usage of mark made the buffer too big, reallocate it
        if (cb.getChars().length > size) {
            cb = new CharChunk(size);
            cb.setLimit(size);
            cb.setOptimizedWrite(false);
            cb.setCharInputChannel(this);
            cb.setCharOutputChannel(this);
        } else {
            cb.recycle();
        }
        markPos = -1;
        bb.recycle(); 
        closed = false;
        
        if (conv != null) {
            conv.recycle();
        }
        
        gotEnc = false;
        enc = null;
        
    
public voidreset()

        if (state == CHAR_STATE) {
            if (markPos < 0) {
                cb.recycle();
                markPos = -1;
                throw new IOException();
            } else {
                cb.setOffset(markPos);
            }
        } else {
            bb.recycle();
        }
    
protected voidsetConverter()


        if (coyoteRequest != null)
            enc = coyoteRequest.getCharacterEncoding();

        gotEnc = true;
        if (enc == null)
            enc = DEFAULT_ENCODING;
        conv = (B2CConverter) encoders.get(enc);
        if (conv == null) {
            if (SecurityUtil.isPackageProtectionEnabled()){
                try{
                    conv = (B2CConverter)AccessController.doPrivileged(
                            new PrivilegedExceptionAction(){

                                public Object run() throws IOException{
                                    return new B2CConverter(enc);
                                }

                            }
                    );              
                }catch(PrivilegedActionException ex){
                    Exception e = ex.getException();
                    if (e instanceof IOException)
                        throw (IOException)e; 
                }
            } else {
                conv = new B2CConverter(enc);
            }
            encoders.put(enc, conv);
        }

    
public voidsetEncoding(java.lang.String s)

        enc = s;
    
public voidsetRequest(org.apache.coyote.Request coyoteRequest)
Associated Coyote request.

param
coyoteRequest Associated Coyote request

	this.coyoteRequest = coyoteRequest;
    
public longskip(long n)


        if (n < 0) {
            throw new IllegalArgumentException();
        }

        long nRead = 0;
        while (nRead < n) {
            if (cb.getLength() >= n) {
                cb.setOffset(cb.getStart() + (int) n);
                nRead = n;
            } else {
                nRead += cb.getLength();
                cb.setOffset(cb.getEnd());
                int toRead = 0;
                if (cb.getChars().length < (n - nRead)) {
                    toRead = cb.getChars().length;
                } else {
                    toRead = (int) (n - nRead);
                }
                int nb = realReadChars(cb.getChars(), 0, toRead);
                if (nb < 0)
                    break;
            }
        }

        return nRead;