Merge commit 'da609f721e54691f27113e877a19637bd332abc3' into less-critical
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 23 Jan 2013 21:57:30 +0000 (22:57 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 23 Jan 2013 21:57:30 +0000 (22:57 +0100)
20 files changed:
pom.xml
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/PostProvider.java
src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
src/main/java/net/pterodactylus/sone/data/Post.java
src/main/java/net/pterodactylus/sone/data/PostBuilder.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/PostBuilderFactory.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/impl/PostBuilderImpl.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/data/impl/PostImpl.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/ViewPostPage.java
src/main/java/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java

diff --git a/pom.xml b/pom.xml
index 6743885..d4637ff 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                        <artifactId>guava</artifactId>
                        <version>14.0-rc1</version>
                </dependency>
+               <dependency>
+                       <groupId>commons-lang</groupId>
+                       <artifactId>commons-lang</artifactId>
+                       <version>2.6</version>
+               </dependency>
        </dependencies>
        <repositories>
                <repository>
index a51247e..2a1ef8e 100644 (file)
@@ -56,6 +56,8 @@ import net.pterodactylus.sone.data.Album;
 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.Profile;
 import net.pterodactylus.sone.data.Profile.Field;
@@ -64,7 +66,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.PostImpl;
 import net.pterodactylus.sone.data.impl.PostReplyImpl;
 import net.pterodactylus.sone.fcp.FcpInterface;
 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
@@ -168,6 +169,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
        /** All known Sones. */
        private final Set<String> knownSones = new HashSet<String>();
 
+       /** The post builder. */
+       private final PostBuilderFactory postBuilderFactory;
+
        /** All posts. */
        private final Map<String, Post> posts = new HashMap<String, Post>();
 
@@ -215,9 +219,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
         *            The WebOfTrust updater
         * @param eventBus
         *            The event bus
+        * @param postBuilderFactory
+        *            The post builder
         */
        @Inject
-       public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus) {
+       public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, PostBuilderFactory postBuilderFactory) {
                super("Sone Core");
                this.configuration = configuration;
                this.freenetInterface = freenetInterface;
@@ -227,6 +233,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                this.updateChecker = new UpdateChecker(eventBus, freenetInterface);
                this.webOfTrustUpdater = webOfTrustUpdater;
                this.eventBus = eventBus;
+               this.postBuilderFactory = postBuilderFactory;
        }
 
        //
@@ -511,35 +518,21 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
        }
 
        /**
-        * Returns the post with the given ID.
+        * Returns a post builder.
         *
-        * @param postId
-        *            The ID of the post to get
-        * @return The post with the given ID, or a new post with the given ID
+        * @return A new post builder
         */
-       public Post getPost(String postId) {
-               return getPost(postId, true);
+       public PostBuilder postBuilder() {
+               return postBuilderFactory.newPostBuilder();
        }
 
        /**
-        * Returns the post with the given ID, optionally creating a new post.
-        *
-        * @param postId
-        *            The ID of the post to get
-        * @param create
-        *            {@code true} it create a new post if no post with the given ID
-        *            exists, {@code false} to return {@code null}
-        * @return The post, or {@code null} if there is no such post
+        * {@inheritDoc}
         */
        @Override
-       public Post getPost(String postId, boolean create) {
+       public Post getPost(String postId) {
                synchronized (posts) {
-                       Post post = posts.get(postId);
-                       if ((post == null) && create) {
-                               post = new PostImpl(postId);
-                               posts.put(postId, post);
-                       }
-                       return post;
+                       return posts.get(postId);
                }
        }
 
@@ -677,7 +670,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                Set<Post> posts = new HashSet<Post>();
                synchronized (bookmarkedPosts) {
                        for (String bookmarkedPostId : bookmarkedPosts) {
-                               Post post = getPost(bookmarkedPostId, false);
+                               Post post = getPost(bookmarkedPostId);
                                if (post != null) {
                                        posts.add(post);
                                }
@@ -1110,16 +1103,18 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                                List<Post> storedPosts = storedSone.getPosts();
                                synchronized (knownPosts) {
                                        for (Post post : sone.getPosts()) {
-                                               post.setSone(storedSone).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));
+                                               PostBuilder postBuilder = postBuilderFactory.newPostBuilder();
+                                               postBuilder.copyPost(post).from(storedSone);
+                                               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));
                                                        }
                                                }
-                                               posts.put(post.getId(), post);
+                                               posts.put(newPost.getId(), newPost);
                                        }
                                }
                        }
@@ -1312,11 +1307,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                                logger.log(Level.WARNING, "Invalid post found, aborting load!");
                                return;
                        }
-                       Post post = getPost(postId).setSone(sone).setTime(postTime).setText(postText);
+                       PostBuilder postBuilder = postBuilderFactory.newPostBuilder().withId(postId).from(sone).withTime(postTime).withText(postText);
                        if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
-                               post.setRecipient(getSone(postRecipientId));
+                               postBuilder.to(getSone(postRecipientId));
                        }
-                       posts.add(post);
+                       posts.add(postBuilder.build());
                }
 
                /* load replies. */
@@ -1538,10 +1533,12 @@ public class Core extends AbstractService implements SoneProvider, PostProvider
                        logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone));
                        return null;
                }
-               final Post post = new PostImpl(sone, time, text.trim());
+               PostBuilder postBuilder = postBuilderFactory.newPostBuilder();
+               postBuilder.from(sone).randomId().withTime(time).withText(text.trim());
                if (recipient != null) {
-                       post.setRecipient(recipient);
+                       postBuilder.to(recipient);
                }
+               final Post post = postBuilder.build();
                synchronized (posts) {
                        posts.put(post.getId(), post);
                }
index c73ad65..e7167cd 100644 (file)
@@ -27,17 +27,12 @@ import net.pterodactylus.sone.data.Post;
 public interface PostProvider {
 
        /**
-        * Returns the post with the given ID, if it exists. If it does not exist
-        * and {@code create} is {@code false}, {@code null} is returned; otherwise,
-        * a new post with the given ID is created and returned.
+        * Returns the post with the given ID.
         *
         * @param postId
         *            The ID of the post to return
-        * @param create
-        *            {@code true} to create a new post if no post with the given ID
-        *            exists, {@code false} to return {@code null} instead
         * @return The post with the given ID, or {@code null}
         */
-       public Post getPost(String postId, boolean create);
+       public Post getPost(String postId);
 
 }
index 70a193a..36b672c 100644 (file)
@@ -31,6 +31,7 @@ import net.pterodactylus.sone.data.Album;
 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.Profile;
 import net.pterodactylus.sone.data.Sone;
@@ -372,11 +373,13 @@ public class SoneDownloader extends AbstractService {
                                        return null;
                                }
                                try {
-                                       Post post = core.getPost(postId).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText);
+                                       PostBuilder postBuilder = core.postBuilder();
+                                       /* TODO - parse time correctly. */
+                                       postBuilder.withId(postId).from(sone).withTime(Long.parseLong(postTime)).withText(postText);
                                        if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
-                                               post.setRecipient(core.getSone(postRecipientId));
+                                               postBuilder.to(core.getSone(postRecipientId));
                                        }
-                                       posts.add(post);
+                                       posts.add(postBuilder.build());
                                } catch (NumberFormatException nfe1) {
                                        /* TODO - mark Sone as bad. */
                                        logger.log(Level.WARNING, String.format("Downloaded post for Sone %s with invalid time: %s", sone, postTime));
index 3486bed..160bb32 100644 (file)
@@ -68,15 +68,6 @@ public interface Post {
        public Sone getSone();
 
        /**
-        * Sets the Sone of this post.
-        *
-        * @param sone
-        *            The Sone of this post
-        * @return This post (for method chaining)
-        */
-       public Post setSone(Sone sone);
-
-       /**
         * Returns the recipient of this post, if any.
         *
         * @return The recipient of this post, or {@code null}
@@ -84,15 +75,6 @@ public interface Post {
        public Sone getRecipient();
 
        /**
-        * Sets the recipient of this post.
-        *
-        * @param recipient
-        *            The recipient of this post, or {@code null}
-        * @return This post (for method chaining)
-        */
-       public Post setRecipient(Sone recipient);
-
-       /**
         * Returns the time of the post.
         *
         * @return The time of the post (in milliseconds since Jan 1, 1970 UTC)
@@ -100,15 +82,6 @@ public interface Post {
        public long getTime();
 
        /**
-        * Sets the time of this post.
-        *
-        * @param time
-        *            The time of this post (in milliseconds since Jan 1, 1970 UTC)
-        * @return This post (for method chaining)
-        */
-       public Post setTime(long time);
-
-       /**
         * Returns the text of the post.
         *
         * @return The text of the post
@@ -116,15 +89,6 @@ public interface Post {
        public String getText();
 
        /**
-        * Sets the text of this post.
-        *
-        * @param text
-        *            The text of this post
-        * @return This post (for method chaining)
-        */
-       public Post setText(String text);
-
-       /**
         * Returns whether this post is known.
         *
         * @return {@code true} if this post is known, {@code false} otherwise
diff --git a/src/main/java/net/pterodactylus/sone/data/PostBuilder.java b/src/main/java/net/pterodactylus/sone/data/PostBuilder.java
new file mode 100644 (file)
index 0000000..00f7354
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Sone - PostBuilder.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 {@link Post} objects.
+ * <p>
+ * A {@link Post} consists of the following elements:
+ * <ul>
+ * <li>an ID,</li>
+ * <li>a {@link Sone sender},</li>
+ * <li>an optional {@link Sone recipient},</li>
+ * <li>a time,</li>
+ * <li>and a text.</li>
+ * </ul>
+ * Except for the recipient, all this elements have to be configured on this
+ * builder. For the ID you have the possibility to configure either a random ID
+ * (which should be used for new posts) or a custom ID you specify (for creating
+ * an existing post). For the time you can use the current time (again, for
+ * creating new posts) or the given time (for loading posts). It is an error to
+ * specify both ways for either the ID or the time.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostBuilder {
+
+       /**
+        * Copies all attributes of the given post to this post builder.
+        *
+        * @param post
+        *            The post whose attributes to copy into this builder
+        * @return This builder
+        * @throws NullPointerException
+        *             if {@code post} is {@code null}
+        */
+       public PostBuilder copyPost(Post post) throws NullPointerException;
+
+       /**
+        * Configures this builder to use the given Sone as sender of the new post.
+        *
+        * @param sender
+        *            The sender of the post
+        * @return This post builder
+        */
+       public PostBuilder from(Sone sender);
+
+       /**
+        * Configures this builder to use a random ID for the new post. If this
+        * method is used, {@link #withId(String)} must not be used.
+        *
+        * @return This post builder
+        */
+       public PostBuilder randomId();
+
+       /**
+        * Configures this builder to use the given ID as ID for the new post. If
+        * this method is used, {@link #randomId()} must not be used.
+        *
+        * @param id
+        *            The ID to use for the post
+        * @return This post builder
+        */
+       public PostBuilder withId(String id);
+
+       /**
+        * Configures this builder to use the current time when creating the post.
+        * If this method is used, {@link #withTime(long)} must not be used.
+        *
+        * @return This post builder
+        */
+       public PostBuilder currentTime();
+
+       /**
+        * Configures the builder to use the given time as time for the new post. If
+        * this method is used, {@link #currentTime()} must not be used.
+        *
+        * @param time
+        *            The time to use for the post
+        * @return This post builder
+        */
+       public PostBuilder withTime(long time);
+
+       /**
+        * Configures the builder to use the given text for the new post.
+        *
+        * @param text
+        *            The text to use for the post
+        * @return This post builder
+        */
+       public PostBuilder withText(String text);
+
+       /**
+        * Configures the builder to use the given {@link Sone} as recipient for the
+        * post.
+        *
+        * @param recipient
+        *            The recipient of the post
+        * @return This post builder
+        */
+       public PostBuilder to(Sone recipient);
+
+       /**
+        * Verifies this builder’s configuration and creates a new post.
+        * <p>
+        * The following conditions must be met in order for this builder to be
+        * configured correctly:
+        * <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(Sone) recipient} must either not have been set, or it
+        * must have been set to a {@link Sone} other than {@link #from(Sone) the
+        * sender}.</li>
+        * </ul>
+        *
+        * @return A new post
+        * @throws IllegalStateException
+        *             if this builder’s configuration is not valid
+        */
+       public Post build() throws IllegalStateException;
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/PostBuilderFactory.java b/src/main/java/net/pterodactylus/sone/data/PostBuilderFactory.java
new file mode 100644 (file)
index 0000000..845cdf6
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Sone - PostBuilderFactory.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 PostBuilder}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public interface PostBuilderFactory {
+
+       /**
+        * Creates a new post builder.
+        *
+        * @return A new post builder
+        */
+       public PostBuilder newPostBuilder();
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java b/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java
new file mode 100644 (file)
index 0000000..402b99a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Sone - DefaultPostBuilderFactory.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.PostBuilder;
+import net.pterodactylus.sone.data.PostBuilderFactory;
+
+/**
+ * {@link PostBuilderFactory} implementation that creates
+ * {@link PostBuilderImpl}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DefaultPostBuilderFactory implements PostBuilderFactory {
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder newPostBuilder() {
+               return new PostBuilderImpl();
+       }
+
+}
diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostBuilderImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostBuilderImpl.java
new file mode 100644 (file)
index 0000000..d407133
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Sone - PostBuilderImpl.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.data.Post;
+import net.pterodactylus.sone.data.PostBuilder;
+import net.pterodactylus.sone.data.Sone;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * {@link PostBuilder} implementation that creates {@link PostImpl} objects.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostBuilderImpl implements PostBuilder {
+
+       /** Wether to create a post with a random ID. */
+       private boolean randomId;
+
+       /** The ID of the post. */
+       private String id;
+
+       /** The sender of the post. */
+       private Sone sender;
+
+       /** Whether to use the current time when creating the post. */
+       private boolean currentTime;
+
+       /** The time of the post. */
+       private long time;
+
+       /** The text of the post. */
+       private String text;
+
+       /** The (optional) recipient of the post. */
+       private Sone recipient;
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder copyPost(Post post) {
+               this.randomId = false;
+               this.id = post.getId();
+               this.sender = post.getSone();
+               this.currentTime = false;
+               this.time = post.getTime();
+               this.text = post.getText();
+               this.recipient = post.getRecipient();
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder randomId() {
+               randomId = true;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder withId(String id) {
+               this.id = id;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder from(Sone sender) {
+               this.sender = sender;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder currentTime() {
+               currentTime = true;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder withTime(long time) {
+               this.time = time;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder withText(String text) {
+               this.text = text;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public PostBuilder to(Sone recipient) {
+               this.recipient = recipient;
+               return this;
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public Post build() {
+               checkState(!randomId && (id == null), "neither random ID or custom ID set");
+               checkState(randomId && (id != null), "both random ID and custom ID set");
+               checkState(sender != null, "sender must not be null");
+               checkState(!currentTime && (time == 0), "neither current time or custom time set");
+               checkState(currentTime && (time != 0), "both current time and custom time set");
+               checkState(!StringUtils.isBlank(text), "text must not be empty");
+               checkState((recipient == null) || !recipient.equals(sender), "sender and recipient must not be the same");
+               return new PostImpl(randomId ? UUID.randomUUID().toString() : id, sender, currentTime ? System.currentTimeMillis() : time, text).setRecipient(recipient);
+       }
+
+}
index f45292b..2cc0b00 100644 (file)
@@ -124,9 +124,12 @@ public class PostImpl implements Post {
        }
 
        /**
-        * {@inheritDoc}
+        * Sets the Sone of this post.
+        *
+        * @param sone
+        *            The Sone of this post
+        * @return This post (for method chaining)
         */
-       @Override
        public PostImpl setSone(Sone sone) {
                this.sone = sone;
                return this;
@@ -141,9 +144,12 @@ public class PostImpl implements Post {
        }
 
        /**
-        * {@inheritDoc}
+        * Sets the recipient of this post.
+        *
+        * @param recipient
+        *            The recipient of this post, or {@code null}
+        * @return This post (for method chaining)
         */
-       @Override
        public PostImpl setRecipient(Sone recipient) {
                if (!sone.equals(recipient)) {
                        this.recipient = recipient;
@@ -160,9 +166,12 @@ public class PostImpl implements Post {
        }
 
        /**
-        * {@inheritDoc}
+        * Sets the time of this post.
+        *
+        * @param time
+        *            The time of this post (in milliseconds since Jan 1, 1970 UTC)
+        * @return This post (for method chaining)
         */
-       @Override
        public PostImpl setTime(long time) {
                this.time = time;
                return this;
@@ -177,9 +186,12 @@ public class PostImpl implements Post {
        }
 
        /**
-        * {@inheritDoc}
+        * Sets the text of this post.
+        *
+        * @param text
+        *            The text of this post
+        * @return This post (for method chaining)
         */
-       @Override
        public PostImpl setText(String text) {
                this.text = text;
                return this;
index a483b01..b9ff03c 100644 (file)
@@ -185,7 +185,7 @@ public abstract class AbstractSoneCommand extends AbstractCommand {
        protected Post getPost(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
                try {
                        String postId = simpleFieldSet.getString(parameterName);
-                       Post post = core.getPost(postId, false);
+                       Post post = core.getPost(postId);
                        if (post == null) {
                                throw new FcpException("Could not load post from “" + postId + "”.");
                        }
index 9909034..1080818 100644 (file)
@@ -25,6 +25,8 @@ import java.util.logging.Logger;
 import net.pterodactylus.sone.core.Core;
 import net.pterodactylus.sone.core.FreenetInterface;
 import net.pterodactylus.sone.core.WebOfTrustUpdater;
+import net.pterodactylus.sone.data.PostBuilderFactory;
+import net.pterodactylus.sone.data.impl.DefaultPostBuilderFactory;
 import net.pterodactylus.sone.fcp.FcpInterface;
 import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend;
 import net.pterodactylus.sone.freenet.plugin.PluginConnector;
@@ -217,6 +219,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr
                                bind(String.class).annotatedWith(Names.named("WebOfTrustContext")).toInstance("Sone");
                                bind(SonePlugin.class).toInstance(SonePlugin.this);
                                bind(FcpInterface.class).in(Singleton.class);
+                               bind(PostBuilderFactory.class).to(DefaultPostBuilderFactory.class).in(Singleton.class);
                                bindListener(Matchers.any(), new TypeListener() {
 
                                        @Override
index 5c59912..a093e46 100644 (file)
@@ -258,7 +258,7 @@ public class SoneTextParser implements Parser<SoneTextParserContext> {
                                        if (linkType == LinkType.POST) {
                                                if (line.length() >= (7 + 36)) {
                                                        String postId = line.substring(7, 43);
-                                                       Post post = postProvider.getPost(postId, false);
+                                                       Post post = postProvider.getPost(postId);
                                                        if ((post != null) && (post.getSone() != null)) {
                                                                parts.add(new PostPart(post));
                                                        } else {
index d552b91..fe50509 100644 (file)
@@ -65,7 +65,7 @@ public class MarkAsKnownPage extends SoneTemplatePage {
                for (StringTokenizer idTokenizer = new StringTokenizer(ids); idTokenizer.hasMoreTokens();) {
                        String id = idTokenizer.nextToken();
                        if (type.equals("post")) {
-                               Post post = webInterface.getCore().getPost(id, false);
+                               Post post = webInterface.getCore().getPost(id);
                                if (post == null) {
                                        continue;
                                }
index 1bca8cd..7352bab 100644 (file)
@@ -322,7 +322,7 @@ public class SearchPage extends SoneTemplatePage {
         */
        private String getPostId(String phrase) {
                String postId = phrase.startsWith("post://") ? phrase.substring(7) : phrase;
-               return (webInterface.getCore().getPost(postId, false) != null) ? postId : null;
+               return (webInterface.getCore().getPost(postId) != null) ? postId : null;
        }
 
        /**
index aaf013d..ca78d99 100644 (file)
@@ -54,7 +54,7 @@ public class ViewPostPage extends SoneTemplatePage {
        @Override
        protected String getPageTitle(FreenetRequest request) {
                String postId = request.getHttpRequest().getParam("post");
-               Post post = webInterface.getCore().getPost(postId, false);
+               Post post = webInterface.getCore().getPost(postId);
                String title = "";
                if ((post != null) && (post.getSone() != null)) {
                        title = post.getText().substring(0, Math.min(20, post.getText().length())) + "…";
index a8c36d5..3beb85d 100644 (file)
@@ -49,7 +49,7 @@ public class DeletePostAjaxPage extends JsonPage {
        @Override
        protected JsonObject createJsonObject(FreenetRequest request) {
                String postId = request.getHttpRequest().getParam("post");
-               Post post = webInterface.getCore().getPost(postId, false);
+               Post post = webInterface.getCore().getPost(postId);
                if ((post == null) || (post.getSone() == null)) {
                        return createErrorJsonObject("invalid-post-id");
                }
index ae813ee..0c2311e 100644 (file)
@@ -59,7 +59,7 @@ public class GetPostAjaxPage extends JsonPage {
        @Override
        protected JsonObject createJsonObject(FreenetRequest request) {
                String postId = request.getHttpRequest().getParam("post");
-               Post post = webInterface.getCore().getPost(postId, false);
+               Post post = webInterface.getCore().getPost(postId);
                if (post == null) {
                        return createErrorJsonObject("invalid-post-id");
                }
index a7f02c9..03bf8c5 100644 (file)
@@ -58,7 +58,7 @@ public class GetTimesAjaxPage extends JsonPage {
                if (allIds.length() > 0) {
                        String[] ids = allIds.split(",");
                        for (String id : ids) {
-                               Post post = webInterface.getCore().getPost(id, false);
+                               Post post = webInterface.getCore().getPost(id);
                                if (post == null) {
                                        continue;
                                }
index a193d75..18450b1 100644 (file)
@@ -57,7 +57,7 @@ public class MarkAsKnownAjaxPage extends JsonPage {
                Core core = webInterface.getCore();
                for (String id : ids) {
                        if (type.equals("post")) {
-                               Post post = core.getPost(id, false);
+                               Post post = core.getPost(id);
                                if (post == null) {
                                        continue;
                                }