šŸ”„ Remove unnecessary imports
[Sone.git] / src / main / java / net / pterodactylus / sone / data / impl / SoneImpl.java
index 154bfc8..f2f2ea6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Sone - SoneImpl.java - Copyright Ā© 2010ā€“2013 David Roden
+ * Sone - SoneImpl.java - Copyright Ā© 2010ā€“2020 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
@@ -19,7 +19,11 @@ package net.pterodactylus.sone.data.impl;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static java.lang.String.format;
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.logging.Logger.getLogger;
+import static net.pterodactylus.sone.data.PostKt.newestPostFirst;
+import static net.pterodactylus.sone.data.ReplyKt.newestReplyFirst;
+import static net.pterodactylus.sone.data.SoneKt.*;
 
 import java.net.MalformedURLException;
 import java.util.ArrayList;
@@ -31,17 +35,20 @@ import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
 import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.AlbumKt;
 import net.pterodactylus.sone.data.Client;
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Profile;
-import net.pterodactylus.sone.data.Reply;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.data.SoneOptions;
 import net.pterodactylus.sone.data.SoneOptions.DefaultSoneOptions;
+import net.pterodactylus.sone.database.Database;
 import net.pterodactylus.sone.freenet.wot.Identity;
-import net.pterodactylus.sone.freenet.wot.OwnIdentity;
 
 import freenet.keys.FreenetURI;
 
@@ -52,13 +59,14 @@ import com.google.common.hash.Hashing;
  * {@link Sone} implementation.
  * <p/>
  * Operations that modify the Sone need to synchronize on the Sone in question.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ā€˜Bombeā€™ Roden</a>
  */
 public class SoneImpl implements Sone {
 
        /** The logger. */
-       private static final Logger logger = getLogger("Sone.Data");
+       private static final Logger logger = getLogger(SoneImpl.class.getName());
+
+       /** The database. */
+       private final Database database;
 
        /** The ID of this Sone. */
        private final String id;
@@ -87,20 +95,17 @@ public class SoneImpl implements Sone {
        /** Whether this Sone is known. */
        private volatile boolean known;
 
-       /** All friend Sones. */
-       private final Set<String> friendSones = new CopyOnWriteArraySet<String>();
-
        /** All posts. */
-       private final Set<Post> posts = new CopyOnWriteArraySet<Post>();
+       private final Set<Post> posts = new CopyOnWriteArraySet<>();
 
        /** All replies. */
-       private final Set<PostReply> replies = new CopyOnWriteArraySet<PostReply>();
+       private final Set<PostReply> replies = new CopyOnWriteArraySet<>();
 
        /** The IDs of all liked posts. */
-       private final Set<String> likedPostIds = new CopyOnWriteArraySet<String>();
+       private final Set<String> likedPostIds = new CopyOnWriteArraySet<>();
 
        /** The IDs of all liked replies. */
-       private final Set<String> likedReplyIds = new CopyOnWriteArraySet<String>();
+       private final Set<String> likedReplyIds = new CopyOnWriteArraySet<>();
 
        /** The root album containing all albums. */
        private final Album rootAlbum = new AlbumImpl(this);
@@ -111,12 +116,14 @@ public class SoneImpl implements Sone {
        /**
         * Creates a new Sone.
         *
+        * @param database The database
         * @param identity
         *              The identity of the Sone
         * @param local
         *              {@code true} if the Sone is a local Sone, {@code false} otherwise
         */
-       public SoneImpl(Identity identity, boolean local) {
+       public SoneImpl(Database database, Identity identity, boolean local) {
+               this.database = database;
                this.id = identity.getId();
                this.identity = identity;
                this.local = local;
@@ -131,6 +138,7 @@ public class SoneImpl implements Sone {
         *
         * @return The identity of this Sone
         */
+       @Nonnull
        public String getId() {
                return id;
        }
@@ -140,6 +148,7 @@ public class SoneImpl implements Sone {
         *
         * @return The identity of this Sone
         */
+       @Nonnull
        public Identity getIdentity() {
                return identity;
        }
@@ -149,6 +158,7 @@ public class SoneImpl implements Sone {
         *
         * @return The name of this Sone
         */
+       @Nonnull
        public String getName() {
                return (identity != null) ? identity.getNickname() : null;
        }
@@ -167,6 +177,7 @@ public class SoneImpl implements Sone {
         *
         * @return The request URI of this Sone
         */
+       @Nonnull
        public FreenetURI getRequestUri() {
                try {
                        return new FreenetURI(getIdentity().getRequestUri())
@@ -182,25 +193,6 @@ public class SoneImpl implements Sone {
        }
 
        /**
-        * Returns the insert URI of this Sone.
-        *
-        * @return The insert URI of this Sone
-        */
-       public FreenetURI getInsertUri() {
-               if (!isLocal()) {
-                       return null;
-               }
-               try {
-                       return new FreenetURI(((OwnIdentity) getIdentity()).getInsertUri())
-                                       .setDocName("Sone")
-                                       .setMetaString(new String[0])
-                                       .setSuggestedEdition(latestEdition);
-               } catch (MalformedURLException e) {
-                       throw new IllegalStateException(format("Own identity %s's insert URI is incorrect.", getIdentity()), e);
-               }
-       }
-
-       /**
         * Returns the latest edition of this Sone.
         *
         * @return The latest edition of this Sone
@@ -241,6 +233,7 @@ public class SoneImpl implements Sone {
         *              The time of the update (in milliseconds since Jan 1, 1970 UTC)
         * @return This Sone (for method chaining)
         */
+       @Nonnull
        public Sone setTime(long time) {
                this.time = time;
                return this;
@@ -251,6 +244,7 @@ public class SoneImpl implements Sone {
         *
         * @return The status of this Sone
         */
+       @Nonnull
        public SoneStatus getStatus() {
                return status;
        }
@@ -264,7 +258,8 @@ public class SoneImpl implements Sone {
         * @throws IllegalArgumentException
         *              if {@code status} is {@code null}
         */
-       public Sone setStatus(SoneStatus status) {
+       @Nonnull
+       public Sone setStatus(@Nonnull SoneStatus status) {
                this.status = checkNotNull(status, "status must not be null");
                return this;
        }
@@ -276,6 +271,7 @@ public class SoneImpl implements Sone {
         *
         * @return A copy of the profile
         */
+       @Nonnull
        public Profile getProfile() {
                return new Profile(profile);
        }
@@ -288,7 +284,7 @@ public class SoneImpl implements Sone {
         * @param profile
         *              The profile to set
         */
-       public void setProfile(Profile profile) {
+       public void setProfile(@Nonnull Profile profile) {
                this.profile = new Profile(profile);
        }
 
@@ -297,6 +293,7 @@ public class SoneImpl implements Sone {
         *
         * @return The client used by this Sone, or {@code null}
         */
+       @Nullable
        public Client getClient() {
                return client;
        }
@@ -308,7 +305,8 @@ public class SoneImpl implements Sone {
         *              The client used by this Sone, or {@code null}
         * @return This Sone (for method chaining)
         */
-       public Sone setClient(Client client) {
+       @Nonnull
+       public Sone setClient(@Nullable Client client) {
                this.client = client;
                return this;
        }
@@ -329,6 +327,7 @@ public class SoneImpl implements Sone {
         *              {@code true} if this Sone is known, {@code false} otherwise
         * @return This Sone
         */
+       @Nonnull
        public Sone setKnown(boolean known) {
                this.known = known;
                return this;
@@ -339,8 +338,9 @@ public class SoneImpl implements Sone {
         *
         * @return The friend Sones of this Sone
         */
+       @Nonnull
        public Collection<String> getFriends() {
-               return new ArrayList<String>(friendSones);
+               return database.getFriends(this);
        }
 
        /**
@@ -351,34 +351,8 @@ public class SoneImpl implements Sone {
         * @return {@code true} if this Sone has the given Sone as a friend, {@code
         *         false} otherwise
         */
-       public boolean hasFriend(String friendSoneId) {
-               return friendSones.contains(friendSoneId);
-       }
-
-       /**
-        * Adds the given Sone as a friend Sone.
-        *
-        * @param friendSone
-        *              The friend Sone to add
-        * @return This Sone (for method chaining)
-        */
-       public Sone addFriend(String friendSone) {
-               if (!friendSone.equals(id)) {
-                       friendSones.add(friendSone);
-               }
-               return this;
-       }
-
-       /**
-        * Removes the given Sone as a friend Sone.
-        *
-        * @param friendSoneId
-        *              The ID of the friend Sone to remove
-        * @return This Sone (for method chaining)
-        */
-       public Sone removeFriend(String friendSoneId) {
-               friendSones.remove(friendSoneId);
-               return this;
+       public boolean hasFriend(@Nonnull String friendSoneId) {
+               return database.isFriend(this, friendSoneId);
        }
 
        /**
@@ -386,12 +360,13 @@ public class SoneImpl implements Sone {
         *
         * @return All posts of this Sone
         */
+       @Nonnull
        public List<Post> getPosts() {
                List<Post> sortedPosts;
                synchronized (this) {
-                       sortedPosts = new ArrayList<Post>(posts);
+                       sortedPosts = new ArrayList<>(posts);
                }
-               Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
+               sortedPosts.sort(newestPostFirst());
                return sortedPosts;
        }
 
@@ -402,7 +377,8 @@ public class SoneImpl implements Sone {
         *              The new (and only) posts of this Sone
         * @return This Sone (for method chaining)
         */
-       public Sone setPosts(Collection<Post> posts) {
+       @Nonnull
+       public Sone setPosts(@Nonnull Collection<Post> posts) {
                synchronized (this) {
                        this.posts.clear();
                        this.posts.addAll(posts);
@@ -417,7 +393,7 @@ public class SoneImpl implements Sone {
         * @param post
         *              The post to add
         */
-       public void addPost(Post post) {
+       public void addPost(@Nonnull Post post) {
                if (post.getSone().equals(this) && posts.add(post)) {
                        logger.log(Level.FINEST, String.format("Adding %s to ā€œ%sā€.", post, getName()));
                }
@@ -429,7 +405,7 @@ public class SoneImpl implements Sone {
         * @param post
         *              The post to remove
         */
-       public void removePost(Post post) {
+       public void removePost(@Nonnull Post post) {
                if (post.getSone().equals(this)) {
                        posts.remove(post);
                }
@@ -440,6 +416,7 @@ public class SoneImpl implements Sone {
         *
         * @return All replies this Sone made
         */
+       @Nonnull
        public Set<PostReply> getReplies() {
                return Collections.unmodifiableSet(replies);
        }
@@ -451,7 +428,8 @@ public class SoneImpl implements Sone {
         *              The new (and only) replies of this Sone
         * @return This Sone (for method chaining)
         */
-       public Sone setReplies(Collection<PostReply> replies) {
+       @Nonnull
+       public Sone setReplies(@Nonnull Collection<PostReply> replies) {
                this.replies.clear();
                this.replies.addAll(replies);
                return this;
@@ -464,7 +442,7 @@ public class SoneImpl implements Sone {
         * @param reply
         *              The reply to add
         */
-       public void addReply(PostReply reply) {
+       public void addReply(@Nonnull PostReply reply) {
                if (reply.getSone().equals(this)) {
                        replies.add(reply);
                }
@@ -476,7 +454,7 @@ public class SoneImpl implements Sone {
         * @param reply
         *              The reply to remove
         */
-       public void removeReply(PostReply reply) {
+       public void removeReply(@Nonnull PostReply reply) {
                if (reply.getSone().equals(this)) {
                        replies.remove(reply);
                }
@@ -487,6 +465,7 @@ public class SoneImpl implements Sone {
         *
         * @return All liked postsā€™ IDs
         */
+       @Nonnull
        public Set<String> getLikedPostIds() {
                return Collections.unmodifiableSet(likedPostIds);
        }
@@ -498,7 +477,8 @@ public class SoneImpl implements Sone {
         *              All liked postsā€™ IDs
         * @return This Sone (for method chaining)
         */
-       public Sone setLikePostIds(Set<String> likedPostIds) {
+       @Nonnull
+       public Sone setLikePostIds(@Nonnull Set<String> likedPostIds) {
                this.likedPostIds.clear();
                this.likedPostIds.addAll(likedPostIds);
                return this;
@@ -512,7 +492,7 @@ public class SoneImpl implements Sone {
         * @return {@code true} if this Sone likes the given post, {@code false}
         *         otherwise
         */
-       public boolean isLikedPostId(String postId) {
+       public boolean isLikedPostId(@Nonnull String postId) {
                return likedPostIds.contains(postId);
        }
 
@@ -523,7 +503,8 @@ public class SoneImpl implements Sone {
         *              The ID of the post
         * @return This Sone (for method chaining)
         */
-       public Sone addLikedPostId(String postId) {
+       @Nonnull
+       public Sone addLikedPostId(@Nonnull String postId) {
                likedPostIds.add(postId);
                return this;
        }
@@ -533,11 +514,9 @@ public class SoneImpl implements Sone {
         *
         * @param postId
         *              The ID of the post
-        * @return This Sone (for method chaining)
         */
-       public Sone removeLikedPostId(String postId) {
+       public void removeLikedPostId(@Nonnull String postId) {
                likedPostIds.remove(postId);
-               return this;
        }
 
        /**
@@ -545,6 +524,7 @@ public class SoneImpl implements Sone {
         *
         * @return All liked repliesā€™ IDs
         */
+       @Nonnull
        public Set<String> getLikedReplyIds() {
                return Collections.unmodifiableSet(likedReplyIds);
        }
@@ -556,7 +536,8 @@ public class SoneImpl implements Sone {
         *              All liked repliesā€™ IDs
         * @return This Sone (for method chaining)
         */
-       public Sone setLikeReplyIds(Set<String> likedReplyIds) {
+       @Nonnull
+       public Sone setLikeReplyIds(@Nonnull Set<String> likedReplyIds) {
                this.likedReplyIds.clear();
                this.likedReplyIds.addAll(likedReplyIds);
                return this;
@@ -570,7 +551,7 @@ public class SoneImpl implements Sone {
         * @return {@code true} if this Sone likes the given reply, {@code false}
         *         otherwise
         */
-       public boolean isLikedReplyId(String replyId) {
+       public boolean isLikedReplyId(@Nonnull String replyId) {
                return likedReplyIds.contains(replyId);
        }
 
@@ -581,7 +562,8 @@ public class SoneImpl implements Sone {
         *              The ID of the reply
         * @return This Sone (for method chaining)
         */
-       public Sone addLikedReplyId(String replyId) {
+       @Nonnull
+       public Sone addLikedReplyId(@Nonnull String replyId) {
                likedReplyIds.add(replyId);
                return this;
        }
@@ -591,11 +573,9 @@ public class SoneImpl implements Sone {
         *
         * @param replyId
         *              The ID of the reply
-        * @return This Sone (for method chaining)
         */
-       public Sone removeLikedReplyId(String replyId) {
+       public void removeLikedReplyId(@Nonnull String replyId) {
                likedReplyIds.remove(replyId);
-               return this;
        }
 
        /**
@@ -603,6 +583,7 @@ public class SoneImpl implements Sone {
         *
         * @return The root album of this Sone
         */
+       @Nonnull
        public Album getRootAlbum() {
                return rootAlbum;
        }
@@ -612,6 +593,7 @@ public class SoneImpl implements Sone {
         *
         * @return The options of this Sone
         */
+       @Nonnull
        public SoneOptions getOptions() {
                return options;
        }
@@ -623,7 +605,7 @@ public class SoneImpl implements Sone {
         *              The options of this Sone
         */
        /* TODO - remove this method again, maybe add an option provider */
-       public void setOptions(SoneOptions options) {
+       public void setOptions(@Nonnull SoneOptions options) {
                this.options = options;
        }
 
@@ -635,46 +617,46 @@ public class SoneImpl implements Sone {
        @Override
        public synchronized String getFingerprint() {
                Hasher hash = Hashing.sha256().newHasher();
-               hash.putString(profile.getFingerprint());
+               hash.putString(profile.getFingerprint(), UTF_8);
 
-               hash.putString("Posts(");
+               hash.putString("Posts(", UTF_8);
                for (Post post : getPosts()) {
-                       hash.putString("Post(").putString(post.getId()).putString(")");
+                       hash.putString("Post(", UTF_8).putString(post.getId(), UTF_8).putString(")", UTF_8);
                }
-               hash.putString(")");
+               hash.putString(")", UTF_8);
 
-               List<PostReply> replies = new ArrayList<PostReply>(getReplies());
-               Collections.sort(replies, Reply.TIME_COMPARATOR);
-               hash.putString("Replies(");
+               List<PostReply> replies = new ArrayList<>(getReplies());
+               replies.sort(newestReplyFirst().reversed());
+               hash.putString("Replies(", UTF_8);
                for (PostReply reply : replies) {
-                       hash.putString("Reply(").putString(reply.getId()).putString(")");
+                       hash.putString("Reply(", UTF_8).putString(reply.getId(), UTF_8).putString(")", UTF_8);
                }
-               hash.putString(")");
+               hash.putString(")", UTF_8);
 
-               List<String> likedPostIds = new ArrayList<String>(getLikedPostIds());
+               List<String> likedPostIds = new ArrayList<>(getLikedPostIds());
                Collections.sort(likedPostIds);
-               hash.putString("LikedPosts(");
+               hash.putString("LikedPosts(", UTF_8);
                for (String likedPostId : likedPostIds) {
-                       hash.putString("Post(").putString(likedPostId).putString(")");
+                       hash.putString("Post(", UTF_8).putString(likedPostId, UTF_8).putString(")", UTF_8);
                }
-               hash.putString(")");
+               hash.putString(")", UTF_8);
 
-               List<String> likedReplyIds = new ArrayList<String>(getLikedReplyIds());
+               List<String> likedReplyIds = new ArrayList<>(getLikedReplyIds());
                Collections.sort(likedReplyIds);
-               hash.putString("LikedReplies(");
+               hash.putString("LikedReplies(", UTF_8);
                for (String likedReplyId : likedReplyIds) {
-                       hash.putString("Reply(").putString(likedReplyId).putString(")");
+                       hash.putString("Reply(", UTF_8).putString(likedReplyId, UTF_8).putString(")", UTF_8);
                }
-               hash.putString(")");
+               hash.putString(")", UTF_8);
 
-               hash.putString("Albums(");
+               hash.putString("Albums(", UTF_8);
                for (Album album : rootAlbum.getAlbums()) {
-                       if (!Album.NOT_EMPTY.apply(album)) {
+                       if (!AlbumKt.notEmpty().invoke(album)) {
                                continue;
                        }
-                       hash.putString(album.getFingerprint());
+                       hash.putString(album.getFingerprint(), UTF_8);
                }
-               hash.putString(")");
+               hash.putString(")", UTF_8);
 
                return hash.hash().toString();
        }
@@ -686,7 +668,7 @@ public class SoneImpl implements Sone {
        /** {@inheritDoc} */
        @Override
        public int compareTo(Sone sone) {
-               return NICE_NAME_COMPARATOR.compare(this, sone);
+               return niceNameComparator().compare(this, sone);
        }
 
        //
@@ -711,7 +693,7 @@ public class SoneImpl implements Sone {
        /** {@inheritDoc} */
        @Override
        public String toString() {
-               return getClass().getName() + "[identity=" + identity + ",friends(" + friendSones.size() + "),posts(" + posts.size() + "),replies(" + replies.size() + "),albums(" + getRootAlbum().getAlbums().size() + ")]";
+               return getClass().getName() + "[identity=" + identity + ",posts(" + posts.size() + "),replies(" + replies.size() + "),albums(" + getRootAlbum().getAlbums().size() + ")]";
        }
 
 }