Move image parsing to new configuration parser.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 9 Sep 2014 18:24:37 +0000 (20:24 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 9 Sep 2014 18:49:44 +0000 (20:49 +0200)
src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java
src/main/java/net/pterodactylus/sone/core/Core.java
src/test/java/net/pterodactylus/sone/Matchers.java
src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java

index 7b7be9f..3d384c1 100644 (file)
@@ -1,5 +1,7 @@
 package net.pterodactylus.sone.core;
 
+import static java.util.Collections.unmodifiableMap;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -10,11 +12,13 @@ import java.util.Set;
 import javax.annotation.Nullable;
 
 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.Profile;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.database.AlbumBuilderFactory;
+import net.pterodactylus.sone.database.ImageBuilderFactory;
 import net.pterodactylus.sone.database.PostBuilder;
 import net.pterodactylus.sone.database.PostBuilderFactory;
 import net.pterodactylus.sone.database.PostReplyBuilder;
@@ -31,6 +35,8 @@ public class ConfigurationSoneParser {
        private final Configuration configuration;
        private final Sone sone;
        private final String sonePrefix;
+       private final Map<String, Album> albums = new HashMap<String, Album>();
+       private final List<Album> topLevelAlbums = new ArrayList<Album>();
 
        public ConfigurationSoneParser(Configuration configuration, Sone sone) {
                this.configuration = configuration;
@@ -183,8 +189,6 @@ public class ConfigurationSoneParser {
 
        public List<Album> parseTopLevelAlbums(
                        AlbumBuilderFactory albumBuilderFactory) {
-               Map<String, Album> albums = new HashMap<String, Album>();
-               List<Album> topLevelAlbums = new ArrayList<Album>();
                int albumCounter = 0;
                while (true) {
                        String albumPrefix = "/Albums/" + albumCounter++;
@@ -224,6 +228,59 @@ public class ConfigurationSoneParser {
                return topLevelAlbums;
        }
 
+       public Map<String, Album> getAlbums() {
+               return unmodifiableMap(albums);
+       }
+
+       public void parseImages(ImageBuilderFactory imageBuilderFactory) {
+               int imageCounter = 0;
+               while (true) {
+                       String imagePrefix = "/Images/" + imageCounter++;
+                       String imageId = getString(imagePrefix + "/ID", null);
+                       if (imageId == null) {
+                               break;
+                       }
+                       String albumId = getString(imagePrefix + "/Album", null);
+                       String key = getString(imagePrefix + "/Key", null);
+                       String title = getString(imagePrefix + "/Title", null);
+                       String description =
+                                       getString(imagePrefix + "/Description", null);
+                       Long creationTime = getLong(imagePrefix + "/CreationTime", null);
+                       Integer width = getInt(imagePrefix + "/Width", null);
+                       Integer height = getInt(imagePrefix + "/Height", null);
+                       if (albumAttributesAreInvalid(albumId, key, title, description,
+                                       creationTime,
+                                       width, height)) {
+                               throw new InvalidImageFound();
+                       }
+                       Album album = albums.get(albumId);
+                       if (album == null) {
+                               throw new InvalidParentAlbumFound(albumId);
+                       }
+                       Image image = imageBuilderFactory.newImageBuilder()
+                                       .withId(imageId)
+                                       .build()
+                                       .modify()
+                                       .setSone(sone)
+                                       .setCreationTime(creationTime)
+                                       .setKey(key)
+                                       .setTitle(title)
+                                       .setDescription(description)
+                                       .setWidth(width)
+                                       .setHeight(height)
+                                       .update();
+                       album.addImage(image);
+               }
+       }
+
+       private boolean albumAttributesAreInvalid(String albumId, String key,
+                       String title, String description, Long creationTime,
+                       Integer width, Integer height) {
+               return (albumId == null) || (key == null) || (title == null) || (
+                               description == null) || (creationTime == null) || (width
+                               == null) || (height == null);
+       }
+
        public static class InvalidPostFound extends RuntimeException { }
 
        public static class InvalidPostReplyFound extends RuntimeException { }
@@ -244,4 +301,6 @@ public class ConfigurationSoneParser {
 
        }
 
+       public static class InvalidImageFound extends RuntimeException { }
+
 }
index e08acd1..91bd0cc 100644 (file)
@@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Predicates.not;
 import static java.lang.String.format;
+import static java.util.logging.Level.WARNING;
 import static net.pterodactylus.sone.data.Sone.LOCAL_SONE_FILTER;
 
 import java.net.MalformedURLException;
@@ -40,6 +41,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidAlbumFound;
+import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidImageFound;
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound;
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
@@ -1141,31 +1143,16 @@ public class Core extends AbstractService implements SoneProvider, PostProvider,
                }
 
                /* load images. */
-               int imageCounter = 0;
-               while (true) {
-                       String imagePrefix = sonePrefix + "/Images/" + imageCounter++;
-                       String imageId = configuration.getStringValue(imagePrefix + "/ID").getValue(null);
-                       if (imageId == null) {
-                               break;
-                       }
-                       String albumId = configuration.getStringValue(imagePrefix + "/Album").getValue(null);
-                       String key = configuration.getStringValue(imagePrefix + "/Key").getValue(null);
-                       String title = configuration.getStringValue(imagePrefix + "/Title").getValue(null);
-                       String description = configuration.getStringValue(imagePrefix + "/Description").getValue(null);
-                       Long creationTime = configuration.getLongValue(imagePrefix + "/CreationTime").getValue(null);
-                       Integer width = configuration.getIntValue(imagePrefix + "/Width").getValue(null);
-                       Integer height = configuration.getIntValue(imagePrefix + "/Height").getValue(null);
-                       if ((albumId == null) || (key == null) || (title == null) || (description == null) || (creationTime == null) || (width == null) || (height == null)) {
-                               logger.log(Level.WARNING, "Invalid image found, aborting load!");
-                               return;
-                       }
-                       Album album = getAlbum(albumId);
-                       if (album == null) {
-                               logger.log(Level.WARNING, "Invalid album image encountered, aborting load!");
-                               return;
-                       }
-                       Image image = getImage(imageId).modify().setSone(sone).setCreationTime(creationTime).setKey(key).setTitle(title).setDescription(description).setWidth(width).setHeight(height).update();
-                       album.addImage(image);
+               try {
+                       configurationSoneParser.parseImages(database);
+               } catch (InvalidImageFound iif) {
+                       logger.log(WARNING, "Invalid image found, aborting load!");
+                       return;
+               } catch (InvalidParentAlbumFound ipaf) {
+                       logger.log(Level.WARNING,
+                                       format("Invalid album image (%s) encountered, aborting load!",
+                                                       ipaf.getAlbumParentId()));
+                       return;
                }
 
                /* load avatar. */
index c73866e..c1052d5 100644 (file)
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 
 import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.Image;
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
 
@@ -182,6 +183,68 @@ public class Matchers {
                };
        }
 
+       public static Matcher<Image> isImage(final String id,
+                       final long creationTime,
+                       final String key, final String title,
+                       final String imageDescription,
+                       final int width, final int height) {
+               return new TypeSafeDiagnosingMatcher<Image>() {
+                       @Override
+                       protected boolean matchesSafely(Image image,
+                                       Description mismatchDescription) {
+                               if (!image.getId().equals(id)) {
+                                       mismatchDescription.appendText("ID is ")
+                                                       .appendValue(image.getId());
+                                       return false;
+                               }
+                               if (image.getCreationTime() != creationTime) {
+                                       mismatchDescription.appendText("created at @")
+                                                       .appendValue(image.getCreationTime());
+                                       return false;
+                               }
+                               if (!image.getKey().equals(key)) {
+                                       mismatchDescription.appendText("key is ")
+                                                       .appendValue(image.getKey());
+                                       return false;
+                               }
+                               if (!image.getTitle().equals(title)) {
+                                       mismatchDescription.appendText("title is ")
+                                                       .appendValue(image.getTitle());
+                                       return false;
+                               }
+                               if (!image.getDescription().equals(imageDescription)) {
+                                       mismatchDescription.appendText("description is ")
+                                                       .appendValue(image.getDescription());
+                                       return false;
+                               }
+                               if (image.getWidth() != width) {
+                                       mismatchDescription.appendText("width is ")
+                                                       .appendValue(image.getWidth());
+                                       return false;
+                               }
+                               if (image.getHeight() != height) {
+                                       mismatchDescription.appendText("height is ")
+                                                       .appendValue(image.getHeight());
+                                       return false;
+                               }
+                               return true;
+                       }
+
+                       @Override
+                       public void describeTo(Description description) {
+                               description.appendText("image with ID ").appendValue(id);
+                               description.appendText(", created at @")
+                                               .appendValue(creationTime);
+                               description.appendText(", has key ").appendValue(key);
+                               description.appendText(", has title ").appendValue(title);
+                               description.appendText(", has description ")
+                                               .appendValue(imageDescription);
+                               description.appendText(", has width ").appendValue(width);
+                               description.appendText(", has height ").appendValue(height);
+                       }
+               };
+       }
+
        private static class PostMatcher extends TypeSafeDiagnosingMatcher<Post> {
 
                private final String postId;
index b5e57f7..03b0672 100644 (file)
@@ -5,6 +5,7 @@ import static com.google.common.base.Optional.of;
 import static java.lang.System.currentTimeMillis;
 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.MatcherAssert.assertThat;
@@ -25,10 +26,12 @@ import static org.mockito.Mockito.when;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidAlbumFound;
+import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidImageFound;
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound;
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
@@ -42,6 +45,8 @@ import net.pterodactylus.sone.data.Profile.Field;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.database.AlbumBuilder;
 import net.pterodactylus.sone.database.AlbumBuilderFactory;
+import net.pterodactylus.sone.database.ImageBuilder;
+import net.pterodactylus.sone.database.ImageBuilderFactory;
 import net.pterodactylus.sone.database.PostBuilder;
 import net.pterodactylus.sone.database.PostBuilderFactory;
 import net.pterodactylus.sone.database.PostReplyBuilder;
@@ -399,6 +404,129 @@ public class ConfigurationSoneParserTest {
                                createAlbumBuilderFactory());
        }
 
+       @Test
+       public void imagesAreParsedCorrectly() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImages();
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+               Map<String, Album> albums = configurationSoneParser.getAlbums();
+               assertThat(albums.get("A1").getImages(),
+                               contains(isImage("I1", 1000L, "K1", "T1", "D1", 16, 9)));
+               assertThat(albums.get("A2").getImages(), contains(
+                               isImage("I2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2)));
+               assertThat(albums.get("A3").getImages(), contains(
+                               isImage("I3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3)));
+       }
+
+       private void setupImages() {
+               setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, 9);
+               setupImage(1, "I2", "A2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2);
+               setupImage(2, "I3", "A3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3);
+               setupImage(3, null, null, 0L, null, null, null, 0, 0);
+       }
+
+       private void setupImage(int imageNumber, String id,
+                       String parentAlbumId, Long creationTime, String key, String title,
+                       String description, Integer width, Integer height) {
+               final String imagePrefix = "Sone/1/Images/" + imageNumber;
+               setupString(imagePrefix + "/ID", id);
+               setupString(imagePrefix + "/Album", parentAlbumId);
+               setupLong(imagePrefix + "/CreationTime", creationTime);
+               setupString(imagePrefix + "/Key", key);
+               setupString(imagePrefix + "/Title", title);
+               setupString(imagePrefix + "/Description", description);
+               setupInteger(imagePrefix + "/Width", width);
+               setupInteger(imagePrefix + "/Height", height);
+       }
+
+       private ImageBuilderFactory createImageBuilderFactory() {
+               ImageBuilderFactory imageBuilderFactory =
+                               mock(ImageBuilderFactory.class);
+               when(imageBuilderFactory.newImageBuilder()).thenAnswer(
+                               new Answer<ImageBuilder>() {
+                                       @Override
+                                       public ImageBuilder answer(InvocationOnMock invocation)
+                                       throws Throwable {
+                                               return new TestImageBuilder();
+                                       }
+                               });
+               return imageBuilderFactory;
+       }
+
+       @Test(expected = InvalidImageFound.class)
+       public void missingAlbumIdIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", null, 1000L, "K1", "T1", "D1", 16, 9);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
+       @Test(expected = InvalidParentAlbumFound.class)
+       public void invalidAlbumIdIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", "A4", 1000L, "K1", "T1", "D1", 16, 9);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
+       @Test(expected = InvalidImageFound.class)
+       public void missingCreationTimeIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", "A1", null, "K1", "T1", "D1", 16, 9);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
+       @Test(expected = InvalidImageFound.class)
+       public void missingKeyIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", "A1", 1000L, null, "T1", "D1", 16, 9);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
+       @Test(expected = InvalidImageFound.class)
+       public void missingTitleIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", "A1", 1000L, "K1", null, "D1", 16, 9);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
+       @Test(expected = InvalidImageFound.class)
+       public void missingDescriptionIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", "A1", 1000L, "K1", "T1", null, 16, 9);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
+       @Test(expected = InvalidImageFound.class)
+       public void missingWidthIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", null, 9);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
+       @Test(expected = InvalidImageFound.class)
+       public void missingHeightIsRecognized() {
+               setupTopLevelAlbums();
+               configurationSoneParser.parseTopLevelAlbums(
+                               createAlbumBuilderFactory());
+               setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, null);
+               configurationSoneParser.parseImages(createImageBuilderFactory());
+       }
+
        private static class TestValue<T> implements Value<T> {
 
                private final AtomicReference<T> value = new AtomicReference<T>();
@@ -657,4 +785,95 @@ public class ConfigurationSoneParserTest {
 
        }
 
+       private static class TestImageBuilder implements ImageBuilder {
+
+               private final Image image;
+
+               private TestImageBuilder() {
+                       image = mock(Image.class);
+                       Image.Modifier imageModifier = new Image.Modifier() {
+                               private Sone sone = image.getSone();
+                               private long creationTime = image.getCreationTime();
+                               private String key = image.getKey();
+                               private String title = image.getTitle();
+                               private String description = image.getDescription();
+                               private int width = image.getWidth();
+                               private int height = image.getHeight();
+
+                               @Override
+                               public Image.Modifier setSone(Sone sone) {
+                                       this.sone = sone;
+                                       return this;
+                               }
+
+                               @Override
+                               public Image.Modifier setCreationTime(long creationTime) {
+                                       this.creationTime = creationTime;
+                                       return this;
+                               }
+
+                               @Override
+                               public Image.Modifier setKey(String key) {
+                                       this.key = key;
+                                       return this;
+                               }
+
+                               @Override
+                               public Image.Modifier setTitle(String title) {
+                                       this.title = title;
+                                       return this;
+                               }
+
+                               @Override
+                               public Image.Modifier setDescription(String description) {
+                                       this.description = description;
+                                       return this;
+                               }
+
+                               @Override
+                               public Image.Modifier setWidth(int width) {
+                                       this.width = width;
+                                       return this;
+                               }
+
+                               @Override
+                               public Image.Modifier setHeight(int height) {
+                                       this.height = height;
+                                       return this;
+                               }
+
+                               @Override
+                               public Image update() throws IllegalStateException {
+                                       when(image.getSone()).thenReturn(sone);
+                                       when(image.getCreationTime()).thenReturn(creationTime);
+                                       when(image.getKey()).thenReturn(key);
+                                       when(image.getTitle()).thenReturn(title);
+                                       when(image.getDescription()).thenReturn(description);
+                                       when(image.getWidth()).thenReturn(width);
+                                       when(image.getHeight()).thenReturn(height);
+                                       return image;
+                               }
+                       };
+                       when(image.modify()).thenReturn(imageModifier);
+               }
+
+               @Override
+               public ImageBuilder randomId() {
+                       when(image.getId()).thenReturn(randomUUID().toString());
+                       return this;
+               }
+
+               @Override
+               public ImageBuilder withId(String id) {
+                       when(image.getId()).thenReturn(id);
+                       return this;
+               }
+
+               @Override
+               public Image build() throws IllegalStateException {
+                       return image;
+               }
+
+       }
+
 }