This is an automated email from the ASF dual-hosted git repository. rouazana pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 805eeab86cb1e4bc6d6d78e0c413cfc314391e34 Author: Matthieu Baechler <[email protected]> AuthorDate: Mon Jul 22 15:19:10 2019 +0200 JAMES-2813 remove ambiguity about from/to version by introducing a SchemaTransition type --- .../migration/CassandraMigrationService.java | 36 +++++------ .../cassandra/versions/SchemaTransition.java | 69 ++++++++++++++++++++++ .../migration/CassandraMigrationServiceTest.java | 43 +++++++------- .../cassandra/versions/SchemaTransitionTest.java | 16 +++++ .../modules/server/CassandraRoutesModule.java | 13 ++-- 5 files changed, 132 insertions(+), 45 deletions(-) diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java index 3aec56a..b52126d 100644 --- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java +++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java @@ -30,6 +30,7 @@ import javax.inject.Named; import org.apache.commons.lang.NotImplementedException; import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO; +import org.apache.james.backends.cassandra.versions.SchemaTransition; import org.apache.james.backends.cassandra.versions.SchemaVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,11 +39,11 @@ public class CassandraMigrationService { public static final String LATEST_VERSION = "latestVersion"; private final CassandraSchemaVersionDAO schemaVersionDAO; private final SchemaVersion latestVersion; - private final Map<SchemaVersion, Migration> allMigrationClazz; + private final Map<SchemaTransition, Migration> allMigrationClazz; private final Logger logger = LoggerFactory.getLogger(CassandraMigrationService.class); @Inject - public CassandraMigrationService(CassandraSchemaVersionDAO schemaVersionDAO, Map<SchemaVersion, Migration> allMigrationClazz, @Named(LATEST_VERSION) SchemaVersion latestVersion) { + public CassandraMigrationService(CassandraSchemaVersionDAO schemaVersionDAO, Map<SchemaTransition, Migration> allMigrationClazz, @Named(LATEST_VERSION) SchemaVersion latestVersion) { this.schemaVersionDAO = schemaVersionDAO; this.latestVersion = latestVersion; this.allMigrationClazz = allMigrationClazz; @@ -60,41 +61,42 @@ public class CassandraMigrationService { SchemaVersion currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION); Migration migrationCombination = IntStream.range(currentVersion.getValue(), newVersion.getValue()) - .boxed() - .map(SchemaVersion::new) + .mapToObj(SchemaVersion::new) + .map(SchemaVersion::next) + .map(SchemaTransition::to) .map(this::validateVersionNumber) .map(this::toMigration) .reduce(Migration.IDENTITY, Migration::combine); return new MigrationTask(migrationCombination, newVersion); } - private SchemaVersion validateVersionNumber(SchemaVersion versionNumber) { - if (!allMigrationClazz.containsKey(versionNumber)) { - String message = String.format("Can not migrate to %d. No migration class registered.", versionNumber.getValue()); + private SchemaTransition validateVersionNumber(SchemaTransition transition) { + if (!allMigrationClazz.containsKey(transition)) { + String message = String.format("Can not migrate from %s to %s. No migration class registered.", transition.fromAsString(), transition.toAsString()); logger.error(message); throw new NotImplementedException(message); } - return versionNumber; + return transition; } public Migration upgradeToLastVersion() { return upgradeToVersion(latestVersion); } - private Migration toMigration(SchemaVersion version) { + private Migration toMigration(SchemaTransition transition) { return () -> { - SchemaVersion newVersion = version.next(); SchemaVersion currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION); - if (currentVersion.isAfterOrEquals(newVersion)) { + SchemaVersion targetVersion = transition.to(); + if (currentVersion.isAfterOrEquals(targetVersion)) { return Migration.Result.COMPLETED; } - logger.info("Migrating to version {} ", newVersion); - return allMigrationClazz.get(version).run() - .onComplete(() -> schemaVersionDAO.updateVersion(newVersion).block(), - () -> logger.info("Migrating to version {} done", newVersion)) - .onFailure(() -> logger.warn(failureMessage(newVersion)), - () -> throwMigrationException(newVersion)); + logger.info("Migrating to version {} ", transition.toAsString()); + return allMigrationClazz.get(transition).run() + .onComplete(() -> schemaVersionDAO.updateVersion(transition.to()).block(), + () -> logger.info("Migrating to version {} done", transition.toAsString())) + .onFailure(() -> logger.warn(failureMessage(transition.to())), + () -> throwMigrationException(transition.to())); }; } diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/SchemaTransition.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/SchemaTransition.java new file mode 100644 index 0000000..68d811d --- /dev/null +++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/SchemaTransition.java @@ -0,0 +1,69 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ +package org.apache.james.backends.cassandra.versions; + +import java.util.Objects; + +public class SchemaTransition { + + public static SchemaTransition to(SchemaVersion toVersion) { + return new SchemaTransition(toVersion); + } + + private final SchemaVersion toVersion; + + private SchemaTransition(SchemaVersion toVersion) { + this.toVersion = toVersion; + } + + public String fromAsString() { + return String.valueOf(toVersion.previous().getValue()); + } + + public String toAsString() { + return String.valueOf(toVersion.getValue()); + } + + public SchemaVersion from() { + return toVersion.previous(); + } + + public SchemaVersion to() { + return toVersion; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof SchemaTransition) { + SchemaTransition that = (SchemaTransition) o; + return Objects.equals(toVersion, that.toVersion); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(toVersion); + } + + @Override + public String toString() { + return "SchemaTransition{ from " + fromAsString() + " to " + toAsString() + "}"; + } +} diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java index 709d63b..e356612 100644 --- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java +++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java @@ -36,6 +36,7 @@ import java.util.concurrent.Executors; import org.apache.commons.lang.NotImplementedException; import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO; +import org.apache.james.backends.cassandra.versions.SchemaTransition; import org.apache.james.backends.cassandra.versions.SchemaVersion; import org.apache.james.task.Task; import org.apache.james.util.concurrent.NamedThreadFactory; @@ -54,6 +55,8 @@ public class CassandraMigrationServiceTest { private static final SchemaVersion INTERMEDIARY_VERSION = new SchemaVersion(2); private static final SchemaVersion CURRENT_VERSION = INTERMEDIARY_VERSION; private static final SchemaVersion OLDER_VERSION = new SchemaVersion(1); + private static final SchemaTransition FROM_OLDER_TO_CURRENT = SchemaTransition.to(CURRENT_VERSION); + private static final SchemaTransition FROM_CURRENT_TO_LATEST = SchemaTransition.to(LATEST_VERSION); private CassandraMigrationService testee; private CassandraSchemaVersionDAO schemaVersionDAO; private ExecutorService executorService; @@ -69,11 +72,9 @@ public class CassandraMigrationServiceTest { successfulMigration = mock(Migration.class); when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED); - Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder() - .put(OLDER_VERSION, successfulMigration) - .put(CURRENT_VERSION, successfulMigration) - .put(LATEST_VERSION, successfulMigration) - .build(); + Map<SchemaTransition, Migration> allMigrationClazz = ImmutableMap.of( + FROM_OLDER_TO_CURRENT, successfulMigration, + FROM_CURRENT_TO_LATEST, successfulMigration); testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION); executorService = Executors.newFixedThreadPool(2, NamedThreadFactory.withClassName(getClass())); @@ -128,15 +129,14 @@ public class CassandraMigrationServiceTest { testee.upgradeToLastVersion().run(); + verify(schemaVersionDAO, times(1)).updateVersion(eq(CURRENT_VERSION)); verify(schemaVersionDAO, times(1)).updateVersion(eq(LATEST_VERSION)); } @Test public void upgradeToVersionShouldThrowOnMissingVersion() throws InterruptedException { - Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder() - .put(OLDER_VERSION, successfulMigration) - .put(LATEST_VERSION, successfulMigration) - .build(); + Map<SchemaTransition, Migration> allMigrationClazz = ImmutableMap.of(FROM_OLDER_TO_CURRENT, successfulMigration); + testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION); when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION))); @@ -148,11 +148,10 @@ public class CassandraMigrationServiceTest { @Test public void upgradeToVersionShouldUpdateIntermediarySuccessfulMigrationsInCaseOfError() throws InterruptedException { try { - Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder() - .put(OLDER_VERSION, successfulMigration) - .put(INTERMEDIARY_VERSION, () -> Migration.Result.PARTIAL) - .put(LATEST_VERSION, successfulMigration) - .build(); + Map<SchemaTransition, Migration> allMigrationClazz = ImmutableMap.of( + FROM_OLDER_TO_CURRENT, successfulMigration, + FROM_CURRENT_TO_LATEST, () -> Migration.Result.PARTIAL); + testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION); when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(Mono.just(Optional.of(OLDER_VERSION))); @@ -170,10 +169,10 @@ public class CassandraMigrationServiceTest { when(migration1.run()).thenReturn(Migration.Result.PARTIAL); Migration migration2 = successfulMigration; - Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder() - .put(OLDER_VERSION, migration1) - .put(CURRENT_VERSION, migration2) - .build(); + Map<SchemaTransition, Migration> allMigrationClazz = ImmutableMap.of( + FROM_OLDER_TO_CURRENT, migration1, + FROM_CURRENT_TO_LATEST, migration2); + testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION); expectedException.expect(MigrationException.class); @@ -188,10 +187,10 @@ public class CassandraMigrationServiceTest { Migration migration2 = mock(Migration.class); when(migration2.run()).thenReturn(Migration.Result.COMPLETED); - Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder() - .put(OLDER_VERSION, migration1) - .put(CURRENT_VERSION, migration2) - .build(); + Map<SchemaTransition, Migration> allMigrationClazz = ImmutableMap.of( + FROM_OLDER_TO_CURRENT, migration1, + FROM_CURRENT_TO_LATEST, migration2); + testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION); expectedException.expect(MigrationException.class); diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/SchemaTransitionTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/SchemaTransitionTest.java new file mode 100644 index 0000000..64defab --- /dev/null +++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/SchemaTransitionTest.java @@ -0,0 +1,16 @@ +package org.apache.james.backends.cassandra.versions; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class SchemaTransitionTest { + + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(SchemaTransition.class) + .verify(); + } + + +} \ No newline at end of file diff --git a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java index 01e4caa..025cbef 100644 --- a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java +++ b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java @@ -22,6 +22,7 @@ package org.apache.james.modules.server; import org.apache.james.backends.cassandra.migration.CassandraMigrationService; import org.apache.james.backends.cassandra.migration.Migration; import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager; +import org.apache.james.backends.cassandra.versions.SchemaTransition; import org.apache.james.backends.cassandra.versions.SchemaVersion; import org.apache.james.mailbox.cassandra.mail.migration.AttachmentMessageIdCreation; import org.apache.james.mailbox.cassandra.mail.migration.AttachmentV2Migration; @@ -38,11 +39,11 @@ import com.google.inject.multibindings.Multibinder; import com.google.inject.name.Names; public class CassandraRoutesModule extends AbstractModule { - private static final SchemaVersion FROM_V2_TO_V3 = new SchemaVersion(2); - private static final SchemaVersion FROM_V3_TO_V4 = new SchemaVersion(3); - private static final SchemaVersion FROM_V4_TO_V5 = new SchemaVersion(4); - private static final SchemaVersion FROM_V5_TO_V6 = new SchemaVersion(5); - private static final SchemaVersion FROM_V6_TO_V7 = new SchemaVersion(6); + private static final SchemaTransition FROM_V2_TO_V3 = SchemaTransition.to(new SchemaVersion(3)); + private static final SchemaTransition FROM_V3_TO_V4 = SchemaTransition.to(new SchemaVersion(4)); + private static final SchemaTransition FROM_V4_TO_V5 = SchemaTransition.to(new SchemaVersion(5)); + private static final SchemaTransition FROM_V5_TO_V6 = SchemaTransition.to(new SchemaVersion(6)); + private static final SchemaTransition FROM_V6_TO_V7 = SchemaTransition.to(new SchemaVersion(7)); @Override protected void configure() { @@ -54,7 +55,7 @@ public class CassandraRoutesModule extends AbstractModule { routesMultibinder.addBinding().to(CassandraMigrationRoutes.class); routesMultibinder.addBinding().to(CassandraMailboxMergingRoutes.class); - MapBinder<SchemaVersion, Migration> allMigrationClazzBinder = MapBinder.newMapBinder(binder(), SchemaVersion.class, Migration.class); + MapBinder<SchemaTransition, Migration> allMigrationClazzBinder = MapBinder.newMapBinder(binder(), SchemaTransition.class, Migration.class); allMigrationClazzBinder.addBinding(FROM_V2_TO_V3).toInstance(() -> Migration.Result.COMPLETED); allMigrationClazzBinder.addBinding(FROM_V3_TO_V4).to(AttachmentV2Migration.class); allMigrationClazzBinder.addBinding(FROM_V4_TO_V5).to(AttachmentMessageIdCreation.class); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
