Class ThresholdEncodedOutput<T,E extends Exception>

java.lang.Object
io.jstach.jstachio.output.ThresholdEncodedOutput<T,E>
Type Parameters:
T - the downstream output type
E - the exception type that can be thrown while writing to the output type
All Implemented Interfaces:
Output<E>, Output.CloseableEncodedOutput<E>, Output.EncodedOutput<E>, LimitEncodedOutput<T,E>, AutoCloseable
Direct Known Subclasses:
ThresholdEncodedOutput.OutputStreamThresholdEncodedOutput

public abstract non-sealed class ThresholdEncodedOutput<T,E extends Exception> extends Object implements LimitEncodedOutput<T,E>
This abstract output will limit buffering by byte count and then fallback to pushing to the downstream output type of T once limit is exceeded. If the limit is not exceeded then the buffered data will be replayed and pushed when closed. Consequently this output strategy is a better fit for integration of blocking APIs such as Servlet based frameworks where the data is pushed instead of pulled. If pulling is more desired (non blocking code generally prefers a pull approach) than BufferedEncodedOutput is a better fit but requires the entire output be buffered.

The output T is lazily created once and only once by calling createConsumer(int) and the total size buffered will be passed if under limit. If the limit is exceeded than the size passed will be -1.

For this implementation to work close() must be called and thus a try-with-resource is recommended regardless if the downstream consumer needs to be closed or not!

The total buffered amount of data is not guaranteed to be exactly at the limit even if the total output is greater than the limit.

The advantages to letting this implementation do the buffering instead of the downstream framework is saving memory in that the pre-encoded parts of the template are just pointers and are not copied multiple times. Since this output instance will be doing the buffering it is important to minimize downstream buffering by letting the framework know that it does not need to buffer.

Example for Servlet output:


 class ServletThresholdEncodedOutput extends ThresholdEncodedOutput.OutputStreamThresholdEncodedOutput {

     private final HttpServletResponse response;

     public ServletThresholdEncodedOutput(Charset charset, HttpServletResponse response) {
         super(charset, calculateLimit(response));
         this.response = response;
     }

     private static int calculateLimit(HttpServletResponse response) {
         int limit = response.getBufferSize();
         if (limit <= 0) {
             return 1024 * 32;
         }
         return limit;
     }

     @Override
     protected OutputStream createConsumer(int size) throws IOException {
         if (size > -1) {
             response.setContentLength(size);
              // It is already all in memory so we do not need a buffer.
             response.setBufferSize(0);
         }
         return response.getOutputStream();
     }

 }
  
Author:
agentgt
See Also:
API Note
This class is not thread safe.
  • Field Details

    • limit

      protected final int limit
      The maximum number of bytes to buffer.
  • Constructor Details

    • ThresholdEncodedOutput

      protected ThresholdEncodedOutput(Charset charset, int limit)
      Create with charset and limit.
      Parameters:
      charset - the encoding to use.
      limit - the amount of total bytes to limit buffering however the total buffered amount of data is not guaranteed to be exactly at the limit even if the total output is greater than the limit.
  • Method Details

    • write

      protected abstract void write(T consumer, byte[] bytes) throws E
      Writes to a consumer.
      Parameters:
      consumer - the consumer created from createConsumer(int).
      bytes - data to be written
      Throws:
      E - if an error happens while using the consumer.
    • createConsumer

      protected abstract T createConsumer(int size) throws E
      Creates the consumer. If size is not -1 than the entire output has been buffered and can be safely used to set Content-Length before creating the actual consumer (often an OutputStream).
      Parameters:
      size - -1 indicates that the output is larger than the limit.
      Returns:
      the created consumer
      Throws:
      E - an error while creating the consumer
    • close

      protected abstract void close(T consumer) throws E
      Called to close the consumer. Implementations can decide whether or not to really close the consumer.
      Parameters:
      consumer - to be closed or not
      Throws:
      E - if an error happens while closing.
    • write

      public void write(byte[] bytes) throws E
      Description copied from interface: Output.EncodedOutput
      Analogous to OutputStream.write(byte[]). Implementations should not alter the byte array.
      Specified by:
      write in interface Output.EncodedOutput<T>
      Parameters:
      bytes - already encoded bytes
      Throws:
      E - if an error happens
    • consumer

      public @Nullable T consumer()
      Description copied from interface: LimitEncodedOutput
      The created consumer. Maybe null but on successful close should not be. This is not to create the consumer but to fetch it after processing has finished since the consumer is created on demand.
      Specified by:
      consumer in interface LimitEncodedOutput<T,E extends Exception>
      Returns:
      created consumer
    • charset

      public Charset charset()
      Description copied from interface: Output.EncodedOutput
      The charset that the encoded output should be.
      Specified by:
      charset in interface Output.EncodedOutput<T>
      Returns:
      expected charset
    • close

      public void close() throws E
      If the limit is not exceeded then the buffered data will be replayed and pushed when closed. Regardless close(Object) will be called on the output like object.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Output.CloseableEncodedOutput<T>
      Throws:
      E - if an error happens while creating or closing the downstream output
    • size

      public int size()
      This is the current written length.
      Specified by:
      size in interface LimitEncodedOutput<T,E extends Exception>
      Returns:
      current written length
    • limit

      public int limit()
      Description copied from interface: LimitEncodedOutput
      Buffer limit
      Specified by:
      limit in interface LimitEncodedOutput<T,E extends Exception>
      Returns:
      limit buffer to this amount of bytes
    • append

      public void append(CharSequence s) throws E
      Description copied from interface: Output
      Specified by:
      append in interface Output<T>
      Parameters:
      s - unlike appendable always non null.
      Throws:
      E - if an error happens while writting to the appendable
    • append

      public void append(String s) throws E
      Description copied from interface: Output
      Analogous to Appendable.append(CharSequence) which by default treats the String as a CharSequence.
      Specified by:
      append in interface Output<T>
      Specified by:
      append in interface Output.EncodedOutput<T>
      Parameters:
      s - unlike appendable always non null.
      Throws:
      E - if an error happens while writting to the appendable