Class RereadableContent

java.lang.Object
de.aristaflow.adept2.util.io.RereadableContent
All Implemented Interfaces:
Closeable, AutoCloseable
Direct Known Subclasses:
FileContent, MemoryContent, WrappingContent

public abstract class RereadableContent extends Object implements Closeable
The RereadableContent can be used when the content of an InputStream needs to be processed multiple times. Depending on its eventual size the whole content of the input stream is buffered in-memory - up to a certain threshold - or in a temporary file.

The RereadableContent as well as the provided input streams must be closed after use! This can be ensured by adhering to the following template:

 try (RereadableContentBuilder rcb = new RereadableContentBuilder();
      RereadableContent rc = rcb.data(inputStream).build())
 {
   ...
   try (InputStream is = rc.getInputStream())
   {
     ...
   }
   ...
   try (InputStream is = rc.getInputStream())
   {
     ...
   }
   ...
 }
 
If you want to fill the builder using an OutputStream make sure to fill and close this before building:
 try (RereadableContentBuilder rcb = new RereadableContentBuilder())
 {
   ...
   try (OutputStream os = rcb.getOutputStream())
   {
     ...
   }
   ...
   try (RereadableContent rc = rcb.build())
   {
     ...
   }
 }
 
You can also let the RereadableContent or the InputStreams get out of the block structure. But make sure to Closeable.close() them all.
 
 RereadableContent rc;
 try (RereadableContentBuilder rcb = new RereadableContentBuilder())
 {
   ...
   try (OutputStream os = rcb.getOutputStream())
   {
     ...
   }
   rc = rbc.build();
 }
 ...
 InputStream is1 = rc.getInputStream())
 ...
 InputStream is2 = input.getInputStream())
 ...
 // Just make sure to close them all (in arbitrary order).
 is1.close();
 ...
 rc.close();
 ...
 is2.close();
 ...
 
 
All InputStream instances created by this class will be AttributedInputStream also providing the size and the SHA-512 hash of the stream data. The created streams will be tracked. The RereadableContent will not be closed when at least one of its input streams is still in use (has not been closed). It is ensured that closing will be done by the last active input stream (or by the RereadableContent). Also all of these will close in a cleanup to make sure that they will be really closed.

This class is thread-safe.

  • Field Details

    • RRC_CONTENT_FILE

      public static final String RRC_CONTENT_FILE
      The name of the Path attribute providing the file containing the content in case of a FileContent. Otherwise this attribute will not be present.
      See Also:
    • RRC_INPUT_STREAM_SIZE

      protected static final String RRC_INPUT_STREAM_SIZE
      The name of the Long attribute providing the size of the input stream in bytes.
      See Also:
    • size

      protected final long size
      The size of the content.
    • sha512hash

      protected final byte[] sha512hash
      The SHA-512 hash of the content.
    • existingStreams

      protected final Collection<Object> existingStreams
      All streams that have been created by this RereadableContent including itself are identified by an arbitrary Object. They have a clean-up task used for InputStream.close() as well as post-mortem action. The task removes the Object and the last one in the collection performs cleaning up the RereadableContent, for instance deleting the temporary file.
    • finalCleanup

      protected final Closeable finalCleanup
      The final clean-up to be executed after all streams and this RereadableContent have been closed/cleaned up.
    • cleanup

      protected final Cleanup<IOException> cleanup
      The clean-up called as post-mortem action of this RereadableContent. Since this is the same logic, it is also used by close().
  • Constructor Details

    • RereadableContent

      protected RereadableContent(long size, byte[] sha512hash, Closeable finalCleanup)
      Creates a new RereadableContent for the designated data.
      Parameters:
      size - The size of the content.
      sha512hash - The SHA-512 hash of the content.
      finalCleanup - The final clean-up to be executed after all streams and the RereadableContent have been closed/cleaned up.
    • RereadableContent

      protected RereadableContent(RereadableContent wrapped) throws IOException
      Creates a new RereadableContent wrapping the designated RereadableContent and creating a new input stream to keep the wrapped RereadableContent alive.
      Parameters:
      wrapped - The wrapped RereadableContent.
      Throws:
      IOException - If creating a new input stream from the designated RereadableContent fails, an IOException will be thrown.
  • Method Details

    • getSize

      public long getSize()
      Gets the size of the content.
      Returns:
      The size of the content.
    • getSHA512Hash

      public byte[] getSHA512Hash()
      Gets the SHA—512 hash of the content.
      Returns:
      The SHA-512 hash of the content.
    • getInputStream

      public AttributedInputStream getInputStream() throws IOException
      Gets an input stream for the data. This method may be called multiple times. The returned stream must be closed properly after use!
      Closing will not affect the InputStream.
      Returns:
      An input stream for the data. The caller is responsible for closing.
      Throws:
      IOException - If there are problems creating a new input stream for the data or this RereadableContent has already been closed, an IOException will be thrown.
    • createInputStream

      protected abstract InputStream createInputStream() throws IOException
      Creates a new input stream for the content.
      Returns:
      A new input stream for the content. The caller is responsible for closing.
      Throws:
      IOException - If there are problems creating a new input stream for the content, an IOException will be thrown.
    • close

      public final void close() throws IOException
      Closes the underlying stream or deletes the underlying file if there is no unclosed getInputStream(). If there are input streams of this RereadableContent that have not been closed yet, closing deferred until closing the last one of these input streams.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Throws:
      IOException - If closing or deleting fails, an IOException will be thrown.
    • equals

      public boolean equals(Object obj)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • getSize

      public static Long getSize(InputStream is)
      Gets the size of the designated input stream in case it is provided via RRC_INPUT_STREAM_SIZE, null otherwise.
      Parameters:
      is - The input stream for which to get the size (from the corresponding attribute).
      Returns:
      The value of the size attribute of the designated input stream or null if not available.