Merge commit 'fcabe38e9b3abacc0d580bf0513600858aee2eca' into less-critical
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 24 Jan 2013 05:10:32 +0000 (06:10 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 24 Jan 2013 05:10:32 +0000 (06:10 +0100)
Conflicts:
src/main/java/net/pterodactylus/sone/core/Core.java

22 files changed:
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/PostReplyProvider.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
src/main/java/net/pterodactylus/sone/core/SoneUri.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/PostReply.java
src/main/java/net/pterodactylus/sone/data/PostReplyBuilder.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/PostReplyBuilderFactory.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/ReplyBuilder.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/impl/AbstractReplyBuilder.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReplyBuilderFactory.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/impl/PostReplyBuilderImpl.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.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/web/DeleteReplyPage.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/ajax/DeleteReplyAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java

index 4356120..f056c0e 100644 (file)
@@ -59,6 +59,8 @@ 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;
@@ -66,7 +68,6 @@ import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
 import net.pterodactylus.sone.data.Sone.SoneStatus;
 import net.pterodactylus.sone.data.TemporaryImage;
-import net.pterodactylus.sone.data.impl.PostReplyImpl;
 import net.pterodactylus.sone.fcp.FcpInterface;
 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
 import net.pterodactylus.sone.freenet.wot.Identity;
@@ -103,7 +104,7 @@ import freenet.keys.FreenetURI;
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
-public class Core extends AbstractService implements SoneProvider, PostProvider {
+public class Core extends AbstractService implements SoneProvider, PostProvider, PostReplyProvider {
 
        /** The logger. */
        private static final Logger logger = Logging.getLogger(Core.class);
@@ -181,6 +182,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
        /** All known posts. */
        private final Set<String> knownPosts = new HashSet<String>();
 
+       /** The post reply builder factory. */
+       private final PostReplyBuilderFactory postReplyBuilderFactory;
+
        /** All replies. */
        private final Map<String, PostReply> replies = new HashMap<String, PostReply>();
 
@@ -224,9 +228,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
         *            The event bus
         * @param postBuilderFactory
         *            The post builder
+        * @param postReplyBuilderFactory
+        *            The post reply builder factory
         */
        @Inject
-       public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, PostBuilderFactory postBuilderFactory) {
+       public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, PostBuilderFactory postBuilderFactory, PostReplyBuilderFactory postReplyBuilderFactory) {
                super("Sone Core");
                this.configuration = configuration;
                this.freenetInterface = freenetInterface;
@@ -237,6 +243,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                this.webOfTrustUpdater = webOfTrustUpdater;
                this.eventBus = eventBus;
                this.postBuilderFactory = postBuilderFactory;
+               this.postReplyBuilderFactory = postReplyBuilderFactory;
        }
 
        //
@@ -561,35 +568,28 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
        }
 
        /**
-        * Returns the reply with the given ID. If there is no reply with the given
-        * ID yet, a new one is created, unless {@code create} is false in which
-        * case {@code null} is returned.
+        * Returns a post reply builder.
         *
-        * @param replyId
-        *            The ID of the reply to get
-        * @param create
-        *            {@code true} to always return a {@link Reply}, {@code false}
-        *            to return {@code null} if no reply can be found
-        * @return The reply, or {@code null} if there is no such reply
+        * @return A new post reply builder
         */
-       public PostReply getPostReply(String replyId, boolean create) {
+       public PostReplyBuilder postReplyBuilder() {
+               return postReplyBuilderFactory.newPostReplyBuilder();
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostReply getPostReply(String replyId) {
                synchronized (replies) {
-                       PostReply reply = replies.get(replyId);
-                       if (create && (reply == null)) {
-                               reply = new PostReplyImpl(replyId);
-                               replies.put(replyId, reply);
-                       }
-                       return reply;
+                       return replies.get(replyId);
                }
        }
 
        /**
-        * 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
+        * {@inheritDoc}
         */
+       @Override
        public List<PostReply> getReplies(final Post post) {
                return Ordering.from(Reply.TIME_COMPARATOR).sortedCopy(FluentIterable.from(getSones()).transformAndConcat(new Function<Sone, Iterable<PostReply>>() {
 
@@ -876,7 +876,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                synchronized (sones) {
                        final Sone sone = getRemoteSone(identity.getId(), true).setIdentity(identity);
                        boolean newSone = sone.getRequestUri() == null;
-                       sone.setRequestUri(getSoneUri(identity.getRequestUri()));
+                       sone.setRequestUri(SoneUri.create(identity.getRequestUri()));
                        sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0));
                        if (newSone) {
                                synchronized (knownSones) {
@@ -1334,7 +1334,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                                logger.log(Level.WARNING, "Invalid reply found, aborting load!");
                                return;
                        }
-                       replies.add(getPostReply(replyId, true).setSone(sone).setPost(getPost(postId)).setTime(replyTime).setText(replyText));
+                       PostReplyBuilder postReplyBuilder = postReplyBuilderFactory.newPostReplyBuilder();
+                       postReplyBuilder.withId(replyId).from(sone).to(postId).withTime(replyTime).withText(replyText);
+                       replies.add(postReplyBuilder.build());
                }
 
                /* load post likes. */
@@ -1659,30 +1661,15 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
         * @return The created reply
         */
        public PostReply createReply(Sone sone, Post post, String text) {
-               return createReply(sone, post, System.currentTimeMillis(), text);
-       }
-
-       /**
-        * Creates a new reply.
-        *
-        * @param sone
-        *            The Sone that creates the reply
-        * @param post
-        *            The post that this reply refers to
-        * @param time
-        *            The time of the reply
-        * @param text
-        *            The text of the reply
-        * @return The created reply
-        */
-       public PostReply createReply(Sone sone, Post post, long time, String text) {
                checkNotNull(text, "text must not be null");
                checkArgument(text.trim().length() > 0, "text must not be empty");
                if (!sone.isLocal()) {
                        logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone));
                        return null;
                }
-               final PostReply reply = new PostReplyImpl(sone, post, System.currentTimeMillis(), text.trim());
+               PostReplyBuilder postReplyBuilder = postReplyBuilderFactory.newPostReplyBuilder();
+               postReplyBuilder.randomId().from(sone).to(post.getId()).currentTime().withText(text.trim());
+               final PostReply reply = postReplyBuilder.build();
                synchronized (replies) {
                        replies.put(reply.getId(), reply);
                }
@@ -2322,23 +2309,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
        }
 
        /**
-        * Generate a Sone URI from the given URI and latest edition.
-        *
-        * @param uriString
-        *            The URI to derive the Sone URI from
-        * @return The derived URI
-        */
-       private static FreenetURI getSoneUri(String uriString) {
-               try {
-                       FreenetURI uri = new FreenetURI(uriString).setDocName("Sone").setMetaString(new String[0]);
-                       return uri;
-               } catch (MalformedURLException mue1) {
-                       logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString), mue1);
-                       return null;
-               }
-       }
-
-       /**
         * Notifies the core that a new {@link OwnIdentity} was added.
         *
         * @param ownIdentityAddedEvent
diff --git a/src/main/java/net/pterodactylus/sone/core/PostReplyProvider.java b/src/main/java/net/pterodactylus/sone/core/PostReplyProvider.java
new file mode 100644 (file)
index 0000000..9854b6c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.core;
+
+import java.util.List;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+
+/**
+ * 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 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);
+
+}
index 36b672c..cf85d03 100644 (file)
@@ -33,6 +33,7 @@ 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;
@@ -406,7 +407,10 @@ public class SoneDownloader extends AbstractService {
                                        return null;
                                }
                                try {
-                                       replies.add(core.getPostReply(replyId, true).setSone(sone).setPost(core.getPost(replyPostId)).setTime(Long.parseLong(replyTime)).setText(replyText));
+                                       PostReplyBuilder postReplyBuilder = core.postReplyBuilder();
+                                       /* TODO - parse time correctly. */
+                                       postReplyBuilder.withId(replyId).from(sone).to(replyPostId).withTime(Long.parseLong(replyTime)).withText(replyText);
+                                       replies.add(postReplyBuilder.build());
                                } catch (NumberFormatException nfe1) {
                                        /* TODO - mark Sone as bad. */
                                        logger.log(Level.WARNING, String.format("Downloaded reply for Sone %s with invalid time: %s", sone, replyTime));
diff --git a/src/main/java/net/pterodactylus/sone/core/SoneUri.java b/src/main/java/net/pterodactylus/sone/core/SoneUri.java
new file mode 100644 (file)
index 0000000..6c5bf16
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Sone - SoneUri.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.core;
+
+import java.net.MalformedURLException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.pterodactylus.util.logging.Logging;
+import freenet.keys.FreenetURI;
+
+/**
+ * Helper class that creates {@link FreenetURI}s for Sone to insert to and
+ * request from.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneUri {
+
+       /** The logger. */
+       private static final Logger logger = Logging.getLogger(SoneUri.class);
+
+       /**
+        * Generate a Sone URI from the given URI.
+        *
+        * @param uri
+        *            The URI to derive the Sone URI from
+        * @return The derived URI
+        */
+       public static FreenetURI create(String uri) {
+               try {
+                       return new FreenetURI(uri).setDocName("Sone").setMetaString(new String[0]);
+               } catch (MalformedURLException mue1) {
+                       /* this should never happen. */
+                       logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uri), mue1);
+                       return null;
+               }
+       }
+
+}
index a4d9ef3..4452e2e 100644 (file)
@@ -35,10 +35,10 @@ public interface PostReply extends Reply<PostReply> {
        /**
         * Sets the post this reply refers to.
         *
-        * @param post
-        *            The post this reply refers to
+        * @param postId
+        *            The ID of the post to reply to
         * @return This reply
         */
-       public PostReply setPost(Post post);
+       public PostReply setPost(String postId);
 
 }
diff --git a/src/main/java/net/pterodactylus/sone/data/PostReplyBuilder.java b/src/main/java/net/pterodactylus/sone/data/PostReplyBuilder.java
new file mode 100644 (file)
index 0000000..1ba7fd5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Sone - PostReplyBuilder.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.data;
+
+/**
+ * Builder for a {@link PostReply} object.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostReplyBuilder extends ReplyBuilder<PostReplyBuilder> {
+
+       /**
+        * Configures this builder to set the given post as post the created reply
+        * refers to.
+        *
+        * @param postId
+        *            The ID of the post the reply refers to
+        * @return This builder
+        */
+       public PostReplyBuilder to(String postId);
+
+       /**
+        * Verifies the configuration of this builder and creates a new post reply.
+        * <p>
+        * The following conditions must be met in order for the configuration to be
+        * considered valid:
+        * <ul>
+        * <li>Exactly one of {@link #randomId()} or {@link #withId(String)} must
+        * have been called.</li>
+        * <li>The {@link #from(Sone) sender} must not be {@code null}.</li>
+        * <li>Exactly one of {@link #currentTime()} or {@link #withTime(long)} must
+        * have been called.</li>
+        * <li>The {@link #withText(String) text} must not be {@code null} and must
+        * contain something other than whitespace.</li>
+        * <li>The {@link #to(String) post} have been set.</li>
+        * </ul>
+        *
+        * @return The created post reply
+        * @throws IllegalStateException
+        *             if this builder’s configuration is not valid
+        */
+       public PostReply build() throws IllegalStateException;
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/PostReplyBuilderFactory.java b/src/main/java/net/pterodactylus/sone/data/PostReplyBuilderFactory.java
new file mode 100644 (file)
index 0000000..17a92f3
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Sone - PostReplyBuilderFactory.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.data;
+
+/**
+ * Factory for {@link PostReplyBuilder}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostReplyBuilderFactory {
+
+       /**
+        * Creates a new post reply builder.
+        *
+        * @return A new post reply builder
+        */
+       public PostReplyBuilder newPostReplyBuilder();
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/ReplyBuilder.java b/src/main/java/net/pterodactylus/sone/data/ReplyBuilder.java
new file mode 100644 (file)
index 0000000..53f3153
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Sone - ReplyBuilder.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.data;
+
+/**
+ * Methods that all reply builders need to implement in order to be able to
+ * create any kind of {@link Reply}.
+ *
+ * @param <B>
+ *            The type of the builder
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface ReplyBuilder<B extends ReplyBuilder<B>> {
+
+       /**
+        * Configures this builder to use a random ID when creating the reply. If
+        * this method is used, {@link #withId(String)} must not be used.
+        *
+        * @return This builder
+        */
+       public B randomId();
+
+       /**
+        * Configures this builder to use the given ID when creating the reply. If
+        * this method is used, {@link #randomId()} must not be used.
+        *
+        * @param id
+        *            The ID of the reply
+        * @return This builder
+        */
+       public B withId(String id);
+
+       /**
+        * Configures this builder to use the given {@link Sone} as sender of the
+        * reply.
+        *
+        * @param sender
+        *            The sender of the reply
+        * @return This builder
+        */
+       public B from(Sone sender);
+
+       /**
+        * Configures this builder to use the current time when creating the reply.
+        * If this method is used, {@link #withTime(long)} must not be used.
+        *
+        * @return This builder
+        */
+       public B currentTime();
+
+       /**
+        * Configures this builder to use the given time when creating the reply. If
+        * this method is used, {@link #currentTime()} must not be used.
+        *
+        * @param time
+        *            The time of the reply
+        * @return This builder
+        */
+       public B withTime(long time);
+
+       /**
+        * Configures this builder to use the given text when creating the reply.
+        *
+        * @param text
+        *            The text of the reply
+        * @return This builder
+        */
+       public B withText(String text);
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AbstractReplyBuilder.java b/src/main/java/net/pterodactylus/sone/data/impl/AbstractReplyBuilder.java
new file mode 100644 (file)
index 0000000..e04e854
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Sone - ReplyBuilder.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.data.impl;
+
+import net.pterodactylus.sone.data.ReplyBuilder;
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * Abstract implementation of a {@link ReplyBuilder}.
+ *
+ * @param <B>
+ *            The interface implemented and exposed by the builder
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class AbstractReplyBuilder<B extends ReplyBuilder<B>> implements ReplyBuilder<B> {
+
+       /** Whether to use a random ID for the reply. */
+       protected boolean randomId;
+
+       /** The ID of the reply. */
+       protected String id;
+
+       /** The sender of the reply. */
+       protected Sone sender;
+
+       /** Whether to use the current time when creating the reply. */
+       protected boolean currentTime;
+
+       /** The time of the reply. */
+       protected long time;
+
+       /** The text of the reply. */
+       protected String text;
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       @SuppressWarnings("unchecked")
+       public B randomId() {
+               this.randomId = true;
+               return (B) this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       @SuppressWarnings("unchecked")
+       public B withId(String id) {
+               this.id = id;
+               return (B) this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       @SuppressWarnings("unchecked")
+       public B from(Sone sender) {
+               this.sender = sender;
+               return (B) this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       @SuppressWarnings("unchecked")
+       public B currentTime() {
+               this.currentTime = true;
+               return (B) this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       @SuppressWarnings("unchecked")
+       public B withTime(long time) {
+               this.time = time;
+               return (B) this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       @SuppressWarnings("unchecked")
+       public B withText(String text) {
+               this.text = text;
+               return (B) this;
+       }
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReplyBuilderFactory.java b/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReplyBuilderFactory.java
new file mode 100644 (file)
index 0000000..80bc3c7
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Sone - DefaultPostReplyBuilderFactory.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.data.impl;
+
+import net.pterodactylus.sone.core.PostProvider;
+import net.pterodactylus.sone.data.PostReplyBuilder;
+import net.pterodactylus.sone.data.PostReplyBuilderFactory;
+
+import com.google.inject.Inject;
+
+/**
+ * {@link PostReplyBuilderFactory} that creates {@link PostReplyBuilderImpl}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DefaultPostReplyBuilderFactory implements PostReplyBuilderFactory {
+
+       /** The post provider. */
+       private final PostProvider postProvider;
+
+       /**
+        * Creates a new default post reply builder factory.
+        *
+        * @param postProvider
+        *            The post provider
+        */
+       @Inject
+       public DefaultPostReplyBuilderFactory(PostProvider postProvider) {
+               this.postProvider = postProvider;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostReplyBuilder newPostReplyBuilder() {
+               return new PostReplyBuilderImpl(postProvider);
+       }
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostReplyBuilderImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostReplyBuilderImpl.java
new file mode 100644 (file)
index 0000000..18ce200
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Sone - PostReplyBuilderImpl.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.data.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.UUID;
+
+import net.pterodactylus.sone.core.PostProvider;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.PostReplyBuilder;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * {@link PostReplyBuilder} implementation that creates {@link PostReplyImpl}
+ * objects.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostReplyBuilderImpl extends AbstractReplyBuilder<PostReplyBuilder> implements PostReplyBuilder {
+
+       /** The post builder. */
+       private final PostProvider postProvider;
+
+       /** The ID of the post the created reply refers to. */
+       private String postId;
+
+       /**
+        * Creates a new post reply builder.
+        *
+        * @param postProvider
+        *            The post provider
+        */
+       public PostReplyBuilderImpl(PostProvider postProvider) {
+               this.postProvider = postProvider;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostReplyBuilder to(String postId) {
+               this.postId = postId;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostReply build() {
+               checkState((randomId && (id == null)) || (!randomId && (id != null)), "either random ID nor custom ID must be set");
+               checkState(sender != null, "sender must not be null");
+               checkState((currentTime && (time == 0)) || (!currentTime && (time >= 0)), "either current time or custom time must be set");
+               checkState(!StringUtils.isBlank(text), "text must not be empty");
+               checkState(postId != null, "post must not be null");
+
+               /* create new post reply. */
+               PostReplyImpl postReplyImpl = new PostReplyImpl(postProvider, randomId ? UUID.randomUUID().toString() : id);
+               postReplyImpl.setSone(sender);
+               postReplyImpl.setPost(postId);
+               postReplyImpl.setTime(currentTime ? System.currentTimeMillis() : time);
+               postReplyImpl.setText(text);
+               return postReplyImpl;
+       }
+}
index 0e66a8f..361a2e9 100644 (file)
 
 package net.pterodactylus.sone.data.impl;
 
-import java.util.UUID;
-
+import net.pterodactylus.sone.core.PostProvider;
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
-import net.pterodactylus.sone.data.Sone;
 
 /**
  * Simple {@link PostReply} implementation.
@@ -30,66 +28,24 @@ import net.pterodactylus.sone.data.Sone;
  */
 public class PostReplyImpl extends ReplyImpl<PostReply> implements PostReply {
 
-       /** The Post this reply refers to. */
-       private volatile Post post;
+       /** The post provider. */
+       private final PostProvider postProvider;
 
-       /**
-        * Creates a new reply.
-        *
-        * @param id
-        *            The ID of the reply
-        */
-       public PostReplyImpl(String id) {
-               this(id, null, null, 0, null);
-       }
+       /** The Post this reply refers to. */
+       private volatile String postId;
 
        /**
         * Creates a new reply.
         *
-        * @param sone
-        *            The sone that posted the reply
-        * @param post
-        *            The post to reply to
-        * @param text
-        *            The text of the reply
-        */
-       public PostReplyImpl(Sone sone, Post post, String text) {
-               this(sone, post, System.currentTimeMillis(), text);
-       }
-
-       /**
-        * Creates a new reply-
-        *
-        * @param sone
-        *            The sone that posted the reply
-        * @param post
-        *            The post to reply to
-        * @param time
-        *            The time of the reply
-        * @param text
-        *            The text of the reply
-        */
-       public PostReplyImpl(Sone sone, Post post, long time, String text) {
-               this(UUID.randomUUID().toString(), sone, post, time, text);
-       }
-
-       /**
-        * Creates a new reply-
-        *
-        * @param sone
-        *            The sone that posted the reply
+        * @param postProvider
+        *            The post provider
         * @param id
         *            The ID of the reply
-        * @param post
-        *            The post to reply to
-        * @param time
-        *            The time of the reply
-        * @param text
-        *            The text of the reply
         */
-       public PostReplyImpl(String id, Sone sone, Post post, long time, String text) {
-               super(id, sone, time, text);
-               this.post = post;
+       public PostReplyImpl(PostProvider postProvider, String id) {
+               super(id);
+               this.postProvider = postProvider;
+               this.postId = postId;
        }
 
        //
@@ -101,19 +57,19 @@ public class PostReplyImpl extends ReplyImpl<PostReply> implements PostReply {
         */
        @Override
        public Post getPost() {
-               return post;
+               return postProvider.getPost(postId);
        }
 
        /**
         * Sets the post this reply refers to.
         *
-        * @param post
-        *            The post this reply refers to
+        * @param postId
+        *            The ID of the post to reply to
         * @return This reply (for method chaining)
         */
        @Override
-       public PostReply setPost(Post post) {
-               this.post = post;
+       public PostReply setPost(String postId) {
+               this.postId = postId;
                return this;
        }
 
index b9ff03c..80802ad 100644 (file)
@@ -211,7 +211,7 @@ public abstract class AbstractSoneCommand extends AbstractCommand {
        protected PostReply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
                try {
                        String replyId = simpleFieldSet.getString(parameterName);
-                       PostReply reply = core.getPostReply(replyId, false);
+                       PostReply reply = core.getPostReply(replyId);
                        if (reply == null) {
                                throw new FcpException("Could not load reply from “" + replyId + "”.");
                        }
index 1080818..1114c42 100644 (file)
@@ -24,9 +24,12 @@ 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.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.fcp.FcpInterface;
 import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend;
 import net.pterodactylus.sone.freenet.plugin.PluginConnector;
@@ -220,6 +223,8 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr
                                bind(SonePlugin.class).toInstance(SonePlugin.this);
                                bind(FcpInterface.class).in(Singleton.class);
                                bind(PostBuilderFactory.class).to(DefaultPostBuilderFactory.class).in(Singleton.class);
+                               bind(PostReplyBuilderFactory.class).to(DefaultPostReplyBuilderFactory.class).in(Singleton.class);
+                               bind(PostProvider.class).to(Core.class).in(Singleton.class);
                                bindListener(Matchers.any(), new TypeListener() {
 
                                        @Override
index 8c07716..25a9e0b 100644 (file)
@@ -53,7 +53,7 @@ public class DeleteReplyPage extends SoneTemplatePage {
        protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
                super.processTemplate(request, templateContext);
                String replyId = request.getHttpRequest().getPartAsStringFailsafe("reply", 36);
-               PostReply reply = webInterface.getCore().getPostReply(replyId, false);
+               PostReply reply = webInterface.getCore().getPostReply(replyId);
                String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
                if (request.getMethod() == Method.POST) {
                        if (!reply.getSone().isLocal()) {
index fe50509..0bf5285 100644 (file)
@@ -71,7 +71,7 @@ public class MarkAsKnownPage extends SoneTemplatePage {
                                }
                                webInterface.getCore().markPostKnown(post);
                        } else if (type.equals("reply")) {
-                               PostReply reply = webInterface.getCore().getPostReply(id, false);
+                               PostReply reply = webInterface.getCore().getPostReply(id);
                                if (reply == null) {
                                        continue;
                                }
index 7352bab..337918d 100644 (file)
@@ -336,7 +336,7 @@ public class SearchPage extends SoneTemplatePage {
         */
        private String getReplyPostId(String phrase) {
                String replyId = phrase.startsWith("reply://") ? phrase.substring(8) : phrase;
-               return (webInterface.getCore().getPostReply(replyId, false) != null) ? webInterface.getCore().getPostReply(replyId, false).getPost().getId() : null;
+               return (webInterface.getCore().getPostReply(replyId) != null) ? webInterface.getCore().getPostReply(replyId).getPost().getId() : null;
        }
 
        /**
index 67bf901..b1a3317 100644 (file)
@@ -49,7 +49,7 @@ public class DeleteReplyAjaxPage extends JsonPage {
        @Override
        protected JsonObject createJsonObject(FreenetRequest request) {
                String replyId = request.getHttpRequest().getParam("reply");
-               PostReply reply = webInterface.getCore().getPostReply(replyId, false);
+               PostReply reply = webInterface.getCore().getPostReply(replyId);
                if (reply == null) {
                        return createErrorJsonObject("invalid-reply-id");
                }
index c1c532b..04191fa 100644 (file)
@@ -67,7 +67,7 @@ public class GetLikesAjaxPage extends JsonPage {
                        Set<Sone> sones = webInterface.getCore().getLikes(post);
                        return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones));
                } else if ("reply".equals(type)) {
-                       PostReply reply = webInterface.getCore().getPostReply(id, false);
+                       PostReply reply = webInterface.getCore().getPostReply(id);
                        Set<Sone> sones = webInterface.getCore().getLikes(reply);
                        return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones));
                }
index 99a7220..6139776 100644 (file)
@@ -62,7 +62,7 @@ public class GetReplyAjaxPage extends JsonPage {
        @Override
        protected JsonObject createJsonObject(FreenetRequest request) {
                String replyId = request.getHttpRequest().getParam("reply");
-               PostReply reply = webInterface.getCore().getPostReply(replyId, false);
+               PostReply reply = webInterface.getCore().getPostReply(replyId);
                if ((reply == null) || (reply.getSone() == null)) {
                        return createErrorJsonObject("invalid-reply-id");
                }
index 03bf8c5..13cf424 100644 (file)
@@ -77,7 +77,7 @@ public class GetTimesAjaxPage extends JsonPage {
                if (allIds.length() > 0) {
                        String[] ids = allIds.split(",");
                        for (String id : ids) {
-                               PostReply reply = webInterface.getCore().getPostReply(id, false);
+                               PostReply reply = webInterface.getCore().getPostReply(id);
                                if (reply == null) {
                                        continue;
                                }
index 18450b1..e9c582a 100644 (file)
@@ -63,7 +63,7 @@ public class MarkAsKnownAjaxPage extends JsonPage {
                                }
                                core.markPostKnown(post);
                        } else if (type.equals("reply")) {
-                               PostReply reply = core.getPostReply(id, false);
+                               PostReply reply = core.getPostReply(id);
                                if (reply == null) {
                                        continue;
                                }