FileDocCategorySizeDatePackage
OutputBuffer.javaAPI DocGlassfish v2 API16697Fri May 04 22:32:44 BST 2007org.apache.coyote.tomcat5

OutputBuffer

public class OutputBuffer extends Writer implements ByteChunk.ByteOutputChannel
The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3 OutputBuffer, with the removal of some of the state handling (which in Coyote is mostly the Processor's responsability).
author
Costin Manolache
author
Remy Maucherat

Fields Summary
private static com.sun.org.apache.commons.logging.Log
log
public static final String
DEFAULT_ENCODING
public static final int
DEFAULT_BUFFER_SIZE
static final int
debug
private org.apache.tomcat.util.buf.ByteChunk
bb
The byte buffer.
private int
state
State of the output buffer.
private boolean
initial
private int
bytesWritten
Number of bytes written.
private int
charsWritten
Number of chars written.
private boolean
closed
Flag which indicates if the output buffer is closed.
private boolean
doFlush
Do a flush on the next operation.
private org.apache.tomcat.util.buf.ByteChunk
outputChunk
Byte chunk used to output 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.C2BConverter
conv
Current char to byte converter.
private org.apache.coyote.Response
response
Associated Coyote response.
private CoyoteResponse
coyoteResponse
private boolean
suspended
Suspended flag. All output bytes will be swallowed if this is true.
Constructors Summary
public OutputBuffer()
Default constructor. Allocate the buffer with the default buffer size.



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


                   
      

        this(DEFAULT_BUFFER_SIZE);

    
public OutputBuffer(boolean chunkingDisabled)

        this(DEFAULT_BUFFER_SIZE, chunkingDisabled);
    
public OutputBuffer(int size)
Alternate constructor which allows specifying the initial buffer size.

param
size Buffer size to use

        // START S1AS8 4861933
        /*
        bb = new ByteChunk(size);
        bb.setLimit(size);
        bb.setByteOutputChannel(this);
        cb = new CharChunk(size);
        cb.setCharOutputChannel(this);
        cb.setLimit(size);
        */
        this(size, false);
        // END S1AS8 4861933
    
public OutputBuffer(int size, boolean chunkingDisabled)

        bb = new ByteChunk(size);
        if (!chunkingDisabled) {
            bb.setLimit(size);
        }
        bb.setByteOutputChannel(this);
    
Methods Summary
private voidaddSessionVersionCookieIfNecessary()
Adds a session version cookie to the response if necessary.


        CoyoteRequest req = (CoyoteRequest) coyoteResponse.getRequest();
        if (req.isRequestedSessionIdFromURL()) {
            return;
        }

        HashMap<String, String> sessionVersions = (HashMap<String, String>)
            req.getAttribute(Globals.SESSION_VERSIONS_REQUEST_ATTRIBUTE);
        if (sessionVersions != null) {
            Cookie cookie = new Cookie(
                Globals.SESSION_VERSION_COOKIE_NAME,
                RequestUtil.makeSessionVersionString(sessionVersions));
            if (sessionVersions.size() > 1
                    || coyoteResponse.getContext() == null) {
                // Cross-context dispatch
                cookie.setPath("/");
            } else {
                cookie.setPath(coyoteResponse.getContext().getName());
            }
            response.addHeader("Set-Cookie",
                               coyoteResponse.getCookieString(cookie));
        }
    
public voidcheckConverter()


        if (!gotEnc)
            setConverter();

    
public voidclose()
Close the output buffer. This tries to calculate the response size if the response has not been committed yet.

throws
IOException An underlying IOException occurred


        if (closed)
            return;
        if (suspended)
            return;

        if ((!response.isCommitted()) 
            && (response.getContentLength() == -1)) {
            // If this didn't cause a commit of the response, the final content
            // length can be calculated
            if (!response.isCommitted()) {
                response.setContentLength(bb.getLength());
            }
        }

        doFlush(false);
        closed = true;

        response.finish();

    
protected voiddoFlush(boolean realFlush)
Flush bytes or chars contained in the buffer.

throws
IOException An underlying IOException occurred


        if (suspended)
            return;

        doFlush = true;
        if (initial){
            addSessionVersionCookieIfNecessary();
            response.sendHeaders();
            initial = false;
        }
        if (bb.getLength() > 0) {
            bb.flushBuffer();
        }
        doFlush = false;

        if (realFlush) {
            response.action(ActionCode.ACTION_CLIENT_FLUSH, response);
            // If some exception occurred earlier, or if some IOE occurred
            // here, notify the servlet with an IOE
            if (response.isExceptionPresent()) {
                throw new ClientAbortException
                    (response.getErrorException());
            }
        }

    
public voidflush()
Flush bytes or chars contained in the buffer.

throws
IOException An underlying IOException occurred

        doFlush(true);
    
public voidflushBytes()
Real write - this buffer will be sent to the client


        if (log.isDebugEnabled())
            log.debug("flushBytes() " + bb.getLength());
        bb.flushBuffer();

    
public intgetBufferSize()

        return bb.getLimit();
    
public intgetBytesWritten()

        return bytesWritten;
    
public intgetCharsWritten()

        return charsWritten;
    
public intgetContentWritten()

        return bytesWritten + charsWritten;
    
public org.apache.coyote.ResponsegetResponse()
Get associated Coyote response.

return
the associated Coyote response

        return this.response;
    
public booleanhasData()
Are there any pending writes waiting to be flushed?

        if (!suspended && (initial || (bb.getLength() > 0))) {
            return true;
        }

        return false;
    
public booleanisNew()
True if this buffer hasn't been used ( since recycle() ) - i.e. no chars or bytes have been added to the buffer.

        return (bytesWritten == 0) && (charsWritten == 0);
    
public booleanisSuspended()
Is the response output suspended ?

return
suspended flag value

        return this.suspended;
    
public voidrealWriteBytes(byte[] buf, int off, int cnt)
Sends the buffer data to the client output, checking the state of Response and calling the right interceptors.

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


        if (log.isDebugEnabled())
            log.debug("realWrite(b, " + off + ", " + cnt + ") " + response);

        if (closed)
            return;
        if (response == null)
            return;

        // If we really have something to write
        if (cnt > 0) {
            addSessionVersionCookieIfNecessary();
            // real write to the adapter
            outputChunk.setBytes(buf, off, cnt);
            try {
                response.doWrite(outputChunk);
            } catch (IOException e) {
                // An IOException on a write is almost always due to
                // the remote client aborting the request.  Wrap this
                // so that it can be handled better by the error dispatcher.
                throw new ClientAbortException(e);
            }
        }

    
public voidrecycle()
Recycle the output buffer.


	if (log.isDebugEnabled())
            log.debug("recycle()");

        initial = true;
        bytesWritten = 0;
        charsWritten = 0;

        bb.recycle(); 
        closed = false;
        suspended = false;

        if (conv!= null) {
            conv.recycle();
        }

        gotEnc = false;
        enc = null;
    
public voidreset()


        bb.recycle();
        bytesWritten = 0;
        charsWritten = 0;
        gotEnc = false;
        enc = null;
        initial = true;

    
public voidsetBufferSize(int size)

        if (size > bb.getLimit()) {
            bb.setLimit(size);
        }
    
protected voidsetConverter()


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

        if (log.isDebugEnabled())
            log.debug("Got encoding: " + enc);

        gotEnc = true;
        if (enc == null)
            enc = DEFAULT_ENCODING;
        conv = (C2BConverter) encoders.get(enc);
        if (conv == null) {
            if (Globals.IS_SECURITY_ENABLED){
                try{
                    conv = (C2BConverter)AccessController.doPrivileged(
                            new PrivilegedExceptionAction(){

                                public Object run() throws IOException{
                                    return C2BConverter.getInstance(bb, enc);
                                }

                            }
                    );              
                }catch(PrivilegedActionException ex){
                    Exception e = ex.getException();
                    if (e instanceof IOException)
                        throw (IOException)e; 
                    
                    if (log.isDebugEnabled())
                        log.debug("setConverter: " + ex.getMessage());
                }
            } else {
                conv = C2BConverter.getInstance(bb, enc);
            }
            encoders.put(enc, conv);

        }
    
public voidsetCoyoteResponse(CoyoteResponse coyoteResponse)

        this.coyoteResponse = coyoteResponse;
        setResponse((Response) coyoteResponse.getCoyoteResponse());
    
public voidsetEncoding(java.lang.String s)

        enc = s;
    
public voidsetResponse(org.apache.coyote.Response response)
Associated Coyote response.

param
response Associated Coyote response

	this.response = response;
    
public voidsetSuspended(boolean suspended)
Set the suspended flag.

param
suspended New suspended flag value

        this.suspended = suspended;
    
public voidwrite(byte[] b, int off, int len)


        if (suspended)
            return;

        writeBytes(b, off, len);

    
public voidwrite(int c)


        if (suspended)
            return;

        checkConverter();
        conv.convert((char) c);
        charsWritten++;
    
public voidwrite(char[] c)


        if (suspended)
            return;

        write(c, 0, c.length);

    
public voidwrite(char[] c, int off, int len)


        if (suspended)
            return;

        checkConverter();
        conv.convert(c, off, len);
        charsWritten += len;
    
public voidwrite(java.lang.String s, int off, int len)
Append a string to the buffer


        if (suspended)
            return;

        charsWritten += len;
        if (s==null)
            s="null";
        checkConverter();
        conv.convert(s, off, len);
    
public voidwrite(java.lang.String s)


        if (suspended)
            return;

        if (s == null)
            s = "null";
        checkConverter();
        conv.convert(s);
    
public voidwriteByte(int b)


        if (suspended)
            return;

        bb.append( (byte)b );
        bytesWritten++;

    
private voidwriteBytes(byte[] b, int off, int len)


        if (closed)
            return;
        if (log.isDebugEnabled())
            log.debug("write(b,off,len)");

        bb.append(b, off, len);
        bytesWritten += len;

        // if called from within flush(), then immediately flush
        // remaining bytes
        if (doFlush) {
            bb.flushBuffer();
        }