Class AbstractPassthroughInputStream
- All Implemented Interfaces:
Closeable, AutoCloseable
InputStream that forwards body bytes and optionally emits
a trailer at EOF.
This abstract helper implements a two-phase read pipeline suitable for
tag-producing or verifying stages. During the BODY phase, bytes are pulled
from the wrapped upstream stream and immediately exposed to the caller while
update(byte[], int, int) is invoked so subclasses can maintain
running state (for example, hash, MAC, or signature update). After upstream
EOF, the TRAILER phase runs once: produceTrailer(byte[]) may write a
finite trailer into an internal buffer, and onCompleted() is called
exactly once.
Phases
- BODY: bytes are read from
FilterInputStream.in, passed through to the caller, and fed toupdate(byte[], int, int). - TRAILER: after EOF from upstream,
produceTrailer(byte[])is invoked once to optionally emit a trailer; thenonCompleted()is called and the stream becomes exhausted.
Subclassing contract
update(byte[], int, int)must be side-effect free with respect to the bytes already returned to the caller; it is for state maintenance only.produceTrailer(byte[])must write at mostbuf.lengthbytes and return the count, or return0to produce no trailer. If more space is required, it must throwIOException.onCompleted()is invoked exactly once afterproduceTrailerreturns, regardless of whether a trailer was produced; it should release resources and may perform final checks. It must not attempt to emit more bytes.
Thread-safety
Instances are not thread-safe. Use a separate instance per stream pipeline.
Example
final class DigestingStream extends AbstractPassthroughInputStream {
private final MessageDigest md;
DigestingStream(InputStream upstream, MessageDigest md) {
super(upstream, 8192);
this.md = md;
}
@Override protected void update(byte[] buf, int off, int len) { md.update(buf, off, len); }
@Override protected int produceTrailer(byte[] buf) {
byte[] tag = md.digest();
System.arraycopy(tag, 0, buf, 0, tag.length);
return tag.length; // append digest at EOF
}
@Override protected void onCompleted() { /* publish metrics, close resources, etc. *\/ }
}
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final byte[]Scratch buffer used to read fromFilterInputStream.in.Fields inherited from class FilterInputStream
in -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedAbstractPassthroughInputStream(InputStream upstream, int bodyBufSize) Constructs a new passthrough stream with an internal buffer sized for body reads. -
Method Summary
Modifier and TypeMethodDescriptionvoidclose()Drains remaining data (including any trailer) and then closes the upstream stream.protected abstract voidNotifies that the stream has fully completed.protected abstract intproduceTrailer(byte[] buf) Produces an optional trailer after upstream EOF.intread()Reads the next byte from this stream.intread(byte[] b, int off, int len) Reads some bytes from this stream into the specified array.protected abstract voidupdate(byte[] buf, int off, int len) Called for each body chunk just read from the upstream.Methods inherited from class FilterInputStream
available, mark, markSupported, read, reset, skipMethods inherited from class InputStream
nullInputStream, readAllBytes, readNBytes, readNBytes, skipNBytes, transferTo
-
Field Details
-
inBuf
protected final byte[] inBufScratch buffer used to read fromFilterInputStream.in. Also used once to hold the trailer, if any.
-
-
Constructor Details
-
AbstractPassthroughInputStream
Constructs a new passthrough stream with an internal buffer sized for body reads.The buffer is allocated as the maximum of
1024and the requestedbodyBufSize, ensuring a reasonable minimum size even if the caller specifies a very small value. The buffer is reused both for normal body reads and, if applicable, for the single trailer emission.- Parameters:
upstream- source input stream to wrapbodyBufSize- requested size of the body buffer, in bytes- Throws:
NullPointerException- ifupstreamisnull
-
-
Method Details
-
update
Called for each body chunk just read from the upstream.Implementations may update running state (e.g., hash or MAC) using the bytes in
buf[off..off+len). Implementations must not modify the visible output of the current chunk.- Parameters:
buf- buffer containing the newly read bytesoff- start offsetlen- number of bytes read- Throws:
IOException- if processing the chunk fails
-
produceTrailer
Produces an optional trailer after upstream EOF.This method is called at most once, after the BODY phase has ended. Implementations should write the trailer bytes (if any) into the provided buffer and return the number of bytes written. A return value of 0 means no trailer will be emitted.
Contract: This method must be side-effect free with respect to subsequent reads; it is followed immediately by a call to
onCompleted(). If a trailer cannot fit intobuf, implementations should throwIOExceptionto avoid truncation.- Parameters:
buf- destination buffer to receive the trailer- Returns:
- number of bytes written to
buf; 0 to emit no trailer - Throws:
IOException- if trailer production fails or the trailer does not fit intobuf
-
onCompleted
Notifies that the stream has fully completed.This method is invoked exactly once, immediately after
produceTrailer(byte[])returns, regardless of whether a trailer was produced. Implementations typically perform final verification, publish flags, and/or release resources here. This method should be idempotent and must not attempt to write further bytes.- Throws:
IOException- if final verification or resource release fails
-
read
Reads the next byte from this stream.- Overrides:
readin classFilterInputStream- Returns:
- next byte as an unsigned int (0..255), or -1 if no more data is available
- Throws:
IOException- if an I/O error occurs
-
read
Reads some bytes from this stream into the specified array.- Overrides:
readin classFilterInputStream- Parameters:
b- target buffer; must not be nulloff- start offset withinblen- maximum number of bytes to read- Returns:
- number of bytes read, or -1 if end-of-stream is reached
- Throws:
IOException- if an I/O error occursNullPointerException- ifbis nullIndexOutOfBoundsException- ifofforlenare invalid forb
-
close
Drains remaining data (including any trailer) and then closes the upstream stream.This method transfers all remaining bytes to
OutputStream.nullOutputStream(), which guarantees that the trailer (if any) is produced andonCompleted()is invoked, and finally callssuper.close().- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceCloseable- Overrides:
closein classFilterInputStream- Throws:
IOException- if an I/O error occurs while draining or closing
-