Remove @author tags
[Sone.git] / src / main / java / net / pterodactylus / sone / template / FilesystemTemplate.java
1 package net.pterodactylus.sone.template;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.InputStreamReader;
8 import java.io.Reader;
9 import java.io.Writer;
10 import java.util.ArrayList;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.concurrent.atomic.AtomicReference;
14
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;
20
21 import com.google.common.base.Charsets;
22
23 /**
24  * {@link Template} implementation that can be reloaded from the filesystem.
25  */
26 public class FilesystemTemplate extends Template {
27
28         private final String filename;
29         private final AtomicReference<LastLoadedTemplate> lastTemplate = new AtomicReference<LastLoadedTemplate>();
30         private final TemplateContext initialContext = new TemplateContext();
31         private final List<Part> parts = new ArrayList<Part>();
32
33         public FilesystemTemplate(String filename) {
34                 this.filename = filename;
35         }
36
37         @Override
38         public TemplateContext getInitialContext() {
39                 loadTemplate();
40                 return initialContext;
41         }
42
43         private void loadTemplate() {
44                 File templateFile = new File(filename);
45                 if (templateWasLoaded() && !templateFileHasBeenModifiedAfterLoading(templateFile)) {
46                         return;
47                 }
48                 try (InputStream templateInputStream = new FileInputStream(templateFile);
49                                 Reader templateReader = new InputStreamReader(templateInputStream, Charsets.UTF_8)) {
50                         Template template = TemplateParser.parse(templateReader);
51                         lastTemplate.set(new LastLoadedTemplate(template));
52                         template.getInitialContext().mergeContext(initialContext);
53                         for (Part part : parts) {
54                                 template.add(part);
55                         }
56                 } catch (IOException e) {
57                         throw new TemplateFileNotFoundException(filename);
58                 }
59         }
60
61         private boolean templateWasLoaded() {
62                 return lastTemplate.get() != null;
63         }
64
65         private boolean templateFileHasBeenModifiedAfterLoading(File templateFile) {
66                 return templateFile.lastModified() > lastTemplate.get().getLoadTime();
67         }
68
69         @Override
70         public void add(Part part) {
71                 loadTemplate();
72                 parts.add(part);
73                 lastTemplate.get().getTemplate().add(part);
74         }
75
76         @Override
77         public void render(TemplateContext templateContext, Writer writer) throws TemplateException {
78                 loadTemplate();
79                 lastTemplate.get().getTemplate().render(templateContext, writer);
80         }
81
82         @Override
83         public Iterator<Part> iterator() {
84                 loadTemplate();
85                 return lastTemplate.get().getTemplate().iterator();
86         }
87
88         @Override
89         public int getLine() {
90                 loadTemplate();
91                 return lastTemplate.get().getTemplate().getLine();
92         }
93
94         @Override
95         public int getColumn() {
96                 loadTemplate();
97                 return lastTemplate.get().getTemplate().getColumn();
98         }
99
100         private static class LastLoadedTemplate {
101
102                 private final Template template;
103                 private final long loadTime = System.currentTimeMillis();
104
105                 private LastLoadedTemplate(Template template) {
106                         this.template = template;
107                 }
108
109                 public Template getTemplate() {
110                         return template;
111                 }
112
113                 public long getLoadTime() {
114                         return loadTime;
115                 }
116
117         }
118
119         /**
120          * Exception that signals that a template file could not be found.
121          */
122         public static class TemplateFileNotFoundException extends RuntimeException {
123
124                 public TemplateFileNotFoundException(String filename) {
125                         super(filename);
126                 }
127
128         }
129
130 }