com.perforce.p4java.impl.mapbased.rpc.stream
Class RpcGZIPOutputStream

java.lang.Object
  extended by java.io.OutputStream
      extended by java.io.FilterOutputStream
          extended by com.perforce.p4java.impl.mapbased.rpc.stream.RpcGZIPOutputStream
All Implemented Interfaces:
Closeable, Flushable

public class RpcGZIPOutputStream
extends FilterOutputStream

A fairly lightweight filter output stream that implements Perforce's GZIP-based connection stream compression for Perforce clients that have the Perforce "client compression" option set.

The implementation here uses the JZlib package because the standard JDK GZIP packages in java.util.zip are not able to cope cleanly with the various flush options needed on a streaming connection like this. Our use of the JZlib package is pretty boring, and is basically just a transliteration of the original C++ API code that dates from about 1999 or so. The implementation here is not thread safe in that there's a buffer in each instantiation of this stream; this could probably be tightened up if there's a need for it.

Note that this implementation requires the upper levels to ensure that the stream is flushed properly with the flush() method whenever an RPC packet is ready for sending; this ensures that GZIP block processing, etc., is done properly and the server sees correct block and stream boundaries. If this isn't done, the server may hang or you may see some very odd client-side errors. The stream should also be closed properly, but that's less of an issue.

Note that there's quite a performance penalty for using connection (a.k.a. client) compression (especially on the server), but if that's what the customer wants, that what the customer gets.


Field Summary
 
Fields inherited from class java.io.FilterOutputStream
out
 
Constructor Summary
RpcGZIPOutputStream(OutputStream out)
           
 
Method Summary
 void close()
          Cleanly close the stream and finalize deflation (compression).
 void flush()
          Flush the results of previous byte deflation (compression) downstream.
protected  String getJZlibErrorStr(int errNum)
          Provide a more human-readable form of the underlying JZlib compression errors.
 void write(byte[] bytes)
          A convenience method for write(bytes, 0, bytes.length).
 void write(byte[] bytes, int offset, int len)
          Deflate (compress) the passed-in bytes and -- if appropriate -- send the compressed bytes downstream to the filter's output stream.
 void write(int b)
          Not used.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

RpcGZIPOutputStream

public RpcGZIPOutputStream(OutputStream out)
                    throws IOException
Throws:
IOException
Method Detail

write

public void write(byte[] bytes)
           throws IOException
A convenience method for write(bytes, 0, bytes.length).

Overrides:
write in class FilterOutputStream
Throws:
IOException
See Also:
FilterOutputStream.write(byte[])

write

public void write(byte[] bytes,
                  int offset,
                  int len)
           throws IOException
Deflate (compress) the passed-in bytes and -- if appropriate -- send the compressed bytes downstream to the filter's output stream.

This write method does not necessarily cause a write to the server -- a write will only occur when the jzBytes buffer is full, or on a later flush. This is a consequence of the way GZIP streaming works here, and means you must ensure that a suitable flush is done at a suitable (packet) boundary. See the comments for flush() below.

Overrides:
write in class FilterOutputStream
Throws:
IOException
See Also:
FilterOutputStream.write(byte[], int, int)

write

public void write(int b)
           throws IOException
Not used. Will cause a UnimplementedError to be thrown if called.

Overrides:
write in class FilterOutputStream
Throws:
IOException
See Also:
FilterOutputStream.write(int)

flush

public void flush()
           throws IOException
Flush the results of previous byte deflation (compression) downstream.

As a consequence of the way GZIP streaming works, this flush is often the only place where bytes are actually written downstream towards the server (the earlier writes may only write to the internal buffer here). Using flush causes a compression boundary, so it should only be used after a complete packet has been put onto this stream -- i.e. users of this stream must call flush appropriately, or the server may not see packets at all.

Specified by:
flush in interface Flushable
Overrides:
flush in class FilterOutputStream
Throws:
IOException
See Also:
FilterOutputStream.flush()

close

public void close()
           throws IOException
Cleanly close the stream and finalize deflation (compression). No one dies if you don't call this properly, but it certainly helps to close the stream cleanly.

Specified by:
close in interface Closeable
Overrides:
close in class FilterOutputStream
Throws:
IOException
See Also:
FilterOutputStream.close()

getJZlibErrorStr

protected String getJZlibErrorStr(int errNum)
Provide a more human-readable form of the underlying JZlib compression errors.

Should be made even more human-readable sometime later -- HR.



Copyright © 2015 Perforce Software. All Rights Reserved.