--- /dev/null
+package net.pterodactylus.sone.main;
+
+import java.io.File;
+
+import net.pterodactylus.sone.template.FilesystemTemplate;
+import net.pterodactylus.util.template.Template;
+
+/**
+ * {@link Loaders} implementation that loads all resources from the filesystem.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DebugLoaders implements Loaders {
+
+ private final String filesystemPath;
+
+ public DebugLoaders(String filesystemPath) {
+ this.filesystemPath = filesystemPath;
+ }
+
+ @Override
+ public Template loadTemplate(String path) {
+ return new FilesystemTemplate(new File(filesystemPath, path).getAbsolutePath());
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.main;
+
+import static net.pterodactylus.util.template.TemplateParser.parse;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+
+import net.pterodactylus.util.io.Closer;
+import net.pterodactylus.util.template.Template;
+
+/**
+ * Default {@link Loaders} implementation that loads resources from the classpath.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DefaultLoaders implements Loaders {
+
+ @Override
+ public Template loadTemplate(String path) {
+ InputStream templateInputStream = null;
+ Reader reader = null;
+ try {
+ templateInputStream = getClass().getResourceAsStream(path);
+ reader = new InputStreamReader(templateInputStream, "UTF-8");
+ return parse(reader);
+ } catch (UnsupportedEncodingException uee1) {
+ throw new RuntimeException("UTF-8 not supported.");
+ } finally {
+ Closer.close(reader);
+ Closer.close(templateInputStream);
+ }
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.main;
+
+import net.pterodactylus.util.template.Template;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Defines loaders for resources that can be loaded from various locations.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+@ImplementedBy(DefaultLoaders.class)
+public interface Loaders {
+
+ Template loadTemplate(String path);
+
+}
bind(Context.class).toInstance(context);
bind(getOptionalContextTypeLiteral()).toInstance(of(context));
bind(SonePlugin.class).toInstance(SonePlugin.this);
+ if (startConfiguration.getBooleanValue("Developer.LoadFromFilesystem").getValue(false)) {
+ String path = startConfiguration.getStringValue("Developer.FilesystemPath").getValue(null);
+ if (path != null) {
+ bind(Loaders.class).toInstance(new DebugLoaders(path));
+ }
+ }
bindListener(Matchers.any(), new TypeListener() {
@Override
--- /dev/null
+package net.pterodactylus.sone.template;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import net.pterodactylus.util.template.Part;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateException;
+import net.pterodactylus.util.template.TemplateParser;
+
+import freenet.support.io.Closer;
+
+import com.google.common.base.Charsets;
+
+/**
+ * {@link Template} implementation that can be reloaded from the filesystem.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class FilesystemTemplate extends Template {
+
+ private final String filename;
+ private final AtomicReference<LastLoadedTemplate> lastTemplate = new AtomicReference<LastLoadedTemplate>();
+ private final TemplateContext initialContext = new TemplateContext();
+ private final List<Part> parts = new ArrayList<Part>();
+
+ public FilesystemTemplate(String filename) {
+ this.filename = filename;
+ }
+
+ @Override
+ public TemplateContext getInitialContext() {
+ loadTemplate();
+ return initialContext;
+ }
+
+ private void loadTemplate() {
+ File templateFile = new File(filename);
+ if (!templateFile.exists()) {
+ throw new TemplateFileNotFoundException(filename);
+ }
+ if (templateWasLoaded() && !templateFileHasBeenModifiedAfterLoading(templateFile)) {
+ return;
+ }
+ InputStream templateInputStream = null;
+ Reader templateReader = null;
+ try {
+ templateInputStream = new FileInputStream(templateFile);
+ templateReader = new InputStreamReader(templateInputStream, Charsets.UTF_8);
+ Template template = TemplateParser.parse(templateReader);
+ lastTemplate.set(new LastLoadedTemplate(template));
+ template.getInitialContext().mergeContext(initialContext);
+ for (Part part : parts) {
+ template.add(part);
+ }
+ } catch (FileNotFoundException e) {
+ throw new TemplateFileNotFoundException(filename);
+ } finally {
+ Closer.close(templateReader);
+ Closer.close(templateInputStream);
+ }
+ }
+
+ private boolean templateWasLoaded() {
+ return lastTemplate.get() != null;
+ }
+
+ private boolean templateFileHasBeenModifiedAfterLoading(File templateFile) {
+ return templateFile.lastModified() > lastTemplate.get().getLoadTime();
+ }
+
+ @Override
+ public void add(Part part) {
+ loadTemplate();
+ parts.add(part);
+ lastTemplate.get().getTemplate().add(part);
+ }
+
+ @Override
+ public void render(TemplateContext templateContext, Writer writer) throws TemplateException {
+ loadTemplate();
+ lastTemplate.get().getTemplate().render(templateContext, writer);
+ }
+
+ @Override
+ public Iterator<Part> iterator() {
+ loadTemplate();
+ return lastTemplate.get().getTemplate().iterator();
+ }
+
+ @Override
+ public int getLine() {
+ loadTemplate();
+ return lastTemplate.get().getTemplate().getLine();
+ }
+
+ @Override
+ public int getColumn() {
+ loadTemplate();
+ return lastTemplate.get().getTemplate().getColumn();
+ }
+
+ private static class LastLoadedTemplate {
+
+ private final Template template;
+ private final long loadTime = System.currentTimeMillis();
+
+ private LastLoadedTemplate(Template template) {
+ this.template = template;
+ }
+
+ public Template getTemplate() {
+ return template;
+ }
+
+ public long getLoadTime() {
+ return loadTime;
+ }
+
+ }
+
+ /**
+ * Exception that signals that a template file could not be found.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ public static class TemplateFileNotFoundException extends RuntimeException {
+
+ public TemplateFileNotFoundException(String filename) {
+ super(filename);
+ }
+
+ }
+
+}
import static net.pterodactylus.util.template.TemplateParser.parse;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import net.pterodactylus.sone.freenet.L10nFilter;
import net.pterodactylus.sone.freenet.wot.Identity;
import net.pterodactylus.sone.freenet.wot.Trust;
+import net.pterodactylus.sone.main.Loaders;
import net.pterodactylus.sone.main.ReparseFilter;
import net.pterodactylus.sone.main.SonePlugin;
import net.pterodactylus.sone.notify.ListNotification;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.sone.web.page.PageToadlet;
import net.pterodactylus.sone.web.page.PageToadletFactory;
-import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.notify.Notification;
import net.pterodactylus.util.notify.NotificationManager;
import net.pterodactylus.util.notify.TemplateNotification;
/** The logger. */
private static final Logger logger = getLogger(WebInterface.class.getName());
+ /** The loaders for templates, pages, and classpath providers. */
+ private final Loaders loaders;
+
/** The notification manager. */
private final NotificationManager notificationManager = new NotificationManager();
* The Sone plugin
*/
@Inject
- public WebInterface(SonePlugin sonePlugin) {
+ public WebInterface(SonePlugin sonePlugin, Loaders loaders) {
this.sonePlugin = sonePlugin;
+ this.loaders = loaders;
formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword();
soneTextParser = new SoneTextParser(getCore(), getCore());
templateContextFactory.addTemplateObject("formPassword", formPassword);
/* create notifications. */
- Template newSoneNotificationTemplate = parseTemplate("/templates/notify/newSoneNotification.html");
+ Template newSoneNotificationTemplate = loaders.loadTemplate("/templates/notify/newSoneNotification.html");
newSoneNotification = new ListNotification<Sone>("new-sone-notification", "sones", newSoneNotificationTemplate, false);
- Template newPostNotificationTemplate = parseTemplate("/templates/notify/newPostNotification.html");
+ Template newPostNotificationTemplate = loaders.loadTemplate("/templates/notify/newPostNotification.html");
newPostNotification = new ListNotification<Post>("new-post-notification", "posts", newPostNotificationTemplate, false);
- Template localPostNotificationTemplate = parseTemplate("/templates/notify/newPostNotification.html");
+ Template localPostNotificationTemplate = loaders.loadTemplate("/templates/notify/newPostNotification.html");
localPostNotification = new ListNotification<Post>("local-post-notification", "posts", localPostNotificationTemplate, false);
- Template newReplyNotificationTemplate = parseTemplate("/templates/notify/newReplyNotification.html");
+ Template newReplyNotificationTemplate = loaders.loadTemplate("/templates/notify/newReplyNotification.html");
newReplyNotification = new ListNotification<PostReply>("new-reply-notification", "replies", newReplyNotificationTemplate, false);
- Template localReplyNotificationTemplate = parseTemplate("/templates/notify/newReplyNotification.html");
+ Template localReplyNotificationTemplate = loaders.loadTemplate("/templates/notify/newReplyNotification.html");
localReplyNotification = new ListNotification<PostReply>("local-reply-notification", "replies", localReplyNotificationTemplate, false);
- Template mentionNotificationTemplate = parseTemplate("/templates/notify/mentionNotification.html");
+ Template mentionNotificationTemplate = loaders.loadTemplate("/templates/notify/mentionNotification.html");
mentionNotification = new ListNotification<Post>("mention-notification", "posts", mentionNotificationTemplate, false);
- Template lockedSonesTemplate = parseTemplate("/templates/notify/lockedSonesNotification.html");
+ Template lockedSonesTemplate = loaders.loadTemplate("/templates/notify/lockedSonesNotification.html");
lockedSonesNotification = new ListNotification<Sone>("sones-locked-notification", "sones", lockedSonesTemplate);
- Template newVersionTemplate = parseTemplate("/templates/notify/newVersionNotification.html");
+ Template newVersionTemplate = loaders.loadTemplate("/templates/notify/newVersionNotification.html");
newVersionNotification = new TemplateNotification("new-version-notification", newVersionTemplate);
- Template insertingImagesTemplate = parseTemplate("/templates/notify/inserting-images-notification.html");
+ Template insertingImagesTemplate = loaders.loadTemplate("/templates/notify/inserting-images-notification.html");
insertingImagesNotification = new ListNotification<Image>("inserting-images-notification", "images", insertingImagesTemplate);
- Template insertedImagesTemplate = parseTemplate("/templates/notify/inserted-images-notification.html");
+ Template insertedImagesTemplate = loaders.loadTemplate("/templates/notify/inserted-images-notification.html");
insertedImagesNotification = new ListNotification<Image>("inserted-images-notification", "images", insertedImagesTemplate);
- Template imageInsertFailedTemplate = parseTemplate("/templates/notify/image-insert-failed-notification.html");
+ Template imageInsertFailedTemplate = loaders.loadTemplate("/templates/notify/image-insert-failed-notification.html");
imageInsertFailedNotification = new ListNotification<Image>("image-insert-failed-notification", "images", imageInsertFailedTemplate);
}
- private Template parseTemplate(String resourceName) {
- InputStream templateInputStream = null;
- Reader reader = null;
- try {
- templateInputStream = getClass().getResourceAsStream(resourceName);
- reader = new InputStreamReader(templateInputStream, "UTF-8");
- return parse(reader);
- } catch (UnsupportedEncodingException uee1) {
- throw new RuntimeException("UTF-8 not supported.");
- } finally {
- Closer.close(reader);
- Closer.close(templateInputStream);
- }
- }
-
//
// ACCESSORS
//
*/
public void setFirstStart(boolean firstStart) {
if (firstStart) {
- Template firstStartNotificationTemplate = parseTemplate("/templates/notify/firstStartNotification.html");
+ Template firstStartNotificationTemplate = loaders.loadTemplate("/templates/notify/firstStartNotification.html");
Notification firstStartNotification = new TemplateNotification("first-start-notification", firstStartNotificationTemplate);
notificationManager.addNotification(firstStartNotification);
}
*/
public void setNewConfig(boolean newConfig) {
if (newConfig && !hasFirstStartNotification()) {
- Template configNotReadNotificationTemplate = parseTemplate("/templates/notify/configNotReadNotification.html");
+ Template configNotReadNotificationTemplate = loaders.loadTemplate("/templates/notify/configNotReadNotification.html");
Notification configNotReadNotification = new TemplateNotification("config-not-read-notification", configNotReadNotificationTemplate);
notificationManager.addNotification(configNotReadNotification);
}
registerToadlets();
/* notification templates. */
- Template startupNotificationTemplate = parseTemplate("/templates/notify/startupNotification.html");
+ Template startupNotificationTemplate = loaders.loadTemplate("/templates/notify/startupNotification.html");
final TemplateNotification startupNotification = new TemplateNotification("startup-notification", startupNotificationTemplate);
notificationManager.addNotification(startupNotification);
}
}, 2, TimeUnit.MINUTES);
- Template wotMissingNotificationTemplate = parseTemplate("/templates/notify/wotMissingNotification.html");
+ Template wotMissingNotificationTemplate = loaders.loadTemplate("/templates/notify/wotMissingNotification.html");
final TemplateNotification wotMissingNotification = new TemplateNotification("wot-missing-notification", wotMissingNotificationTemplate);
ticker.scheduleAtFixedRate(new Runnable() {
*/
private void registerToadlets() {
Template emptyTemplate = parse(new StringReader(""));
- Template loginTemplate = parseTemplate("/templates/login.html");
- Template indexTemplate = parseTemplate("/templates/index.html");
- Template newTemplate = parseTemplate("/templates/new.html");
- Template knownSonesTemplate = parseTemplate("/templates/knownSones.html");
- Template createSoneTemplate = parseTemplate("/templates/createSone.html");
- Template createPostTemplate = parseTemplate("/templates/createPost.html");
- Template createReplyTemplate = parseTemplate("/templates/createReply.html");
- Template bookmarksTemplate = parseTemplate("/templates/bookmarks.html");
- Template searchTemplate = parseTemplate("/templates/search.html");
- Template editProfileTemplate = parseTemplate("/templates/editProfile.html");
- Template editProfileFieldTemplate = parseTemplate("/templates/editProfileField.html");
- Template deleteProfileFieldTemplate = parseTemplate("/templates/deleteProfileField.html");
- Template viewSoneTemplate = parseTemplate("/templates/viewSone.html");
- Template viewPostTemplate = parseTemplate("/templates/viewPost.html");
- Template deletePostTemplate = parseTemplate("/templates/deletePost.html");
- Template deleteReplyTemplate = parseTemplate("/templates/deleteReply.html");
- Template deleteSoneTemplate = parseTemplate("/templates/deleteSone.html");
- Template imageBrowserTemplate = parseTemplate("/templates/imageBrowser.html");
- Template createAlbumTemplate = parseTemplate("/templates/createAlbum.html");
- Template deleteAlbumTemplate = parseTemplate("/templates/deleteAlbum.html");
- Template deleteImageTemplate = parseTemplate("/templates/deleteImage.html");
- Template noPermissionTemplate = parseTemplate("/templates/noPermission.html");
- Template emptyImageTitleTemplate = parseTemplate("/templates/emptyImageTitle.html");
- Template emptyAlbumTitleTemplate = parseTemplate("/templates/emptyAlbumTitle.html");
- Template optionsTemplate = parseTemplate("/templates/options.html");
- Template rescueTemplate = parseTemplate("/templates/rescue.html");
- Template aboutTemplate = parseTemplate("/templates/about.html");
- Template invalidTemplate = parseTemplate("/templates/invalid.html");
- Template postTemplate = parseTemplate("/templates/include/viewPost.html");
- Template replyTemplate = parseTemplate("/templates/include/viewReply.html");
- Template openSearchTemplate = parseTemplate("/templates/xml/OpenSearch.xml");
+ Template loginTemplate = loaders.loadTemplate("/templates/login.html");
+ Template indexTemplate = loaders.loadTemplate("/templates/index.html");
+ Template newTemplate = loaders.loadTemplate("/templates/new.html");
+ Template knownSonesTemplate = loaders.loadTemplate("/templates/knownSones.html");
+ Template createSoneTemplate = loaders.loadTemplate("/templates/createSone.html");
+ Template createPostTemplate = loaders.loadTemplate("/templates/createPost.html");
+ Template createReplyTemplate = loaders.loadTemplate("/templates/createReply.html");
+ Template bookmarksTemplate = loaders.loadTemplate("/templates/bookmarks.html");
+ Template searchTemplate = loaders.loadTemplate("/templates/search.html");
+ Template editProfileTemplate = loaders.loadTemplate("/templates/editProfile.html");
+ Template editProfileFieldTemplate = loaders.loadTemplate("/templates/editProfileField.html");
+ Template deleteProfileFieldTemplate = loaders.loadTemplate("/templates/deleteProfileField.html");
+ Template viewSoneTemplate = loaders.loadTemplate("/templates/viewSone.html");
+ Template viewPostTemplate = loaders.loadTemplate("/templates/viewPost.html");
+ Template deletePostTemplate = loaders.loadTemplate("/templates/deletePost.html");
+ Template deleteReplyTemplate = loaders.loadTemplate("/templates/deleteReply.html");
+ Template deleteSoneTemplate = loaders.loadTemplate("/templates/deleteSone.html");
+ Template imageBrowserTemplate = loaders.loadTemplate("/templates/imageBrowser.html");
+ Template createAlbumTemplate = loaders.loadTemplate("/templates/createAlbum.html");
+ Template deleteAlbumTemplate = loaders.loadTemplate("/templates/deleteAlbum.html");
+ Template deleteImageTemplate = loaders.loadTemplate("/templates/deleteImage.html");
+ Template noPermissionTemplate = loaders.loadTemplate("/templates/noPermission.html");
+ Template emptyImageTitleTemplate = loaders.loadTemplate("/templates/emptyImageTitle.html");
+ Template emptyAlbumTitleTemplate = loaders.loadTemplate("/templates/emptyAlbumTitle.html");
+ Template optionsTemplate = loaders.loadTemplate("/templates/options.html");
+ Template rescueTemplate = loaders.loadTemplate("/templates/rescue.html");
+ Template aboutTemplate = loaders.loadTemplate("/templates/about.html");
+ Template invalidTemplate = loaders.loadTemplate("/templates/invalid.html");
+ Template postTemplate = loaders.loadTemplate("/templates/include/viewPost.html");
+ Template replyTemplate = loaders.loadTemplate("/templates/include/viewReply.html");
+ Template openSearchTemplate = loaders.loadTemplate("/templates/xml/OpenSearch.xml");
PageToadletFactory pageToadletFactory = new PageToadletFactory(sonePlugin.pluginRespirator().getHLSimpleClient(), "/Sone/");
pageToadlets.add(pageToadletFactory.createPageToadlet(new RedirectPage<FreenetRequest>("", "index.html")));
synchronized (soneInsertNotifications) {
TemplateNotification templateNotification = soneInsertNotifications.get(sone);
if (templateNotification == null) {
- templateNotification = new TemplateNotification(parseTemplate("/templates/notify/soneInsertNotification.html"));
+ templateNotification = new TemplateNotification(loaders.loadTemplate("/templates/notify/soneInsertNotification.html"));
templateNotification.set("insertSone", sone);
soneInsertNotifications.put(sone, templateNotification);
}
--- /dev/null
+package net.pterodactylus.sone.main;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Unit test for {@link DebugLoaders}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DebugLoadersTest {
+
+ @Rule
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ private final StringWriter stringWriter = new StringWriter();
+ private final TemplateContext templateContext = new TemplateContext();
+ private String templatePath;
+ private Loaders loaders;
+
+ @Before
+ public void setupLoader() throws IOException {
+ templatePath = temporaryFolder.newFolder("temps").getPath();
+ loaders = new DebugLoaders(templatePath);
+ }
+
+ @Test
+ public void debugLoaderCanLoadTemplatesFromFilesystem() throws IOException {
+ File templateFile = new File(templatePath, "template.txt");
+ Files.write("<%if foo>foo<%else>bar<%/if>", templateFile, Charsets.UTF_8);
+ Template template = loaders.loadTemplate("/template.txt");
+ template.render(templateContext, stringWriter);
+ assertThat(stringWriter.toString(), is("bar"));
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.main;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.io.StringWriter;
+
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+
+import org.junit.Test;
+
+/**
+ * Unit test for {@link DefaultLoaders}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DefaultLoadersTest {
+
+ private final Loaders loaders = new DefaultLoaders();
+ private final StringWriter stringWriter = new StringWriter();
+ private final TemplateContext templateContext = new TemplateContext();
+
+ @Test
+ public void templateCanBeLoadedFromTheClasspath() {
+ Template template = loaders.loadTemplate("/net/pterodactylus/sone/main/template.txt");
+ template.render(templateContext, stringWriter);
+ assertThat(stringWriter.toString(), is("Template. bar\n"));
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.template;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReference;
+
+import net.pterodactylus.util.template.Part;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateException;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit test for {@link FilesystemTemplate}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class FilesystemTemplateTest {
+
+ private final File tempFile;
+ private final FilesystemTemplate filesystemTemplate;
+ private final AtomicReference<StringWriter> stringWriter = new AtomicReference<StringWriter>(new StringWriter());
+ private final TemplateContext templateContext = new TemplateContext();
+
+ public FilesystemTemplateTest() throws IOException {
+ tempFile = File.createTempFile("template-", ".dat");
+ writeTemplate("Text");
+ filesystemTemplate = new FilesystemTemplate(tempFile.getAbsolutePath());
+ }
+
+ private void writeTemplate(String text) throws IOException {
+ Files.write(text + ".<%foreach values value><% value><%/foreach>", tempFile, Charsets.UTF_8);
+ }
+
+ @Before
+ public void setupTemplateContext() {
+ templateContext.set("values", Arrays.asList("a", 1));
+ }
+
+ @Test(expected = FilesystemTemplate.TemplateFileNotFoundException.class)
+ public void loadingTemplateFromNonExistingFileThrowsException() throws IOException {
+ FilesystemTemplate filesystemTemplate = new FilesystemTemplate("/a/b/c.dat");
+ filesystemTemplate.getInitialContext();
+ }
+
+ @Test
+ public void templateCanBeLoadedFromTheFilesystem() {
+ filesystemTemplate.render(templateContext, stringWriter.get());
+ assertThat(getRenderedString(), is("Text.a1"));
+ }
+
+ @Test
+ public void templateCanBeReloaded() throws IOException, InterruptedException {
+ filesystemTemplate.render(templateContext, stringWriter.get());
+ assertThat(getRenderedString(), is("Text.a1"));
+ Thread.sleep(1000);
+ writeTemplate("New");
+ filesystemTemplate.render(templateContext, stringWriter.get());
+ assertThat(getRenderedString(), is("New.a1"));
+ }
+
+ @Test
+ public void templateIsNotReloadedIfNotChanged() {
+ filesystemTemplate.render(templateContext, stringWriter.get());
+ assertThat(getRenderedString(), is("Text.a1"));
+ filesystemTemplate.render(templateContext, stringWriter.get());
+ assertThat(getRenderedString(), is("Text.a1"));
+ }
+
+ private String getRenderedString() {
+ String renderedString = stringWriter.get().toString();
+ stringWriter.set(new StringWriter());
+ return renderedString;
+ }
+
+ @Test
+ public void initialContextIsCopiedToReloadedTemplates() throws IOException, InterruptedException {
+ filesystemTemplate.getInitialContext().set("values", "test");
+ Thread.sleep(1000);
+ writeTemplate("New");
+ assertThat(filesystemTemplate.getInitialContext().get("values"), is((Object) "test"));
+ }
+
+ @Test
+ public void partsAreCopiedToReloadedTemplates() throws InterruptedException, IOException {
+ filesystemTemplate.add(new Part() {
+ @Override
+ public void render(TemplateContext templateContext, Writer writer) throws TemplateException {
+ try {
+ writer.write(".Test");
+ } catch (IOException e) {
+ throw new TemplateException(e);
+ }
+ }
+ });
+ Thread.sleep(1000);
+ writeTemplate("New");
+ filesystemTemplate.render(templateContext, stringWriter.get());
+ assertThat(getRenderedString(), is("New.a1.Test"));
+ }
+
+}
--- /dev/null
+Template. <%if foo>foo<%else>bar<%/if>