Merge commit 'c30ad3a3fcfc66d0c1757a50afe413d9942d7793' into less-critical
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 25 Jan 2013 19:14:21 +0000 (20:14 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 25 Jan 2013 19:14:21 +0000 (20:14 +0100)
1  2 
src/main/java/net/pterodactylus/sone/core/Core.java

@@@ -87,13 -87,9 +87,13 @@@ import net.pterodactylus.util.number.Nu
  import net.pterodactylus.util.service.AbstractService;
  import net.pterodactylus.util.thread.NamedThreadFactory;
  
 +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;
 +import com.google.common.collect.Ordering;
  import com.google.common.eventbus.EventBus;
  import com.google.common.eventbus.Subscribe;
  import com.google.inject.Inject;
@@@ -153,7 -149,7 +153,7 @@@ public class Core extends AbstractServi
        private volatile FcpInterface fcpInterface;
  
        /** The times Sones were followed. */
-       private final Map<Sone, Long> soneFollowingTimes = new HashMap<Sone, Long>();
+       private final Map<String, Long> soneFollowingTimes = new HashMap<String, Long>();
  
        /** Locked local Sones. */
        /* synchronize on itself. */
         * {@inheritDoc}
         */
        @Override
 -      public Post getPost(String postId) {
 +      public Optional<Post> getPost(String postId) {
                synchronized (posts) {
 -                      return posts.get(postId);
 +                      return Optional.fromNullable(posts.get(postId));
                }
        }
  
         * {@inheritDoc}
         */
        @Override
 -      public PostReply getPostReply(String replyId) {
 +      public Optional<PostReply> getPostReply(String replyId) {
                synchronized (replies) {
 -                      return replies.get(replyId);
 +                      return Optional.fromNullable(replies.get(replyId));
                }
        }
  
         * {@inheritDoc}
         */
        @Override
 -      public List<PostReply> getReplies(Post post) {
 -              Set<Sone> sones = getSones();
 -              List<PostReply> replies = new ArrayList<PostReply>();
 -              for (Sone sone : sones) {
 -                      for (PostReply reply : sone.getReplies()) {
 -                              if (reply.getPost().equals(post)) {
 -                                      replies.add(reply);
 -                              }
 +      public List<PostReply> getReplies(final Post post) {
 +              return Ordering.from(Reply.TIME_COMPARATOR).sortedCopy(FluentIterable.from(getSones()).transformAndConcat(new Function<Sone, Iterable<PostReply>>() {
 +
 +                      @Override
 +                      public Iterable<PostReply> apply(Sone sone) {
 +                              return sone.getReplies();
                        }
 -              }
 -              Collections.sort(replies, Reply.TIME_COMPARATOR);
 -              return replies;
 +              }).filter(new Predicate<PostReply>() {
 +
 +                      @Override
 +                      public boolean apply(PostReply reply) {
 +                              return post.getId().equals(reply.getPostId());
 +                      }
 +              }));
        }
  
        /**
                Set<Post> posts = new HashSet<Post>();
                synchronized (bookmarkedPosts) {
                        for (String bookmarkedPostId : bookmarkedPosts) {
 -                              Post post = getPost(bookmarkedPostId);
 -                              if (post != null) {
 -                                      posts.add(post);
 +                              Optional<Post> post = getPost(bookmarkedPostId);
 +                              if (!post.isPresent()) {
 +                                      posts.add(post.get());
                                }
                        }
                }
                sone.getOptions().addBooleanOption("ShowNotification/NewReplies", new DefaultOption<Boolean>(true));
                sone.getOptions().addEnumOption("ShowCustomAvatars", new DefaultOption<ShowCustomAvatars>(ShowCustomAvatars.NEVER));
  
-               followSone(sone, getSone("nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"));
+               followSone(sone, "nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI");
                touchConfiguration();
                return sone;
        }
                                        eventBus.post(new NewSoneFoundEvent(sone));
                                        for (Sone localSone : getLocalSones()) {
                                                if (localSone.getOptions().getBooleanOption("AutoFollow").get()) {
-                                                       followSone(localSone, sone);
+                                                       followSone(localSone, sone.getId());
                                                }
                                        }
                                }
        public void followSone(Sone sone, String soneId) {
                checkNotNull(sone, "sone must not be null");
                checkNotNull(soneId, "soneId must not be null");
-               Sone followedSone = getSone(soneId, true);
-               if (followedSone == null) {
-                       logger.log(Level.INFO, String.format("Ignored Sone with invalid ID: %s", soneId));
-                       return;
-               }
-               followSone(sone, getSone(soneId));
-       }
-       /**
-        * Lets the given local Sone follow the other given Sone. If the given Sone
-        * was not followed by any local Sone before, this will mark all elements of
-        * the followed Sone as read that have been created before the current
-        * moment.
-        *
-        * @param sone
-        *            The local Sone that should follow the other Sone
-        * @param followedSone
-        *            The Sone that should be followed
-        */
-       public void followSone(Sone sone, Sone followedSone) {
-               checkNotNull(sone, "sone must not be null");
-               checkNotNull(followedSone, "followedSone must not be null");
-               sone.addFriend(followedSone.getId());
+               sone.addFriend(soneId);
                synchronized (soneFollowingTimes) {
-                       if (!soneFollowingTimes.containsKey(followedSone)) {
+                       if (!soneFollowingTimes.containsKey(soneId)) {
                                long now = System.currentTimeMillis();
-                               soneFollowingTimes.put(followedSone, now);
+                               soneFollowingTimes.put(soneId, now);
+                               Sone followedSone = getSone(soneId);
+                               if (followedSone == null) {
+                                       return;
+                               }
                                for (Post post : followedSone.getPosts()) {
                                        if (post.getTime() < now) {
                                                markPostKnown(post);
        public void unfollowSone(Sone sone, String soneId) {
                checkNotNull(sone, "sone must not be null");
                checkNotNull(soneId, "soneId must not be null");
-               unfollowSone(sone, getSone(soneId, false));
-       }
-       /**
-        * Lets the given local Sone unfollow the other given Sone. If the given
-        * local Sone is the last local Sone that followed the given Sone, its
-        * following time will be removed.
-        *
-        * @param sone
-        *            The local Sone that should unfollow another Sone
-        * @param unfollowedSone
-        *            The Sone being unfollowed
-        */
-       public void unfollowSone(Sone sone, Sone unfollowedSone) {
-               checkNotNull(sone, "sone must not be null");
-               checkNotNull(unfollowedSone, "unfollowedSone must not be null");
-               sone.removeFriend(unfollowedSone.getId());
+               sone.removeFriend(soneId);
                boolean unfollowedSoneStillFollowed = false;
                for (Sone localSone : getLocalSones()) {
-                       unfollowedSoneStillFollowed |= localSone.hasFriend(unfollowedSone.getId());
+                       unfollowedSoneStillFollowed |= localSone.hasFriend(soneId);
                }
                if (!unfollowedSoneStillFollowed) {
                        synchronized (soneFollowingTimes) {
-                               soneFollowingTimes.remove(unfollowedSone);
+                               soneFollowingTimes.remove(soneId);
                        }
                }
                touchConfiguration();
                                List<Post> storedPosts = storedSone.getPosts();
                                synchronized (knownPosts) {
                                        for (Post post : sone.getPosts()) {
 -                                              PostBuilder postBuilder = postBuilderFactory.newPostBuilder();
 -                                              postBuilder.copyPost(post).from(storedSone.getId());
 -                                              Post newPost = postBuilder.build().setKnown(knownPosts.contains(post.getId()));
 -                                              if (!storedPosts.contains(newPost)) {
 -                                                      if (newPost.getTime() < getSoneFollowingTime(sone)) {
 -                                                              knownPosts.add(newPost.getId());
 -                                                              newPost.setKnown(true);
 -                                                      } else if (!knownPosts.contains(newPost.getId())) {
 -                                                              eventBus.post(new NewPostFoundEvent(newPost));
 +                                              post.setKnown(knownPosts.contains(post.getId()));
 +                                              if (!storedPosts.contains(post)) {
 +                                                      if (post.getTime() < getSoneFollowingTime(sone)) {
 +                                                              knownPosts.add(post.getId());
 +                                                              post.setKnown(true);
 +                                                      } else if (!knownPosts.contains(post.getId())) {
 +                                                              eventBus.post(new NewPostFoundEvent(post));
                                                        }
                                                }
 -                                              posts.put(newPost.getId(), newPost);
 +                                              posts.put(post.getId(), post);
                                        }
                                }
                        }
                                        }
                                }
                        }
 -                      synchronized (storedSone) {
 -                              if (!soneRescueMode || (sone.getTime() > storedSone.getTime())) {
 -                                      storedSone.setTime(sone.getTime());
 -                              }
 -                              storedSone.setClient(sone.getClient());
 -                              storedSone.setProfile(sone.getProfile());
 -                              if (soneRescueMode) {
 -                                      for (Post post : sone.getPosts()) {
 -                                              storedSone.addPost(post);
 -                                      }
 -                                      for (PostReply reply : sone.getReplies()) {
 -                                              storedSone.addReply(reply);
 -                                      }
 -                                      for (String likedPostId : sone.getLikedPostIds()) {
 -                                              storedSone.addLikedPostId(likedPostId);
 -                                      }
 -                                      for (String likedReplyId : sone.getLikedReplyIds()) {
 -                                              storedSone.addLikedReplyId(likedReplyId);
 -                                      }
 -                                      for (Album album : sone.getAlbums()) {
 -                                              storedSone.addAlbum(album);
 -                                      }
 -                              } else {
 -                                      storedSone.setPosts(sone.getPosts());
 -                                      storedSone.setReplies(sone.getReplies());
 -                                      storedSone.setLikePostIds(sone.getLikedPostIds());
 -                                      storedSone.setLikeReplyIds(sone.getLikedReplyIds());
 -                                      storedSone.setAlbums(sone.getAlbums());
 -                              }
 -                              storedSone.setLatestEdition(sone.getLatestEdition());
 +                      synchronized (sones) {
 +                              sones.put(sone.getId(), sone);
                        }
                }
        }
                                logger.log(Level.WARNING, "Invalid post found, aborting load!");
                                return;
                        }
 -                      PostBuilder postBuilder = postBuilderFactory.newPostBuilder().withId(postId).from(sone.getId()).withTime(postTime).withText(postText);
 +                      PostBuilder postBuilder = postBuilder().withId(postId).from(sone.getId()).withTime(postTime).withText(postText);
                        if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
                                postBuilder.to(postRecipientId);
                        }
                webOfTrustUpdater.stop();
                updateChecker.stop();
                soneDownloader.stop();
 +              soneDownloaders.shutdown();
                identityManager.stop();
        }
  
                        for (PostReply reply : sone.getReplies()) {
                                String replyPrefix = sonePrefix + "/Replies/" + replyCounter++;
                                configuration.getStringValue(replyPrefix + "/ID").setValue(reply.getId());
 -                              configuration.getStringValue(replyPrefix + "/Post/ID").setValue(reply.getPost().getId());
 +                              configuration.getStringValue(replyPrefix + "/Post/ID").setValue(reply.getPostId());
                                configuration.getLongValue(replyPrefix + "/Time").setValue(reply.getTime());
                                configuration.getStringValue(replyPrefix + "/Text").setValue(reply.getText());
                        }
                        /* save Sone following times. */
                        soneCounter = 0;
                        synchronized (soneFollowingTimes) {
-                               for (Entry<Sone, Long> soneFollowingTime : soneFollowingTimes.entrySet()) {
-                                       configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey().getId());
+                               for (Entry<String, Long> soneFollowingTime : soneFollowingTimes.entrySet()) {
+                                       configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey());
                                        configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").setValue(soneFollowingTime.getValue());
                                        ++soneCounter;
                                }
                                logger.log(Level.WARNING, String.format("Ignoring Sone with invalid ID: %s", soneId));
                        } else {
                                synchronized (soneFollowingTimes) {
-                                       soneFollowingTimes.put(getSone(soneId), time);
+                                       soneFollowingTimes.put(soneId, time);
                                }
                        }
                        ++soneCounter;