1 package net.pterodactylus.sone.template;
4 import java.io.FileInputStream;
5 import java.io.FileNotFoundException;
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 freenet.support.io.Closer;
23 import com.google.common.base.Charsets;
26 * {@link Template} implementation that can be reloaded from the filesystem.
28 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
30 public class FilesystemTemplate extends Template {
32 private final String filename;
33 private final AtomicReference<LastLoadedTemplate> lastTemplate = new AtomicReference<LastLoadedTemplate>();
34 private final TemplateContext initialContext = new TemplateContext();
35 private final List<Part> parts = new ArrayList<Part>();
37 public FilesystemTemplate(String filename) {
38 this.filename = filename;
42 public TemplateContext getInitialContext() {
44 return initialContext;
47 private void loadTemplate() {
48 File templateFile = new File(filename);
49 if (!templateFile.exists()) {
50 throw new TemplateFileNotFoundException(filename);
52 if (templateWasLoaded() && !templateFileHasBeenModifiedAfterLoading(templateFile)) {
55 InputStream templateInputStream = null;
56 Reader templateReader = null;
58 templateInputStream = new FileInputStream(templateFile);
59 templateReader = new InputStreamReader(templateInputStream, Charsets.UTF_8);
60 Template template = TemplateParser.parse(templateReader);
61 lastTemplate.set(new LastLoadedTemplate(template));
62 template.getInitialContext().mergeContext(initialContext);
63 for (Part part : parts) {
66 } catch (FileNotFoundException e) {
67 throw new TemplateFileNotFoundException(filename);
69 Closer.close(templateReader);
70 Closer.close(templateInputStream);
74 private boolean templateWasLoaded() {
75 return lastTemplate.get() != null;
78 private boolean templateFileHasBeenModifiedAfterLoading(File templateFile) {
79 return templateFile.lastModified() > lastTemplate.get().getLoadTime();
83 public void add(Part part) {
86 lastTemplate.get().getTemplate().add(part);
90 public void render(TemplateContext templateContext, Writer writer) throws TemplateException {
92 lastTemplate.get().getTemplate().render(templateContext, writer);
96 public Iterator<Part> iterator() {
98 return lastTemplate.get().getTemplate().iterator();
102 public int getLine() {
104 return lastTemplate.get().getTemplate().getLine();
108 public int getColumn() {
110 return lastTemplate.get().getTemplate().getColumn();
113 private static class LastLoadedTemplate {
115 private final Template template;
116 private final long loadTime = System.currentTimeMillis();
118 private LastLoadedTemplate(Template template) {
119 this.template = template;
122 public Template getTemplate() {
126 public long getLoadTime() {
133 * Exception that signals that a template file could not be found.
135 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
137 public static class TemplateFileNotFoundException extends RuntimeException {
139 public TemplateFileNotFoundException(String filename) {