From 01540cbd527e955dac1e41c2e6855a89ab12605c Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 21 Sep 2014 12:18:34 +0200 Subject: [PATCH] Store Sones in the database, too. --- .../java/net/pterodactylus/sone/core/Core.java | 16 +-- .../net/pterodactylus/sone/database/Database.java | 7 +- .../pterodactylus/sone/database/SoneDatabase.java | 11 ++ .../net/pterodactylus/sone/database/SoneStore.java | 14 ++ .../sone/database/memory/MemoryDatabase.java | 96 +++++++++++++- .../sone/database/memory/MemoryDatabaseTest.java | 145 +++++++++++++++++++++ 6 files changed, 268 insertions(+), 21 deletions(-) create mode 100644 src/main/java/net/pterodactylus/sone/database/SoneDatabase.java create mode 100644 src/main/java/net/pterodactylus/sone/database/SoneStore.java diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 5867415..47a77ee 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -990,21 +990,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } }); soneChangeDetector.detectChanges(sone); - /* store posts. */ - database.storePosts(sone, sone.getPosts()); - database.storePostReplies(sone, sone.getReplies()); - for (Album album : storedSone.get().getRootAlbum().getAlbums()) { - database.removeAlbum(album); - for (Image image : album.getImages()) { - database.removeImage(image); - } - } - for (Album album : toAllAlbums.apply(sone)) { - database.storeAlbum(album); - for (Image image : album.getImages()) { - database.storeImage(image); - } - } + database.storeSone(sone); synchronized (sones) { sone.setOptions(storedSone.get().getOptions()); sone.setKnown(storedSone.get().isKnown()); diff --git a/src/main/java/net/pterodactylus/sone/database/Database.java b/src/main/java/net/pterodactylus/sone/database/Database.java index 051e442..1d871b9 100644 --- a/src/main/java/net/pterodactylus/sone/database/Database.java +++ b/src/main/java/net/pterodactylus/sone/database/Database.java @@ -23,14 +23,13 @@ import com.google.common.util.concurrent.Service; import com.google.inject.ImplementedBy; /** - * Database for Sone data. This interface combines the various provider, store, - * and builder factory interfaces into a single interface and adds some methods - * necessary for lifecycle management. + * Database for Sone data. This interface combines the various provider, + * store, and builder factory interfaces into a single interface. * * @author David ‘Bombe’ Roden */ @ImplementedBy(MemoryDatabase.class) -public interface Database extends Service, PostDatabase, PostReplyDatabase, AlbumDatabase, ImageDatabase { +public interface Database extends Service, SoneDatabase, PostDatabase, PostReplyDatabase, AlbumDatabase, ImageDatabase { /** * Saves the database. diff --git a/src/main/java/net/pterodactylus/sone/database/SoneDatabase.java b/src/main/java/net/pterodactylus/sone/database/SoneDatabase.java new file mode 100644 index 0000000..0f97103 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/SoneDatabase.java @@ -0,0 +1,11 @@ +package net.pterodactylus.sone.database; + +/** + * Combines a {@link SoneProvider} and a {@link SoneStore} into a Sone + * database. + * + * @author David ‘Bombe’ Roden + */ +public interface SoneDatabase extends SoneProvider, SoneStore { + +} diff --git a/src/main/java/net/pterodactylus/sone/database/SoneStore.java b/src/main/java/net/pterodactylus/sone/database/SoneStore.java new file mode 100644 index 0000000..010fa60 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/SoneStore.java @@ -0,0 +1,14 @@ +package net.pterodactylus.sone.database; + +import net.pterodactylus.sone.data.Sone; + +/** + * Interface for a store for {@link Sone}s. + * + * @author David ‘Bombe’ Roden + */ +public interface SoneStore { + + void storeSone(Sone sone); + +} 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 5a29285..c9dd543 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java @@ -19,12 +19,15 @@ package net.pterodactylus.sone.database.memory; 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; @@ -79,6 +82,8 @@ 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(); @@ -162,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 // diff --git a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java b/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java index db18cd2..0753021 100644 --- a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java +++ b/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java @@ -18,15 +18,29 @@ package net.pterodactylus.sone.database.memory; import static com.google.common.base.Optional.of; +import static java.util.Arrays.asList; import static java.util.UUID.randomUUID; +import static net.pterodactylus.sone.Matchers.isAlbum; +import static net.pterodactylus.sone.Matchers.isImage; +import static net.pterodactylus.sone.Matchers.isPost; +import static net.pterodactylus.sone.Matchers.isPostReply; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import net.pterodactylus.sone.TestAlbumBuilder; +import net.pterodactylus.sone.TestImageBuilder; +import net.pterodactylus.sone.TestPostBuilder; +import net.pterodactylus.sone.TestPostReplyBuilder; import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.AlbumImpl; +import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; @@ -53,6 +67,137 @@ public class MemoryDatabaseTest { } @Test + public void storedSoneIsMadeAvailable() { + Post firstPost = new TestPostBuilder().withId("post1") + .from(SONE_ID) + .withTime(1000L) + .withText("post1") + .build(); + Post secondPost = new TestPostBuilder().withId("post2") + .from(SONE_ID) + .withTime(2000L) + .withText("post2") + .to(RECIPIENT_ID) + .build(); + List posts = asList(firstPost, secondPost); + when(sone.getPosts()).thenReturn(posts); + PostReply firstPostFirstReply = + new TestPostReplyBuilder().withId("reply1") + .from(SONE_ID) + .to(firstPost.getId()) + .withTime(3000L) + .withText("reply1") + .build(); + PostReply firstPostSecondReply = + new TestPostReplyBuilder().withId("reply3") + .from(RECIPIENT_ID) + .to(firstPost.getId()) + .withTime(5000L) + .withText("reply3") + .build(); + PostReply secondPostReply = + new TestPostReplyBuilder().withId("reply2") + .from(SONE_ID) + .to(secondPost.getId()) + .withTime(4000L) + .withText("reply2") + .build(); + Set postReplies = new HashSet( + asList(firstPostFirstReply, firstPostSecondReply, + secondPostReply)); + when(sone.getReplies()).thenReturn(postReplies); + Album firstAlbum = new TestAlbumBuilder().withId("album1") + .by(sone) + .build() + .modify() + .setTitle("album1") + .setDescription("album-description1") + .update(); + Album secondAlbum = new TestAlbumBuilder().withId("album2").by( + sone).build().modify().setTitle("album2").setDescription( + "album-description2").setAlbumImage("image1").update(); + Album thirdAlbum = new TestAlbumBuilder().withId("album3").by( + sone).build().modify().setTitle("album3").setDescription( + "album-description3").update(); + firstAlbum.addAlbum(thirdAlbum); + Album rootAlbum = mock(Album.class); + when(rootAlbum.getAlbums()).thenReturn( + asList(firstAlbum, secondAlbum)); + when(sone.getRootAlbum()).thenReturn(rootAlbum); + Image firstImage = new TestImageBuilder().withId("image1") + .build() + .modify() + .setSone(sone) + .setCreationTime(1000L) + .setKey("KSK@image1") + .setTitle("image1") + .setDescription("image-description1") + .setWidth(16) + .setHeight(9) + .update(); + Image secondImage = new TestImageBuilder().withId("image2") + .build() + .modify() + .setSone(sone) + .setCreationTime(2000L) + .setKey("KSK@image2") + .setTitle("image2") + .setDescription("image-description2") + .setWidth(32) + .setHeight(18) + .update(); + Image thirdImage = new TestImageBuilder().withId("image3") + .build() + .modify() + .setSone(sone) + .setCreationTime(3000L) + .setKey("KSK@image3") + .setTitle("image3") + .setDescription("image-description3") + .setWidth(48) + .setHeight(27) + .update(); + firstAlbum.addImage(firstImage); + firstAlbum.addImage(thirdImage); + secondAlbum.addImage(secondImage); + memoryDatabase.storeSone(sone); + assertThat(memoryDatabase.getPost("post1").get(), + isPost(firstPost.getId(), 1000L, "post1", + Optional.absent())); + assertThat(memoryDatabase.getPost("post2").get(), + isPost(secondPost.getId(), 2000L, "post2", of(RECIPIENT_ID))); + assertThat(memoryDatabase.getPost("post3").isPresent(), is(false)); + assertThat(memoryDatabase.getPostReply("reply1").get(), + isPostReply("reply1", "post1", 3000L, "reply1")); + assertThat(memoryDatabase.getPostReply("reply2").get(), + isPostReply("reply2", "post2", 4000L, "reply2")); + assertThat(memoryDatabase.getPostReply("reply3").get(), + isPostReply("reply3", "post1", 5000L, "reply3")); + assertThat(memoryDatabase.getPostReply("reply4").isPresent(), + is(false)); + assertThat(memoryDatabase.getAlbum("album1").get(), + isAlbum("album1", null, "album1", "album-description1", + null)); + assertThat(memoryDatabase.getAlbum("album2").get(), + isAlbum("album2", null, "album2", "album-description2", + "image1")); + assertThat(memoryDatabase.getAlbum("album3").get(), + isAlbum("album3", "album1", "album3", "album-description3", + null)); + assertThat(memoryDatabase.getAlbum("album4").isPresent(), is(false)); + assertThat(memoryDatabase.getImage("image1").get(), + isImage("image1", 1000L, "KSK@image1", "image1", + "image-description1", 16, 9)); + assertThat(memoryDatabase.getImage("image2").get(), + isImage("image2", 2000L, "KSK@image2", "image2", + "image-description2", 32, 18)); + assertThat(memoryDatabase.getImage("image3").get(), + isImage("image3", 3000L, "KSK@image3", "image3", + "image-description3", 48, 27)); + assertThat(memoryDatabase.getImage("image4").isPresent(), is(false)); + } + + @Test public void postRecipientsAreDetectedCorrectly() { Post postWithRecipient = createPost(of(RECIPIENT_ID)); memoryDatabase.storePost(postWithRecipient); -- 2.7.4