Set Sone in album builder, remote getOrCreate method from core.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 8 Sep 2014 18:43:58 +0000 (20:43 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 8 Sep 2014 18:43:58 +0000 (20:43 +0200)
17 files changed:
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/SoneDownloaderImpl.java
src/main/java/net/pterodactylus/sone/data/Album.java
src/main/java/net/pterodactylus/sone/data/AlbumImpl.java
src/main/java/net/pterodactylus/sone/data/SoneImpl.java
src/main/java/net/pterodactylus/sone/data/impl/AbstractAlbumBuilder.java
src/main/java/net/pterodactylus/sone/data/impl/AlbumBuilderImpl.java
src/main/java/net/pterodactylus/sone/database/AlbumBuilder.java
src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java
src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java
src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java
src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java
src/main/java/net/pterodactylus/sone/web/SearchPage.java
src/main/java/net/pterodactylus/sone/web/UploadImagePage.java
src/main/java/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.java
src/test/java/net/pterodactylus/sone/core/SoneDownloaderTest.java
src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java

index 2fdd01a..a6b4c96 100644 (file)
@@ -67,6 +67,7 @@ import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
 import net.pterodactylus.sone.data.Sone.SoneStatus;
 import net.pterodactylus.sone.data.SoneImpl;
 import net.pterodactylus.sone.data.TemporaryImage;
+import net.pterodactylus.sone.database.AlbumBuilder;
 import net.pterodactylus.sone.database.Database;
 import net.pterodactylus.sone.database.DatabaseException;
 import net.pterodactylus.sone.database.PostBuilder;
@@ -584,16 +585,8 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                return posts;
        }
 
-       /**
-        * Returns the album with the given ID, creating a new album if no album
-        * with the given ID can be found.
-        *
-        * @param albumId
-        *            The ID of the album
-        * @return The album with the given ID
-        */
-       public Album getOrCreateAlbum(String albumId) {
-               return getAlbum(albumId, true);
+       public AlbumBuilder albumBuilder() {
+               return database.newAlbumBuilder();
        }
 
        /**
@@ -602,23 +595,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         *
         * @param albumId
         *            The ID of the album
-        * @param create
-        *            {@code true} to create a new album if none exists for the
-        *            given ID
         * @return The album with the given ID, or {@code null} if no album with the
-        *         given ID exists and {@code create} is {@code false}
+        *         given ID exists
         */
-       public Album getAlbum(String albumId, boolean create) {
-               Optional<Album> album = database.getAlbum(albumId);
-               if (album.isPresent()) {
-                       return album.get();
-               }
-               if (!create) {
-                       return null;
-               }
-               Album newAlbum = database.newAlbumBuilder().withId(albumId).build();
-               database.storeAlbum(newAlbum);
-               return newAlbum;
+       public Album getAlbum(String albumId) {
+               return database.getAlbum(albumId).orNull();
        }
 
        /**
@@ -1159,9 +1140,17 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                                logger.log(Level.WARNING, "Invalid album found, aborting load!");
                                return;
                        }
-                       Album album = getOrCreateAlbum(albumId).setSone(sone).modify().setTitle(albumTitle).setDescription(albumDescription).setAlbumImage(albumImageId).update();
+                       Album album = database.newAlbumBuilder()
+                                       .withId(albumId)
+                                       .by(sone)
+                                       .build()
+                                       .modify()
+                                       .setTitle(albumTitle)
+                                       .setDescription(albumDescription)
+                                       .setAlbumImage(albumImageId)
+                                       .update();
                        if (albumParentId != null) {
-                               Album parentAlbum = getAlbum(albumParentId, false);
+                               Album parentAlbum = getAlbum(albumParentId);
                                if (parentAlbum == null) {
                                        logger.log(Level.WARNING, String.format("Invalid parent album ID: %s", albumParentId));
                                        return;
@@ -1193,7 +1182,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                                logger.log(Level.WARNING, "Invalid image found, aborting load!");
                                return;
                        }
-                       Album album = getAlbum(albumId, false);
+                       Album album = getAlbum(albumId);
                        if (album == null) {
                                logger.log(Level.WARNING, "Invalid album image encountered, aborting load!");
                                return;
@@ -1444,9 +1433,8 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
         * @return The new album
         */
        public Album createAlbum(Sone sone, Album parent) {
-               Album album = database.newAlbumBuilder().randomId().build();
+               Album album = database.newAlbumBuilder().randomId().by(sone).build();
                database.storeAlbum(album);
-               album.setSone(sone);
                parent.addAlbum(album);
                return album;
        }
index ca47132..ebdbecb 100644 (file)
@@ -449,13 +449,20 @@ public class SoneDownloaderImpl extends AbstractService implements SoneDownloade
                                }
                                Album parent = null;
                                if (parentId != null) {
-                                       parent = core.getAlbum(parentId, false);
+                                       parent = core.getAlbum(parentId);
                                        if (parent == null) {
                                                logger.log(Level.WARNING, String.format("Downloaded Sone %s has album with invalid parent!", sone));
                                                return null;
                                        }
                                }
-                               Album album = core.getOrCreateAlbum(id).setSone(sone).modify().setTitle(title).setDescription(description).update();
+                               Album album = core.albumBuilder()
+                                               .withId(id)
+                                               .by(sone)
+                                               .build()
+                                               .modify()
+                                               .setTitle(title)
+                                               .setDescription(description)
+                                               .update();
                                if (parent != null) {
                                        parent.addAlbum(album);
                                } else {
index 09a7da4..f968f00 100644 (file)
@@ -116,16 +116,6 @@ public interface Album extends Identified, Fingerprintable {
        Sone getSone();
 
        /**
-        * Sets the owner of the album. The owner can only be set as long as the
-        * current owner is {@code null}.
-        *
-        * @param sone
-        *              The album owner
-        * @return This album
-        */
-       Album setSone(Sone sone);
-
-       /**
         * Returns the nested albums.
         *
         * @return The nested albums
index f489b0b..b60e99e 100644 (file)
@@ -47,7 +47,7 @@ public class AlbumImpl implements Album {
        private final String id;
 
        /** The Sone this album belongs to. */
-       private Sone sone;
+       private final Sone sone;
 
        /** Nested albums. */
        private final List<Album> albums = new ArrayList<Album>();
@@ -71,8 +71,8 @@ public class AlbumImpl implements Album {
        private String albumImage;
 
        /** Creates a new album with a random ID. */
-       public AlbumImpl() {
-               this(UUID.randomUUID().toString());
+       public AlbumImpl(Sone sone) {
+               this(sone, UUID.randomUUID().toString());
        }
 
        /**
@@ -81,7 +81,8 @@ public class AlbumImpl implements Album {
         * @param id
         *              The ID of the album
         */
-       public AlbumImpl(String id) {
+       public AlbumImpl(Sone sone, String id) {
+               this.sone = checkNotNull(sone, "Sone must not be null");
                this.id = checkNotNull(id, "id must not be null");
        }
 
@@ -100,14 +101,6 @@ public class AlbumImpl implements Album {
        }
 
        @Override
-       public Album setSone(Sone sone) {
-               checkNotNull(sone, "sone must not be null");
-               checkState((this.sone == null) || (this.sone.equals(sone)), "album owner must not already be set to some other Sone");
-               this.sone = sone;
-               return this;
-       }
-
-       @Override
        public List<Album> getAlbums() {
                return new ArrayList<Album>(albums);
        }
index 848fc04..1fe971f 100644 (file)
@@ -99,7 +99,7 @@ public class SoneImpl implements Sone {
        private final Set<String> likedReplyIds = new CopyOnWriteArraySet<String>();
 
        /** The root album containing all albums. */
-       private final Album rootAlbum = new AlbumImpl().setSone(this);
+       private final Album rootAlbum = new AlbumImpl(this);
 
        /** Sone-specific options. */
        private SoneOptions options = new DefaultSoneOptions();
index 312c795..8e15b6f 100644 (file)
@@ -19,6 +19,7 @@ package net.pterodactylus.sone.data.impl;
 
 import static com.google.common.base.Preconditions.checkState;
 
+import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.database.AlbumBuilder;
 
 /**
@@ -34,6 +35,7 @@ public abstract class AbstractAlbumBuilder implements AlbumBuilder {
 
        /** The ID of the album to create. */
        protected String id;
+       protected Sone sone;
 
        @Override
        public AlbumBuilder randomId() {
@@ -47,6 +49,11 @@ public abstract class AbstractAlbumBuilder implements AlbumBuilder {
                return this;
        }
 
+       public AlbumBuilder by(Sone sone) {
+               this.sone = sone;
+               return this;
+       }
+
        //
        // PROTECTED METHODS
        //
@@ -59,6 +66,7 @@ public abstract class AbstractAlbumBuilder implements AlbumBuilder {
         */
        protected void validate() throws IllegalStateException {
                checkState((randomId && (id == null)) || (!randomId && (id != null)), "exactly one of random ID or custom ID must be set");
+               checkState(sone != null, "Sone must not be null");
        }
 
 }
index 3403a62..785a4af 100644 (file)
@@ -31,7 +31,7 @@ public class AlbumBuilderImpl extends AbstractAlbumBuilder {
        @Override
        public Album build() throws IllegalStateException {
                validate();
-               return randomId ? new AlbumImpl() : new AlbumImpl(id);
+               return randomId ? new AlbumImpl(sone) : new AlbumImpl(sone, id);
        }
 
 }
index b888828..a084ae7 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.sone.database;
 
 import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.Sone;
 
 /**
  * Builder for {@link Album} objects.
@@ -42,6 +43,8 @@ public interface AlbumBuilder {
         */
        AlbumBuilder withId(String id);
 
+       AlbumBuilder by(Sone sone);
+
        /**
         * Creates the album.
         *
index a8d024a..76a71d6 100644 (file)
@@ -63,7 +63,7 @@ public class CreateAlbumPage extends SoneTemplatePage {
                        String description = request.getHttpRequest().getPartAsStringFailsafe("description", 256).trim();
                        Sone currentSone = getCurrentSone(request.getToadletContext());
                        String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", 36);
-                       Album parent = webInterface.getCore().getAlbum(parentId, false);
+                       Album parent = webInterface.getCore().getAlbum(parentId);
                        if (parentId.equals("")) {
                                parent = currentSone.getRootAlbum();
                        }
index 391e9ff..98e8909 100644 (file)
@@ -50,7 +50,7 @@ public class DeleteAlbumPage extends SoneTemplatePage {
                super.processTemplate(request, templateContext);
                if (request.getMethod() == Method.POST) {
                        String albumId = request.getHttpRequest().getPartAsStringFailsafe("album", 36);
-                       Album album = webInterface.getCore().getAlbum(albumId, false);
+                       Album album = webInterface.getCore().getAlbum(albumId);
                        if (album == null) {
                                throw new RedirectException("invalid.html");
                        }
@@ -68,7 +68,7 @@ public class DeleteAlbumPage extends SoneTemplatePage {
                        throw new RedirectException("imageBrowser.html?album=" + parentAlbum.getId());
                }
                String albumId = request.getHttpRequest().getParam("album");
-               Album album = webInterface.getCore().getAlbum(albumId, false);
+               Album album = webInterface.getCore().getAlbum(albumId);
                if (album == null) {
                        throw new RedirectException("invalid.html");
                }
index 9e4aae9..7debd3d 100644 (file)
@@ -51,7 +51,7 @@ public class EditAlbumPage extends SoneTemplatePage {
                super.processTemplate(request, templateContext);
                if (request.getMethod() == Method.POST) {
                        String albumId = request.getHttpRequest().getPartAsStringFailsafe("album", 36);
-                       Album album = webInterface.getCore().getAlbum(albumId, false);
+                       Album album = webInterface.getCore().getAlbum(albumId);
                        if (album == null) {
                                throw new RedirectException("invalid.html");
                        }
index 766f018..0dbe4e7 100644 (file)
@@ -69,7 +69,7 @@ public class ImageBrowserPage extends SoneTemplatePage {
                super.processTemplate(request, templateContext);
                String albumId = request.getHttpRequest().getParam("album", null);
                if (albumId != null) {
-                       Album album = webInterface.getCore().getAlbum(albumId, false);
+                       Album album = webInterface.getCore().getAlbum(albumId);
                        templateContext.set("albumRequested", true);
                        templateContext.set("album", album);
                        templateContext.set("page", request.getHttpRequest().getParam("page"));
index 3f6d065..508d30b 100644 (file)
@@ -354,7 +354,7 @@ public class SearchPage extends SoneTemplatePage {
         */
        private String getAlbumId(String phrase) {
                String albumId = phrase.startsWith("album://") ? phrase.substring(8) : phrase;
-               return (webInterface.getCore().getAlbum(albumId, false) != null) ? albumId : null;
+               return (webInterface.getCore().getAlbum(albumId) != null) ? albumId : null;
        }
 
        /**
index 2079cac..b7e9e93 100644 (file)
@@ -81,7 +81,7 @@ public class UploadImagePage extends SoneTemplatePage {
                if (request.getMethod() == Method.POST) {
                        Sone currentSone = getCurrentSone(request.getToadletContext());
                        String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", 36);
-                       Album parent = webInterface.getCore().getAlbum(parentId, false);
+                       Album parent = webInterface.getCore().getAlbum(parentId);
                        if (parent == null) {
                                /* TODO - signal error */
                                return;
index 74a73b8..4c3d2ba 100644 (file)
@@ -49,7 +49,7 @@ public class EditAlbumAjaxPage extends JsonPage {
        @Override
        protected JsonReturnObject createJsonObject(FreenetRequest request) {
                String albumId = request.getHttpRequest().getParam("album");
-               Album album = webInterface.getCore().getAlbum(albumId, false);
+               Album album = webInterface.getCore().getAlbum(albumId);
                if (album == null) {
                        return createErrorJsonObject("invalid-album-id");
                }
index c17c12f..b05d2ca 100644 (file)
@@ -1,6 +1,7 @@
 package net.pterodactylus.sone.core;
 
 import static com.google.common.base.Optional.of;
+import static java.util.UUID.randomUUID;
 import static net.pterodactylus.sone.data.Sone.SoneStatus.downloading;
 import static net.pterodactylus.sone.data.Sone.SoneStatus.idle;
 import static net.pterodactylus.sone.data.Sone.SoneStatus.unknown;
@@ -16,6 +17,7 @@ import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -34,7 +36,7 @@ import java.util.Set;
 
 import net.pterodactylus.sone.core.FreenetInterface.Fetched;
 import net.pterodactylus.sone.data.Album;
-import net.pterodactylus.sone.data.AlbumImpl;
+import net.pterodactylus.sone.data.Album.Modifier;
 import net.pterodactylus.sone.data.Client;
 import net.pterodactylus.sone.data.Image;
 import net.pterodactylus.sone.data.ImageImpl;
@@ -43,6 +45,7 @@ import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Profile;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.data.Sone.SoneStatus;
+import net.pterodactylus.sone.database.AlbumBuilder;
 import net.pterodactylus.sone.database.PostBuilder;
 import net.pterodactylus.sone.database.PostReplyBuilder;
 import net.pterodactylus.sone.freenet.wot.Identity;
@@ -53,7 +56,9 @@ import freenet.keys.FreenetURI;
 import freenet.support.api.Bucket;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -78,6 +83,10 @@ public class SoneDownloaderTest {
        private final PostReplyBuilder postReplyBuilder = mock(PostReplyBuilder.class);
        private final Set<PostReply> createdPostReplies = new HashSet<PostReply>();
        private PostReply postReply = mock(PostReply.class);
+       private final AlbumBuilder albumBuilder = mock(AlbumBuilder.class);
+       private final ListMultimap<Album, Album> nestedAlbums = ArrayListMultimap.create();
+       private final ListMultimap<Album, Image> albumImages = ArrayListMultimap.create();
+       private Album album = mock(Album.class);
        private final Map<String, Album> albums = new HashMap<String, Album>();
 
        @Before
@@ -208,16 +217,113 @@ public class SoneDownloaderTest {
        }
 
        @Before
-       public void setupAlbums() {
-               albums.put("album-id-1", new AlbumImpl("album-id-1"));
-               albums.put("album-id-2", new AlbumImpl("album-id-2"));
-               when(core.getOrCreateAlbum(anyString())).thenAnswer(new Answer<Album>() {
+       public void setupAlbum() {
+               setupAlbum(album);
+       }
+
+       private void setupAlbum(final Album album) {
+               when(album.getAlbumImage()).thenReturn(mock(Image.class));
+               doAnswer(new Answer<Void>() {
                        @Override
-                       public Album answer(InvocationOnMock invocation) throws Throwable {
-                               return albums.get(invocation.getArguments()[0]);
+                       public Void answer(InvocationOnMock invocation) {
+                               nestedAlbums.put(album, (Album) invocation.getArguments()[0]);
+                               return null;
+                       }
+               }).when(album).addAlbum(any(Album.class));
+               doAnswer(new Answer<Void>() {
+                       @Override
+                       public Void answer(InvocationOnMock invocation) {
+                               albumImages.put(album, (Image) invocation.getArguments()[0]);
+                               return null;
+                       }
+               }).when(album).addImage(any(Image.class));
+               when(album.getAlbums()).thenAnswer(new Answer<List<Album>>() {
+                       @Override
+                       public List<Album> answer(InvocationOnMock invocation) {
+                               return nestedAlbums.get(album);
+                       }
+               });
+               when(album.getImages()).thenAnswer(new Answer<List<Image>>() {
+                       @Override
+                       public List<Image> answer(InvocationOnMock invocation) {
+                               return albumImages.get(album);
                        }
                });
-               when(core.getAlbum(anyString(), anyBoolean())).thenAnswer(new Answer<Album>() {
+               final Modifier albumModifier = new Modifier() {
+                       private String title = album.getTitle();
+                       private String description = album.getDescription();
+                       private String imageId = album.getAlbumImage().getId();
+
+                       @Override
+                       public Modifier setTitle(String title) {
+                               this.title = title;
+                               return this;
+                       }
+
+                       @Override
+                       public Modifier setDescription(String description) {
+                               this.description = description;
+                               return this;
+                       }
+
+                       @Override
+                       public Modifier setAlbumImage(String imageId) {
+                               this.imageId = imageId;
+                               return this;
+                       }
+
+                       @Override
+                       public Album update() throws IllegalStateException {
+                               when(album.getTitle()).thenReturn(title);
+                               when(album.getDescription()).thenReturn(description);
+                               Image image = mock(Image.class);
+                               when(image.getId()).thenReturn(imageId);
+                               when(album.getAlbumImage()).thenReturn(image);
+                               return album;
+                       }
+               };
+               when(album.modify()).thenReturn(albumModifier);
+       }
+
+       @Before
+       public void setupAlbumBuilder() {
+               when(albumBuilder.withId(anyString())).thenAnswer(new Answer<AlbumBuilder>() {
+                       @Override
+                       public AlbumBuilder answer(InvocationOnMock invocation) {
+                               when(album.getId()).thenReturn((String) invocation.getArguments()[0]);
+                               return albumBuilder;
+                       }
+               });
+               when(albumBuilder.randomId()).thenAnswer(new Answer<AlbumBuilder>() {
+                       @Override
+                       public AlbumBuilder answer(InvocationOnMock invocation) {
+                               when(album.getId()).thenReturn(randomUUID().toString());
+                               return albumBuilder;
+                       }
+               });
+               when(albumBuilder.by(any(Sone.class))).thenAnswer(new Answer<AlbumBuilder>() {
+                       @Override
+                       public AlbumBuilder answer(InvocationOnMock invocation) {
+                               when(album.getSone()).thenReturn((Sone) invocation.getArguments()[0]);
+                               return albumBuilder;
+                       }
+               });
+               when(albumBuilder.build()).thenAnswer(new Answer<Album>() {
+                       @Override
+                       public Album answer(InvocationOnMock invocation) {
+                               Album album = SoneDownloaderTest.this.album;
+                               albums.put(album.getId(), album);
+                               SoneDownloaderTest.this.album = mock(Album.class);
+                               setupAlbum(SoneDownloaderTest.this.album);
+                               return album;
+                       }
+               });
+               when(core.albumBuilder()).thenReturn(albumBuilder);
+       }
+
+       @Before
+       public void setupAlbums() {
+               when(core.getAlbum(anyString())).thenAnswer(new Answer<Album>() {
                        @Override
                        public Album answer(InvocationOnMock invocation) throws Throwable {
                                return albums.get(invocation.getArguments()[0]);
index 056a06d..74c58ca 100644 (file)
@@ -20,9 +20,11 @@ package net.pterodactylus.sone.database.memory;
 import static com.google.common.base.Optional.of;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
 
 import net.pterodactylus.sone.data.Album;
 import net.pterodactylus.sone.data.AlbumImpl;
+import net.pterodactylus.sone.data.Sone;
 
 import com.google.common.base.Optional;
 import org.junit.Test;
@@ -38,7 +40,7 @@ public class MemoryDatabaseTest {
 
        @Test
        public void testBasicAlbumFunctionality() {
-               Album newAlbum = new AlbumImpl();
+               Album newAlbum = new AlbumImpl(mock(Sone.class));
                assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(Optional.<Album>absent()));
                memoryDatabase.storeAlbum(newAlbum);
                assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(of(newAlbum)));