X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fdatabase%2Fmemory%2FMemoryDatabase.java;h=00bb5c94ebce934c2224220c714aad47dfd8bec2;hp=3f30d1191783091355523cd050c77fd860f7f3c5;hb=667a3a2d8544cf91f00baba1aaf9f55cead7d006;hpb=6f019de1d4d9742981d851ac3c9097cca8bff58e diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java index 3f30d11..00bb5c9 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java @@ -17,28 +17,37 @@ package net.pterodactylus.sone.database.memory; -import static com.google.common.base.Preconditions.*; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Predicates.not; +import static com.google.common.collect.FluentIterable.from; +import static java.util.Collections.unmodifiableCollection; +import static net.pterodactylus.sone.data.Reply.TIME_COMPARATOR; +import static net.pterodactylus.sone.data.Sone.LOCAL_SONE_FILTER; +import static net.pterodactylus.sone.data.Sone.toAllAlbums; +import static net.pterodactylus.sone.data.Sone.toAllImages; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import net.pterodactylus.sone.data.Album; +import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.data.impl.AlbumBuilderImpl; +import net.pterodactylus.sone.data.impl.ImageBuilderImpl; +import net.pterodactylus.sone.database.AlbumBuilder; import net.pterodactylus.sone.database.Database; import net.pterodactylus.sone.database.DatabaseException; +import net.pterodactylus.sone.database.ImageBuilder; import net.pterodactylus.sone.database.PostBuilder; import net.pterodactylus.sone.database.PostDatabase; import net.pterodactylus.sone.database.PostReplyBuilder; @@ -47,16 +56,21 @@ import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import com.google.common.collect.SortedSetMultimap; import com.google.common.collect.TreeMultimap; import com.google.common.util.concurrent.AbstractService; import com.google.inject.Inject; +import com.google.inject.Singleton; /** * Memory-based {@link PostDatabase} implementation. * * @author David ‘Bombe’ Roden */ +@Singleton public class MemoryDatabase extends AbstractService implements Database { /** The lock. */ @@ -68,14 +82,13 @@ public class MemoryDatabase extends AbstractService implements Database { /** The configuration. */ private final Configuration configuration; + private final Map allSones = new HashMap(); + /** All posts by their ID. */ private final Map allPosts = new HashMap(); /** All posts by their Sones. */ - private final Map> sonePosts = new HashMap>(); - - /** All posts by their recipient. */ - private final Map> recipientPosts = new HashMap>(); + private final Multimap sonePosts = HashMultimap.create(); /** Whether posts are known. */ private final Set knownPosts = new HashSet(); @@ -90,14 +103,17 @@ public class MemoryDatabase extends AbstractService implements Database { public int compare(String leftString, String rightString) { return leftString.compareTo(rightString); } - }, PostReply.TIME_COMPARATOR); - - /** Replies by post. */ - private final Map> postReplies = new HashMap>(); + }, TIME_COMPARATOR); /** Whether post replies are known. */ private final Set knownPostReplies = new HashSet(); + private final Map allAlbums = new HashMap(); + private final Multimap soneAlbums = HashMultimap.create(); + + private final Map allImages = new HashMap(); + private final Multimap soneImages = HashMultimap.create(); + /** * Creates a new memory database. * @@ -151,6 +167,93 @@ public class MemoryDatabase extends AbstractService implements Database { } } + @Override + public void storeSone(Sone sone) { + lock.writeLock().lock(); + try { + Collection removedPosts = sonePosts.removeAll(sone.getId()); + for (Post removedPost : removedPosts) { + allPosts.remove(removedPost.getId()); + } + Collection removedPostReplies = + sonePostReplies.removeAll(sone.getId()); + for (PostReply removedPostReply : removedPostReplies) { + allPostReplies.remove(removedPostReply.getId()); + } + Collection removedAlbums = + soneAlbums.removeAll(sone.getId()); + for (Album removedAlbum : removedAlbums) { + allAlbums.remove(removedAlbum.getId()); + } + Collection removedImages = + soneImages.removeAll(sone.getId()); + for (Image removedImage : removedImages) { + allImages.remove(removedImage.getId()); + } + + allSones.put(sone.getId(), sone); + sonePosts.putAll(sone.getId(), sone.getPosts()); + for (Post post : sone.getPosts()) { + allPosts.put(post.getId(), post); + } + sonePostReplies.putAll(sone.getId(), sone.getReplies()); + for (PostReply postReply : sone.getReplies()) { + allPostReplies.put(postReply.getId(), postReply); + } + soneAlbums.putAll(sone.getId(), toAllAlbums.apply(sone)); + for (Album album : toAllAlbums.apply(sone)) { + allAlbums.put(album.getId(), album); + } + soneImages.putAll(sone.getId(), toAllImages.apply(sone)); + for (Image image : toAllImages.apply(sone)) { + allImages.put(image.getId(), image); + } + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public Optional getSone(String soneId) { + lock.readLock().lock(); + try { + return fromNullable(allSones.get(soneId)); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public Collection getSones() { + lock.readLock().lock(); + try { + return unmodifiableCollection(allSones.values()); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public Collection getLocalSones() { + lock.readLock().lock(); + try { + return from(allSones.values()).filter(LOCAL_SONE_FILTER).toSet(); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public Collection getRemoteSones() { + lock.readLock().lock(); + try { + return from(allSones.values()) + .filter(not(LOCAL_SONE_FILTER)) .toSet(); + } finally { + lock.readLock().unlock(); + } + } + // // POSTPROVIDER METHODS // @@ -160,7 +263,7 @@ public class MemoryDatabase extends AbstractService implements Database { public Optional getPost(String postId) { lock.readLock().lock(); try { - return Optional.fromNullable(allPosts.get(postId)); + return fromNullable(allPosts.get(postId)); } finally { lock.readLock().unlock(); } @@ -174,11 +277,15 @@ public class MemoryDatabase extends AbstractService implements Database { /** {@inheritDocs} */ @Override - public Collection getDirectedPosts(String recipientId) { + public Collection getDirectedPosts(final String recipientId) { lock.readLock().lock(); try { - Collection posts = recipientPosts.get(recipientId); - return (posts == null) ? Collections.emptySet() : new HashSet(posts); + return from(sonePosts.values()).filter(new Predicate() { + @Override + public boolean apply(Post post) { + return post.getRecipientId().asSet().contains(recipientId); + } + }).toSet(); } finally { lock.readLock().unlock(); } @@ -206,9 +313,6 @@ public class MemoryDatabase extends AbstractService implements Database { try { allPosts.put(post.getId(), post); getPostsFrom(post.getSone().getId()).add(post); - if (post.getRecipientId().isPresent()) { - getPostsTo(post.getRecipientId().get()).add(post); - } } finally { lock.writeLock().unlock(); } @@ -222,9 +326,6 @@ public class MemoryDatabase extends AbstractService implements Database { try { allPosts.remove(post.getId()); getPostsFrom(post.getSone().getId()).remove(post); - if (post.getRecipientId().isPresent()) { - getPostsTo(post.getRecipientId().get()).remove(post); - } post.getSone().removePost(post); } finally { lock.writeLock().unlock(); @@ -245,21 +346,15 @@ public class MemoryDatabase extends AbstractService implements Database { lock.writeLock().lock(); try { /* remove all posts by the Sone. */ - getPostsFrom(sone.getId()).clear(); - for (Post post : posts) { + Collection oldPosts = getPostsFrom(sone.getId()); + for (Post post : oldPosts) { allPosts.remove(post.getId()); - if (post.getRecipientId().isPresent()) { - getPostsTo(post.getRecipientId().get()).remove(post); - } } /* add new posts. */ getPostsFrom(sone.getId()).addAll(posts); for (Post post : posts) { allPosts.put(post.getId(), post); - if (post.getRecipientId().isPresent()) { - getPostsTo(post.getRecipientId().get()).add(post); - } } } finally { lock.writeLock().unlock(); @@ -276,9 +371,6 @@ public class MemoryDatabase extends AbstractService implements Database { getPostsFrom(sone.getId()).clear(); for (Post post : sone.getPosts()) { allPosts.remove(post.getId()); - if (post.getRecipientId().isPresent()) { - getPostsTo(post.getRecipientId().get()).remove(post); - } } } finally { lock.writeLock().unlock(); @@ -294,7 +386,7 @@ public class MemoryDatabase extends AbstractService implements Database { public Optional getPostReply(String id) { lock.readLock().lock(); try { - return Optional.fromNullable(allPostReplies.get(id)); + return fromNullable(allPostReplies.get(id)); } finally { lock.readLock().unlock(); } @@ -302,13 +394,16 @@ public class MemoryDatabase extends AbstractService implements Database { /** {@inheritDocs} */ @Override - public List getReplies(String postId) { + public List getReplies(final String postId) { lock.readLock().lock(); try { - if (!postReplies.containsKey(postId)) { - return Collections.emptyList(); - } - return new ArrayList(postReplies.get(postId)); + return from(allPostReplies.values()) + .filter(new Predicate() { + @Override + public boolean apply(PostReply postReply) { + return postReply.getPostId().equals(postId); + } + }).toSortedList(TIME_COMPARATOR); } finally { lock.readLock().unlock(); } @@ -334,13 +429,6 @@ public class MemoryDatabase extends AbstractService implements Database { lock.writeLock().lock(); try { allPostReplies.put(postReply.getId(), postReply); - if (postReplies.containsKey(postReply.getPostId())) { - postReplies.get(postReply.getPostId()).add(postReply); - } else { - TreeSet replies = new TreeSet(Reply.TIME_COMPARATOR); - replies.add(postReply); - postReplies.put(postReply.getPostId(), replies); - } } finally { lock.writeLock().unlock(); } @@ -366,13 +454,6 @@ public class MemoryDatabase extends AbstractService implements Database { for (PostReply postReply : postReplies) { allPostReplies.put(postReply.getId(), postReply); sonePostReplies.put(postReply.getSone().getId(), postReply); - if (this.postReplies.containsKey(postReply.getPostId())) { - this.postReplies.get(postReply.getPostId()).add(postReply); - } else { - TreeSet replies = new TreeSet(Reply.TIME_COMPARATOR); - replies.add(postReply); - this.postReplies.put(postReply.getPostId(), replies); - } } } finally { lock.writeLock().unlock(); @@ -385,12 +466,6 @@ public class MemoryDatabase extends AbstractService implements Database { lock.writeLock().lock(); try { allPostReplies.remove(postReply.getId()); - if (postReplies.containsKey(postReply.getPostId())) { - postReplies.get(postReply.getPostId()).remove(postReply); - if (postReplies.get(postReply.getPostId()).isEmpty()) { - postReplies.remove(postReply.getPostId()); - } - } } finally { lock.writeLock().unlock(); } @@ -412,6 +487,104 @@ public class MemoryDatabase extends AbstractService implements Database { } // + // ALBUMPROVDER METHODS + // + + @Override + public Optional getAlbum(String albumId) { + lock.readLock().lock(); + try { + return fromNullable(allAlbums.get(albumId)); + } finally { + lock.readLock().unlock(); + } + } + + // + // ALBUMBUILDERFACTORY METHODS + // + + @Override + public AlbumBuilder newAlbumBuilder() { + return new AlbumBuilderImpl(); + } + + // + // ALBUMSTORE METHODS + // + + @Override + public void storeAlbum(Album album) { + lock.writeLock().lock(); + try { + allAlbums.put(album.getId(), album); + soneAlbums.put(album.getSone().getId(), album); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public void removeAlbum(Album album) { + lock.writeLock().lock(); + try { + allAlbums.remove(album.getId()); + soneAlbums.remove(album.getSone().getId(), album); + } finally { + lock.writeLock().unlock(); + } + } + + // + // IMAGEPROVIDER METHODS + // + + @Override + public Optional getImage(String imageId) { + lock.readLock().lock(); + try { + return fromNullable(allImages.get(imageId)); + } finally { + lock.readLock().unlock(); + } + } + + // + // IMAGEBUILDERFACTORY METHODS + // + + @Override + public ImageBuilder newImageBuilder() { + return new ImageBuilderImpl(); + } + + // + // IMAGESTORE METHODS + // + + @Override + public void storeImage(Image image) { + lock.writeLock().lock(); + try { + allImages.put(image.getId(), image); + soneImages.put(image.getSone().getId(), image); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public void removeImage(Image image) { + lock.writeLock().lock(); + try { + allImages.remove(image.getId()); + soneImages.remove(image.getSone().getId(), image); + } finally { + lock.writeLock().unlock(); + } + } + + // // PACKAGE-PRIVATE METHODS // @@ -503,57 +676,12 @@ public class MemoryDatabase extends AbstractService implements Database { * @return All posts */ private Collection getPostsFrom(String soneId) { - Collection posts = null; lock.readLock().lock(); try { - posts = sonePosts.get(soneId); + return sonePosts.get(soneId); } finally { lock.readLock().unlock(); } - if (posts != null) { - return posts; - } - - posts = new HashSet(); - lock.writeLock().lock(); - try { - sonePosts.put(soneId, posts); - } finally { - lock.writeLock().unlock(); - } - - return posts; - } - - /** - * Gets all posts that are directed the given Sone, creating a new collection - * if there is none yet. - * - * @param recipientId - * The ID of the Sone to get the posts for - * @return All posts - */ - private Collection getPostsTo(String recipientId) { - Collection posts = null; - lock.readLock().lock(); - try { - posts = recipientPosts.get(recipientId); - } finally { - lock.readLock().unlock(); - } - if (posts != null) { - return posts; - } - - posts = new HashSet(); - lock.writeLock().lock(); - try { - recipientPosts.put(recipientId, posts); - } finally { - lock.writeLock().unlock(); - } - - return posts; } /** Loads the known posts. */ @@ -604,10 +732,7 @@ public class MemoryDatabase extends AbstractService implements Database { private Collection getRepliesFrom(String id) { lock.readLock().lock(); try { - if (sonePostReplies.containsKey(id)) { - return Collections.unmodifiableCollection(sonePostReplies.get(id)); - } - return Collections.emptySet(); + return unmodifiableCollection(sonePostReplies.get(id)); } finally { lock.readLock().unlock(); }