org.hd.d.pg2k.webSvr.util
Class CompressionResponseStream

java.lang.Object
  extended by java.io.OutputStream
      extended by javax.servlet.ServletOutputStream
          extended by org.hd.d.pg2k.webSvr.util.CompressionResponseStream
All Implemented Interfaces:
java.io.Closeable, java.io.Flushable

public final class CompressionResponseStream
extends javax.servlet.ServletOutputStream

Implementation of ServletOutputStream that works with CompressionServletResponseWrapper implementation.

Version:
$Revision: 1.8 $, $Date: 2004/12/21 19:03:34 $
Author:
Amy Roh (original), Damon Hart-Davis

Field Summary
private  byte[] buf1
          Private per-instance buffer for write(int); never null.
private  java.io.ByteArrayOutputStream buffer
          Buffer in which we accumulate output before starting compressed stream.
private static int BUFSIZE
          Minimum output buffer size to mop up output from GZIPOutputStream.
protected  boolean closed
          Has this stream been closed?
protected  java.io.OutputStream compressedStream
          The underlying gzip output stream to which we should write data.
private  int compressionThreshold
          The threshold number which decides to compress or not; non-negative.
private static boolean FLUSH_GZIP
          If false, suppress flushes of the GZIP output stream itself until the stream is closed.
private  javax.servlet.ServletOutputStream output
          The underlying servlet output stream to which we should write data; never null.
private  javax.servlet.http.HttpServletResponse response
          The response with which this servlet output stream is associated; never null.
private static boolean USE_JAZZLIB
          If true, use JazzLib's flush()able Deflator rather than the JDK's.
private  CompressionServletResponseWrapper wrapper
          The wrapper that created this; never null.
 
Constructor Summary
CompressionResponseStream(CompressionServletResponseWrapper wrapper, javax.servlet.http.HttpServletResponse response)
          Construct a servlet output stream associated with the specified Response.
 
Method Summary
 void close()
          Close this output stream.
 void flush()
          Flush any buffered data for this output stream, and force the response to be committed.
private  void makeSureGZOSCreated()
          Create the GZIPOutputStream if necessary and advertise the Content-Encoding in the HTTP headers.
private  void reapplySuppledContentHeaders()
          Reapply user-supplied header values that would have conflicted with compression.
protected  void setBuffer(int threshold)
          Set the compressionThreshold; must not be negative.
 void write(byte[] b)
          Write the specified byte array to our output stream.
 void write(byte[] b, int off, int len)
          Write the specified array portion to our output stream.
 void write(int b)
          Write the specified byte to our output stream.
private  void writeToGZip(byte[] b, int off, int len)
          Write the specified array portion to our compressed GZIP output stream.
 
Methods inherited from class javax.servlet.ServletOutputStream
print, print, print, print, print, print, print, println, println, println, println, println, println, println, println
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

compressionThreshold

private int compressionThreshold
The threshold number which decides to compress or not; non-negative. Users can configure in web.xml to set it to fit their needs.

If positive, size of output below which we will not attempt to compress but will leave the output is it arrived.


buffer

private java.io.ByteArrayOutputStream buffer
Buffer in which we accumulate output before starting compressed stream. Initially null, created on demand if the the compressionThreshold is positive, flushed into the compression stream and destroyed if it overflows during a write() or if still extant and close().


compressedStream

protected java.io.OutputStream compressedStream
The underlying gzip output stream to which we should write data. If this is non-null then we are committed to writing the stream compressed.

As an emergency swerve if we discover that someelse in the filter chain decided late to add a content encoding, this may in fact be a pass-through stream.


closed

protected boolean closed
Has this stream been closed?


response

private final javax.servlet.http.HttpServletResponse response
The response with which this servlet output stream is associated; never null.


wrapper

private final CompressionServletResponseWrapper wrapper
The wrapper that created this; never null.


output

private final javax.servlet.ServletOutputStream output
The underlying servlet output stream to which we should write data; never null.


BUFSIZE

private static final int BUFSIZE
Minimum output buffer size to mop up output from GZIPOutputStream. Without this, the leading and trailing bytes are liable to end up as separate length==1 (HTTP/1.1) chunks because of the implementation of GZIPOutputStream up to JDK1.3.0.

Using a BufferedOutputStream helps ensure that the chunks are large and efficent both to represent and to transmit.

See Also:
Constant Field Values

USE_JAZZLIB

private static final boolean USE_JAZZLIB
If true, use JazzLib's flush()able Deflator rather than the JDK's.

See Also:
Constant Field Values

FLUSH_GZIP

private static final boolean FLUSH_GZIP
If false, suppress flushes of the GZIP output stream itself until the stream is closed. This is because a flush() generally cannot push out anything useful with Sun's GZIPOutputStream up to an including JDK 5, ie that the client could actually uncompress immediately, and so just represents a waste of network packets and bandwidth.

If we use JazzLib then flush() is useful.

See Also:
Constant Field Values

buf1

private final byte[] buf1
Private per-instance buffer for write(int); never null.

Constructor Detail

CompressionResponseStream

public CompressionResponseStream(CompressionServletResponseWrapper wrapper,
                                 javax.servlet.http.HttpServletResponse response)
                          throws java.io.IOException
Construct a servlet output stream associated with the specified Response.

Parameters:
response - the associated response
Throws:
java.io.IOException
Method Detail

setBuffer

protected void setBuffer(int threshold)
Set the compressionThreshold; must not be negative. Zero means always compress.

This value may be ignored, ie treated as if zero.


close

public void close()
           throws java.io.IOException
Close this output stream. Cause any buffered data to be flushed and any further output data to throw an IOException.

Specified by:
close in interface java.io.Closeable
Overrides:
close in class java.io.OutputStream
Throws:
java.io.IOException

flush

public void flush()
           throws java.io.IOException
Flush any buffered data for this output stream, and force the response to be committed. This may resist attempting the flush() the compressed stream as it will have no effect other than to wastefully push out some header bytes at most.

This will always ensure that the underlying stream is directly or indirectly flushed so as to commit the response.

Specified by:
flush in interface java.io.Flushable
Overrides:
flush in class java.io.OutputStream
Throws:
java.io.IOException

makeSureGZOSCreated

private void makeSureGZOSCreated()
                          throws java.io.IOException
Create the GZIPOutputStream if necessary and advertise the Content-Encoding in the HTTP headers. It does nothing if the compressedStream is no longer null.

After this completes compressedStream will not be null.

Calling this commits us to whether we will use compression at all for this HTTP request. We will apply compression unless we find another Content-Encoding is being applied.

We wrap the output in a BufferedOutputStream first to soak up the single-byte leading and trailing writes that GZIPOutputStream up to JDK 1.4.0 does, and to avoid sending redundant blocks of data downstream (such as the gzip header) before we have to, since these will otherwise get sent as separate chunks/packets in some cases.

We also take this opportunity to add the "Content-Encoding" header to indicate that the output is GZIPed, and to add a "Vary" header to indicate that this content encoding was negotiated with the client so caches/proxies can handle differently-able clients properly.

We double-check that the a Content-Encoding has not now been applied since this might happen lazily. If it has then we duck and dive by using the raw underlying stream.

Throws:
java.io.IOException

reapplySuppledContentHeaders

private void reapplySuppledContentHeaders()
Reapply user-supplied header values that would have conflicted with compression. We can reapply these Content-XXX headers to improve on-the-wire integrity.

We carefully avoid overwriting any values that have been set elsewhere.


write

public void write(int b)
           throws java.io.IOException
Write the specified byte to our output stream. This is likely to be hideously inefficient compared to the multi-byte write() calls.

Specified by:
write in class java.io.OutputStream
Parameters:
b - The byte to be written
Throws:
java.io.IOException - if an input/output error occurs

write

public void write(byte[] b)
           throws java.io.IOException
Write the specified byte array to our output stream.

Overrides:
write in class java.io.OutputStream
Parameters:
b - The byte array to be written; never null
Throws:
java.io.IOException - if an input/output error occurs

write

public void write(byte[] b,
                  int off,
                  int len)
           throws java.io.IOException
Write the specified array portion to our output stream. All write()s to this output stream ultimately pass through this method.

Overrides:
write in class java.io.OutputStream
Parameters:
b - the byte array containing the bytes to be written
off - zero-relative starting offset of the bytes to be written
len - the number of bytes to be written
Throws:
java.io.IOException - if an input/output error occurs

writeToGZip

private void writeToGZip(byte[] b,
                         int off,
                         int len)
                  throws java.io.IOException
Write the specified array portion to our compressed GZIP output stream.

Throws:
java.io.IOException - if an input/output error occurs

DHD Multimedia Gallery V1.57.21

Copyright (c) 1996-2011, Damon Hart-Davis. All rights reserved.