Merge branch 'partial-rewrite' into less-critical
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sat, 26 Jan 2013 11:35:09 +0000 (12:35 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sat, 26 Jan 2013 11:35:09 +0000 (12:35 +0100)
Conflicts:
src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java
src/main/java/net/pterodactylus/sone/text/SoneTextParser.java

14 files changed:
1  2 
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java
src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java
src/main/java/net/pterodactylus/sone/database/PostProvider.java
src/main/java/net/pterodactylus/sone/database/PostReplyProvider.java
src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java
src/main/java/net/pterodactylus/sone/main/SonePlugin.java
src/main/java/net/pterodactylus/sone/text/SoneTextParser.java
src/main/java/net/pterodactylus/sone/web/MarkAsKnownPage.java
src/main/java/net/pterodactylus/sone/web/SearchPage.java
src/main/java/net/pterodactylus/sone/web/ViewSonePage.java
src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java

@@@ -56,17 -56,20 +56,20 @@@ import net.pterodactylus.sone.data.Albu
  import net.pterodactylus.sone.data.Client;
  import net.pterodactylus.sone.data.Image;
  import net.pterodactylus.sone.data.Post;
- import net.pterodactylus.sone.data.PostBuilder;
- import net.pterodactylus.sone.data.PostBuilderFactory;
  import net.pterodactylus.sone.data.PostReply;
- import net.pterodactylus.sone.data.PostReplyBuilder;
- import net.pterodactylus.sone.data.PostReplyBuilderFactory;
  import net.pterodactylus.sone.data.Profile;
  import net.pterodactylus.sone.data.Profile.Field;
  import net.pterodactylus.sone.data.Reply;
  import net.pterodactylus.sone.data.Sone;
  import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
  import net.pterodactylus.sone.data.Sone.SoneStatus;
+ import net.pterodactylus.sone.database.PostBuilder;
+ import net.pterodactylus.sone.database.PostBuilderFactory;
+ import net.pterodactylus.sone.database.PostProvider;
+ import net.pterodactylus.sone.database.PostReplyBuilder;
+ import net.pterodactylus.sone.database.PostReplyBuilderFactory;
+ import net.pterodactylus.sone.database.PostReplyProvider;
+ import net.pterodactylus.sone.database.SoneProvider;
  import net.pterodactylus.sone.data.TemporaryImage;
  import net.pterodactylus.sone.fcp.FcpInterface;
  import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
@@@ -87,13 -90,9 +90,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;
@@@ -361,30 -360,9 +364,9 @@@ public class Core extends AbstractServi
         * @return The Sone with the given ID, or {@code null} if there is no such
         *         Sone
         */
-       public Sone getSone(String id) {
-               return getSone(id, true);
-       }
-       /**
-        * Returns the Sone with the given ID, regardless whether it’s local or
-        * remote.
-        *
-        * @param id
-        *            The ID of the Sone to get
-        * @param create
-        *            {@code true} to create a new Sone if none exists,
-        *            {@code false} to return {@code null} if a Sone with the given
-        *            ID does not exist
-        * @return The Sone with the given ID, or {@code null} if there is no such
-        *         Sone
-        */
        @Override
-       public Sone getSone(String id, boolean create) {
+       public Sone getSone(String id) {
                synchronized (sones) {
-                       if (!sones.containsKey(id) && create) {
-                               Sone sone = new Sone(id, false);
-                               sones.put(id, sone);
-                       }
                        return sones.get(id);
                }
        }
         */
        public long getSoneFollowingTime(Sone sone) {
                synchronized (soneFollowingTimes) {
 -                      if (soneFollowingTimes.containsKey(sone)) {
 -                              return soneFollowingTimes.get(sone);
 -                      }
 -                      return Long.MAX_VALUE;
 +                      return Optional.fromNullable(soneFollowingTimes.get(sone.getId())).or(Long.MAX_VALUE);
                }
        }
  
         * {@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));
                }
        }
  
        /**
-        * Returns all posts that have the given Sone as recipient.
-        *
-        * @see Post#getRecipient()
-        * @param recipient
-        *            The recipient of the posts
-        * @return All posts that have the given Sone as recipient
+        * {@inheritDoc}
         */
-       public Set<Post> getDirectedPosts(Sone recipient) {
-               checkNotNull(recipient, "recipient must not be null");
-               Set<Post> directedPosts = new HashSet<Post>();
+       @Override
+       public Collection<Post> getDirectedPosts(final String recipientId) {
+               checkNotNull(recipientId, "recipient must not be null");
                synchronized (posts) {
-                       for (Post post : posts.values()) {
-                               if (recipient.equals(post.getRecipient())) {
-                                       directedPosts.add(post);
+                       return Collections2.filter(posts.values(), new Predicate<Post>() {
+                               @Override
+                               public boolean apply(Post post) {
+                                       return (post.getRecipient() != null) && (post.getRecipient().getId().equals(recipientId));
                                }
-                       }
+                       });
                }
-               return directedPosts;
        }
        /**
         * Returns a post reply builder.
         *
         * {@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());
                                }
                        }
                }
                                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());
                        }
                        /* some local identity still trusts this identity, don’t remove. */
                        return;
                }
-               Sone sone = getSone(identity.getId(), false);
+               Sone sone = getSone(identity.getId());
                if (sone == null) {
                        /* TODO - we don’t have the Sone anymore. should this happen? */
                        return;
@@@ -31,12 -31,12 +31,12 @@@ import net.pterodactylus.sone.data.Albu
  import net.pterodactylus.sone.data.Client;
  import net.pterodactylus.sone.data.Image;
  import net.pterodactylus.sone.data.Post;
- import net.pterodactylus.sone.data.PostBuilder;
  import net.pterodactylus.sone.data.PostReply;
- import net.pterodactylus.sone.data.PostReplyBuilder;
  import net.pterodactylus.sone.data.Profile;
  import net.pterodactylus.sone.data.Sone;
  import net.pterodactylus.sone.data.Sone.SoneStatus;
+ import net.pterodactylus.sone.database.PostBuilder;
+ import net.pterodactylus.sone.database.PostReplyBuilder;
  import net.pterodactylus.util.io.Closer;
  import net.pterodactylus.util.logging.Logging;
  import net.pterodactylus.util.number.Numbers;
@@@ -166,7 -166,6 +166,7 @@@ public class SoneDownloader extends Abs
                        Sone parsedSone = parseSone(sone, fetchResults.getFetchResult(), fetchResults.getFreenetUri());
                        if (parsedSone != null) {
                                if (!fetchOnly) {
 +                                      parsedSone.setStatus((parsedSone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
                                        core.updateSone(parsedSone);
                                        addSone(parsedSone);
                                }
  
  package net.pterodactylus.sone.data.impl;
  
- import com.google.inject.Inject;
+ import net.pterodactylus.sone.database.PostBuilder;
+ import net.pterodactylus.sone.database.PostBuilderFactory;
+ import net.pterodactylus.sone.database.SoneProvider;
  
- import net.pterodactylus.sone.core.SoneProvider;
- import net.pterodactylus.sone.data.PostBuilder;
- import net.pterodactylus.sone.data.PostBuilderFactory;
++import com.google.inject.Inject;
 +
  /**
   * {@link PostBuilderFactory} implementation that creates
   * {@link PostBuilderImpl}s.
@@@ -40,7 -38,6 +40,7 @@@ public class DefaultPostBuilderFactory 
         * @param soneProvider
         *            The Sone provider
         */
 +      @Inject
        public DefaultPostBuilderFactory(SoneProvider soneProvider) {
                this.soneProvider = soneProvider;
        }
  
  package net.pterodactylus.sone.data.impl;
  
- import net.pterodactylus.sone.core.PostProvider;
- import net.pterodactylus.sone.core.SoneProvider;
  import net.pterodactylus.sone.data.Post;
  import net.pterodactylus.sone.data.PostReply;
+ import net.pterodactylus.sone.database.PostProvider;
+ import net.pterodactylus.sone.database.SoneProvider;
  
 +import com.google.common.base.Optional;
 +
  /**
   * Simple {@link PostReply} implementation.
   *
@@@ -66,18 -64,10 +66,18 @@@ public class PostReplyImpl extends Repl
        //
  
        /**
 +       * {@inheritDocs}
 +       */
 +      @Override
 +      public String getPostId() {
 +              return postId;
 +      }
 +
 +      /**
         * {@inheritDoc}
         */
        @Override
 -      public Post getPost() {
 +      public Optional<Post> getPost() {
                return postProvider.getPost(postId);
        }
  
index 0000000,865376b..13845da
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,50 +1,52 @@@
 -      public Post getPost(String postId);
+ /*
+  * Sone - PostProvider.java - Copyright © 2011–2013 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.database;
+ import java.util.Collection;
+ import net.pterodactylus.sone.data.Post;
++import com.google.common.base.Optional;
++
+ /**
+  * Interface for objects that can provide {@link Post}s by their ID.
+  *
+  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+  */
+ public interface PostProvider {
+       /**
+        * Returns the post with the given ID.
+        *
+        * @param postId
+        *            The ID of the post to return
+        * @return The post with the given ID, or {@code null}
+        */
++      public Optional<Post> getPost(String postId);
+       /**
+        * Returns all posts that have the given Sone as recipient.
+        *
+        * @see Post#getRecipient()
+        * @param recipientId
+        *            The ID of the recipient of the posts
+        * @return All posts that have the given Sone as recipient
+        */
+       public Collection<Post> getDirectedPosts(String recipientId);
+ }
index 0000000,2ad38a6..8098f1d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,50 +1,52 @@@
 -      public PostReply getPostReply(String id);
+ /*
+  * Sone - PostReplyProvider.java - Copyright © 2013 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.database;
+ import java.util.List;
+ import net.pterodactylus.sone.data.Post;
+ import net.pterodactylus.sone.data.PostReply;
++import com.google.common.base.Optional;
++
+ /**
+  * Interface for objects that can provide {@link PostReply}s.
+  *
+  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+  */
+ public interface PostReplyProvider {
+       /**
+        * Returns the reply with the given ID.
+        *
+        * @param id
+        *            The ID of the reply to get
+        * @return The reply, or {@code null} if there is no such reply
+        */
++      public Optional<PostReply> getPostReply(String id);
+       /**
+        * Returns all replies for the given post, order ascending by time.
+        *
+        * @param post
+        *            The post to get all replies for
+        * @return All replies for the given post
+        */
+       public List<PostReply> getReplies(Post post);
+ }
@@@ -33,7 -33,6 +33,7 @@@ import net.pterodactylus.sone.freenet.f
  import net.pterodactylus.sone.freenet.fcp.FcpException;
  import net.pterodactylus.sone.template.SoneAccessor;
  
 +import com.google.common.base.Optional;
  import com.google.common.collect.Collections2;
  
  import freenet.node.FSParseException;
@@@ -163,7 -162,7 +163,7 @@@ public abstract class AbstractSoneComma
                if (mandatory && (soneId == null)) {
                        throw new FcpException("Could not load Sone ID from “" + parameterName + "”.");
                }
-               Sone sone = localOnly ? core.getLocalSone(soneId, false) : core.getSone(soneId, false);
+               Sone sone = localOnly ? core.getLocalSone(soneId, false) : core.getSone(soneId);
                if (mandatory && (sone == null)) {
                        throw new FcpException("Could not load Sone from “" + soneId + "”.");
                }
        protected Post getPost(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
                try {
                        String postId = simpleFieldSet.getString(parameterName);
 -                      Post post = core.getPost(postId);
 -                      if (post == null) {
 +                      Optional<Post> post = core.getPost(postId);
 +                      if (!post.isPresent()) {
                                throw new FcpException("Could not load post from “" + postId + "”.");
                        }
 -                      return post;
 +                      return post.get();
                } catch (FSParseException fspe1) {
                        throw new FcpException("Could not post ID from “" + parameterName + "”.", fspe1);
                }
        protected PostReply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
                try {
                        String replyId = simpleFieldSet.getString(parameterName);
 -                      PostReply reply = core.getPostReply(replyId);
 -                      if (reply == null) {
 +                      Optional<PostReply> reply = core.getPostReply(replyId);
 +                      if (!reply.isPresent()) {
                                throw new FcpException("Could not load reply from “" + replyId + "”.");
                        }
 -                      return reply;
 +                      return reply.get();
                } catch (FSParseException fspe1) {
                        throw new FcpException("Could not reply ID from “" + parameterName + "”.", fspe1);
                }
@@@ -24,13 -24,13 +24,13 @@@ import java.util.logging.Logger
  
  import net.pterodactylus.sone.core.Core;
  import net.pterodactylus.sone.core.FreenetInterface;
- import net.pterodactylus.sone.core.PostProvider;
- import net.pterodactylus.sone.core.SoneProvider;
  import net.pterodactylus.sone.core.WebOfTrustUpdater;
- import net.pterodactylus.sone.data.PostBuilderFactory;
- import net.pterodactylus.sone.data.PostReplyBuilderFactory;
  import net.pterodactylus.sone.data.impl.DefaultPostBuilderFactory;
  import net.pterodactylus.sone.data.impl.DefaultPostReplyBuilderFactory;
+ import net.pterodactylus.sone.database.PostBuilderFactory;
+ import net.pterodactylus.sone.database.PostProvider;
+ import net.pterodactylus.sone.database.PostReplyBuilderFactory;
+ import net.pterodactylus.sone.database.SoneProvider;
  import net.pterodactylus.sone.fcp.FcpInterface;
  import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend;
  import net.pterodactylus.sone.freenet.plugin.PluginConnector;
@@@ -213,7 -213,6 +213,7 @@@ public class SonePlugin implements Fred
  
                        @Override
                        protected void configure() {
 +                              bind(Core.class).in(Singleton.class);
                                bind(EventBus.class).toInstance(eventBus);
                                bind(Configuration.class).toInstance(startConfiguration);
                                bind(FreenetInterface.class).in(Singleton.class);
@@@ -26,14 -26,12 +26,15 @@@ import java.util.logging.Logger
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
- import com.google.common.base.Optional;
- import net.pterodactylus.sone.core.PostProvider;
- import net.pterodactylus.sone.core.SoneProvider;
  import net.pterodactylus.sone.data.Post;
  import net.pterodactylus.sone.data.Sone;
+ import net.pterodactylus.sone.database.PostProvider;
+ import net.pterodactylus.sone.database.SoneProvider;
  import net.pterodactylus.util.io.Closer;
  import net.pterodactylus.util.logging.Logging;
++
++import com.google.common.base.Optional;
++
  import freenet.keys.FreenetURI;
  
  /**
@@@ -241,7 -239,7 +242,7 @@@ public class SoneTextParser implements 
                                        if (linkType == LinkType.SONE) {
                                                if (line.length() >= (7 + 43)) {
                                                        String soneId = line.substring(7, 50);
-                                                       Sone sone = soneProvider.getSone(soneId, false);
+                                                       Sone sone = soneProvider.getSone(soneId);
                                                        if (sone == null) {
                                                                /*
                                                                 * don’t use create=true above, we don’t want
                                        if (linkType == LinkType.POST) {
                                                if (line.length() >= (7 + 36)) {
                                                        String postId = line.substring(7, 43);
 -                                                      Post post = postProvider.getPost(postId);
 -                                                      if ((post != null) && (post.getSone() != null)) {
 -                                                              parts.add(new PostPart(post));
 +                                                      Optional<Post> post = postProvider.getPost(postId);
 +                                                      if (post.isPresent()) {
 +                                                              parts.add(new PostPart(post.get()));
                                                        } else {
                                                                parts.add(new PlainTextPart(line.substring(0, 43)));
                                                        }
@@@ -27,8 -27,6 +27,8 @@@ import net.pterodactylus.sone.web.page.
  import net.pterodactylus.util.template.Template;
  import net.pterodactylus.util.template.TemplateContext;
  
 +import com.google.common.base.Optional;
 +
  /**
   * Page that lets the user mark a number of {@link Sone}s, {@link Post}s, or
   * {@link Reply Replie}s as known.
@@@ -67,19 -65,19 +67,19 @@@ public class MarkAsKnownPage extends So
                for (StringTokenizer idTokenizer = new StringTokenizer(ids); idTokenizer.hasMoreTokens();) {
                        String id = idTokenizer.nextToken();
                        if (type.equals("post")) {
 -                              Post post = webInterface.getCore().getPost(id);
 -                              if (post == null) {
 +                              Optional<Post> post = webInterface.getCore().getPost(id);
 +                              if (!post.isPresent()) {
                                        continue;
                                }
 -                              webInterface.getCore().markPostKnown(post);
 +                              webInterface.getCore().markPostKnown(post.get());
                        } else if (type.equals("reply")) {
 -                              PostReply reply = webInterface.getCore().getPostReply(id);
 -                              if (reply == null) {
 +                              Optional<PostReply> reply = webInterface.getCore().getPostReply(id);
 +                              if (!reply.isPresent()) {
                                        continue;
                                }
 -                              webInterface.getCore().markReplyKnown(reply);
 +                              webInterface.getCore().markReplyKnown(reply.get());
                        } else if (type.equals("sone")) {
-                               Sone sone = webInterface.getCore().getSone(id, false);
+                               Sone sone = webInterface.getCore().getSone(id);
                                if (sone == null) {
                                        continue;
                                }
@@@ -44,7 -44,6 +44,7 @@@ import net.pterodactylus.util.text.Stri
  import net.pterodactylus.util.text.TextException;
  
  import com.google.common.base.Function;
 +import com.google.common.base.Optional;
  import com.google.common.base.Predicate;
  import com.google.common.cache.CacheBuilder;
  import com.google.common.cache.CacheLoader;
@@@ -310,7 -309,7 +310,7 @@@ public class SearchPage extends SoneTem
         */
        private String getSoneId(String phrase) {
                String soneId = phrase.startsWith("sone://") ? phrase.substring(7) : phrase;
-               return (webInterface.getCore().getSone(soneId, false) != null) ? soneId : null;
+               return (webInterface.getCore().getSone(soneId) != null) ? soneId : null;
        }
  
        /**
         */
        private String getPostId(String phrase) {
                String postId = phrase.startsWith("post://") ? phrase.substring(7) : phrase;
 -              return (webInterface.getCore().getPost(postId) != null) ? postId : null;
 +              return (webInterface.getCore().getPost(postId).isPresent()) ? postId : null;
        }
  
        /**
         */
        private String getReplyPostId(String phrase) {
                String replyId = phrase.startsWith("reply://") ? phrase.substring(8) : phrase;
 -              return (webInterface.getCore().getPostReply(replyId) != null) ? webInterface.getCore().getPostReply(replyId).getPost().getId() : null;
 +              Optional<PostReply> postReply = webInterface.getCore().getPostReply(replyId);
 +              if (!postReply.isPresent()) {
 +                      return null;
 +              }
 +              return postReply.get().getPostId();
        }
  
        /**
@@@ -36,8 -36,6 +36,8 @@@ import net.pterodactylus.util.number.Nu
  import net.pterodactylus.util.template.Template;
  import net.pterodactylus.util.template.TemplateContext;
  
 +import com.google.common.base.Optional;
 +
  /**
   * Lets the user browser another Sone.
   *
@@@ -67,7 -65,7 +67,7 @@@ public class ViewSonePage extends SoneT
        @Override
        protected String getPageTitle(FreenetRequest request) {
                String soneId = request.getHttpRequest().getParam("sone");
-               Sone sone = webInterface.getCore().getSone(soneId, false);
+               Sone sone = webInterface.getCore().getSone(soneId);
                if ((sone != null) && (sone.getTime() > 0)) {
                        String soneName = SoneAccessor.getNiceName(sone);
                        return soneName + " - " + webInterface.getL10n().getString("Page.ViewSone.Title");
        protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
                super.processTemplate(request, templateContext);
                String soneId = request.getHttpRequest().getParam("sone");
-               Sone sone = webInterface.getCore().getSone(soneId, false);
+               Sone sone = webInterface.getCore().getSone(soneId);
                templateContext.set("sone", sone);
                templateContext.set("soneId", soneId);
                if (sone == null) {
                        return;
                }
                List<Post> sonePosts = sone.getPosts();
-               sonePosts.addAll(webInterface.getCore().getDirectedPosts(sone));
+               sonePosts.addAll(webInterface.getCore().getDirectedPosts(sone.getId()));
                Collections.sort(sonePosts, Post.TIME_COMPARATOR);
                Pagination<Post> postPagination = new Pagination<Post>(sonePosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("postPage"), 0));
                templateContext.set("postPagination", postPagination);
                Set<PostReply> replies = sone.getReplies();
                final Map<Post, List<PostReply>> repliedPosts = new HashMap<Post, List<PostReply>>();
                for (PostReply reply : replies) {
 -                      Post post = reply.getPost();
 -                      if (repliedPosts.containsKey(post) || sone.equals(post.getSone()) || (sone.equals(post.getRecipient()))) {
 +                      Optional<Post> post = reply.getPost();
 +                      if (!post.isPresent() || repliedPosts.containsKey(post.get()) || sone.equals(post.get().getSone()) || (sone.equals(post.get().getRecipient()))) {
                                continue;
                        }
 -                      repliedPosts.put(post, webInterface.getCore().getReplies(post));
 +                      repliedPosts.put(post.get(), webInterface.getCore().getReplies(post.get()));
                }
                List<Post> posts = new ArrayList<Post>(repliedPosts.keySet());
                Collections.sort(posts, new Comparator<Post>() {
@@@ -74,7 -74,7 +74,7 @@@ public class GetStatusAjaxPage extends 
                        String[] soneIds = loadSoneIds.split(",");
                        for (String soneId : soneIds) {
                                /* just add it, we skip null further down. */
-                               sones.add(webInterface.getCore().getSone(soneId, false));
+                               sones.add(webInterface.getCore().getSone(soneId));
                        }
                }
                JsonArray jsonSones = new JsonArray();
                        });
                }
                /* remove replies to unknown posts. */
 -              newReplies = Collections2.filter(newReplies, new Predicate<PostReply>() {
 -
 -                      @Override
 -                      public boolean apply(PostReply reply) {
 -                              return (reply.getPost() != null) && (reply.getPost().getSone() != null);
 -                      }
 -              });
 +              newReplies = Collections2.filter(newReplies, PostReply.HAS_POST_FILTER);
                JsonArray jsonReplies = new JsonArray();
                for (PostReply reply : newReplies) {
                        JsonObject jsonReply = new JsonObject();
                        jsonReply.put("id", reply.getId());
                        jsonReply.put("sone", reply.getSone().getId());
 -                      jsonReply.put("post", reply.getPost().getId());
 -                      jsonReply.put("postSone", reply.getPost().getSone().getId());
 +                      jsonReply.put("post", reply.getPostId());
 +                      jsonReply.put("postSone", reply.getPost().get().getSone().getId());
                        jsonReplies.add(jsonReply);
                }
                return createSuccessJsonObject().put("loggedIn", currentSone != null).put("options", createJsonOptions(currentSone)).put("sones", jsonSones).put("notificationHash", notifications.hashCode()).put("newPosts", jsonPosts).put("newReplies", jsonReplies);
@@@ -26,8 -26,6 +26,8 @@@ import net.pterodactylus.sone.web.WebIn
  import net.pterodactylus.sone.web.page.FreenetRequest;
  import net.pterodactylus.util.json.JsonObject;
  
 +import com.google.common.base.Optional;
 +
  /**
   * AJAX page that lets the user mark a number of {@link Sone}s, {@link Post}s,
   * or {@link Reply}s as known.
@@@ -59,19 -57,19 +59,19 @@@ public class MarkAsKnownAjaxPage extend
                Core core = webInterface.getCore();
                for (String id : ids) {
                        if (type.equals("post")) {
 -                              Post post = core.getPost(id);
 -                              if (post == null) {
 +                              Optional<Post> post = core.getPost(id);
 +                              if (!post.isPresent()) {
                                        continue;
                                }
 -                              core.markPostKnown(post);
 +                              core.markPostKnown(post.get());
                        } else if (type.equals("reply")) {
 -                              PostReply reply = core.getPostReply(id);
 -                              if (reply == null) {
 +                              Optional<PostReply> reply = core.getPostReply(id);
 +                              if (!reply.isPresent()) {
                                        continue;
                                }
 -                              core.markReplyKnown(reply);
 +                              core.markReplyKnown(reply.get());
                        } else if (type.equals("sone")) {
-                               Sone sone = core.getSone(id, false);
+                               Sone sone = core.getSone(id);
                                if (sone == null) {
                                        continue;
                                }