001package io.jstach.jstachio; 002 003import java.io.IOException; 004import java.io.OutputStream; 005import java.io.OutputStreamWriter; 006 007import io.jstach.jstache.JStacheConfig; 008import io.jstach.jstache.JStacheFlags; 009import io.jstach.jstache.JStacheType; 010 011/** 012 * A JStachio Template is a renderer that has template meta data. 013 * <p> 014 * Generated code implements this interface. 015 * <p> 016 * While many of the methods allow passing in custom Escapers care must be taken to choose 017 * a proper escaper that supports the original media type and charset of the template. 018 * There is currently no runtime checking that the escaper supports the template's media 019 * type and charset. 020 * 021 * @author agentgt 022 * @param <T> the model type 023 */ 024public interface Template<T> extends Renderer<T>, TemplateInfo { 025 026 /** 027 * Renders the passed in model to an appendable like output. 028 * @param <A> output type 029 * @param <E> error type 030 * @param model a model assumed never to be <code>null</code>. 031 * @param appendable the appendable to write to. 032 * @throws E if there is an error writing to the output 033 * @apiNote if the eventual output is to be bytes use 034 * {@link #write(Object, io.jstach.jstachio.Output.EncodedOutput)} as it will leverage 035 * pre-encoding if the template has it. 036 */ 037 @Override 038 public <A extends Output<E>, E extends Exception> A execute(T model, A appendable) throws E; 039 040 /** 041 * Renders the passed in model directly to a binary stream possibly leveraging 042 * pre-encoded parts of the template. 043 * @param <A> output type 044 * @param <E> error type 045 * @param model a model assumed never to be <code>null</code>. 046 * @param output to write to. 047 * @return the passed in output for convenience 048 * @throws E if an error occurs while writing to output 049 * @apiNote for performance and code generation reasons templates do not do validation 050 * that the encoded output has the correct charset. 051 */ 052 default <A extends io.jstach.jstachio.Output.EncodedOutput<E>, E extends Exception> A write( // 053 T model, // 054 A output) throws E { 055 return execute(model, output); 056 } 057 058 /** 059 * Renders the passed in model directly to a binary stream using the 060 * {@link #templateCharset()} for encoding. If the template is pre-encoded the 061 * pre-encoded parts of the template will be written to the stream for performance 062 * otherwise an {@link OutputStreamWriter} will wrap the outputstream. 063 * @param model a model assumed never to be <code>null</code>. 064 * @param outputStream to write to. 065 * @throws IOException if an error occurs while writing to the outputStream 066 * @apiNote The stream will not be closed but might be flushed by this call. 067 * @see EncodedTemplate 068 */ 069 default void write(T model, // 070 OutputStream outputStream) throws IOException { 071 OutputStreamWriter ow = new OutputStreamWriter(outputStream, templateCharset()); 072 execute(model, ow); 073 ow.flush(); 074 } 075 076 /** 077 * Creates a template model pair. 078 * @param model never <code>null</code> model. 079 * @return executable template model pair. 080 */ 081 default TemplateModel model(T model) { 082 return TemplateModel.of(this, model); 083 } 084 085 /** 086 * <strong>EXPERIMENTAL</strong> support of pre-encoded templates that have the static 087 * parts of the template already encoded into bytes. By default all 088 * {@link JStacheType#JSTACHIO} templates that are generated are of this type. To 089 * disable see {@link JStacheFlags.Flag#PRE_ENCODE_DISABLE}. 090 * <p> 091 * This interface is to support 092 * <a href="https://github.com/fizzed/rocker#near-zero-copy-rendering"> Rocker style 093 * near zero-copy rendering</a> where the static template parts are stored as byte 094 * arrays. 095 * <p> 096 * The passed in {@link OutputStream} <em>will only have 097 * {@link OutputStream#write(byte[])} called</em> thus an array or list of byte arrays 098 * can be accumulated to support almost zero-copy. <strong> Consequently absolutely no 099 * mutation of the byte arrays should happen as they could be reusable static parts of 100 * the template! </strong> 101 * <p> 102 * <em>Overall it is recommended that you do not use this interface unless you have an 103 * intimate knowledge of how your platform buffers data and have byte like access as 104 * current JMH benchmarking indicates that 105 * {@link String#getBytes(java.nio.charset.Charset)} is generally much faster for raw 106 * byte conversion albeit at the possible cost of increased memory. One should peform 107 * their own benchmarking to confirm using this interface is worth it. </em> 108 * 109 * @author agentgt 110 * @param <T> the model type 111 * @apiNote The passed in {@link OutputStream} <em>will only have 112 * {@link OutputStream#write(byte[])} called</em> and no mutation of the passed in 113 * byte array should happen downstream. 114 * @see JStacheFlags.Flag#PRE_ENCODE_DISABLE 115 */ 116 public interface EncodedTemplate<T> extends Template<T> { 117 118 /** 119 * Renders the passed in model directly to a binary stream leveraging pre-encoded 120 * parts of the template. This <em>may</em> improve performance when rendering 121 * UTF-8 to an OutputStream as some of the encoding is done in advance. Because 122 * the encoding is done statically you cannot pass the charset in. The chosen 123 * charset comes from {@link JStacheConfig#charset()}. 124 * @param model a model assumed never to be <code>null</code>. 125 * @param outputStream to write to. 126 * @throws IOException if an error occurs while writing to the outputStream 127 * @apiNote The stream will not be closed or flushed by this call. 128 */ 129 @Override 130 default void write(T model, // 131 OutputStream outputStream) throws IOException { 132 write(model, Output.of(outputStream, templateCharset())); 133 } 134 135 /** 136 * Renders the passed in model directly to a binary stream leveraging pre-encoded 137 * parts of the template. This <em>may</em> improve performance when rendering 138 * UTF-8 to an OutputStream as some of the encoding is done in advance. Because 139 * the encoding is done statically you cannot pass the charset in. The chosen 140 * charset comes from {@link JStacheConfig#charset()}. 141 * @param <A> output type 142 * @param <E> error type 143 * @param model a model assumed never to be <code>null</code>. 144 * @param output to write to. 145 * @return the passed in output for convenience 146 * @throws E if an error occurs while writing to output 147 */ 148 @Override 149 public <A extends io.jstach.jstachio.Output.EncodedOutput<E>, E extends Exception> A write( // 150 T model, // 151 A output) throws E; 152 153 @Override 154 default TemplateModel model(T model) { 155 return TemplateModel.of(this, model); 156 } 157 158 } 159 160}