Search in sources :

Example 1 with TemplateOutputException

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;
}
Also used : TemplateManager(org.thymeleaf.engine.TemplateManager) TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) TemplateEngineException(org.thymeleaf.exceptions.TemplateEngineException) BigDecimal(java.math.BigDecimal)

Example 2 with TemplateOutputException

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);
    }
}
Also used : TemplateManager(org.thymeleaf.engine.TemplateManager) TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) TemplateEngineException(org.thymeleaf.exceptions.TemplateEngineException) IOException(java.io.IOException) BigDecimal(java.math.BigDecimal)

Example 3 with TemplateOutputException

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;
}
Also used : TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) TemplateEngineException(org.thymeleaf.exceptions.TemplateEngineException) IOException(java.io.IOException) BigDecimal(java.math.BigDecimal) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException) IOException(java.io.IOException) TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) TemplateEngineException(org.thymeleaf.exceptions.TemplateEngineException)

Example 4 with TemplateOutputException

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);
}
Also used : WritableByteChannel(java.nio.channels.WritableByteChannel) TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) CharsetEncoder(java.nio.charset.CharsetEncoder)

Example 5 with TemplateOutputException

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);
    }
}
Also used : TemplateOutputException(org.thymeleaf.exceptions.TemplateOutputException) IOException(java.io.IOException)

Aggregations

TemplateOutputException (org.thymeleaf.exceptions.TemplateOutputException)6 IOException (java.io.IOException)4 BigDecimal (java.math.BigDecimal)3 TemplateEngineException (org.thymeleaf.exceptions.TemplateEngineException)3 TemplateProcessingException (org.thymeleaf.exceptions.TemplateProcessingException)3 TemplateManager (org.thymeleaf.engine.TemplateManager)2 WritableByteChannel (java.nio.channels.WritableByteChannel)1 CharsetEncoder (java.nio.charset.CharsetEncoder)1