io.mangoo.templating.TemplateEngine Maven / Gradle / Ivy
The newest version!
package io.mangoo.templating;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import freemarker.cache.MruCacheStorage;
import freemarker.core.HTMLOutputFormat;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.Version;
import io.mangoo.constants.NotNull;
import io.mangoo.core.Application;
import io.mangoo.exceptions.MangooTemplateEngineException;
import io.mangoo.records.Source;
import io.undertow.server.HttpServerExchange;
import no.api.freemarker.java8.Java8ObjectWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
public class TemplateEngine {
private final Configuration configuration = new Configuration(VERSION);
private static final String NUMBER_FORMAT = "0.######";
private static final String DEFAULT_TEMPLATES_DIR = "/templates/defaults/";
private static final String TEMPLATES_FOLDER = "templates/";
private static final String TEMPLATE_SUFFIX = ".ftl";
private static final String REGEX = "\n";
private static final int MIN_LINES = 6;
private static final int MAX_LINES = 8;
private static final int MAX_CHARS = 65_536;
private static final int ONE_SECOND_MS = 1000;
private static final int STRONG_SIZE_LIMIT = 20;
private static final Version VERSION = new Version(2, 3, 33);
public TemplateEngine() {
configuration.setClassForTemplateLoading(getClass(), "/" + TEMPLATES_FOLDER);
configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
configuration.setOutputEncoding(StandardCharsets.UTF_8.name());
configuration.setLocalizedLookup(false);
configuration.setNumberFormat(NUMBER_FORMAT);
configuration.setAPIBuiltinEnabled(true);
configuration.setObjectWrapper(new Java8ObjectWrapper(VERSION));
configuration.setOutputFormat(HTMLOutputFormat.INSTANCE);
configuration.setRecognizeStandardFileExtensions(false);
if (Application.inDevMode()) {
configuration.setTemplateUpdateDelayMilliseconds(ONE_SECOND_MS);
} else {
configuration.setTemplateUpdateDelayMilliseconds(Integer.MAX_VALUE);
configuration.setCacheStorage(new MruCacheStorage(STRONG_SIZE_LIMIT, Integer.MAX_VALUE));
}
}
@SuppressFBWarnings(value = "TEMPLATE_INJECTION_FREEMARKER")
public String renderTemplate(TemplateContext context) throws MangooTemplateEngineException {
Template template;
try {
template = configuration.getTemplate(context.getTemplatePath());
} catch (IOException e) {
throw new MangooTemplateEngineException("Template not found on path: " + context.getTemplatePath(), e);
}
var buffer = new StringWriter(MAX_CHARS);
try {
template.process(context.getContent(), buffer);
} catch (TemplateException | IOException e) {
throw new MangooTemplateEngineException("Failed to process template", e);
}
return buffer.toString();
}
@SuppressFBWarnings({"PATH_TRAVERSAL_IN","TEMPLATE_INJECTION_FREEMARKER"})
public String renderException(HttpServerExchange exchange, Throwable cause, boolean templateException) throws MangooTemplateEngineException {
Map content = new HashMap<>();
content.put("templateException", templateException);
if (templateException) {
content.put("exceptions", cause.getMessage().split(REGEX)); //NOSONAR Method is only used in development mode
} else {
var stackTraceElement = cause.getStackTrace()[0];
String sourceCodePath = getSourceCodePath(stackTraceElement);
List