Merge branch 'release-0.8.6' 0.8.6
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 5 Jul 2013 19:09:34 +0000 (21:09 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 5 Jul 2013 19:09:34 +0000 (21:09 +0200)
pom.xml
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
src/main/java/net/pterodactylus/sone/core/UpdateChecker.java
src/main/java/net/pterodactylus/sone/data/Album.java
src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java
src/main/java/net/pterodactylus/sone/main/SonePlugin.java
src/main/java/net/pterodactylus/sone/template/ParserFilter.java
src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java
src/main/resources/templates/imageBrowser.html

diff --git a/pom.xml b/pom.xml
index a3d564e..d2f00a4 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
        <modelVersion>4.0.0</modelVersion>
        <groupId>net.pterodactylus</groupId>
        <artifactId>sone</artifactId>
-       <version>0.8.5</version>
+       <version>0.8.6</version>
        <dependencies>
                <dependency>
                        <groupId>net.pterodactylus</groupId>
index d66e032..7b4bc4b 100644 (file)
@@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -93,8 +92,11 @@ import net.pterodactylus.util.thread.NamedThreadFactory;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
-import com.google.common.collect.Collections2;
 import com.google.common.collect.FluentIterable;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
 import com.google.common.eventbus.EventBus;
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
@@ -183,7 +185,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        private final Set<String> bookmarkedPosts = new HashSet<String>();
 
        /** Trusted identities, sorted by own identities. */
-       private final Map<OwnIdentity, Set<Identity>> trustedIdentities = Collections.synchronizedMap(new HashMap<OwnIdentity, Set<Identity>>());
+       private final Multimap<OwnIdentity, Identity> trustedIdentities = Multimaps.synchronizedSetMultimap(HashMultimap.<OwnIdentity, Identity>create());
 
        /** All known albums. */
        private final Map<String, Album> albums = new HashMap<String, Album>();
@@ -332,7 +334,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        @Override
        public Collection<Sone> getSones() {
                synchronized (sones) {
-                       return Collections.unmodifiableCollection(sones.values());
+                       return ImmutableSet.copyOf(sones.values());
                }
        }
 
@@ -358,13 +360,13 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        @Override
        public Collection<Sone> getLocalSones() {
                synchronized (sones) {
-                       return Collections2.filter(sones.values(), new Predicate<Sone>() {
+                       return FluentIterable.from(sones.values()).filter(new Predicate<Sone>() {
 
                                @Override
                                public boolean apply(Sone sone) {
                                        return sone.isLocal();
                                }
-                       });
+                       }).toSet();
                }
        }
 
@@ -399,13 +401,13 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        @Override
        public Collection<Sone> getRemoteSones() {
                synchronized (sones) {
-                       return Collections2.filter(sones.values(), new Predicate<Sone>() {
+                       return FluentIterable.from(sones.values()).filter(new Predicate<Sone>() {
 
                                @Override
                                public boolean apply(Sone sone) {
                                        return !sone.isLocal();
                                }
-                       });
+                       }).toSet();
                }
        }
 
@@ -469,7 +471,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                checkNotNull(origin, "origin must not be null");
                checkNotNull(target, "target must not be null");
                checkArgument(origin.getIdentity() instanceof OwnIdentity, "origin’s identity must be an OwnIdentity");
-               return trustedIdentities.containsKey(origin.getIdentity()) && trustedIdentities.get(origin.getIdentity()).contains(target.getIdentity());
+               return trustedIdentities.containsEntry(origin.getIdentity(), target.getIdentity());
        }
 
        /**
@@ -601,7 +603,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                synchronized (bookmarkedPosts) {
                        for (String bookmarkedPostId : bookmarkedPosts) {
                                Optional<Post> post = getPost(bookmarkedPostId);
-                               if (!post.isPresent()) {
+                               if (post.isPresent()) {
                                        posts.add(post.get());
                                }
                        }
@@ -739,6 +741,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        logger.log(Level.WARNING, "Given OwnIdentity is null!");
                        return null;
                }
+               logger.info(String.format("Adding Sone from OwnIdentity: %s", ownIdentity));
                synchronized (sones) {
                        final Sone sone;
                        try {
@@ -751,7 +754,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        sone.setClient(new Client("Sone", SonePlugin.VERSION.toString()));
                        sone.setKnown(true);
                        /* TODO - load posts ’n stuff */
-                       trustedIdentities.put(ownIdentity, Collections.synchronizedSet(new HashSet<Identity>()));
                        sones.put(ownIdentity.getId(), sone);
                        final SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, sone);
                        soneInserters.put(sone, soneInserter);
@@ -800,7 +802,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        return null;
                }
                synchronized (sones) {
-                       final Sone sone = getRemoteSone(identity.getId(), true).setIdentity(identity);
+                       final Sone sone = getRemoteSone(identity.getId(), true);
+                       if (sone.isLocal()) {
+                               return sone;
+                       }
+                       sone.setIdentity(identity);
                        boolean newSone = sone.getRequestUri() == null;
                        sone.setRequestUri(SoneUri.create(identity.getRequestUri()));
                        sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0));
@@ -1045,6 +1051,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        }
                        synchronized (sones) {
                                sone.setOptions(storedSone.get().getOptions());
+                               sone.setKnown(storedSone.get().isKnown());
                                sones.put(sone.getId(), sone);
                        }
                }
@@ -1111,6 +1118,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        logger.log(Level.FINE, String.format("Tried to load non-local Sone: %s", sone));
                        return;
                }
+               logger.info(String.format("Loading local Sone: %s", sone));
 
                /* initialize options. */
                sone.getOptions().addBooleanOption("AutoFollow", new DefaultOption<Boolean>(false));
@@ -1322,6 +1330,8 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                for (PostReply reply : replies) {
                        reply.setKnown(true);
                }
+
+               logger.info(String.format("Sone loaded successfully: %s", sone));
        }
 
        /**
@@ -2123,7 +2133,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        public void ownIdentityRemoved(OwnIdentityRemovedEvent ownIdentityRemovedEvent) {
                OwnIdentity ownIdentity = ownIdentityRemovedEvent.ownIdentity();
                logger.log(Level.FINEST, String.format("Removing OwnIdentity: %s", ownIdentity));
-               trustedIdentities.remove(ownIdentity);
+               trustedIdentities.removeAll(ownIdentity);
        }
 
        /**
@@ -2136,7 +2146,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        public void identityAdded(IdentityAddedEvent identityAddedEvent) {
                Identity identity = identityAddedEvent.identity();
                logger.log(Level.FINEST, String.format("Adding Identity: %s", identity));
-               trustedIdentities.get(identityAddedEvent.ownIdentity()).add(identity);
+               trustedIdentities.put(identityAddedEvent.ownIdentity(), identity);
                addRemoteSone(identity);
        }
 
@@ -2155,6 +2165,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                        @SuppressWarnings("synthetic-access")
                        public void run() {
                                Sone sone = getRemoteSone(identity.getId(), false);
+                               if (sone.isLocal()) {
+                                       return;
+                               }
                                sone.setIdentity(identity);
                                sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), sone.getLatestEdition()));
                                soneDownloader.addSone(sone);
@@ -2173,9 +2186,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
        public void identityRemoved(IdentityRemovedEvent identityRemovedEvent) {
                OwnIdentity ownIdentity = identityRemovedEvent.ownIdentity();
                Identity identity = identityRemovedEvent.identity();
-               trustedIdentities.get(ownIdentity).remove(identity);
+               trustedIdentities.remove(ownIdentity, identity);
                boolean foundIdentity = false;
-               for (Entry<OwnIdentity, Set<Identity>> trustedIdentity : trustedIdentities.entrySet()) {
+               for (Entry<OwnIdentity, Collection<Identity>> trustedIdentity : trustedIdentities.asMap().entrySet()) {
                        if (trustedIdentity.getKey().equals(ownIdentity)) {
                                continue;
                        }
index e0ee363..f493fdc 100644 (file)
@@ -97,9 +97,10 @@ public class SoneDownloader extends AbstractService {
         *            The Sone to add
         */
        public void addSone(Sone sone) {
-               if (sones.add(sone)) {
-                       freenetInterface.registerUsk(sone, this);
+               if (!sones.add(sone)) {
+                       freenetInterface.unregisterUsk(sone);
                }
+               freenetInterface.registerUsk(sone, this);
        }
 
        /**
index b1248ab..bb7016d 100644 (file)
@@ -53,7 +53,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 = 56;
+       private static final int LATEST_EDITION = 58;
 
        /** The event bus. */
        private final EventBus eventBus;
index 5375d98..cb7b4f3 100644 (file)
@@ -20,6 +20,7 @@ package net.pterodactylus.sone.data;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
+import static java.util.Arrays.asList;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -30,6 +31,7 @@ import java.util.UUID;
 
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.FluentIterable;
@@ -67,6 +69,24 @@ public class Album implements Fingerprintable {
                }
        };
 
+       /**
+        * Filter that removes all albums that do not have any images in any album
+        * below it.
+        */
+       public static final Predicate<Album> NOT_EMPTY = new Predicate<Album>() {
+
+               @Override
+               public boolean apply(Album album) {
+                       return FluentIterable.from(asList(album)).transformAndConcat(FLATTENER).anyMatch(new Predicate<Album>() {
+
+                               @Override
+                               public boolean apply(Album album) {
+                                       return !album.getImages().isEmpty();
+                               }
+                       });
+               }
+       };
+
        /** The ID of this album. */
        private final String id;
 
index de36ca1..77e0480 100644 (file)
@@ -171,7 +171,9 @@ public class IdentityManager extends AbstractService {
                        boolean identitiesLoaded = false;
                        try {
                                /* get all identities with the wanted context from WoT. */
+                               logger.finer("Getting all Own Identities from WoT...");
                                ownIdentities = webOfTrustConnector.loadAllOwnIdentities();
+                               logger.finest(String.format("Loaded %d Own Identities.", ownIdentities.size()));
 
                                /* load trusted identities. */
                                for (OwnIdentity ownIdentity : ownIdentities) {
@@ -188,7 +190,9 @@ public class IdentityManager extends AbstractService {
                                        }
 
                                        /* load trusted identities. */
+                                       logger.finer(String.format("Getting trusted identities for %s...", ownIdentity.getId()));
                                        Set<Identity> trustedIdentities = webOfTrustConnector.loadTrustedIdentities(ownIdentity, context);
+                                       logger.finest(String.format("Got %d trusted identities.", trustedIdentities.size()));
                                        for (Identity identity : trustedIdentities) {
                                                identities.put(identity.getId(), identity);
                                        }
@@ -210,6 +214,7 @@ public class IdentityManager extends AbstractService {
                                        /* find new identities. */
                                        for (Identity currentIdentity : currentIdentities.get(ownIdentity).values()) {
                                                if (!oldIdentities.containsKey(ownIdentity) || !oldIdentities.get(ownIdentity).containsKey(currentIdentity.getId())) {
+                                                       logger.finest(String.format("Identity added for %s: %s", ownIdentity.getId(), currentIdentity));
                                                        eventBus.post(new IdentityAddedEvent(ownIdentity, currentIdentity));
                                                }
                                        }
@@ -218,6 +223,7 @@ public class IdentityManager extends AbstractService {
                                        if (oldIdentities.containsKey(ownIdentity)) {
                                                for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) {
                                                        if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) {
+                                                               logger.finest(String.format("Identity removed for %s: %s", ownIdentity.getId(), oldIdentity));
                                                                eventBus.post(new IdentityRemovedEvent(ownIdentity, oldIdentity));
                                                        }
                                                }
@@ -231,11 +237,13 @@ public class IdentityManager extends AbstractService {
                                                        Set<String> oldContexts = oldIdentity.getContexts();
                                                        Set<String> newContexts = newIdentity.getContexts();
                                                        if (oldContexts.size() != newContexts.size()) {
+                                                               logger.finest(String.format("Contexts changed for %s: was: %s, is now: %s", ownIdentity.getId(), oldContexts, newContexts));
                                                                eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
                                                                continue;
                                                        }
                                                        for (String oldContext : oldContexts) {
                                                                if (!newContexts.contains(oldContext)) {
+                                                                       logger.finest(String.format("Context was removed for %s: %s", ownIdentity.getId(), oldContext));
                                                                        eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
                                                                        break;
                                                                }
@@ -251,11 +259,13 @@ public class IdentityManager extends AbstractService {
                                                        Map<String, String> oldProperties = oldIdentity.getProperties();
                                                        Map<String, String> newProperties = newIdentity.getProperties();
                                                        if (oldProperties.size() != newProperties.size()) {
+                                                               logger.finest(String.format("Properties changed for %s: was: %s, is now: %s", ownIdentity.getId(), oldProperties, newProperties));
                                                                eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
                                                                continue;
                                                        }
                                                        for (Entry<String, String> oldProperty : oldProperties.entrySet()) {
                                                                if (!newProperties.containsKey(oldProperty.getKey()) || !newProperties.get(oldProperty.getKey()).equals(oldProperty.getValue())) {
+                                                                       logger.finest(String.format("Property was removed for %s: %s", ownIdentity.getId(), oldProperty));
                                                                        eventBus.post(new IdentityUpdatedEvent(ownIdentity, newIdentity));
                                                                        break;
                                                                }
@@ -291,6 +301,7 @@ public class IdentityManager extends AbstractService {
                        for (OwnIdentity oldOwnIdentity : currentOwnIdentities.values()) {
                                OwnIdentity newOwnIdentity = newOwnIdentities.get(oldOwnIdentity.getId());
                                if ((newOwnIdentity == null) || ((context != null) && oldOwnIdentity.hasContext(context) && !newOwnIdentity.hasContext(context))) {
+                                       logger.finest(String.format("Own Identity removed: %s", oldOwnIdentity));
                                        eventBus.post(new OwnIdentityRemovedEvent(new DefaultOwnIdentity(oldOwnIdentity)));
                                }
                        }
@@ -299,6 +310,7 @@ public class IdentityManager extends AbstractService {
                        for (OwnIdentity currentOwnIdentity : newOwnIdentities.values()) {
                                OwnIdentity oldOwnIdentity = currentOwnIdentities.get(currentOwnIdentity.getId());
                                if (((oldOwnIdentity == null) && ((context == null) || currentOwnIdentity.hasContext(context))) || ((oldOwnIdentity != null) && (context != null) && (!oldOwnIdentity.hasContext(context) && currentOwnIdentity.hasContext(context)))) {
+                                       logger.finest(String.format("Own Identity added: %s", currentOwnIdentity));
                                        eventBus.post(new OwnIdentityAddedEvent(new DefaultOwnIdentity(currentOwnIdentity)));
                                }
                        }
index 9626c57..6f2a908 100644 (file)
@@ -104,7 +104,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr
        }
 
        /** The version. */
-       public static final Version VERSION = new Version(0, 8, 5);
+       public static final Version VERSION = new Version(0, 8, 6);
 
        /** The logger. */
        private static final Logger logger = Logging.getLogger(SonePlugin.class);
index 8833a2d..bd6903b 100644 (file)
@@ -94,7 +94,7 @@ public class ParserFilter implements Filter {
                int cutOffLength = Numbers.safeParseInteger(parameters.get("cut-off-length"), Numbers.safeParseInteger(templateContext.get(String.valueOf(parameters.get("cut-off-length"))), length));
                Object sone = parameters.get("sone");
                if (sone instanceof String) {
-                       sone = core.getSone((String) sone);
+                       sone = core.getSone((String) sone).orNull();
                }
                FreenetRequest request = (FreenetRequest) templateContext.get("request");
                SoneTextParserContext context = new SoneTextParserContext(request, (Sone) sone);
index 37268ec..9dec1dc 100644 (file)
 
 package net.pterodactylus.sone.web;
 
+import static net.pterodactylus.sone.data.Album.FLATTENER;
+import static net.pterodactylus.sone.data.Album.NOT_EMPTY;
+import static net.pterodactylus.sone.data.Album.TITLE_COMPARATOR;
+
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -90,9 +94,9 @@ public class ImageBrowserPage extends SoneTemplatePage {
                        templateContext.set("galleryRequested", true);
                        List<Album> albums = new ArrayList<Album>();
                        for (Sone sone : webInterface.getCore().getSones()) {
-                               albums.addAll(FluentIterable.from(sone.getAlbums()).transformAndConcat(Album.FLATTENER).toList());
+                               albums.addAll(FluentIterable.from(sone.getAlbums()).transformAndConcat(FLATTENER).filter(NOT_EMPTY).toList());
                        }
-                       Collections.sort(albums, Album.TITLE_COMPARATOR);
+                       Collections.sort(albums, TITLE_COMPARATOR);
                        Pagination<Album> albumPagination = new Pagination<Album>(albums, 12).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
                        templateContext.set("albumPagination", albumPagination);
                        templateContext.set("albums", albumPagination.getItems());
index 7752ffb..a80680f 100644 (file)
                                <%last><%= true|store key==endRow><%/last>
                                <%if endRow>
                                        </div>
-                                       <%include include/pagination.html pageParameter=="page">
                                <%/if>
+                <%last><%include include/pagination.html pageParameter=="page"><%/last>
                        <%/foreach>
 
                        <%if album.sone.local>