Class SerializableInputStreamContainer

  • All Implemented Interfaces:
    Serializable
    Direct Known Subclasses:
    SerializableInputStreamContainer

    public class SerializableInputStreamContainer
    extends Object
    implements Serializable
    Carries an InputStream across the master ⇄ frontend RPC boundary, which a stream cannot cross on its own. An RpcHandler method that would take a stream takes a container instead, and the caller keeps its stream-based signature.

    The content is copied only when it has to be. As long as the call stays on one server, the container hands out the very stream it was given, so nothing is read or buffered. The content is read in full when the container is serialized, i.e. when the call actually goes to the other server.

    Two consequences of that, both intentional:

    • A container that was transferred is repeatable: it holds the content, so every call to getInputStream() returns a fresh stream over it. A container that was not transferred hands out its source stream, which like any stream can be read once.
    • Reading the source stream and transferring the container afterwards would send whatever is left of the stream, which is usually nothing. That is a silent data loss, so it is refused: serializing a container whose source stream was already handed out throws an IllegalStateException.

    The content is held in memory while it crosses the boundary, which is inherent to transferring it at all. There is therefore always a limit on how much is carried, DEFAULT_MAX_BYTES unless a different one is given. The limit is applied while the source is read, so content that exceeds it is never held in full. A caller that knowingly transfers more passes its own limit, or NO_LIMIT to take responsibility for the size itself.

    Instances are not thread-safe.

    This class is intended for internal use by the RPC framework and should not be used by plugins.

    Since:
    8.5.6
    See Also:
    Serialized Form
    • Field Detail

      • DEFAULT_MAX_BYTES

        public static final long DEFAULT_MAX_BYTES
        How much content a container carries unless it is given a different limit: 16 MiB.

        Well above what the boundary is used for (certificate and key files, configuration exports) and low enough that several transfers at once cannot exhaust the heap of a server they all share. Transferring more is a deliberate act, not something a caller should end up doing by not thinking about it.

        See Also:
        Constant Field Values
      • NO_LIMIT

        public static final long NO_LIMIT
        Limit meaning that content is carried no matter how much of it there is.
        See Also:
        Constant Field Values
    • Constructor Detail

      • SerializableInputStreamContainer

        public SerializableInputStreamContainer​(InputStream source)
        A container for the content of the given stream, up to DEFAULT_MAX_BYTES.
        Parameters:
        source - the stream to carry. Must not be null. It is not read until the container is serialized, and it is never closed by the container.
        Throws:
        NullPointerException - if source is null.
        Since:
        8.5.6
      • SerializableInputStreamContainer

        public SerializableInputStreamContainer​(InputStream source,
                                                long maxBytes)
        A container for the content of the given stream, up to the given limit.

        The limit is applied while the source is read, so a source that exceeds it costs no more memory than the limit itself. Exceeding it fails the transfer with an IOException rather than truncating the content, since half a payload is not a payload.

        Parameters:
        source - the stream to carry. Must not be null. It is not read until the container is serialized, and it is never closed by the container.
        maxBytes - how much content may be read from source, or NO_LIMIT for no limit. Must not be negative unless it is NO_LIMIT.
        Throws:
        NullPointerException - if source is null.
        IllegalArgumentException - if maxBytes is negative and not NO_LIMIT.
        Since:
        8.5.6
    • Method Detail

      • of

        public static SerializableInputStreamContainer of​(byte[] data,
                                                          long maxBytes)
        A container for content that is already at hand, up to the given limit. It needs no stream to be read from and is therefore repeatable from the start.

        The content is at hand, so the limit is checked right away rather than when the container is transferred: a caller finds out where the offending content came from instead of somewhere down the call chain.

        Parameters:
        data - the content. Must not be null. It is copied, so later changes to the array do not affect the container.
        maxBytes - how much content may be carried, or NO_LIMIT for no limit. Must not be negative unless it is NO_LIMIT.
        Returns:
        the container.
        Throws:
        NullPointerException - if data is null.
        IllegalArgumentException - if maxBytes is negative and not NO_LIMIT, or if data is longer than maxBytes.
        Since:
        8.5.6
      • getInputStream

        public InputStream getInputStream()
        The content of this container as a stream.

        Once the container holds the content, i.e. after it was transferred or after it was built from bytes, this returns a fresh stream on every call. Before that it returns the source stream itself, which can be read once, and doing so gives up the ability to transfer the container.

        Returns:
        the stream. Never null.
        Since:
        8.5.6