From: David ‘Bombe’ Roden Date: Sat, 12 Jan 2013 16:41:27 +0000 (+0100) Subject: Merge branch 'next' into new-database-38 X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=refs%2Fheads%2Fnew-database-38;hp=927de326e0af0f11a27b3444f4e25b0796c877db;p=Sone.git Merge branch 'next' into new-database-38 Conflicts: src/main/java/net/pterodactylus/sone/core/Core.java src/main/java/net/pterodactylus/sone/web/SearchPage.java --- diff --git a/pom.xml b/pom.xml index 9ea02ae..0e2cc60 100644 --- a/pom.xml +++ b/pom.xml @@ -2,12 +2,12 @@ 4.0.0 net.pterodactylus sone - 0.8.2 + 0.8.4 net.pterodactylus utils - 0.12 + 0.12.3-SNAPSHOT junit diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 0b1379a..1bb638a 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -61,6 +61,7 @@ import net.pterodactylus.util.config.ConfigurationException; import net.pterodactylus.util.logging.Logging; import net.pterodactylus.util.number.Numbers; import net.pterodactylus.util.service.AbstractService; +import net.pterodactylus.util.thread.NamedThreadFactory; import net.pterodactylus.util.thread.Ticker; import net.pterodactylus.util.validation.EqualityValidator; import net.pterodactylus.util.validation.IntegerRangeValidator; @@ -79,6 +80,9 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis /** The logger. */ private static final Logger logger = Logging.getLogger(Core.class); + /** The start time. */ + private final long startupTime = System.currentTimeMillis(); + /** The options. */ private final Options options = new Options(); @@ -110,7 +114,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis private final ImageInserter imageInserter; /** Sone downloader thread-pool. */ - private final ExecutorService soneDownloaders = Executors.newFixedThreadPool(10); + private final ExecutorService soneDownloaders = Executors.newFixedThreadPool(10, new NamedThreadFactory("Sone Downloader %2$d")); /** The update checker. */ private final UpdateChecker updateChecker; @@ -228,6 +232,15 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis // /** + * Returns the time Sone was started. + * + * @return The startup time (in milliseconds since Jan 1, 1970 UTC) + */ + public long getStartupTime() { + return startupTime; + } + + /** * Sets the configuration to use. This will automatically save the current * configuration to the given configuration. * @@ -1056,8 +1069,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis if (!storedPosts.contains(post)) { if (post.getTime() < getSoneFollowingTime(sone)) { knownPosts.add(post.getId()); + post.setKnown(true); } else if (!knownPosts.contains(post.getId())) { - sone.setKnown(false); coreListenerManager.fireNewPostFound(post); } } @@ -1081,8 +1094,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis if (!storedReplies.contains(reply)) { if (reply.getTime() < getSoneFollowingTime(sone)) { knownReplies.add(reply.getId()); + reply.setKnown(true); } else if (!knownReplies.contains(reply.getId())) { - reply.setKnown(false); coreListenerManager.fireNewReplyFound(reply); } } @@ -1429,6 +1442,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * @return The created post */ public Post createPost(Sone sone, Sone recipient, long time, String text) { + Validation.begin().isNotNull("Text", text).check().isGreater("Text Length", text.length(), 0).check(); if (!sone.isLocal()) { logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone)); return null; @@ -1569,6 +1583,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * @return The created reply */ public PostReply createReply(Sone sone, Post post, long time, String text) { + Validation.begin().isNotNull("Text", text).check().isGreater("Text Length", text.trim().length(), 0).check(); if (!sone.isLocal()) { logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone)); return null; @@ -2260,7 +2275,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis */ @Override public void identityUpdated(OwnIdentity ownIdentity, final Identity identity) { - new Thread(new Runnable() { + soneDownloaders.execute(new Runnable() { @Override @SuppressWarnings("synthetic-access") @@ -2271,7 +2286,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis soneDownloader.addSone(sone); soneDownloader.fetchSone(sone); } - }).start(); + }); } /** diff --git a/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java index 003e276..3f4d235 100644 --- a/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java +++ b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java @@ -49,7 +49,7 @@ public class UpdateChecker { private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/"; /** The current latest known edition. */ - private static final int LATEST_EDITION = 49; + private static final int LATEST_EDITION = 55; /** The Freenet interface. */ private final FreenetInterface freenetInterface; diff --git a/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java b/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java index b3222be..c1ed953 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java +++ b/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java @@ -27,7 +27,6 @@ import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.freenet.fcp.Command.AccessType; import net.pterodactylus.sone.freenet.fcp.Command.ErrorResponse; import net.pterodactylus.sone.freenet.fcp.Command.Response; -import net.pterodactylus.sone.freenet.fcp.FcpException; import net.pterodactylus.util.logging.Logging; import net.pterodactylus.util.validation.Validation; import freenet.pluginmanager.FredPluginFCP; @@ -172,9 +171,9 @@ public class FcpInterface { try { Response response = command.execute(parameters, data, AccessType.values()[accessType]); sendReply(pluginReplySender, identifier, response); - } catch (FcpException fe1) { + } catch (Exception e1) { logger.log(Level.WARNING, "Could not process FCP command “%s”.", command); - sendReply(pluginReplySender, identifier, new ErrorResponse("Error executing command: " + fe1.getMessage())); + sendReply(pluginReplySender, identifier, new ErrorResponse("Error executing command: " + e1.getMessage())); } } catch (PluginNotFoundException pnfe1) { logger.log(Level.WARNING, "Could not find destination plugin: " + pluginReplySender); diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java index 3c3c9f9..568a637 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java @@ -59,21 +59,28 @@ public class IdentityManager extends AbstractService { private final WebOfTrustConnector webOfTrustConnector; /** The context to filter for. */ - private volatile String context; + private final String context; /** The currently known own identities. */ /* synchronize access on syncObject. */ - private Map currentOwnIdentities = new HashMap(); + private final Map currentOwnIdentities = new HashMap(); + + /** The last time all identities were loaded. */ + private volatile long identitiesLastLoaded; /** * Creates a new identity manager. * * @param webOfTrustConnector * The Web of Trust connector + * @param context + * The context to focus on (may be {@code null} to ignore + * contexts) */ - public IdentityManager(WebOfTrustConnector webOfTrustConnector) { + public IdentityManager(WebOfTrustConnector webOfTrustConnector, String context) { super("Sone Identity Manager", false); this.webOfTrustConnector = webOfTrustConnector; + this.context = context; } // @@ -105,13 +112,13 @@ public class IdentityManager extends AbstractService { // /** - * Sets the context to filter own identities and trusted identities for. + * Returns the last time all identities were loaded. * - * @param context - * The context to filter for, or {@code null} to not filter + * @return The last time all identities were loaded (in milliseconds since + * Jan 1, 1970 UTC) */ - public void setContext(String context) { - this.context = context; + public long getIdentitiesLastLoaded() { + return identitiesLastLoaded; } /** @@ -179,19 +186,23 @@ public class IdentityManager extends AbstractService { /* load trusted identities. */ for (OwnIdentity ownIdentity : ownIdentities) { + currentOwnIdentities.put(ownIdentity.getId(), ownIdentity); + Map identities = new HashMap(); + currentIdentities.put(ownIdentity, identities); + + /* if the context doesn’t match, skip getting trusted identities. */ if ((context != null) && !ownIdentity.hasContext(context)) { continue; } - currentOwnIdentities.put(ownIdentity.getId(), ownIdentity); + /* load trusted identities. */ Set trustedIdentities = webOfTrustConnector.loadTrustedIdentities(ownIdentity, context); - Map identities = new HashMap(); - currentIdentities.put(ownIdentity, identities); for (Identity identity : trustedIdentities) { identities.put(identity.getId(), identity); } } identitiesLoaded = true; + identitiesLastLoaded = System.currentTimeMillis(); } catch (WebOfTrustException wote1) { logger.log(Level.WARNING, "WoT has disappeared!", wote1); } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java index 53a45b1..c4e8d89 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java @@ -144,8 +144,8 @@ public class WebOfTrustConnector { identity.setContexts(parseContexts("Contexts" + identityCounter + ".", fields)); identity.setProperties(parseProperties("Properties" + identityCounter + ".", fields)); Integer trust = Numbers.safeParseInteger(fields.get("Trust" + identityCounter), null); - int score = Numbers.safeParseInteger(fields.get("Score" + identityCounter)); - int rank = Numbers.safeParseInteger(fields.get("Rank" + identityCounter)); + int score = Numbers.safeParseInteger(fields.get("Score" + identityCounter), 0); + int rank = Numbers.safeParseInteger(fields.get("Rank" + identityCounter), 0); identity.setTrust(ownIdentity, new Trust(trust, score, rank)); identities.add(identity); } diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index 42e2fe1..1bc8b5a 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -86,7 +86,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr } /** The version. */ - public static final Version VERSION = new Version(0, 8, 2); + public static final Version VERSION = new Version(0, 8, 4); /** The logger. */ private static final Logger logger = Logging.getLogger(SonePlugin.class); @@ -188,8 +188,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr /* create web of trust connector. */ PluginConnector pluginConnector = new PluginConnector(pluginRespirator); webOfTrustConnector = new WebOfTrustConnector(pluginConnector); - identityManager = new IdentityManager(webOfTrustConnector); - identityManager.setContext("Sone"); + identityManager = new IdentityManager(webOfTrustConnector, "Sone"); /* create Sone database. */ Database soneDatabase = new MemoryDatabase(); diff --git a/src/main/java/net/pterodactylus/sone/template/ParserFilter.java b/src/main/java/net/pterodactylus/sone/template/ParserFilter.java index 1936656..b8af831 100644 --- a/src/main/java/net/pterodactylus/sone/template/ParserFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/ParserFilter.java @@ -20,7 +20,9 @@ package net.pterodactylus.sone.template; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; +import java.io.UnsupportedEncodingException; import java.io.Writer; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -213,7 +215,12 @@ public class ParserFilter implements Filter { * The part to render */ private void render(Writer writer, LinkPart linkPart) { - renderLink(writer, "/?_CHECKED_HTTP_=" + linkPart.getLink(), linkPart.getText(), linkPart.getTitle(), "internet"); + try { + renderLink(writer, "/external-link/?_CHECKED_HTTP_=" + URLEncoder.encode(linkPart.getLink(), "UTF-8"), linkPart.getText(), linkPart.getTitle(), "internet"); + } catch (UnsupportedEncodingException uee1) { + /* not possible for UTF-8. */ + throw new RuntimeException("The JVM does not support UTF-8 encoding!", uee1); + } } /** @@ -249,7 +256,13 @@ public class ParserFilter implements Filter { for (Part part : parts) { excerpt.append(part.getText()); if (excerpt.length() > 20) { - excerpt.setLength(20); + int lastSpace = excerpt.lastIndexOf(" ", 20); + if (lastSpace > -1) { + excerpt.setLength(lastSpace); + } else { + excerpt.setLength(20); + } + excerpt.append("…"); break; } } diff --git a/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java b/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java index 19db65b..2c209d5 100644 --- a/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java +++ b/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java @@ -56,28 +56,50 @@ public class SoneTextParser implements Parser { private enum LinkType { /** Link is a KSK. */ - KSK, + KSK("KSK@"), /** Link is a CHK. */ - CHK, + CHK("CHK@"), /** Link is an SSK. */ - SSK, + SSK("SSK@"), /** Link is a USK. */ - USK, + USK("USK@"), /** Link is HTTP. */ - HTTP, + HTTP("http://"), /** Link is HTTPS. */ - HTTPS, + HTTPS("https://"), /** Link is a Sone. */ - SONE, + SONE("sone://"), /** Link is a post. */ - POST, + POST("post://"); + + /** The scheme identifying this link type. */ + private final String scheme; + + /** + * Creates a new link type identified by the given scheme. + * + * @param scheme + * The scheme of the link type + */ + private LinkType(String scheme) { + this.scheme = scheme; + } + + /** + * Returns the scheme of this link type. + * + * @return The scheme of this link type + */ + public String getScheme() { + return scheme; + } } @@ -201,6 +223,20 @@ public class SoneTextParser implements Parser { } lineComplete = false; + Matcher matcher = whitespacePattern.matcher(line); + int nextSpace = matcher.find(0) ? matcher.start() : line.length(); + String link = line.substring(0, nextSpace); + String name = link; + logger.log(Level.FINER, String.format("Found link: %s", link)); + logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk)); + + /* if there is no text after the scheme, it’s not a link! */ + if (link.equals(linkType.getScheme())) { + parts.add(new PlainTextPart(linkType.getScheme())); + line = line.substring(linkType.getScheme().length()); + continue; + } + if (linkType == LinkType.SONE) { if (line.length() >= (7 + 43)) { String soneId = line.substring(7, 50); @@ -236,12 +272,6 @@ public class SoneTextParser implements Parser { } continue; } - Matcher matcher = whitespacePattern.matcher(line); - int nextSpace = matcher.find(0) ? matcher.start() : line.length(); - String link = line.substring(0, nextSpace); - String name = link; - logger.log(Level.FINER, String.format("Found link: %s", link)); - logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk)); if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) { FreenetURI uri; diff --git a/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java b/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java index a1b759b..51a72b8 100644 --- a/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java +++ b/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java @@ -77,7 +77,7 @@ public class EditProfilePage extends SoneTemplatePage { birthDay = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("birth-day", 256).trim()); birthMonth = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("birth-month", 256).trim()); birthYear = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("birth-year", 256).trim()); - avatarId = request.getHttpRequest().getPartAsStringFailsafe("avatar-id", 36); + avatarId = request.getHttpRequest().getPartAsStringFailsafe("avatarId", 36); profile.setFirstName(firstName.length() > 0 ? firstName : null); profile.setMiddleName(middleName.length() > 0 ? middleName : null); profile.setLastName(lastName.length() > 0 ? lastName : null); @@ -139,7 +139,7 @@ public class EditProfilePage extends SoneTemplatePage { templateContext.set("birthDay", birthDay); templateContext.set("birthMonth", birthMonth); templateContext.set("birthYear", birthYear); - templateContext.set("avatar-id", avatarId); + templateContext.set("avatarId", avatarId); templateContext.set("fields", fields); } diff --git a/src/main/java/net/pterodactylus/sone/web/SearchPage.java b/src/main/java/net/pterodactylus/sone/web/SearchPage.java index 691453d..524e501 100644 --- a/src/main/java/net/pterodactylus/sone/web/SearchPage.java +++ b/src/main/java/net/pterodactylus/sone/web/SearchPage.java @@ -111,6 +111,26 @@ public class SearchPage extends SoneTemplatePage { throw new RedirectException("index.html"); } + /* check for a couple of shortcuts. */ + if (phrases.size() == 1) { + String phrase = phrases.get(0).getPhrase(); + + /* is it a Sone ID? */ + redirectIfNotNull(getSoneId(phrase), "viewSone.html?sone="); + + /* is it a post ID? */ + redirectIfNotNull(getPostId(phrase), "viewPost.html?post="); + + /* is it a reply ID? show the post. */ + redirectIfNotNull(getReplyPostId(phrase), "viewPost.html?post="); + + /* is it an album ID? */ + redirectIfNotNull(getAlbumId(phrase), "imageBrowser.html?album="); + + /* is it an image ID? */ + redirectIfNotNull(getImageId(phrase), "imageBrowser.html?image="); + } + Collection sones = webInterface.getCore().getSones(); Set> soneHits = getHits(sones, phrases, SoneStringGenerator.COMPLETE_GENERATOR); @@ -271,6 +291,91 @@ public class SearchPage extends SoneTemplatePage { } /** + * Throws a + * {@link net.pterodactylus.sone.web.page.FreenetTemplatePage.RedirectException} + * if the given object is not {@code null}, appending the object to the + * given target URL. + * + * @param object + * The object on which to redirect + * @param target + * The target of the redirect + * @throws RedirectException + * if {@code object} is not {@code null} + */ + private static void redirectIfNotNull(String object, String target) throws RedirectException { + if (object != null) { + throw new RedirectException(target + object); + } + } + + /** + * If the given phrase contains a Sone ID (optionally prefixed by + * “sone://”), returns said Sone ID, otherwise return {@code null}. + * + * @param phrase + * The phrase that maybe is a Sone ID + * @return The Sone ID, or {@code null} + */ + private String getSoneId(String phrase) { + String soneId = phrase.startsWith("sone://") ? phrase.substring(7) : phrase; + return (webInterface.getCore().getSone(soneId, false) != null) ? soneId : null; + } + + /** + * If the given phrase contains a post ID (optionally prefixed by + * “post://”), returns said post ID, otherwise return {@code null}. + * + * @param phrase + * The phrase that maybe is a post ID + * @return The post ID, or {@code null} + */ + private String getPostId(String phrase) { + String postId = phrase.startsWith("post://") ? phrase.substring(7) : phrase; + return (webInterface.getCore().getPost(postId, false) != null) ? postId : null; + } + + /** + * If the given phrase contains a reply ID (optionally prefixed by + * “reply://”), returns the ID of the post the reply belongs to, otherwise + * return {@code null}. + * + * @param phrase + * The phrase that maybe is a reply ID + * @return The reply’s post ID, or {@code null} + */ + private String getReplyPostId(String phrase) { + String replyId = phrase.startsWith("reply://") ? phrase.substring(8) : phrase; + return (webInterface.getCore().getReply(replyId, false) != null) ? webInterface.getCore().getReply(replyId, false).getPost().getId() : null; + } + + /** + * If the given phrase contains an album ID (optionally prefixed by + * “album://”), returns said album ID, otherwise return {@code null}. + * + * @param phrase + * The phrase that maybe is an album ID + * @return The album ID, or {@code null} + */ + private String getAlbumId(String phrase) { + String albumId = phrase.startsWith("album://") ? phrase.substring(8) : phrase; + return (webInterface.getCore().getAlbum(albumId, false) != null) ? albumId : null; + } + + /** + * If the given phrase contains an image ID (optionally prefixed by + * “image://”), returns said image ID, otherwise return {@code null}. + * + * @param phrase + * The phrase that maybe is an image ID + * @return The image ID, or {@code null} + */ + private String getImageId(String phrase) { + String imageId = phrase.startsWith("image://") ? phrase.substring(8) : phrase; + return (webInterface.getCore().getImage(imageId, false) != null) ? imageId : null; + } + + /** * Converts a given object into a {@link String}. * * @param diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index b5f6dfb..75b5f50 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -103,18 +103,13 @@ import net.pterodactylus.sone.web.ajax.UntrustAjaxPage; 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.cache.Cache; -import net.pterodactylus.util.cache.CacheException; -import net.pterodactylus.util.cache.CacheItem; -import net.pterodactylus.util.cache.DefaultCacheItem; -import net.pterodactylus.util.cache.MemoryCache; -import net.pterodactylus.util.cache.ValueRetriever; import net.pterodactylus.util.collection.SetBuilder; import net.pterodactylus.util.collection.filter.Filters; import net.pterodactylus.util.logging.Logging; 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; @@ -123,15 +118,13 @@ import net.pterodactylus.util.template.HtmlFilter; import net.pterodactylus.util.template.MatchFilter; import net.pterodactylus.util.template.ModFilter; import net.pterodactylus.util.template.PaginationFilter; -import net.pterodactylus.util.template.Provider; import net.pterodactylus.util.template.ReflectionAccessor; import net.pterodactylus.util.template.ReplaceFilter; import net.pterodactylus.util.template.StoreFilter; import net.pterodactylus.util.template.Template; -import net.pterodactylus.util.template.TemplateContext; import net.pterodactylus.util.template.TemplateContextFactory; -import net.pterodactylus.util.template.TemplateException; import net.pterodactylus.util.template.TemplateParser; +import net.pterodactylus.util.template.TemplateProvider; import net.pterodactylus.util.template.XmlFilter; import net.pterodactylus.util.thread.Ticker; import net.pterodactylus.util.version.Version; @@ -222,7 +215,6 @@ public class WebInterface implements CoreListener { * @param sonePlugin * The Sone plugin */ - @SuppressWarnings("synthetic-access") public WebInterface(SonePlugin sonePlugin) { this.sonePlugin = sonePlugin; formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword(); @@ -261,8 +253,8 @@ public class WebInterface implements CoreListener { templateContextFactory.addFilter("unique", new UniqueElementFilter()); templateContextFactory.addFilter("mod", new ModFilter()); templateContextFactory.addFilter("paginate", new PaginationFilter()); - templateContextFactory.addProvider(Provider.TEMPLATE_CONTEXT_PROVIDER); - templateContextFactory.addProvider(new ClassPathTemplateProvider()); + templateContextFactory.addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER); + templateContextFactory.addProvider(new ClassPathTemplateProvider(WebInterface.class, "/templates/")); templateContextFactory.addTemplateObject("webInterface", this); templateContextFactory.addTemplateObject("formPassword", formPassword); @@ -1011,66 +1003,4 @@ public class WebInterface implements CoreListener { notificationManager.addNotification(imageInsertFailedNotification); } - /** - * Template provider implementation that uses - * {@link WebInterface#createReader(String)} to load templates for - * inclusion. - * - * @author David ‘Bombe’ Roden - */ - private class ClassPathTemplateProvider implements Provider { - - /** Cache for templates. */ - private final Cache templateCache = new MemoryCache(new ValueRetriever() { - - @Override - @SuppressWarnings("synthetic-access") - public CacheItem