X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fdatabase%2Fmemory%2FMemoryDatabase.java;h=bace9d9fbe592535f8d6aecc6ba991917fc75a4c;hb=9d9b901b7173a9b8221a8b830ece31bc5ee36578;hp=c73513d92ae4d95e3f60b0a826e9c5df18fbdc58;hpb=403b51bcf5b736808e3c554b8589759e7d3d5d47;p=Sone.git 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 c73513d..bace9d9 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java @@ -22,6 +22,7 @@ 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.emptyList; +import static java.util.logging.Logger.getLogger; import static net.pterodactylus.sone.data.Sone.LOCAL_SONE_FILTER; import java.util.ArrayList; @@ -35,6 +36,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.logging.Level; +import java.util.logging.Logger; import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Image; @@ -44,7 +47,6 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.data.impl.DefaultSoneBuilder; import net.pterodactylus.sone.database.Database; import net.pterodactylus.sone.database.DatabaseException; -import net.pterodactylus.sone.database.PostDatabase; import net.pterodactylus.sone.database.SoneBuilder; import net.pterodactylus.sone.freenet.wot.Identity; import net.pterodactylus.util.config.Configuration; @@ -55,8 +57,6 @@ import com.google.common.base.Optional; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.HashMultimap; import com.google.common.collect.ListMultimap; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; import com.google.common.collect.SetMultimap; import com.google.common.collect.SortedSetMultimap; import com.google.common.collect.TreeMultimap; @@ -64,36 +64,28 @@ import com.google.common.util.concurrent.AbstractService; import com.google.inject.Inject; /** - * Memory-based {@link PostDatabase} implementation. + * Memory-based {@link Database} implementation. * * @author David ‘Bombe’ Roden */ public class MemoryDatabase extends AbstractService implements Database { + private static final Logger logger = getLogger(MemoryDatabase.class.getName()); + /** The lock. */ private final ReadWriteLock lock = new ReentrantReadWriteLock(); /** The configuration. */ private final Configuration configuration; - private final Map identities = Maps.newHashMap(); private final Map sones = new HashMap(); - - /** All posts by their ID. */ - private final Map allPosts = new HashMap(); - - /** All posts by their Sones. */ - private final Multimap sonePosts = HashMultimap.create(); - private final SetMultimap likedPosts = HashMultimap.create(); - - /** All posts by their recipient. */ - private final Multimap recipientPosts = HashMultimap.create(); - - /** Whether posts are known. */ - private final Set knownPosts = new HashSet(); + private final MemoryIdentityDatabase memoryIdentityDatabase; + private final MemoryPostDatabase memoryPostDatabase; /** All post replies by their ID. */ private final Map allPostReplies = new HashMap(); + private final SetMultimap likedPostRepliesBySone = HashMultimap.create(); + private final SetMultimap postReplyLikingSones = HashMultimap.create(); /** Replies sorted by Sone. */ private final SortedSetMultimap sonePostReplies = TreeMultimap.create(new Comparator() { @@ -131,16 +123,8 @@ public class MemoryDatabase extends AbstractService implements Database { @Inject public MemoryDatabase(Configuration configuration) { this.configuration = configuration; - } - - // - // DATABASE METHODS - // - - @Override - public void save() throws DatabaseException { - saveKnownPosts(); - saveKnownPostReplies(); + memoryPostDatabase = new MemoryPostDatabase(this, lock, configuration); + memoryIdentityDatabase = new MemoryIdentityDatabase(lock); } // @@ -149,7 +133,7 @@ public class MemoryDatabase extends AbstractService implements Database { @Override protected void doStart() { - loadKnownPosts(); + memoryPostDatabase.start(); loadKnownPostReplies(); notifyStarted(); } @@ -157,21 +141,21 @@ public class MemoryDatabase extends AbstractService implements Database { @Override protected void doStop() { try { - save(); - notifyStopped(); + memoryPostDatabase.stop(); } catch (DatabaseException de1) { - notifyFailed(de1); + logger.log(Level.WARNING, "Could not stop post database!", de1); } + notifyStopped(); } @Override public Optional getIdentity(String identityId) { - lock.readLock().lock(); - try { - return fromNullable(identities.get(identityId)); - } finally { - lock.readLock().unlock(); - } + return memoryIdentityDatabase.getIdentity(identityId); + } + + @Override + public void storeIdentity(Identity identitiy) { + memoryIdentityDatabase.storeIdentity(identitiy); } @Override @@ -225,6 +209,16 @@ public class MemoryDatabase extends AbstractService implements Database { } @Override + public void storeSone(Sone sone) { + lock.writeLock().lock(); + try { + sones.put(sone.getId(), sone); + } finally { + lock.writeLock().unlock(); + } + } + + @Override public SoneBuilder newSoneBuilder() { return new DefaultSoneBuilder(this) { @Override @@ -247,63 +241,64 @@ public class MemoryDatabase extends AbstractService implements Database { @Override public Function> getPost() { - return new Function>() { - @Override - public Optional apply(String postId) { - return (postId == null) ? Optional.absent() : getPost(postId); - } - }; + return memoryPostDatabase.getPost(); } @Override public Optional getPost(String postId) { - lock.readLock().lock(); - try { - return fromNullable(allPosts.get(postId)); - } finally { - lock.readLock().unlock(); - } + return memoryPostDatabase.getPost(postId); } @Override public Collection getPosts(String soneId) { - lock.readLock().lock(); - try { - return new HashSet(sonePosts.get(soneId)); - } finally { - lock.readLock().unlock(); - } + return memoryPostDatabase.getPosts(soneId); } @Override public Collection getDirectedPosts(String recipientId) { - lock.readLock().lock(); - try { - Collection posts = recipientPosts.get(recipientId); - return (posts == null) ? Collections.emptySet() : new HashSet(posts); - } finally { - lock.readLock().unlock(); - } + return memoryPostDatabase.getDirectedPosts(recipientId); + } + + /** + * Returns whether the given post is known. + * + * @param post + * The post + * @return {@code true} if the post is known, {@code false} otherwise + */ + @Override + public boolean isPostKnown(Post post) { + return memoryPostDatabase.isPostKnown(post); + } + + /** + * Sets whether the given post is known. + * + * @param post + * The post + */ + @Override + public void setPostKnown(Post post) { + memoryPostDatabase.setPostKnown(post); } @Override public void likePost(Post post, Sone localSone) { - lock.writeLock().lock(); - try { - likedPosts.put(localSone.getId(), post.getId()); - } finally { - lock.writeLock().unlock(); - } + memoryPostDatabase.likePost(post, localSone); } @Override public void unlikePost(Post post, Sone localSone) { - lock.writeLock().lock(); - try { - likedPosts.remove(localSone.getId(), post.getId()); - } finally { - lock.writeLock().unlock(); - } + memoryPostDatabase.unlikePost(post, localSone); + } + + public boolean isLiked(Post post, Sone sone) { + return memoryPostDatabase.isLiked(post, sone); + } + + @Override + public Set getLikes(Post post) { + return memoryPostDatabase.getLikes(post); } // @@ -312,109 +307,90 @@ public class MemoryDatabase extends AbstractService implements Database { @Override public void storePost(Post post) { - checkNotNull(post, "post must not be null"); - lock.writeLock().lock(); - try { - allPosts.put(post.getId(), post); - sonePosts.put(post.getSone().getId(), post); - if (post.getRecipientId().isPresent()) { - recipientPosts.put(post.getRecipientId().get(), post); - } - } finally { - lock.writeLock().unlock(); - } + memoryPostDatabase.storePost(post); } @Override public void removePost(Post post) { - checkNotNull(post, "post must not be null"); - lock.writeLock().lock(); + memoryPostDatabase.removePost(post); + } + + @Override + public void storePosts(Sone sone, Collection posts) throws IllegalArgumentException { + /* verify that all posts are from the same Sone. */ + + memoryPostDatabase.storePosts(sone, posts); + } + + @Override + public void removePosts(Sone sone) { + memoryPostDatabase.removePosts(sone); + } + + // + // POSTREPLYPROVIDER METHODS + // + + @Override + public Optional getPostReply(String id) { + lock.readLock().lock(); try { - allPosts.remove(post.getId()); - sonePosts.remove(post.getSone().getId(), post); - if (post.getRecipientId().isPresent()) { - recipientPosts.remove(post.getRecipientId().get(), post); - } - post.getSone().removePost(post); + return fromNullable(allPostReplies.get(id)); } finally { - lock.writeLock().unlock(); + lock.readLock().unlock(); } } @Override - public void storePosts(Sone sone, Collection posts) throws IllegalArgumentException { - checkNotNull(sone, "sone must not be null"); - /* verify that all posts are from the same Sone. */ - for (Post post : posts) { - if (!sone.equals(post.getSone())) { - throw new IllegalArgumentException(String.format("Post from different Sone found: %s", post)); + public List getReplies(String postId) { + lock.readLock().lock(); + try { + if (!postReplies.containsKey(postId)) { + return emptyList(); } + return new ArrayList(postReplies.get(postId)); + } finally { + lock.readLock().unlock(); } + } + @Override + public void likePostReply(PostReply postReply, Sone localSone) { lock.writeLock().lock(); try { - /* remove all posts by the Sone. */ - sonePosts.removeAll(sone.getId()); - for (Post post : posts) { - allPosts.remove(post.getId()); - if (post.getRecipientId().isPresent()) { - recipientPosts.remove(post.getRecipientId().get(), post); - } - } - - /* add new posts. */ - sonePosts.putAll(sone.getId(), posts); - for (Post post : posts) { - allPosts.put(post.getId(), post); - if (post.getRecipientId().isPresent()) { - recipientPosts.put(post.getRecipientId().get(), post); - } - } + likedPostRepliesBySone.put(localSone.getId(), postReply.getId()); + postReplyLikingSones.put(postReply.getId(), localSone.getId()); } finally { lock.writeLock().unlock(); } } @Override - public void removePosts(Sone sone) { - checkNotNull(sone, "sone must not be null"); + public void unlikePostReply(PostReply postReply, Sone localSone) { lock.writeLock().lock(); try { - /* remove all posts by the Sone. */ - sonePosts.removeAll(sone.getId()); - for (Post post : sone.getPosts()) { - allPosts.remove(post.getId()); - if (post.getRecipientId().isPresent()) { - recipientPosts.remove(post.getRecipientId().get(), post); - } - } + likedPostRepliesBySone.remove(localSone.getId(), postReply.getId()); + postReplyLikingSones.remove(postReply.getId(), localSone.getId()); } finally { lock.writeLock().unlock(); } } - // - // POSTREPLYPROVIDER METHODS - // - @Override - public Optional getPostReply(String id) { + public boolean isLiked(PostReply postReply, Sone sone) { lock.readLock().lock(); try { - return fromNullable(allPostReplies.get(id)); + return postReplyLikingSones.containsEntry(postReply.getId(), sone.getId()); } finally { lock.readLock().unlock(); } } @Override - public List getReplies(String postId) { + public Set getLikes(PostReply postReply) { lock.readLock().lock(); try { - if (!postReplies.containsKey(postId)) { - return emptyList(); - } - return new ArrayList(postReplies.get(postId)); + return from(postReplyLikingSones.get(postReply.getId())).transform(getSone()).transformAndConcat(this.unwrap()).toSet(); } finally { lock.readLock().unlock(); } @@ -680,88 +656,9 @@ public class MemoryDatabase extends AbstractService implements Database { } // - // PACKAGE-PRIVATE METHODS - // - - /** - * Returns whether the given post is known. - * - * @param post - * The post - * @return {@code true} if the post is known, {@code false} otherwise - */ - boolean isPostKnown(Post post) { - lock.readLock().lock(); - try { - return knownPosts.contains(post.getId()); - } finally { - lock.readLock().unlock(); - } - } - - /** - * Sets whether the given post is known. - * - * @param post - * The post - * @param known - * {@code true} if the post is known, {@code false} otherwise - */ - void setPostKnown(Post post, boolean known) { - lock.writeLock().lock(); - try { - if (known) { - knownPosts.add(post.getId()); - } else { - knownPosts.remove(post.getId()); - } - } finally { - lock.writeLock().unlock(); - } - } - - // // PRIVATE METHODS // - /** Loads the known posts. */ - private void loadKnownPosts() { - lock.writeLock().lock(); - try { - int postCounter = 0; - while (true) { - String knownPostId = configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").getValue(null); - if (knownPostId == null) { - break; - } - knownPosts.add(knownPostId); - } - } finally { - lock.writeLock().unlock(); - } - } - - /** - * Saves the known posts to the configuration. - * - * @throws DatabaseException - * if a configuration error occurs - */ - private void saveKnownPosts() throws DatabaseException { - lock.readLock().lock(); - try { - int postCounter = 0; - for (String knownPostId : knownPosts) { - configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").setValue(knownPostId); - } - configuration.getStringValue("KnownPosts/" + postCounter + "/ID").setValue(null); - } catch (ConfigurationException ce1) { - throw new DatabaseException("Could not save database.", ce1); - } finally { - lock.readLock().unlock(); - } - } - /** * Returns all replies by the given Sone. * @@ -837,4 +734,13 @@ public class MemoryDatabase extends AbstractService implements Database { }; } + static Function, Iterable> unwrap() { + return new Function, Iterable>() { + @Override + public Iterable apply(Optional input) { + return (input == null) ? Collections.emptyList() : input.asSet(); + } + }; + } + }