From 423461c3ba10c12b717d92ae30522994fee44b86 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Sun, 11 Mar 2018 21:58:59 +0100 Subject: [PATCH] Store loaded indexes in persistent storage. Signed-off-by: Yahor Berdnikau --- .../cache/serializers/ArtistSerializer.kt | 60 +++++++++++++++++++ .../cache/serializers/IndexesSerializer.kt | 44 ++++++++++++++ .../moire/ultrasonic/cache/BaseStorageTest.kt | 6 ++ .../cache/serializers/ArtistSerializerTest.kt | 57 ++++++++++++++++++ .../serializers/IndexesSerializerTest.kt | 40 +++++++++++++ .../serializers/MusicFolderSerializerTest.kt | 7 +-- .../ultrasonic/service/RESTMusicService.java | 25 ++------ 7 files changed, 215 insertions(+), 24 deletions(-) create mode 100644 cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializer.kt create mode 100644 cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializer.kt create mode 100644 cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializerTest.kt create mode 100644 cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializerTest.kt diff --git a/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializer.kt b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializer.kt new file mode 100644 index 00000000..96e1a9f0 --- /dev/null +++ b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializer.kt @@ -0,0 +1,60 @@ +@file:JvmMultifileClass +@file:JvmName("DomainSerializers") +package org.moire.ultrasonic.cache.serializers + +import com.twitter.serial.serializer.CollectionSerializers +import com.twitter.serial.serializer.ObjectSerializer +import com.twitter.serial.serializer.SerializationContext +import com.twitter.serial.stream.SerializerDefs +import com.twitter.serial.stream.SerializerInput +import com.twitter.serial.stream.SerializerOutput +import org.moire.ultrasonic.domain.Artist + +private const val SERIALIZER_VERSION = 1 + +/** + * Serializer/deserializer for [Artist] domain entity. + */ +val artistSerializer get() = object : ObjectSerializer(SERIALIZER_VERSION) { + override fun serializeObject( + context: SerializationContext, + output: SerializerOutput>, + item: Artist + ) { + output.writeString(item.id) + .writeString(item.name) + .writeString(item.index) + .writeString(item.coverArt) + .apply { + val albumCount = item.albumCount + if (albumCount != null) writeLong(albumCount) else writeNull() + } + .writeInt(item.closeness) + } + + override fun deserializeObject( + context: SerializationContext, + input: SerializerInput, + versionNumber: Int + ): Artist? { + if (versionNumber != SERIALIZER_VERSION) return null + + val id = input.readString() + val name = input.readString() + val index = input.readString() + val coverArt = input.readString() + val albumCount = if (input.peekType() == SerializerDefs.TYPE_NULL) { + input.readNull() + null + } else { + input.readLong() + } + val closeness = input.readInt() + return Artist(id, name, index, coverArt, albumCount, closeness) + } +} + +/** + * Serializer/deserializer for list of [Artist] domain entities. + */ +val artistListSerializer = CollectionSerializers.getListSerializer(artistSerializer) diff --git a/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializer.kt b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializer.kt new file mode 100644 index 00000000..e59e837c --- /dev/null +++ b/cache/src/main/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializer.kt @@ -0,0 +1,44 @@ +@file:JvmMultifileClass +@file:JvmName("DomainSerializers") +package org.moire.ultrasonic.cache.serializers + +import com.twitter.serial.serializer.CollectionSerializers +import com.twitter.serial.serializer.ObjectSerializer +import com.twitter.serial.serializer.SerializationContext +import com.twitter.serial.stream.SerializerInput +import com.twitter.serial.stream.SerializerOutput +import org.moire.ultrasonic.domain.Artist +import org.moire.ultrasonic.domain.Indexes + +private const val SERIALIZATION_VERSION = 1 + +val indexesSerializer get() = object : ObjectSerializer(SERIALIZATION_VERSION) { + override fun serializeObject( + context: SerializationContext, + output: SerializerOutput>, + item: Indexes + ) { + output.writeLong(item.lastModified) + .writeString(item.ignoredArticles) + .writeObject>(context, item.shortcuts, + CollectionSerializers.getListSerializer(artistSerializer)) + .writeObject>(context, item.artists, + CollectionSerializers.getListSerializer(artistSerializer)) + } + + override fun deserializeObject( + context: SerializationContext, + input: SerializerInput, + versionNumber: Int + ): Indexes? { + if (versionNumber != SERIALIZATION_VERSION) return null + + val lastModified = input.readLong() + val ignoredArticles = input.readString() ?: return null + val shortcutsList = input.readObject(context, + CollectionSerializers.getListSerializer(artistSerializer)) ?: return null + val artistsList = input.readObject(context, + CollectionSerializers.getListSerializer(artistSerializer)) ?: return null + return Indexes(lastModified, ignoredArticles, shortcutsList, artistsList) + } +} diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/BaseStorageTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/BaseStorageTest.kt index 5a6d127b..dd4a3ae7 100644 --- a/cache/src/test/kotlin/org/moire/ultrasonic/cache/BaseStorageTest.kt +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/BaseStorageTest.kt @@ -1,6 +1,7 @@ package org.moire.ultrasonic.cache import com.nhaarman.mockito_kotlin.mock +import com.twitter.serial.util.SerializationUtils import org.amshove.kluent.`it returns` import org.junit.Before import org.junit.Rule @@ -31,4 +32,9 @@ abstract class BaseStorageTest { } protected val storageDir get() = File(mockDirectories.getInternalDataDir(), STORAGE_DIR_NAME) + + protected fun validateSerializedData(index: Int = 0) { + val serializedFileBytes = storageDir.listFiles()[index].readBytes() + SerializationUtils.validateSerializedData(serializedFileBytes) + } } diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializerTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializerTest.kt new file mode 100644 index 00000000..74bc4221 --- /dev/null +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/ArtistSerializerTest.kt @@ -0,0 +1,57 @@ +package org.moire.ultrasonic.cache.serializers + +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.cache.BaseStorageTest +import org.moire.ultrasonic.domain.Artist + +/** + * [Artist] serializers test. + */ +class ArtistSerializerTest : BaseStorageTest() { + @Test + fun `Should correctly serialize Artist object`() { + val item = Artist("id", "name", "index", "coverArt", 1, 0) + + storage.store("some-name", item, artistSerializer) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize Artist object`() { + val itemName = "some-name" + val item = Artist("id", "name", "index", "coverArt", null, 0) + storage.store(itemName, item, artistSerializer) + + val loadedItem = storage.load(itemName, artistSerializer) + + loadedItem `should equal` item + } + + @Test + fun `Should correctly serialize list of Artists`() { + val itemsList = listOf( + Artist(id = "1"), + Artist(id = "2", name = "some") + ) + + storage.store("some-name", itemsList, artistListSerializer) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize list of Artists`() { + val name = "some-name" + val itemsList = listOf( + Artist(id = "1"), + Artist(id = "2", name = "some") + ) + storage.store(name, itemsList, artistListSerializer) + + val loadedItems = storage.load(name, artistListSerializer) + + loadedItems `should equal` itemsList + } +} diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializerTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializerTest.kt new file mode 100644 index 00000000..704d59ac --- /dev/null +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/IndexesSerializerTest.kt @@ -0,0 +1,40 @@ +package org.moire.ultrasonic.cache.serializers + +import org.amshove.kluent.`should equal` +import org.junit.Test +import org.moire.ultrasonic.cache.BaseStorageTest +import org.moire.ultrasonic.domain.Artist +import org.moire.ultrasonic.domain.Indexes + +/** + * Test [Indexes] domain entity serializer. + */ +class IndexesSerializerTest : BaseStorageTest() { + @Test + fun `Should correctly serialize Indexes object`() { + val item = Indexes(220L, "", mutableListOf( + Artist("12") + ), mutableListOf( + Artist("233", "some") + )) + + storage.store("some-name", item, indexesSerializer) + + validateSerializedData() + } + + @Test + fun `Should correctly deserialize Indexes object`() { + val name = "some-name" + val item = Indexes(220L, "", mutableListOf( + Artist("12") + ), mutableListOf( + Artist("233", "some") + )) + storage.store(name, item, indexesSerializer) + + val loadedItem = storage.load(name, indexesSerializer) + + loadedItem `should equal` item + } +} diff --git a/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializerTest.kt b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializerTest.kt index 0fedccf1..602ffa47 100644 --- a/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializerTest.kt +++ b/cache/src/test/kotlin/org/moire/ultrasonic/cache/serializers/MusicFolderSerializerTest.kt @@ -1,6 +1,5 @@ package org.moire.ultrasonic.cache.serializers -import com.twitter.serial.util.SerializationUtils import org.amshove.kluent.`should equal` import org.junit.Test import org.moire.ultrasonic.cache.BaseStorageTest @@ -16,8 +15,7 @@ class MusicFolderSerializerTest : BaseStorageTest() { storage.store("some-name", item, musicFolderSerializer) - val serializedFileBytes = storageDir.listFiles()[0].readBytes() - SerializationUtils.validateSerializedData(serializedFileBytes) + validateSerializedData() } @Test @@ -40,8 +38,7 @@ class MusicFolderSerializerTest : BaseStorageTest() { storage.store("some-name", itemsList, musicFolderListSerializer) - val serializedFileBytes = storageDir.listFiles()[0].readBytes() - SerializationUtils.validateSerializedData(serializedFileBytes) + validateSerializedData() } @Test diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java index 61d50c89..03978c28 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/RESTMusicService.java @@ -120,6 +120,7 @@ public class RESTMusicService implements MusicService { private static final String TAG = RESTMusicService.class.getSimpleName(); private static final String MUSIC_FOLDER_STORAGE_NAME = "music_folder"; + private static final String INDEXES_STORAGE_NAME = "indexes"; private final SubsonicAPIClient subsonicAPIClient; private final PermanentFileStorage fileStorage; @@ -155,8 +156,8 @@ public class RESTMusicService implements MusicService { public List getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List cachedMusicFolders = fileStorage - .load(MUSIC_FOLDER_STORAGE_NAME, DomainSerializers.getMusicFolderListSerializer()); + List cachedMusicFolders = fileStorage.load(MUSIC_FOLDER_STORAGE_NAME, + DomainSerializers.getMusicFolderListSerializer()); if (cachedMusicFolders != null && !refresh) { return cachedMusicFolders; } @@ -177,7 +178,8 @@ public class RESTMusicService implements MusicService { boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Indexes cachedIndexes = readCachedIndexes(context, musicFolderId); + Indexes cachedIndexes = fileStorage.load(INDEXES_STORAGE_NAME, + DomainSerializers.getIndexesSerializer()); if (cachedIndexes != null && !refresh) { return cachedIndexes; } @@ -188,25 +190,10 @@ public class RESTMusicService implements MusicService { checkResponseSuccessful(response); Indexes indexes = APIIndexesConverter.toDomainEntity(response.body().getIndexes()); - writeCachedIndexes(context, indexes, musicFolderId); + fileStorage.store(INDEXES_STORAGE_NAME, indexes, DomainSerializers.getIndexesSerializer()); return indexes; } - private static Indexes readCachedIndexes(Context context, String musicFolderId) { - String filename = getCachedIndexesFilename(context, musicFolderId); - return FileUtil.deserialize(context, filename); - } - - private static void writeCachedIndexes(Context context, Indexes indexes, String musicFolderId) { - String filename = getCachedIndexesFilename(context, musicFolderId); - FileUtil.serialize(context, indexes, filename); - } - - private static String getCachedIndexesFilename(Context context, String musicFolderId) { - String s = Util.getRestUrl(context, null) + musicFolderId; - return String.format(Locale.US, "indexes-%d.ser", Math.abs(s.hashCode())); - } - @Override public Indexes getArtists(boolean refresh, Context context,