Java tutorial
/* * Copyright 2015-2017 Emmanuel Keller / QWAZR * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.qwazr.library.freemarker; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.qwazr.library.AbstractLibrary; import com.qwazr.library.LibraryManager; import freemarker.cache.TemplateLoader; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.TemplateExceptionHandler; import org.apache.commons.lang3.builder.HashCodeBuilder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; public class FreeMarkerTool extends AbstractLibrary implements Closeable { @JsonProperty("output_encoding") public final String outputEncoding; @JsonProperty("default_encoding") public final String defaultEncoding; @JsonProperty("default_content_type") public final String defaultContentType; @JsonProperty("use_classloader") public final Boolean useClassloader; @JsonProperty("template_path") public final String templatePath; @JsonProperty("localized_lookup") public final Boolean localizedLookup; @JsonProperty("template_loaders") public final List<Loader> templateLoaders; public static class Loader { public enum Type { resource, file } public final Type type; public final String path; @JsonIgnore private final int hashCode; Loader(Type type, String path, int hashCode) { this.type = type; this.path = path; this.hashCode = hashCode; } Loader(@JsonProperty("type") Type type, @JsonProperty("path") String path) { this(type, path, new HashCodeBuilder().append(type.ordinal()).append(path).build()); } @JsonIgnore public TemplateLoader build() { final Type t = type == null ? Type.resource : type; switch (t) { case file: return new FileTemplateLoader(new File(Objects.requireNonNull(path, "The path is missing"))); default: case resource: return new ResourceTemplateLoader(null, path == null ? null : p -> path + p); } } @JsonIgnore @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object o) { if (o == null || !(o instanceof Loader)) return false; final Loader l = (Loader) o; return Objects.equals(l.path, path) && type == l.type; } } @JsonIgnore private volatile Configuration cfg = null; private final static String DEFAULT_CHARSET = "UTF-8"; private final static String DEFAULT_CONTENT_TYPE = "text/html"; @JsonCreator FreeMarkerTool(@JsonProperty("output_encoding") String outputEncoding, @JsonProperty("default_encoding") String defaultEncoding, @JsonProperty("default_content_type") String defaultContentType, @JsonProperty("use_classloader") Boolean useClassloader, @JsonProperty("template_path") String templatePath, @JsonProperty("localized_lookup") Boolean localizedLookup, @JsonProperty("template_loaders") Collection<Loader> templateLoaders) { this.outputEncoding = outputEncoding; this.defaultEncoding = defaultEncoding; this.defaultContentType = defaultContentType; this.useClassloader = useClassloader; this.templatePath = templatePath; this.localizedLookup = localizedLookup; this.templateLoaders = templateLoaders == null ? null : new ArrayList<>(templateLoaders); } FreeMarkerTool(FreeMarkerToolBuilder builder) { this(builder.outputEncoding, builder.defaultEncoding, builder.defaultContentType, builder.useClassloader, builder.templatePath, builder.localizedLookup, builder.templateLoaders); } @Override public void load() { cfg = new Configuration(Configuration.VERSION_2_3_26); final MultiTemplateLoader.Builder builder = MultiTemplateLoader.of(); if (useClassloader != null && useClassloader) builder.loader(new Loader(Loader.Type.resource, null).build()); else builder.loader(new FileTemplateLoader(templatePath != null ? new File(templatePath) : libraryManager == null ? null : libraryManager.getDataDirectory().toFile())); if (templateLoaders != null) templateLoaders.forEach(loader -> builder.loader(loader.build())); cfg.setTemplateLoader(builder.build()); cfg.setOutputEncoding(outputEncoding == null ? DEFAULT_CHARSET : outputEncoding); cfg.setDefaultEncoding(defaultEncoding == null ? DEFAULT_CHARSET : defaultEncoding); cfg.setLocalizedLookup(localizedLookup == null ? false : localizedLookup); cfg.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); } @Override public void close() { if (cfg != null) { cfg.clearTemplateCache(); cfg = null; } } public void template(final String templatePath, final Locale locale, final Map<String, Object> dataModel, final HttpServletResponse response) throws TemplateException, IOException { if (response.getContentType() == null) response.setContentType(defaultContentType == null ? DEFAULT_CONTENT_TYPE : defaultContentType); response.setCharacterEncoding(DEFAULT_CHARSET); final Template template = cfg.getTemplate(templatePath, locale); template.process(dataModel, response.getWriter()); } public void template(final String templatePath, final Map<String, Object> dataModel, final HttpServletResponse response) throws TemplateException, IOException { template(templatePath, null, dataModel, response); } public void template(final String templatePath, final HttpServletRequest request, final HttpServletResponse response) throws IOException, TemplateException { final Map<String, Object> variables = new HashMap<>(); variables.put("request", request); variables.put("session", request.getSession()); final Enumeration<String> attrNames = request.getAttributeNames(); if (attrNames != null) { while (attrNames.hasMoreElements()) { final String attrName = attrNames.nextElement(); variables.put(attrName, request.getAttribute(attrName)); } } template(templatePath, variables, response); } public String template(final String templatePath, final Locale locale, final Map<String, Object> dataModel) throws TemplateException, IOException { final Template template = cfg.getTemplate(templatePath, locale); try (final StringWriter stringWriter = new StringWriter()) { template.process(dataModel, stringWriter); return stringWriter.toString(); } } public String template(final String templatePath, final Map<String, Object> dataModel) throws TemplateException, IOException { return template(templatePath, null, dataModel); } @JsonIgnore public static FreeMarkerToolBuilder of() { return of(null); } @JsonIgnore public static FreeMarkerToolBuilder of(LibraryManager libraryManager) { return new FreeMarkerToolBuilder(libraryManager); } }