--- /dev/null
+package net.pterodactylus.sone.main;
+
+import java.io.File;
+
+import net.pterodactylus.sone.template.FilesystemTemplate;
+import net.pterodactylus.sone.web.ReloadingPage;
+import net.pterodactylus.util.template.FilesystemTemplateProvider;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateProvider;
+import net.pterodactylus.util.web.Page;
+import net.pterodactylus.util.web.Request;
+
+/**
+ * {@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());
+ }
+
+ @Override
+ public <REQ extends Request> Page<REQ> loadStaticPage(String basePath, String prefix, String mimeType) {
+ return new ReloadingPage<REQ>(basePath, new File(filesystemPath, prefix).getAbsolutePath(), mimeType);
+ }
+
+ @Override
+ public TemplateProvider getTemplateProvider() {
+ return new FilesystemTemplateProvider(new File(filesystemPath, "/templates/").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.sone.web.WebInterface;
+import net.pterodactylus.util.io.Closer;
+import net.pterodactylus.util.template.ClassPathTemplateProvider;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateProvider;
+import net.pterodactylus.util.web.Page;
+import net.pterodactylus.util.web.Request;
+import net.pterodactylus.util.web.StaticPage;
+
+/**
+ * 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);
+ }
+ }
+
+ @Override
+ public <REQ extends Request> Page<REQ> loadStaticPage(String pathPrefix, String basePath, String mimeType) {
+ return new StaticPage<REQ>(pathPrefix, basePath, mimeType);
+ }
+
+ @Override
+ public TemplateProvider getTemplateProvider() {
+ return new ClassPathTemplateProvider(WebInterface.class, "/templates/");
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.main;
+
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateProvider;
+import net.pterodactylus.util.web.Page;
+import net.pterodactylus.util.web.Request;
+
+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);
+ <REQ extends Request> Page<REQ> loadStaticPage(String basePath, String prefix, String mimeType);
+ TemplateProvider getTemplateProvider();
+
+}
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);
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * Sone - ReloadingPage.java - Copyright © 2010–2015 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.web;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import net.pterodactylus.util.io.Closer;
+import net.pterodactylus.util.io.StreamCopier;
+import net.pterodactylus.util.web.Page;
+import net.pterodactylus.util.web.Request;
+import net.pterodactylus.util.web.Response;
+
+/**
+ * {@link Page} implementation that delivers static files from the filesystem.
+ *
+ * @param <REQ>
+ * The type of the request
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ReloadingPage<REQ extends Request> implements Page<REQ> {
+
+ private final String pathPrefix;
+ private final String filesystemPath;
+ private final String mimeType;
+
+ public ReloadingPage(String pathPrefix, String filesystemPathPrefix, String mimeType) {
+ this.pathPrefix = pathPrefix;
+ this.filesystemPath = filesystemPathPrefix;
+ this.mimeType = mimeType;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getPath() {
+ return pathPrefix;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isPrefixPage() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Response handleRequest(REQ request, Response response) throws IOException {
+ String path = request.getUri().getPath();
+ int lastSlash = path.lastIndexOf('/');
+ String filename = path.substring(lastSlash + 1);
+ InputStream fileInputStream = new FileInputStream(new File(filesystemPath, filename));
+ if (fileInputStream == null) {
+ return response.setStatusCode(404).setStatusText("Not found.");
+ }
+ OutputStream contentOutputStream = response.getContent();
+ try {
+ StreamCopier.copy(fileInputStream, contentOutputStream);
+ } finally {
+ Closer.close(fileInputStream);
+ Closer.close(contentOutputStream);
+ }
+ return response.setStatusCode(200).setStatusText("OK").setContentType(mimeType);
+ }
+}
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;
-import net.pterodactylus.util.template.ClassPathTemplateProvider;
import net.pterodactylus.util.template.CollectionSortFilter;
import net.pterodactylus.util.template.ContainsFilter;
import net.pterodactylus.util.template.DateFilter;
import net.pterodactylus.util.template.TemplateProvider;
import net.pterodactylus.util.template.XmlFilter;
import net.pterodactylus.util.web.RedirectPage;
-import net.pterodactylus.util.web.StaticPage;
import net.pterodactylus.util.web.TemplatePage;
import com.google.common.collect.Collections2;
/** 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.addFilter("mod", new ModFilter());
templateContextFactory.addFilter("paginate", new PaginationFilter());
templateContextFactory.addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER);
- templateContextFactory.addProvider(new ClassPathTemplateProvider(WebInterface.class, "/templates/"));
+ templateContextFactory.addProvider(loaders.getTemplateProvider());
templateContextFactory.addTemplateObject("webInterface", this);
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")));
pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("emptyAlbumTitle.html", emptyAlbumTitleTemplate, "Page.EmptyAlbumTitle.Title", this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationPage(emptyTemplate, this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("invalid.html", invalidTemplate, "Page.Invalid.Title", this)));
- pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage<FreenetRequest>("css/", "/static/css/", "text/css")));
- pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage<FreenetRequest>("javascript/", "/static/javascript/", "text/javascript")));
- pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage<FreenetRequest>("images/", "/static/images/", "image/png")));
+ pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.<FreenetRequest>loadStaticPage("css/", "/static/css/", "text/css")));
+ pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.<FreenetRequest>loadStaticPage("javascript/", "/static/javascript/", "text/javascript")));
+ pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.<FreenetRequest>loadStaticPage("images/", "/static/images/", "image/png")));
pageToadlets.add(pageToadletFactory.createPageToadlet(new TemplatePage<FreenetRequest>("OpenSearch.xml", "application/opensearchdescription+xml", templateContextFactory, openSearchTemplate)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new GetImagePage(this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTranslationPage(this)));
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 static org.hamcrest.Matchers.startsWith;
+import static org.mockito.Mockito.mock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateProvider;
+import net.pterodactylus.util.web.Method;
+import net.pterodactylus.util.web.Page;
+import net.pterodactylus.util.web.Response;
+
+import freenet.clients.http.ToadletContext;
+import freenet.support.api.HTTPRequest;
+
+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 Loaders loaders;
+
+ @Before
+ public void setupLoader() throws IOException {
+ String templatePath = temporaryFolder.newFolder("temps").getPath();
+ loaders = new DebugLoaders(templatePath);
+ File templateFile = new File(templatePath, "template.txt");
+ Files.write("<%if foo>foo<%else>bar<%/if>", templateFile, Charsets.UTF_8);
+ new File(templatePath, "templates").mkdir();
+ File secondTemplateFile = new File(templatePath, "templates/template.txt");
+ Files.write("<%if foo>foo<%else>bar<%/if>", secondTemplateFile, Charsets.UTF_8);
+ }
+
+ @Test
+ public void debugLoaderCanLoadTemplatesFromFilesystem() throws IOException {
+ Template template = loaders.loadTemplate("/template.txt");
+ template.render(templateContext, stringWriter);
+ assertThat(stringWriter.toString(), is("bar"));
+ }
+
+ @Test
+ public void staticPageIsServedFromFilesystem() throws URISyntaxException, IOException {
+ Page<FreenetRequest> page = loaders.loadStaticPage("text/", "", "text/plain");
+ URI uri = new URI("http://some.host/text/template.txt");
+ Method method = Method.GET;
+ HTTPRequest httpRequest = mock(HTTPRequest.class);
+ ToadletContext toadletContext = mock(ToadletContext.class);
+ FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext);
+ OutputStream outputStream = new ByteArrayOutputStream();
+ Response response = new Response(outputStream);
+ page.handleRequest(request, response);
+ assertThat(response.getContentType(), startsWith("text/plain"));
+ assertThat(response.getStatusCode(), is(200));
+ }
+
+ @Test
+ public void templateProviderLocatesTemplatesInFileSystem() {
+ TemplateProvider templateProvider = loaders.getTemplateProvider();
+ Template template = templateProvider.getTemplate(templateContext, "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 static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.startsWith;
+import static org.mockito.Mockito.mock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateProvider;
+import net.pterodactylus.util.web.Method;
+import net.pterodactylus.util.web.Page;
+import net.pterodactylus.util.web.Response;
+
+import freenet.clients.http.ToadletContext;
+import freenet.support.api.HTTPRequest;
+
+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"));
+ }
+
+ @Test
+ public void staticPageIsServedFromClasspath() throws IOException, URISyntaxException {
+ Page<FreenetRequest> staticPage = loaders.loadStaticPage("text/", "/net/pterodactylus/sone/main/", "text/plain");
+ URI uri = new URI("http://some.host/text/template.txt");
+ Method method = Method.GET;
+ HTTPRequest httpRequest = mock(HTTPRequest.class);
+ ToadletContext toadletContext = mock(ToadletContext.class);
+ FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext);
+ OutputStream outputStream = new ByteArrayOutputStream();
+ Response response = new Response(outputStream);
+ staticPage.handleRequest(request, response);
+ assertThat(response.getContentType(), startsWith("text/plain"));
+ assertThat(response.getStatusCode(), is(200));
+ }
+
+ @Test
+ public void templateIsLocatedInClasspath() {
+ TemplateProvider templateProvider = loaders.getTemplateProvider();
+ Template template = templateProvider.getTemplate(templateContext, "about.html");
+ assertThat(template, notNullValue());
+ }
+
+}
--- /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>
--- /dev/null
+<%if foo>foo<%else>bar<%/if>
\ No newline at end of file