use of org.thymeleaf.exceptions.TemplateOutputException in project thymeleaf by thymeleaf.
the class TemplateEngine method processThrottled.
public final IThrottledTemplateProcessor processThrottled(final TemplateSpec templateSpec, final IContext context) {
if (!this.initialized) {
initialize();
}
final IThrottledTemplateProcessor throttledTemplateProcessor;
try {
Validate.notNull(templateSpec, "Template Specification cannot be null");
Validate.notNull(context, "Context cannot be null");
if (logger.isTraceEnabled()) {
logger.trace("[THYMELEAF][{}] STARTING PREPARATION OF THROTTLED TEMPLATE \"{}\" WITH LOCALE {}", new Object[] { TemplateEngine.threadIndex(), templateSpec, context.getLocale() });
}
final long startNanos = System.nanoTime();
final TemplateManager templateManager = this.configuration.getTemplateManager();
throttledTemplateProcessor = templateManager.parseAndProcessThrottled(templateSpec, context);
final long endNanos = System.nanoTime();
if (logger.isTraceEnabled()) {
logger.trace("[THYMELEAF][{}] FINISHED PREPARATION OF THROTTLED TEMPLATE \"{}\" WITH LOCALE {}", new Object[] { TemplateEngine.threadIndex(), templateSpec, context.getLocale() });
}
if (timerLogger.isTraceEnabled()) {
final BigDecimal elapsed = BigDecimal.valueOf(endNanos - startNanos);
final BigDecimal elapsedMs = elapsed.divide(BigDecimal.valueOf(NANOS_IN_SECOND), RoundingMode.HALF_UP);
timerLogger.trace("[THYMELEAF][{}][{}][{}][{}][{}] TEMPLATE \"{}\" WITH LOCALE {} PREPARED FOR THROTTLED PROCESSING IN {} nanoseconds (approx. {}ms)", new Object[] { TemplateEngine.threadIndex(), LoggingUtils.loggifyTemplateName(templateSpec.getTemplate()), context.getLocale(), elapsed, elapsedMs, templateSpec, context.getLocale(), elapsed, elapsedMs });
}
} catch (final TemplateOutputException e) {
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception preparing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
throw e;
} catch (final TemplateEngineException e) {
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception preparing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
throw e;
} catch (final RuntimeException e) {
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception preparing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
throw new TemplateProcessingException("Exception preparing throttled template", templateSpec.toString(), e);
}
return throttledTemplateProcessor;
}
use of org.thymeleaf.exceptions.TemplateOutputException in project thymeleaf by thymeleaf.
the class TemplateEngine method process.
public final void process(final TemplateSpec templateSpec, final IContext context, final Writer writer) {
if (!this.initialized) {
initialize();
}
try {
Validate.notNull(templateSpec, "Template Specification cannot be null");
Validate.notNull(context, "Context cannot be null");
Validate.notNull(writer, "Writer cannot be null");
if (logger.isTraceEnabled()) {
logger.trace("[THYMELEAF][{}] STARTING PROCESS OF TEMPLATE \"{}\" WITH LOCALE {}", new Object[] { TemplateEngine.threadIndex(), templateSpec, context.getLocale() });
}
final long startNanos = System.nanoTime();
final TemplateManager templateManager = this.configuration.getTemplateManager();
templateManager.parseAndProcess(templateSpec, context, writer);
final long endNanos = System.nanoTime();
if (logger.isTraceEnabled()) {
logger.trace("[THYMELEAF][{}] FINISHED PROCESS AND OUTPUT OF TEMPLATE \"{}\" WITH LOCALE {}", new Object[] { TemplateEngine.threadIndex(), templateSpec, context.getLocale() });
}
if (timerLogger.isTraceEnabled()) {
final BigDecimal elapsed = BigDecimal.valueOf(endNanos - startNanos);
final BigDecimal elapsedMs = elapsed.divide(BigDecimal.valueOf(NANOS_IN_SECOND), RoundingMode.HALF_UP);
timerLogger.trace("[THYMELEAF][{}][{}][{}][{}][{}] TEMPLATE \"{}\" WITH LOCALE {} PROCESSED IN {} nanoseconds (approx. {}ms)", new Object[] { TemplateEngine.threadIndex(), LoggingUtils.loggifyTemplateName(templateSpec.getTemplate()), context.getLocale(), elapsed, elapsedMs, templateSpec, context.getLocale(), elapsed, elapsedMs });
}
/*
* Finally, flush the writer in order to make sure that everything has been written to output
*/
try {
writer.flush();
} catch (final IOException e) {
throw new TemplateOutputException("An error happened while flushing output writer", templateSpec.getTemplate(), -1, -1, e);
}
} catch (final TemplateOutputException e) {
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception processing template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
throw e;
} catch (final TemplateEngineException e) {
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception processing template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
throw e;
} catch (final RuntimeException e) {
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception processing template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), templateSpec, e.getMessage() }), e);
throw new TemplateProcessingException("Exception processing template", templateSpec.toString(), e);
}
}
use of org.thymeleaf.exceptions.TemplateOutputException in project thymeleaf by thymeleaf.
the class ThrottledTemplateProcessor method process.
private int process(final int maxOutput, final String outputType) {
int writtenCount = 0;
try {
if (this.allProcessingFinished || maxOutput == 0) {
// No bytes written
return 0;
}
if (logger.isTraceEnabled()) {
logger.trace("[THYMELEAF][{}] Starting throttled process (limit:{} {}) of template \"{}\" with locale {}", new Object[] { TemplateEngine.threadIndex(), Integer.valueOf(maxOutput), outputType, this.templateSpec, this.context.getLocale() });
}
final long startNanos = System.nanoTime();
// Save the initial written count so that we can know at the end how many bytes were written
final int initialWrittenCount = this.writer.getWrittenCount();
// Set the new limit for the writer (might provoke overflow being processed)
this.writer.allow(maxOutput);
// Maybe by processing all overflow we just finished
if (!computeFinish() && !this.writer.isStopped()) {
if (this.flowController.processorTemplateHandlerPending) {
this.processorTemplateHandler.handlePending();
}
if (!computeFinish() && !this.writer.isStopped()) {
this.offset += this.templateModel.process(this.templateHandler, this.offset, this.flowController);
if (this.offset == this.templateModel.size()) {
EngineContextManager.disposeEngineContext(this.context);
this.eventProcessingFinished = true;
computeFinish();
}
}
}
final long endNanos = System.nanoTime();
/*
* Finally, flush the writer in order to make sure that everything has been written to output
*/
try {
this.writer.flush();
} catch (final IOException e) {
throw new TemplateOutputException("An error happened while flushing output writer", templateSpec.getTemplate(), -1, -1, e);
}
writtenCount = this.writer.getWrittenCount() - initialWrittenCount;
if (logger.isTraceEnabled()) {
logger.trace("[THYMELEAF][{}] Finished throttled process (limit:{} {}, output: {} {}) of template \"{}\" with locale {}", new Object[] { TemplateEngine.threadIndex(), Integer.valueOf(maxOutput), outputType, Integer.valueOf(writtenCount), outputType, this.templateSpec, this.context.getLocale() });
}
if (timerLogger.isTraceEnabled()) {
final BigDecimal elapsed = BigDecimal.valueOf(endNanos - startNanos);
final BigDecimal elapsedMs = elapsed.divide(BigDecimal.valueOf(NANOS_IN_SECOND), RoundingMode.HALF_UP);
timerLogger.trace("[THYMELEAF][{}][{}][{}][{}][{}] TEMPLATE \"{}\" WITH LOCALE {} PROCESSED (THROTTLED, LIMIT:{} {}, OUTPUT: {} {}) IN {} nanoseconds (approx. {}ms)", new Object[] { TemplateEngine.threadIndex(), LoggingUtils.loggifyTemplateName(this.templateSpec.getTemplate()), this.context.getLocale(), elapsed, elapsedMs, this.templateSpec, this.context.getLocale(), Integer.valueOf(maxOutput), outputType, Integer.valueOf(writtenCount), outputType, elapsed, elapsedMs });
}
} catch (final TemplateOutputException e) {
this.eventProcessingFinished = true;
this.allProcessingFinished = true;
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception processing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), this.templateSpec, e.getMessage() }), e);
throw e;
} catch (final TemplateEngineException e) {
this.eventProcessingFinished = true;
this.allProcessingFinished = true;
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception processing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), this.templateSpec, e.getMessage() }), e);
throw e;
} catch (final Exception e) {
this.eventProcessingFinished = true;
this.allProcessingFinished = true;
// We log the exception just in case higher levels do not end up logging it (e.g. they could simply display traces in the browser
logger.error(String.format("[THYMELEAF][%s] Exception processing throttled template \"%s\": %s", new Object[] { TemplateEngine.threadIndex(), this.templateSpec, e.getMessage() }), e);
throw new TemplateProcessingException("Exception processing throttled template", this.templateSpec.toString(), e);
}
reportFinish(outputType);
return writtenCount;
}
use of org.thymeleaf.exceptions.TemplateOutputException in project thymeleaf by thymeleaf.
the class ThrottledTemplateWriter method setOutput.
void setOutput(final OutputStream outputStream, final Charset charset, final int maxOutputInBytes) {
if (this.adapter != null && this.adapter instanceof ThrottledTemplateWriterWriterAdapter) {
throw new TemplateOutputException("The throttled processor has already been initialized to use char-based output (Writer), " + "but an OutputStream has been specified.", this.templateName, -1, -1, null);
}
if (this.adapter == null) {
final int adapterOverflowBufferIncrementBytes = (maxOutputInBytes == Integer.MAX_VALUE ? 128 : // output size could be too small, so we will set a minimum of 16b, and max of 128b
Math.min(128, Math.max(16, maxOutputInBytes / 8)));
this.adapter = new ThrottledTemplateWriterOutputStreamAdapter(this.templateName, this.flowController, adapterOverflowBufferIncrementBytes);
// We cannot directly use a java.io.OutputStreamWriter here because that class uses a CharsetEncoder
// underneath that always creates a 8192byte (8KB) buffer, and there is no way to configure that.
//
// The problem with such buffer is that we are counting the number of output bytes at the OutputStream
// wrapper (the adapter we just created), which is set as the output of the OutputStreamWriter, and which
// does not receive any bytes until the OutputStreamWriter flushes its 8KB buffer. But in a scenario in
// which, for instance, we only need 100 bytes to complete our output chunk, this would mean we would still
// have an overflow of more than 8,000 bytes. And that basically renders this whole template throttling
// mechanism useless.
//
// So we will use an alternative construct to OutputStreamWriter, based on a WritableByteChannel. This
// will basically work in the same way as an OutputStreamWriter, but by building it manually we will be
// able to specify the size of the buffer to be used.
//
// And we do not want the buffer at the Writer -> OutputStream converter to completely disappear, because
// it actually improves the performance of the converter. So we will use the maxOutputInBytes (the size
// of the output to be obtained from the throttled template the first time) as an approximate measure
// of what we will need in subsequent calls, and we will to try to adjust the size of the buffer so
// that we make the most use of it without needing to flush too often, nor 'losing' chars in the buffer.
//
// Last, note that in order to avoid this 'loss of chars' we will combine this with 'flush' calls at the
// 'isOverflown()' and 'isStopped()' calls.
final CharsetEncoder charsetEncoder = charset.newEncoder();
int channelBufferSize = (maxOutputInBytes == Integer.MAX_VALUE ? 1024 : // will set a minimum of 64b and a max of 512b.
Math.min(512, Math.max(64, adapterOverflowBufferIncrementBytes * 2)));
final WritableByteChannel channel = Channels.newChannel((ThrottledTemplateWriterOutputStreamAdapter) this.adapter);
this.writer = Channels.newWriter(channel, charsetEncoder, channelBufferSize);
// Use of a wrapping BufferedWriter is recommended by OutputStreamWriter javadoc for improving efficiency,
// avoiding frequent converter invocations (note that the character converter also has its own buffer).
// this.writer = new BufferedWriter(new OutputStreamWriter((ThrottledTemplateWriterOutputStreamAdapter)this.adapter, charset));
}
((ThrottledTemplateWriterOutputStreamAdapter) this.adapter).setOutputStream(outputStream);
}
use of org.thymeleaf.exceptions.TemplateOutputException in project thymeleaf by thymeleaf.
the class ThrottledTemplateWriterOutputStreamAdapter method allow.
public void allow(final int limit) {
if (limit == Integer.MAX_VALUE || limit < 0) {
this.unlimited = true;
this.limit = -1;
} else {
this.unlimited = false;
this.limit = limit;
}
this.flowController.stopProcessing = (this.limit == 0);
if (this.overflowSize == 0 || this.limit == 0) {
return;
}
try {
if (this.unlimited || this.limit > this.overflowSize) {
this.os.write(this.overflow, 0, this.overflowSize);
if (!this.unlimited) {
this.limit -= this.overflowSize;
}
this.writtenCount += this.overflowSize;
this.overflowSize = 0;
return;
}
this.os.write(this.overflow, 0, this.limit);
if (this.limit < this.overflowSize) {
System.arraycopy(this.overflow, this.limit, this.overflow, 0, this.overflowSize - this.limit);
}
this.overflowSize -= this.limit;
this.writtenCount += this.limit;
this.limit = 0;
this.flowController.stopProcessing = true;
} catch (final IOException e) {
throw new TemplateOutputException("Exception while trying to write overflowed buffer in throttled template", this.templateName, -1, -1, e);
}
}
Aggregations