org.archive.io
Class RecordingOutputStream

java.lang.Object
  extended by java.io.OutputStream
      extended by org.archive.io.RecordingOutputStream
All Implemented Interfaces:
java.io.Closeable, java.io.Flushable

public class RecordingOutputStream
extends java.io.OutputStream

An output stream that records all writes to wrapped output stream. A RecordingOutputStream can be wrapped around any other OutputStream to record all bytes written to it. You can then request a ReplayInputStream to read those bytes.

The RecordingOutputStream uses an in-memory buffer and backing disk file to allow it to record streams of arbitrary length limited only by available disk space.

As long as the stream recorded is smaller than the in-memory buffer, no disk access will occur.

Recorded content can be recovered as a ReplayInputStream (via getReplayInputStream() or, for only the content after the content-begin-mark is set, getContentReplayInputStream() ) or as a ReplayCharSequence (via getReplayCharSequence()).

This class is also used as a straight output stream by RecordingInputStream to which it records all reads. RecordingInputStream is exploiting the file backed buffer facility of this class passing null for the stream to wrap. TODO: Make a FileBackedOutputStream class that is subclassed by RecordingInputStream.

Author:
gojomo

Field Summary
protected  byte[] bufStreamBuf
          Reusable buffer for FastBufferedOutputStream
protected static java.util.logging.Logger logger
           
protected static long MAX_HEADER_MATERIAL
          Maximum amount of header material to accept without the content body beginning -- if more, throw a RecorderTooMuchHeaderException.
protected  long maxLength
          maximum length of material to record before throwing exception
protected  long maxRateBytesPerMs
          maximum rate to record (adds delays to hit target rate)
protected  long startTime
          time recording begins for timeout, rate calculations
protected  long timeoutMs
          maximum time to record before throwing exception
 
Constructor Summary
RecordingOutputStream(int bufferSize, java.lang.String backingFilename)
          Create a new RecordingOutputStream.
 
Method Summary
protected  void checkLimits()
          Check any enforced limits.
 void close()
           
protected  void closeDiskStream()
           
 void closeRecorder()
           
 void flush()
           
 long getContentBegin()
          Return stored content-begin-mark (which is also end-of-headers)
 ReplayInputStream getContentReplayInputStream()
          Return a replay stream, cued up to begining of content
 byte[] getDigestValue()
          Return the digest value for any recorded, digested data.
 long getRemainingLength()
          Return number of bytes that could be recorded without hitting length limit
 ReplayCharSequence getReplayCharSequence()
           
 ReplayCharSequence getReplayCharSequence(java.lang.String characterEncoding)
           
 ReplayCharSequence getReplayCharSequence(java.lang.String characterEncoding, long startOffset)
           
 ReplayInputStream getReplayInputStream()
           
 ReplayInputStream getReplayInputStream(long skip)
           
 long getResponseContentLength()
           
 long getSize()
           
 boolean isOpen()
           
 void mark()
          When used alongside a mark-supporting RecordingInputStream, remember a position reachable by a future reset().
 void markContentBegin()
          Remember the current position as the start of the "response body".
 void open()
          Wrap the given stream, both recording and passing along any data written to this RecordingOutputStream.
 void open(java.io.OutputStream wrappedStream)
          Wrap the given stream, both recording and passing along any data written to this RecordingOutputStream.
 void reset()
          When used alongside a mark-supporting RecordingInputStream, reset the position to that saved by previous mark().
 void resetLimits()
          Reset limits to effectively-unlimited defaults
 void setDigest(java.security.MessageDigest md)
          Sets a digest function which may be applied to recorded data.
 void setDigest(java.lang.String algorithm)
          Sets a digest function which may be applied to recorded data.
 void setLimits(long length, long milliseconds, long rateKBps)
          Set limits on length, time, and rate to enforce.
 void setSha1Digest()
          Convenience method for setting SHA1 digest.
 void startDigest()
          Starts digesting recorded data, if a MessageDigest has been set.
 void write(byte[] b, int off, int len)
           
 void write(int b)
           
 
Methods inherited from class java.io.OutputStream
write
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

logger

protected static java.util.logging.Logger logger

bufStreamBuf

protected byte[] bufStreamBuf
Reusable buffer for FastBufferedOutputStream


MAX_HEADER_MATERIAL

protected static final long MAX_HEADER_MATERIAL
Maximum amount of header material to accept without the content body beginning -- if more, throw a RecorderTooMuchHeaderException. TODO: make configurable? make smaller?

See Also:
Constant Field Values

maxLength

protected long maxLength
maximum length of material to record before throwing exception


timeoutMs

protected long timeoutMs
maximum time to record before throwing exception


maxRateBytesPerMs

protected long maxRateBytesPerMs
maximum rate to record (adds delays to hit target rate)


startTime

protected long startTime
time recording begins for timeout, rate calculations

Constructor Detail

RecordingOutputStream

public RecordingOutputStream(int bufferSize,
                             java.lang.String backingFilename)
Create a new RecordingOutputStream.

Parameters:
bufferSize - Buffer size to use.
backingFilename - Name of backing file to use.
Method Detail

open

public void open()
          throws java.io.IOException
Wrap the given stream, both recording and passing along any data written to this RecordingOutputStream.

Throws:
java.io.IOException - If failed creation of backing file.

open

public void open(java.io.OutputStream wrappedStream)
          throws java.io.IOException
Wrap the given stream, both recording and passing along any data written to this RecordingOutputStream.

Parameters:
wrappedStream - Stream to wrap. May be null for case where we want to write to a file backed stream only.
Throws:
java.io.IOException - If failed creation of backing file.

write

public void write(int b)
           throws java.io.IOException
Specified by:
write in class java.io.OutputStream
Throws:
java.io.IOException

write

public void write(byte[] b,
                  int off,
                  int len)
           throws java.io.IOException
Overrides:
write in class java.io.OutputStream
Throws:
java.io.IOException

checkLimits

protected void checkLimits()
                    throws RecorderIOException
Check any enforced limits.

Throws:
RecorderIOException

close

public void close()
           throws java.io.IOException
Specified by:
close in interface java.io.Closeable
Overrides:
close in class java.io.OutputStream
Throws:
java.io.IOException

closeDiskStream

protected void closeDiskStream()
                        throws java.io.IOException
Throws:
java.io.IOException

closeRecorder

public void closeRecorder()
                   throws java.io.IOException
Throws:
java.io.IOException

flush

public void flush()
           throws java.io.IOException
Specified by:
flush in interface java.io.Flushable
Overrides:
flush in class java.io.OutputStream
Throws:
java.io.IOException

getReplayInputStream

public ReplayInputStream getReplayInputStream()
                                       throws java.io.IOException
Throws:
java.io.IOException

getReplayInputStream

public ReplayInputStream getReplayInputStream(long skip)
                                       throws java.io.IOException
Throws:
java.io.IOException

getContentReplayInputStream

public ReplayInputStream getContentReplayInputStream()
                                              throws java.io.IOException
Return a replay stream, cued up to begining of content

Returns:
An RIS.
Throws:
java.io.IOException

getSize

public long getSize()

markContentBegin

public void markContentBegin()
Remember the current position as the start of the "response body". Useful when recording HTTP traffic as a way to start replays after the headers.


getContentBegin

public long getContentBegin()
Return stored content-begin-mark (which is also end-of-headers)


startDigest

public void startDigest()
Starts digesting recorded data, if a MessageDigest has been set.


setSha1Digest

public void setSha1Digest()
Convenience method for setting SHA1 digest.

See Also:
setDigest(String)

setDigest

public void setDigest(java.lang.String algorithm)
Sets a digest function which may be applied to recorded data. The difference between calling this method and setDigest(MessageDigest) is that this method tries to reuse MethodDigest instance if already allocated and of appropriate algorithm.

Parameters:
algorithm - Message digest algorithm to use.
See Also:
setDigest(MessageDigest)

setDigest

public void setDigest(java.security.MessageDigest md)
Sets a digest function which may be applied to recorded data. As usually only a subset of the recorded data should be fed to the digest, you must also call startDigest() to begin digesting.

Parameters:
md - Message digest function to use.

getDigestValue

public byte[] getDigestValue()
Return the digest value for any recorded, digested data. Call only after all data has been recorded; otherwise, the running digest state is ruined.

Returns:
the digest final value

getReplayCharSequence

public ReplayCharSequence getReplayCharSequence()
                                         throws java.io.IOException
Throws:
java.io.IOException

getReplayCharSequence

public ReplayCharSequence getReplayCharSequence(java.lang.String characterEncoding)
                                         throws java.io.IOException
Throws:
java.io.IOException

getReplayCharSequence

public ReplayCharSequence getReplayCharSequence(java.lang.String characterEncoding,
                                                long startOffset)
                                         throws java.io.IOException
Parameters:
characterEncoding - Encoding of recorded stream.
Returns:
A ReplayCharSequence Will return null if an IOException. Call close on returned RCS when done.
Throws:
java.io.IOException

getResponseContentLength

public long getResponseContentLength()

isOpen

public boolean isOpen()
Returns:
True if this ROS is open.

mark

public void mark()
When used alongside a mark-supporting RecordingInputStream, remember a position reachable by a future reset().


reset

public void reset()
When used alongside a mark-supporting RecordingInputStream, reset the position to that saved by previous mark(). Until the position again reached "new" material, none of the bytes pushed to this stream will be digested or recorded.


setLimits

public void setLimits(long length,
                      long milliseconds,
                      long rateKBps)
Set limits on length, time, and rate to enforce.

Parameters:
length -
milliseconds -
rateKBps -

resetLimits

public void resetLimits()
Reset limits to effectively-unlimited defaults


getRemainingLength

public long getRemainingLength()
Return number of bytes that could be recorded without hitting length limit

Returns:
long byte count


Copyright © 2003-2011 Internet Archive. All Rights Reserved.