1 package net.pterodactylus.sone.template;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.InputStreamReader;
10 import java.util.ArrayList;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.concurrent.atomic.AtomicReference;
15 import net.pterodactylus.util.template.Part;
16 import net.pterodactylus.util.template.Template;
17 import net.pterodactylus.util.template.TemplateContext;
18 import net.pterodactylus.util.template.TemplateException;
19 import net.pterodactylus.util.template.TemplateParser;
21 import com.google.common.base.Charsets;
24 * {@link Template} implementation that can be reloaded from the filesystem.
26 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
28 public class FilesystemTemplate extends Template {
30 private final String filename;
31 private final AtomicReference<LastLoadedTemplate> lastTemplate = new AtomicReference<LastLoadedTemplate>();
32 private final TemplateContext initialContext = new TemplateContext();
33 private final List<Part> parts = new ArrayList<Part>();
35 public FilesystemTemplate(String filename) {
36 this.filename = filename;
40 public TemplateContext getInitialContext() {
42 return initialContext;
45 private void loadTemplate() {
46 File templateFile = new File(filename);
47 if (templateWasLoaded() && !templateFileHasBeenModifiedAfterLoading(templateFile)) {
50 try (InputStream templateInputStream = new FileInputStream(templateFile);
51 Reader templateReader = new InputStreamReader(templateInputStream, Charsets.UTF_8)) {
52 Template template = TemplateParser.parse(templateReader);
53 lastTemplate.set(new LastLoadedTemplate(template));
54 template.getInitialContext().mergeContext(initialContext);
55 for (Part part : parts) {
58 } catch (IOException e) {
59 throw new TemplateFileNotFoundException(filename);
63 private boolean templateWasLoaded() {
64 return lastTemplate.get() != null;
67 private boolean templateFileHasBeenModifiedAfterLoading(File templateFile) {
68 return templateFile.lastModified() > lastTemplate.get().getLoadTime();
72 public void add(Part part) {
75 lastTemplate.get().getTemplate().add(part);
79 public void render(TemplateContext templateContext, Writer writer) throws TemplateException {
81 lastTemplate.get().getTemplate().render(templateContext, writer);
85 public Iterator<Part> iterator() {
87 return lastTemplate.get().getTemplate().iterator();
91 public int getLine() {
93 return lastTemplate.get().getTemplate().getLine();
97 public int getColumn() {
99 return lastTemplate.get().getTemplate().getColumn();
102 private static class LastLoadedTemplate {
104 private final Template template;
105 private final long loadTime = System.currentTimeMillis();
107 private LastLoadedTemplate(Template template) {
108 this.template = template;
111 public Template getTemplate() {
115 public long getLoadTime() {
122 * Exception that signals that a template file could not be found.
124 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
126 public static class TemplateFileNotFoundException extends RuntimeException {
128 public TemplateFileNotFoundException(String filename) {