X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fdatabase%2Fmemory%2FMemoryDatabase.java;h=a19290e5360b874eb7b8a638c25b274858cda937;hb=918190a7948e8c45398059dec7c446c8662450ae;hp=db64c79688965eaa30742c71061788798862d362;hpb=4479b8a9e2e8b3a51b998c757e6c26ee2853bbd5;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 db64c79..a19290e 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java @@ -17,7 +17,12 @@ 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.emptyList; +import static net.pterodactylus.sone.data.Sone.LOCAL_SONE_FILTER; import java.util.ArrayList; import java.util.Collection; @@ -33,20 +38,27 @@ 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.database.Database; import net.pterodactylus.sone.database.DatabaseException; -import net.pterodactylus.sone.database.PostBuilder; import net.pterodactylus.sone.database.PostDatabase; -import net.pterodactylus.sone.database.PostReplyBuilder; -import net.pterodactylus.sone.database.SoneProvider; +import net.pterodactylus.sone.database.SoneBuilder; +import net.pterodactylus.sone.freenet.wot.Identity; import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; +import com.google.common.base.Function; 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.SortedSetMultimap; import com.google.common.collect.TreeMultimap; import com.google.common.util.concurrent.AbstractService; @@ -62,17 +74,17 @@ public class MemoryDatabase extends AbstractService implements Database { /** The lock. */ private final ReadWriteLock lock = new ReentrantReadWriteLock(); - /** The Sone provider. */ - private final SoneProvider soneProvider; - /** 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 Map> sonePosts = new HashMap>(); + private final Multimap sonePosts = HashMultimap.create(); /** All posts by their recipient. */ private final Map> recipientPosts = new HashMap>(); @@ -98,17 +110,20 @@ public class MemoryDatabase extends AbstractService implements Database { /** Whether post replies are known. */ private final Set knownPostReplies = new HashSet(); + private final Map allAlbums = new HashMap(); + private final ListMultimap albumChildren = ArrayListMultimap.create(); + private final ListMultimap albumImages = ArrayListMultimap.create(); + + private final Map allImages = new HashMap(); + /** * Creates a new memory database. * - * @param soneProvider - * The Sone provider * @param configuration - * The configuration for loading and saving elements + * The configuration for loading and saving elements */ @Inject - public MemoryDatabase(SoneProvider soneProvider, Configuration configuration) { - this.soneProvider = soneProvider; + public MemoryDatabase(Configuration configuration) { this.configuration = configuration; } @@ -116,12 +131,6 @@ public class MemoryDatabase extends AbstractService implements Database { // DATABASE METHODS // - /** - * Saves the database. - * - * @throws DatabaseException - * if an error occurs while saving - */ @Override public void save() throws DatabaseException { saveKnownPosts(); @@ -132,9 +141,6 @@ public class MemoryDatabase extends AbstractService implements Database { // SERVICE METHODS // - /** - * {@inheritDocs} - */ @Override protected void doStart() { loadKnownPosts(); @@ -142,9 +148,6 @@ public class MemoryDatabase extends AbstractService implements Database { notifyStarted(); } - /** - * {@inheritDocs} - */ @Override protected void doStop() { try { @@ -155,71 +158,107 @@ public class MemoryDatabase extends AbstractService implements Database { } } + @Override + public Optional getIdentity(String identityId) { + lock.readLock().lock(); + try { + return fromNullable(identities.get(identityId)); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public Optional getSone(String soneId) { + lock.readLock().lock(); + try { + return fromNullable(sones.get(soneId)); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public Collection getSones() { + lock.readLock().lock(); + try { + return Collections.unmodifiableCollection(sones.values()); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public Collection getLocalSones() { + lock.readLock().lock(); + try { + return from(getSones()).filter(LOCAL_SONE_FILTER).toSet(); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public Collection getRemoteSones() { + lock.readLock().lock(); + try { + return from(getSones()).filter(not(LOCAL_SONE_FILTER)).toSet(); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public SoneBuilder newSoneBuilder() { + return null; + } + // // POSTPROVIDER METHODS // - /** - * {@inheritDocs} - */ @Override public Optional getPost(String postId) { lock.readLock().lock(); try { - return Optional.fromNullable(allPosts.get(postId)); + return fromNullable(allPosts.get(postId)); } finally { lock.readLock().unlock(); } } - /** - * {@inheritDocs} - */ @Override public Collection getPosts(String soneId) { - return new HashSet(getPostsFrom(soneId)); + lock.readLock().lock(); + try { + return new HashSet(sonePosts.get(soneId)); + } finally { + lock.readLock().unlock(); + } } - /** - * {@inheritDocs} - */ @Override public Collection getDirectedPosts(String recipientId) { lock.readLock().lock(); try { Collection posts = recipientPosts.get(recipientId); - return (posts == null) ? Collections. emptySet() : new HashSet(posts); + return (posts == null) ? Collections.emptySet() : new HashSet(posts); } finally { lock.readLock().unlock(); } } // - // POSTBUILDERFACTORY METHODS - // - - /** - * {@inheritDocs} - */ - @Override - public PostBuilder newPostBuilder() { - return new MemoryPostBuilder(this, soneProvider); - } - - // // POSTSTORE METHODS // - /** - * {@inheritDocs} - */ @Override public void storePost(Post post) { checkNotNull(post, "post must not be null"); lock.writeLock().lock(); try { allPosts.put(post.getId(), post); - getPostsFrom(post.getSone().getId()).add(post); + sonePosts.put(post.getSone().getId(), post); if (post.getRecipientId().isPresent()) { getPostsTo(post.getRecipientId().get()).add(post); } @@ -228,16 +267,13 @@ public class MemoryDatabase extends AbstractService implements Database { } } - /** - * {@inheritDocs} - */ @Override public void removePost(Post post) { checkNotNull(post, "post must not be null"); lock.writeLock().lock(); try { allPosts.remove(post.getId()); - getPostsFrom(post.getSone().getId()).remove(post); + sonePosts.remove(post.getSone().getId(), post); if (post.getRecipientId().isPresent()) { getPostsTo(post.getRecipientId().get()).remove(post); } @@ -247,9 +283,6 @@ public class MemoryDatabase extends AbstractService implements Database { } } - /** - * {@inheritDocs} - */ @Override public void storePosts(Sone sone, Collection posts) throws IllegalArgumentException { checkNotNull(sone, "sone must not be null"); @@ -263,7 +296,7 @@ public class MemoryDatabase extends AbstractService implements Database { lock.writeLock().lock(); try { /* remove all posts by the Sone. */ - getPostsFrom(sone.getId()).clear(); + sonePosts.removeAll(sone.getId()); for (Post post : posts) { allPosts.remove(post.getId()); if (post.getRecipientId().isPresent()) { @@ -272,7 +305,7 @@ public class MemoryDatabase extends AbstractService implements Database { } /* add new posts. */ - getPostsFrom(sone.getId()).addAll(posts); + sonePosts.putAll(sone.getId(), posts); for (Post post : posts) { allPosts.put(post.getId(), post); if (post.getRecipientId().isPresent()) { @@ -284,16 +317,13 @@ public class MemoryDatabase extends AbstractService implements Database { } } - /** - * {@inheritDocs} - */ @Override public void removePosts(Sone sone) { checkNotNull(sone, "sone must not be null"); lock.writeLock().lock(); try { /* remove all posts by the Sone. */ - getPostsFrom(sone.getId()).clear(); + sonePosts.removeAll(sone.getId()); for (Post post : sone.getPosts()) { allPosts.remove(post.getId()); if (post.getRecipientId().isPresent()) { @@ -309,28 +339,22 @@ public class MemoryDatabase extends AbstractService implements Database { // POSTREPLYPROVIDER METHODS // - /** - * {@inheritDocs} - */ @Override public Optional getPostReply(String id) { lock.readLock().lock(); try { - return Optional.fromNullable(allPostReplies.get(id)); + return fromNullable(allPostReplies.get(id)); } finally { lock.readLock().unlock(); } } - /** - * {@inheritDocs} - */ @Override public List getReplies(String postId) { lock.readLock().lock(); try { if (!postReplies.containsKey(postId)) { - return Collections.emptyList(); + return emptyList(); } return new ArrayList(postReplies.get(postId)); } finally { @@ -339,24 +363,36 @@ public class MemoryDatabase extends AbstractService implements Database { } // - // POSTREPLYBUILDERFACTORY METHODS + // POSTREPLYSTORE METHODS // /** - * {@inheritDocs} + * Returns whether the given post reply is known. + * + * @param postReply + * The post reply + * @return {@code true} if the given post reply is known, {@code false} + * otherwise */ - @Override - public PostReplyBuilder newPostReplyBuilder() { - return new MemoryPostReplyBuilder(this, soneProvider); + public boolean isPostReplyKnown(PostReply postReply) { + lock.readLock().lock(); + try { + return knownPostReplies.contains(postReply.getId()); + } finally { + lock.readLock().unlock(); + } } - // - // POSTREPLYSTORE METHODS - // + @Override + public void setPostReplyKnown(PostReply postReply) { + lock.writeLock().lock(); + try { + knownPostReplies.add(postReply.getId()); + } finally { + lock.writeLock().unlock(); + } + } - /** - * {@inheritDocs} - */ @Override public void storePostReply(PostReply postReply) { lock.writeLock().lock(); @@ -374,9 +410,6 @@ public class MemoryDatabase extends AbstractService implements Database { } } - /** - * {@inheritDocs} - */ @Override public void storePostReplies(Sone sone, Collection postReplies) { checkNotNull(sone, "sone must not be null"); @@ -409,9 +442,6 @@ public class MemoryDatabase extends AbstractService implements Database { } } - /** - * {@inheritDocs} - */ @Override public void removePostReply(PostReply postReply) { lock.writeLock().lock(); @@ -428,9 +458,6 @@ public class MemoryDatabase extends AbstractService implements Database { } } - /** - * {@inheritDocs} - */ @Override public void removePostReplies(Sone sone) { checkNotNull(sone, "sone must not be null"); @@ -446,126 +473,220 @@ public class MemoryDatabase extends AbstractService implements Database { } // - // PACKAGE-PRIVATE METHODS + // ALBUMPROVDER 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) { + @Override + public Optional getAlbum(String albumId) { lock.readLock().lock(); try { - return knownPosts.contains(post.getId()); + return fromNullable(allAlbums.get(albumId)); } 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) { + @Override + public List getAlbums(Album parent) { + lock.readLock().lock(); + try { + return from(albumChildren.get(parent.getId())).transformAndConcat(getAlbum()).toList(); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public void moveUp(Album album) { lock.writeLock().lock(); try { - if (known) { - knownPosts.add(post.getId()); - } else { - knownPosts.remove(post.getId()); + List albums = albumChildren.get(album.getParent().getId()); + int currentIndex = albums.indexOf(album.getId()); + if (currentIndex == 0) { + return; } + albums.remove(album.getId()); + albums.add(currentIndex - 1, album.getId()); } finally { lock.writeLock().unlock(); } } - /** - * Returns whether the given post reply is known. - * - * @param postReply - * The post reply - * @return {@code true} if the given post reply is known, {@code false} - * otherwise - */ - boolean isPostReplyKnown(PostReply postReply) { + @Override + public void moveDown(Album album) { + lock.writeLock().lock(); + try { + List albums = albumChildren.get(album.getParent().getId()); + int currentIndex = albums.indexOf(album.getId()); + if (currentIndex == (albums.size() - 1)) { + return; + } + albums.remove(album.getId()); + albums.add(currentIndex + 1, album.getId()); + } finally { + lock.writeLock().unlock(); + } + } + + // + // ALBUMSTORE METHODS + // + + @Override + public void storeAlbum(Album album) { + lock.writeLock().lock(); + try { + allAlbums.put(album.getId(), album); + albumChildren.put(album.getParent().getId(), album.getId()); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public void removeAlbum(Album album) { + lock.writeLock().lock(); + try { + allAlbums.remove(album.getId()); + albumChildren.remove(album.getParent().getId(), album.getId()); + } finally { + lock.writeLock().unlock(); + } + } + + // + // IMAGEPROVIDER METHODS + // + + @Override + public Optional getImage(String imageId) { lock.readLock().lock(); try { - return knownPostReplies.contains(postReply.getId()); + return fromNullable(allImages.get(imageId)); } finally { lock.readLock().unlock(); } } - /** - * Sets whether the given post reply is known. - * - * @param postReply - * The post reply - * @param known - * {@code true} if the post reply is known, {@code false} - * otherwise - */ - void setPostReplyKnown(PostReply postReply, boolean known) { + @Override + public List getImages(Album parent) { + lock.readLock().lock(); + try { + return from(albumImages.get(parent.getId())).transformAndConcat(getImage()).toList(); + } finally { + lock.readLock().unlock(); + } + } + + @Override + public void moveUp(Image image) { lock.writeLock().lock(); try { - if (known) { - knownPostReplies.add(postReply.getId()); - } else { - knownPostReplies.remove(postReply.getId()); + List images = albumImages.get(image.getAlbum().getId()); + int currentIndex = images.indexOf(image.getId()); + if (currentIndex == 0) { + return; } + images.remove(image.getId()); + images.add(currentIndex - 1, image.getId()); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public void moveDown(Image image) { + lock.writeLock().lock(); + try { + List images = albumChildren.get(image.getAlbum().getId()); + int currentIndex = images.indexOf(image.getId()); + if (currentIndex == (images.size() - 1)) { + return; + } + images.remove(image.getId()); + images.add(currentIndex + 1, image.getId()); } finally { lock.writeLock().unlock(); } } // - // PRIVATE METHODS + // IMAGESTORE METHODS + // + + @Override + public void storeImage(Image image) { + lock.writeLock().lock(); + try { + allImages.put(image.getId(), image); + albumImages.put(image.getAlbum().getId(), image.getId()); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public void removeImage(Image image) { + lock.writeLock().lock(); + try { + allImages.remove(image.getId()); + albumImages.remove(image.getAlbum().getId(), image.getId()); + } finally { + lock.writeLock().unlock(); + } + } + + // + // PACKAGE-PRIVATE METHODS // /** - * Gets all posts for the given Sone, creating a new collection if there is - * none yet. + * Returns whether the given post is known. * - * @param soneId - * The ID of the Sone to get the posts for - * @return All posts + * @param post + * The post + * @return {@code true} if the post is known, {@code false} otherwise */ - private Collection getPostsFrom(String soneId) { - Collection posts = null; + boolean isPostKnown(Post post) { lock.readLock().lock(); try { - posts = sonePosts.get(soneId); + return knownPosts.contains(post.getId()); } finally { lock.readLock().unlock(); } - if (posts != null) { - return posts; - } + } - posts = new HashSet(); + /** + * 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 { - sonePosts.put(soneId, posts); + if (known) { + knownPosts.add(post.getId()); + } else { + knownPosts.remove(post.getId()); + } } finally { lock.writeLock().unlock(); } - - return posts; } + // + // PRIVATE METHODS + // + /** - * Gets all posts that are directed the given Sone, creating a new - * collection if there is none yet. + * 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 + * The ID of the Sone to get the posts for * @return All posts */ private Collection getPostsTo(String recipientId) { @@ -591,9 +712,7 @@ public class MemoryDatabase extends AbstractService implements Database { return posts; } - /** - * Loads the known posts. - */ + /** Loads the known posts. */ private void loadKnownPosts() { lock.writeLock().lock(); try { @@ -614,7 +733,7 @@ public class MemoryDatabase extends AbstractService implements Database { * Saves the known posts to the configuration. * * @throws DatabaseException - * if a configuration error occurs + * if a configuration error occurs */ private void saveKnownPosts() throws DatabaseException { lock.readLock().lock(); @@ -671,7 +790,7 @@ public class MemoryDatabase extends AbstractService implements Database { * Saves the known post replies to the configuration. * * @throws DatabaseException - * if a configuration error occurs + * if a configuration error occurs */ private void saveKnownPostReplies() throws DatabaseException { lock.readLock().lock(); @@ -688,4 +807,22 @@ public class MemoryDatabase extends AbstractService implements Database { } } + private Function> getAlbum() { + return new Function>() { + @Override + public Iterable apply(String input) { + return (input == null) ? Collections.emptyList() : getAlbum(input).asSet(); + } + }; + } + + private Function> getImage() { + return new Function>() { + @Override + public Iterable apply(String input) { + return (input == null) ? Collections.emptyList() : getImage(input).asSet(); + } + }; + } + }