JAMES-2589 BlobStoreChoosingModule should expose UnionBlobStore
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/732a8bc9 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/732a8bc9 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/732a8bc9 Branch: refs/heads/master Commit: 732a8bc9f2f34605a5cd9f0b225e4975e644dd0e Parents: 5015c7e Author: Benoit Tellier <[email protected]> Authored: Fri Nov 16 11:54:54 2018 +0700 Committer: Benoit Tellier <[email protected]> Committed: Wed Nov 21 09:53:27 2018 +0700 ---------------------------------------------------------------------- .../apache/james/blob/union/UnionBlobStore.java | 33 +++++++++- .../james/blob/union/UnionBlobStoreTest.java | 66 ++++++++++++++++---- .../guice/cassandra-rabbitmq-guice/pom.xml | 4 ++ .../BlobStoreChoosingConfiguration.java | 7 ++- .../blobstore/BlobStoreChoosingModule.java | 9 ++- .../BlobStoreChoosingConfigurationTest.java | 21 +++++-- .../blobstore/BlobStoreChoosingModuleTest.java | 23 +++++++ 7 files changed, 140 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/732a8bc9/server/blob/blob-union/src/main/java/org/apache/james/blob/union/UnionBlobStore.java ---------------------------------------------------------------------- diff --git a/server/blob/blob-union/src/main/java/org/apache/james/blob/union/UnionBlobStore.java b/server/blob/blob-union/src/main/java/org/apache/james/blob/union/UnionBlobStore.java index 97bad3f..e18e564 100644 --- a/server/blob/blob-union/src/main/java/org/apache/james/blob/union/UnionBlobStore.java +++ b/server/blob/blob-union/src/main/java/org/apache/james/blob/union/UnionBlobStore.java @@ -38,14 +38,43 @@ import com.google.common.base.MoreObjects; public class UnionBlobStore implements BlobStore { + @FunctionalInterface + public interface RequireCurrent { + RequireLegacy current(BlobStore blobStore); + } + + @FunctionalInterface + public interface RequireLegacy { + Builder legacy(BlobStore blobStore); + } + + public static class Builder { + private final BlobStore currentBlobStore; + private final BlobStore legacyBlobStore; + + Builder(BlobStore currentBlobStore, BlobStore legacyBlobStore) { + this.currentBlobStore = currentBlobStore; + this.legacyBlobStore = legacyBlobStore; + } + + public UnionBlobStore build() { + return new UnionBlobStore( + currentBlobStore, + legacyBlobStore); + } + } + private static final Logger LOGGER = LoggerFactory.getLogger(UnionBlobStore.class); private static final int UNAVAILABLE = -1; + public static RequireCurrent builder() { + return current -> legacy -> new Builder(current, legacy); + } + private final BlobStore currentBlobStore; private final BlobStore legacyBlobStore; - @VisibleForTesting - UnionBlobStore(BlobStore currentBlobStore, BlobStore legacyBlobStore) { + private UnionBlobStore(BlobStore currentBlobStore, BlobStore legacyBlobStore) { this.currentBlobStore = currentBlobStore; this.legacyBlobStore = legacyBlobStore; } http://git-wip-us.apache.org/repos/asf/james-project/blob/732a8bc9/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java ---------------------------------------------------------------------- diff --git a/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java b/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java index c3aecb7..d5a6977 100644 --- a/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java +++ b/server/blob/blob-union/src/test/java/org/apache/james/blob/union/UnionBlobStoreTest.java @@ -120,7 +120,10 @@ class UnionBlobStoreTest implements BlobStoreContract { void setup() { currentBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - unionBlobStore = new UnionBlobStore(currentBlobStore, legacyBlobStore); + unionBlobStore = UnionBlobStore.builder() + .current(currentBlobStore) + .legacy(legacyBlobStore) + .build(); } @Override @@ -139,7 +142,10 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void saveShouldFallBackToLegacyWhenCurrentGotException() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new ThrowingBlobStore(), legacyBlobStore); + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new ThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = unionBlobStore.save(BLOB_CONTENT).get(); SoftAssertions.assertSoftly(softly -> { @@ -153,7 +159,10 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void saveInputStreamShouldFallBackToLegacyWhenCurrentGotException() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new ThrowingBlobStore(), legacyBlobStore); + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new ThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = unionBlobStore.save(new ByteArrayInputStream(BLOB_CONTENT)).get(); SoftAssertions.assertSoftly(softly -> { @@ -171,7 +180,10 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void saveShouldFallBackToLegacyWhenCurrentCompletedExceptionally() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new FutureThrowingBlobStore(), legacyBlobStore); + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new FutureThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = unionBlobStore.save(BLOB_CONTENT).get(); SoftAssertions.assertSoftly(softly -> { @@ -185,7 +197,10 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void saveInputStreamShouldFallBackToLegacyWhenCurrentCompletedExceptionally() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new FutureThrowingBlobStore(), legacyBlobStore); + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new FutureThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = unionBlobStore.save(new ByteArrayInputStream(BLOB_CONTENT)).get(); SoftAssertions.assertSoftly(softly -> { @@ -204,7 +219,10 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void readShouldReturnFallbackToLegacyWhenCurrentGotException() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new ThrowingBlobStore(), legacyBlobStore); + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new ThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = legacyBlobStore.save(BLOB_CONTENT).get(); assertThat(unionBlobStore.read(blobId)) @@ -214,7 +232,11 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void readBytesShouldReturnFallbackToLegacyWhenCurrentGotException() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new ThrowingBlobStore(), legacyBlobStore); + + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new ThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = legacyBlobStore.save(BLOB_CONTENT).get(); assertThat(unionBlobStore.readBytes(blobId).get()) @@ -229,7 +251,10 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void readShouldReturnFallbackToLegacyWhenCurrentCompletedExceptionally() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new FutureThrowingBlobStore(), legacyBlobStore); + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new FutureThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = legacyBlobStore.save(BLOB_CONTENT).get(); assertThat(unionBlobStore.read(blobId)) @@ -239,7 +264,10 @@ class UnionBlobStoreTest implements BlobStoreContract { @Test void readBytesShouldReturnFallbackToLegacyWhenCurrentCompletedExceptionally() throws Exception { MemoryBlobStore legacyBlobStore = new MemoryBlobStore(BLOB_ID_FACTORY); - UnionBlobStore unionBlobStore = new UnionBlobStore(new FutureThrowingBlobStore(), legacyBlobStore); + UnionBlobStore unionBlobStore = UnionBlobStore.builder() + .current(new FutureThrowingBlobStore()) + .legacy(legacyBlobStore) + .build(); BlobId blobId = legacyBlobStore.save(BLOB_CONTENT).get(); assertThat(unionBlobStore.readBytes(blobId).get()) @@ -266,9 +294,18 @@ class UnionBlobStoreTest implements BlobStoreContract { Stream<Arguments> blobStoresCauseReturnExceptionallyFutures() { List<UnionBlobStore> futureThrowingUnionBlobStores = ImmutableList.of( - new UnionBlobStore(new ThrowingBlobStore(), new FutureThrowingBlobStore()), - new UnionBlobStore(new FutureThrowingBlobStore(), new ThrowingBlobStore()), - new UnionBlobStore(new FutureThrowingBlobStore(), new FutureThrowingBlobStore())); + UnionBlobStore.builder() + .current(new ThrowingBlobStore()) + .legacy(new FutureThrowingBlobStore()) + .build(), + UnionBlobStore.builder() + .current(new FutureThrowingBlobStore()) + .legacy(new ThrowingBlobStore()) + .build(), + UnionBlobStore.builder() + .current(new FutureThrowingBlobStore()) + .legacy(new FutureThrowingBlobStore()) + .build()); return blobStoreOperationsReturnFutures() .flatMap(blobStoreFunction -> futureThrowingUnionBlobStores @@ -277,7 +314,10 @@ class UnionBlobStoreTest implements BlobStoreContract { } Stream<Arguments> blobStoresCauseThrowExceptions() { - UnionBlobStore throwingUnionBlobStore = new UnionBlobStore(new ThrowingBlobStore(), new ThrowingBlobStore()); + UnionBlobStore throwingUnionBlobStore = UnionBlobStore.builder() + .current(new ThrowingBlobStore()) + .legacy(new ThrowingBlobStore()) + .build(); return StreamUtils.flatten( blobStoreOperationsReturnFutures() http://git-wip-us.apache.org/repos/asf/james-project/blob/732a8bc9/server/container/guice/cassandra-rabbitmq-guice/pom.xml ---------------------------------------------------------------------- diff --git a/server/container/guice/cassandra-rabbitmq-guice/pom.xml b/server/container/guice/cassandra-rabbitmq-guice/pom.xml index d079dd7..716b626 100644 --- a/server/container/guice/cassandra-rabbitmq-guice/pom.xml +++ b/server/container/guice/cassandra-rabbitmq-guice/pom.xml @@ -99,6 +99,10 @@ </dependency> <dependency> <groupId>${james.groupId}</groupId> + <artifactId>blob-union</artifactId> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> <artifactId>james-server-cassandra-guice</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/james-project/blob/732a8bc9/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfiguration.java ---------------------------------------------------------------------- diff --git a/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfiguration.java b/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfiguration.java index 10ea54f..f3a15c3 100644 --- a/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfiguration.java +++ b/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfiguration.java @@ -33,7 +33,8 @@ public class BlobStoreChoosingConfiguration { public enum BlobStoreImplName { CASSANDRA("cassandra"), - OBJECTSTORAGE("objectstorage"); + OBJECTSTORAGE("objectstorage"), + UNION("union"); static String supportedImplNames() { return Stream.of(BlobStoreImplName.values()) @@ -81,6 +82,10 @@ public class BlobStoreChoosingConfiguration { return new BlobStoreChoosingConfiguration(BlobStoreImplName.OBJECTSTORAGE); } + public static BlobStoreChoosingConfiguration union() { + return new BlobStoreChoosingConfiguration(BlobStoreImplName.UNION); + } + private final BlobStoreImplName implementation; BlobStoreChoosingConfiguration(BlobStoreImplName implementation) { http://git-wip-us.apache.org/repos/asf/james-project/blob/732a8bc9/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingModule.java ---------------------------------------------------------------------- diff --git a/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingModule.java b/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingModule.java index 20e04b1..737033b 100644 --- a/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingModule.java +++ b/server/container/guice/cassandra-rabbitmq-guice/src/main/java/org/apache/james/modules/blobstore/BlobStoreChoosingModule.java @@ -31,6 +31,7 @@ import org.apache.james.blob.api.BlobStore; import org.apache.james.blob.cassandra.CassandraBlobModule; import org.apache.james.blob.cassandra.CassandraBlobsDAO; import org.apache.james.blob.objectstorage.ObjectStorageBlobsDAO; +import org.apache.james.blob.union.UnionBlobStore; import org.apache.james.modules.mailbox.ConfigurationComponent; import org.apache.james.modules.objectstorage.ObjectStorageDependenciesModule; import org.apache.james.utils.PropertiesProvider; @@ -45,9 +46,6 @@ import com.google.inject.multibindings.Multibinder; public class BlobStoreChoosingModule extends AbstractModule { private static final Logger LOGGER = LoggerFactory.getLogger(BlobStoreChoosingModule.class); - @VisibleForTesting - static final String BLOB_STORE_CONFIGURATION_FILE = "blobstore"; - @Override protected void configure() { install(new ObjectStorageDependenciesModule()); @@ -81,6 +79,11 @@ public class BlobStoreChoosingModule extends AbstractModule { return swiftBlobStoreProvider.get(); case CASSANDRA: return cassandraBlobStoreProvider.get(); + case UNION: + return UnionBlobStore.builder() + .current(swiftBlobStoreProvider.get()) + .legacy(cassandraBlobStoreProvider.get()) + .build(); default: throw new RuntimeException(String.format("can not get the right blobstore provider with configuration %s", choosingConfiguration.toString())); http://git-wip-us.apache.org/repos/asf/james-project/blob/732a8bc9/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfigurationTest.java ---------------------------------------------------------------------- diff --git a/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfigurationTest.java b/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfigurationTest.java index b97f5ad..fee6599 100644 --- a/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfigurationTest.java +++ b/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingConfigurationTest.java @@ -31,6 +31,7 @@ class BlobStoreChoosingConfigurationTest { private static final String OBJECT_STORAGE = "objectstorage"; private static final String CASSANDRA = "cassandra"; + private static final String UNION = "union"; @Test void shouldMatchBeanContract() { @@ -44,7 +45,7 @@ class BlobStoreChoosingConfigurationTest { assertThatThrownBy(() -> BlobStoreChoosingConfiguration.from(configuration)) .isInstanceOf(IllegalStateException.class) - .hasMessage("implementation property is missing please use one of supported values in: cassandra, objectstorage"); + .hasMessage("implementation property is missing please use one of supported values in: cassandra, objectstorage, union"); } @Test @@ -54,7 +55,7 @@ class BlobStoreChoosingConfigurationTest { assertThatThrownBy(() -> BlobStoreChoosingConfiguration.from(configuration)) .isInstanceOf(IllegalStateException.class) - .hasMessage("implementation property is missing please use one of supported values in: cassandra, objectstorage"); + .hasMessage("implementation property is missing please use one of supported values in: cassandra, objectstorage, union"); } @Test @@ -64,7 +65,7 @@ class BlobStoreChoosingConfigurationTest { assertThatThrownBy(() -> BlobStoreChoosingConfiguration.from(configuration)) .isInstanceOf(IllegalStateException.class) - .hasMessage("implementation property is missing please use one of supported values in: cassandra, objectstorage"); + .hasMessage("implementation property is missing please use one of supported values in: cassandra, objectstorage, union"); } @Test @@ -74,7 +75,7 @@ class BlobStoreChoosingConfigurationTest { assertThatThrownBy(() -> BlobStoreChoosingConfiguration.from(configuration)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("un_supported is not a valid name of BlobStores, please use one of supported values in: cassandra, objectstorage"); + .hasMessage("un_supported is not a valid name of BlobStores, please use one of supported values in: cassandra, objectstorage, union"); } @Test @@ -90,6 +91,18 @@ class BlobStoreChoosingConfigurationTest { } @Test + void fromShouldReturnConfigurationWhenBlobStoreImplIsUnion() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("implementation", UNION); + + assertThat( + BlobStoreChoosingConfiguration.from(configuration) + .getImplementation() + .getName()) + .isEqualTo(UNION); + } + + @Test void fromShouldReturnConfigurationWhenBlobStoreImplIsSwift() { PropertiesConfiguration configuration = new PropertiesConfiguration(); configuration.addProperty("implementation", OBJECT_STORAGE); http://git-wip-us.apache.org/repos/asf/james-project/blob/732a8bc9/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingModuleTest.java ---------------------------------------------------------------------- diff --git a/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingModuleTest.java b/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingModuleTest.java index c881cf3..6dc472f 100644 --- a/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingModuleTest.java +++ b/server/container/guice/cassandra-rabbitmq-guice/src/test/java/org/apache/james/modules/blobstore/BlobStoreChoosingModuleTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.mock; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.james.blob.cassandra.CassandraBlobsDAO; import org.apache.james.blob.objectstorage.ObjectStorageBlobsDAO; +import org.apache.james.blob.union.UnionBlobStore; import org.apache.james.modules.blobstore.BlobStoreChoosingConfiguration.BlobStoreImplName; import org.apache.james.modules.mailbox.ConfigurationComponent; import org.apache.james.modules.objectstorage.FakePropertiesProvider; @@ -104,6 +105,19 @@ class BlobStoreChoosingModuleTest { } @Test + void provideChoosingConfigurationShouldReturnUnionConfigurationWhenConfigurationImplIsUnion() throws Exception { + BlobStoreChoosingModule module = new BlobStoreChoosingModule(); + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("implementation", BlobStoreImplName.UNION.getName()); + FakePropertiesProvider propertyProvider = FakePropertiesProvider.builder() + .register(ConfigurationComponent.NAME, configuration) + .build(); + + assertThat(module.provideChoosingConfiguration(propertyProvider)) + .isEqualTo(BlobStoreChoosingConfiguration.union()); + } + + @Test void provideChoosingConfigurationShouldReturnCassandraFactoryWhenConfigurationImplIsCassandra() throws Exception { BlobStoreChoosingModule module = new BlobStoreChoosingModule(); PropertiesConfiguration configuration = new PropertiesConfiguration(); @@ -133,4 +147,13 @@ class BlobStoreChoosingModuleTest { CASSANDRA_BLOBSTORE_PROVIDER, SWIFT_BLOBSTORE_PROVIDER)) .isEqualTo(CASSANDRA_BLOBSTORE); } + + @Test + void provideBlobStoreShouldReturnUnionBlobStoreWhenUnionConfigured() { + BlobStoreChoosingModule module = new BlobStoreChoosingModule(); + + assertThat(module.provideBlobStore(BlobStoreChoosingConfiguration.union(), + CASSANDRA_BLOBSTORE_PROVIDER, SWIFT_BLOBSTORE_PROVIDER)) + .isInstanceOf(UnionBlobStore.class); + } } \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
