[Major] refactored the handling with code and data migration versions -

The version handling with code and data migrations was messed up. The
migration version was set after the data migration and then the code
migration used this value for further processing. Now there are two
attributes for the migration version (code and data). The files for the
data migration and the classes for the code migration have now
individual versions.
This commit is contained in:
Reto Breitenmoser 2015-05-22 18:21:41 +02:00
parent 74366ea8a5
commit f72f6a1c0e
9 changed files with 146 additions and 59 deletions

View File

@ -18,6 +18,9 @@ package li.strolch.migrations;
import java.io.File;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.command.parameter.SetParameterCommand;
import li.strolch.model.Resource;
import li.strolch.model.parameter.StringParameter;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.utils.Version;
@ -35,4 +38,15 @@ public class CodeMigration extends Migration {
public void migrate(ComponentContainer container, Certificate certificate) {
logger.info("[" + this.realm + "] Running no-op migration " + this.version);
}
@Override
protected void setNewVersion(SetParameterCommand cmd, Resource migrationsRes) {
StringParameter currentCodeVersionP = migrationsRes.getParameter(BAG_PARAMETERS, PARAM_CURRENT_CODE_VERSION);
cmd.setParameter(currentCodeVersionP);
cmd.setValueAsString(getVersion().toString());
}
}

View File

@ -18,7 +18,8 @@ package li.strolch.migrations;
import static li.strolch.migrations.Migration.BAG_PARAMETERS;
import static li.strolch.migrations.Migration.MIGRATIONS_ID;
import static li.strolch.migrations.Migration.MIGRATIONS_TYPE;
import static li.strolch.migrations.Migration.PARAM_CURRENT_VERSION;
import static li.strolch.migrations.Migration.PARAM_CURRENT_DATA_VERSION;
import static li.strolch.migrations.Migration.PARAM_CURRENT_CODE_VERSION;
import java.util.HashMap;
import java.util.Map;
@ -35,7 +36,7 @@ import ch.eitchnet.utils.Version;
public class CurrentMigrationVersionQuery {
private ComponentContainer container;
private Map<String, Version> currentVersions;
private Map<String, MigrationVersion> currentVersions;
/**
* @param container
@ -55,29 +56,46 @@ public class CurrentMigrationVersionQuery {
Resource migrationsRes = tx.getResourceBy(MIGRATIONS_TYPE, MIGRATIONS_ID);
if (migrationsRes == null) {
this.currentVersions.put(realmName, Version.emptyVersion);
this.currentVersions.put(realmName, new MigrationVersion(Version.emptyVersion,Version.emptyVersion));
continue;
}
StringParameter currentVersionP = migrationsRes.getParameter(BAG_PARAMETERS, PARAM_CURRENT_VERSION);
if (currentVersionP == null) {
this.currentVersions.put(realmName, Version.emptyVersion);
continue;
StringParameter currentDataVersionP = migrationsRes.getParameter(BAG_PARAMETERS, PARAM_CURRENT_DATA_VERSION);
StringParameter currentCodeVersionP = migrationsRes.getParameter(BAG_PARAMETERS, PARAM_CURRENT_CODE_VERSION);
if (currentDataVersionP == null && currentCodeVersionP == null) {
this.currentVersions.put(realmName, new MigrationVersion(Version.emptyVersion,Version.emptyVersion));
} else if(currentDataVersionP == null && currentCodeVersionP != null) {
Version codeVersion = getVersionFromParam(currentCodeVersionP);
this.currentVersions.put(realmName, new MigrationVersion(Version.emptyVersion,codeVersion));
} else if (currentDataVersionP != null && currentCodeVersionP == null) {
Version dataVersion = getVersionFromParam(currentDataVersionP);
this.currentVersions.put(realmName, new MigrationVersion(dataVersion,Version.emptyVersion));
} else {
Version dataVersion = getVersionFromParam(currentDataVersionP);
Version codeVersion = getVersionFromParam(currentCodeVersionP);
this.currentVersions.put(realmName, new MigrationVersion(dataVersion,codeVersion));
}
String versionS = currentVersionP.getValue();
if (!Version.isParseable(versionS)) {
throw new StrolchConfigurationException("Version value " + versionS + " is not valid for "
+ currentVersionP.getLocator());
}
Version version = Version.valueOf(versionS);
this.currentVersions.put(realmName, version);
}
}
}
public Map<String, Version> getCurrentVersions() {
/**
* @param versionS
* @return
*/
private Version getVersionFromParam(StringParameter versionP) {
String versionS = versionP.getValue();
if (!Version.isParseable(versionS)) {
throw new StrolchConfigurationException("Version value " + versionS + " is not valid for "
+ versionP.getLocator());
}
Version version = Version.valueOf(versionS);
return version;
}
public Map<String, MigrationVersion> getCurrentVersions() {
return this.currentVersions;
}

View File

@ -21,8 +21,11 @@ import java.util.Collections;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.command.XmlImportModelCommand;
import li.strolch.command.parameter.SetParameterCommand;
import li.strolch.exception.StrolchException;
import li.strolch.model.ModelStatistics;
import li.strolch.model.Resource;
import li.strolch.model.parameter.StringParameter;
import li.strolch.persistence.api.StrolchTransaction;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.utils.Version;
@ -60,4 +63,13 @@ public class DataMigration extends Migration {
logger.info(MessageFormat
.format("[{0}] Data migration for {1} loaded {2} Resources and {3} Orders.", getRealm(), getVersion(), statistics.nrOfResources, statistics.nrOfOrders)); //$NON-NLS-1$
}
@Override
protected void setNewVersion(SetParameterCommand cmd, Resource migrationsRes) {
StringParameter currentDataVersionP = migrationsRes.getParameter(BAG_PARAMETERS, PARAM_CURRENT_DATA_VERSION);
cmd.setParameter(currentDataVersionP);
cmd.setValueAsString(getVersion().toString());
}
}

View File

@ -36,7 +36,8 @@ public abstract class Migration {
public static final String MIGRATIONS_TYPE = "Migrations";
public static final String MIGRATIONS_ID = "migrations";
public static final String BAG_PARAMETERS = "parameters";
public static final String PARAM_CURRENT_VERSION = "currentVersion";
public static final String PARAM_CURRENT_DATA_VERSION = "currentDataVersion";
public static final String PARAM_CURRENT_CODE_VERSION = "currentCodeVersion";
protected static final Logger logger = LoggerFactory.getLogger(CodeMigration.class);
@ -75,9 +76,13 @@ public abstract class Migration {
ParameterBag bag = new ParameterBag(BAG_PARAMETERS, BAG_PARAMETERS, BAG_PARAMETERS);
migrationsRes.addParameterBag(bag);
StringParameter currentVersionP = new StringParameter(PARAM_CURRENT_VERSION, PARAM_CURRENT_VERSION,
getVersion().toString());
bag.addParameter(currentVersionP);
StringParameter currentDataVersionP = new StringParameter(PARAM_CURRENT_DATA_VERSION,
PARAM_CURRENT_DATA_VERSION, getVersion().toString());
bag.addParameter(currentDataVersionP);
StringParameter currentCodeVersionP = new StringParameter(PARAM_CURRENT_CODE_VERSION,
PARAM_CURRENT_CODE_VERSION, getVersion().toString());
bag.addParameter(currentCodeVersionP);
AddResourceCommand cmd = new AddResourceCommand(container, tx);
cmd.setResource(migrationsRes);
@ -85,16 +90,15 @@ public abstract class Migration {
tx.addCommand(cmd);
} else {
StringParameter currentVersionP = migrationsRes.getParameter(BAG_PARAMETERS, PARAM_CURRENT_VERSION);
SetParameterCommand cmd = new SetParameterCommand(container, tx);
cmd.setParameter(currentVersionP);
cmd.setValueAsString(getVersion().toString());
setNewVersion(cmd,migrationsRes);
tx.addCommand(cmd);
}
}
public abstract void migrate(ComponentContainer container, Certificate certificate);
protected abstract void setNewVersion(SetParameterCommand cmd,Resource migrationsRes);
}

View File

@ -0,0 +1,37 @@
/**
*
*/
package li.strolch.migrations;
import ch.eitchnet.utils.Version;
/**
* Migration versions for data and code migrations
*
* @author Reto Breitenmoser <reto.breitenmoser@4trees.ch>
*/
public class MigrationVersion {
private Version dataVersion;
private Version codeVersion;
public MigrationVersion(Version dataVersion, Version codeVersion) {
this.dataVersion = dataVersion;
this.codeVersion = codeVersion;
}
/**
* @return the dataVersion
*/
public Version getDataVersion() {
return dataVersion;
}
/**
* @return the codeVersion
*/
public Version getCodeVersion() {
return codeVersion;
}
}

View File

@ -81,20 +81,21 @@ public class Migrations {
logDetectedMigrations(this.realmNames, this.dataMigrations, this.codeMigrations);
}
public void runMigrations(Certificate certificate, Map<String, Version> currentVersions) {
public void runMigrations(Certificate certificate, Map<String, MigrationVersion> currentVersions) {
MapOfLists<String, Version> migrationsRan = new MapOfLists<>();
for (Entry<String, Version> entry : currentVersions.entrySet()) {
for (Entry<String, MigrationVersion> entry : currentVersions.entrySet()) {
String realm = entry.getKey();
Version currentVersion = entry.getValue();
MigrationVersion currentVersion = entry.getValue();
if (this.verbose)
logger.info("[" + realm + "] Performing all migrations after " + currentVersion);
Version nextPossibleVersion = currentVersion.add(0, 0, 1);
CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleVersion, null);
DataMigration currentDataMigration = new DataMigration(realm, nextPossibleVersion, null);
Version nextPossibleCodeVersion = currentVersion.getCodeVersion().add(0, 0, 1);
Version nextPossibleDataVersion = currentVersion.getDataVersion().add(0, 0, 1);
CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleCodeVersion, null);
DataMigration currentDataMigration = new DataMigration(realm, nextPossibleDataVersion, null);
SortedSet<DataMigration> dataMigrations = this.dataMigrations.get(realm);
if (dataMigrations != null && !dataMigrations.isEmpty()) {
@ -131,7 +132,7 @@ public class Migrations {
* @param cert
* @param codeMigrationsByRealm
*/
public void runCodeMigrations(Certificate cert, Map<String, Version> currentVersions,
public void runCodeMigrations(Certificate cert, Map<String, MigrationVersion> currentVersions,
MapOfLists<String, CodeMigration> codeMigrationsByRealm) {
MapOfLists<String, Version> migrationsRan = new MapOfLists<>();
@ -142,21 +143,21 @@ public class Migrations {
if (!this.realmNames.contains(realm))
continue;
Version currentVersion = currentVersions.get(realm);
MigrationVersion currentVersion = currentVersions.get(realm);
List<CodeMigration> listOfMigrations = codeMigrationsByRealm.getList(realm);
SortedSet<CodeMigration> migrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion()));
migrations.addAll(listOfMigrations);
Version nextVersion = currentVersion.add(0, 0, 1);
Version nextVersion = currentVersion.getCodeVersion().add(0, 0, 1);
CodeMigration nextMigration = new CodeMigration(realm, nextVersion);
SortedSet<CodeMigration> migrationsToRun = migrations.tailSet(nextMigration);
for (CodeMigration migration : migrationsToRun) {
DBC.INTERIM.assertEquals("Realms do not match!", realm, migration.getRealm());
Version migrateVersion = migration.getVersion();
boolean isLaterMigration = migrateVersion.compareTo(currentVersion) > 0;
DBC.INTERIM.assertTrue("Current version " + currentVersion + " is not before next " + migrateVersion,
boolean isLaterMigration = migrateVersion.compareTo(currentVersion.getCodeVersion()) > 0;
DBC.INTERIM.assertTrue("Current version " + currentVersion.getCodeVersion() + " is not before next " + migrateVersion,
isLaterMigration);
String msg = "[{0}] Running code migration {1} {2}";
@ -264,15 +265,16 @@ public class Migrations {
return migrationsByRealm;
}
public MapOfLists<String, Version> getMigrationsToRun(Map<String, Version> currentVersions) {
public MapOfLists<String, Version> getMigrationsToRun(Map<String, MigrationVersion> currentVersions) {
MapOfLists<String, Version> migrationsToRun = new MapOfLists<>();
for (Entry<String, Version> entry : currentVersions.entrySet()) {
for (Entry<String, MigrationVersion> entry : currentVersions.entrySet()) {
String realm = entry.getKey();
Version nextPossibleVersion = entry.getValue().add(0, 0, 1);
CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleVersion, null);
DataMigration currentDataMigration = new DataMigration(realm, nextPossibleVersion, null);
Version nextPossibleCodeVersion = entry.getValue().getCodeVersion().add(0, 0, 1);
Version nextPossibleDataVersion = entry.getValue().getDataVersion().add(0, 0, 1);
CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleCodeVersion, null);
DataMigration currentDataMigration = new DataMigration(realm, nextPossibleDataVersion, null);
SortedSet<CodeMigration> allCodeMigrations = this.codeMigrations.get(realm);
if (allCodeMigrations != null) {

View File

@ -62,7 +62,7 @@ public class MigrationsHandler extends StrolchComponent {
return this.migrations.getMigrationsRan();
}
public Map<String, Version> getCurrentVersions(Certificate cert) {
public Map<String, MigrationVersion> getCurrentVersions(Certificate cert) {
CurrentMigrationVersionQuery query = new CurrentMigrationVersionQuery(getContainer());
query.doQuery(cert);
return query.getCurrentVersions();
@ -75,7 +75,7 @@ public class MigrationsHandler extends StrolchComponent {
Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), this.verbose);
migrations.parseMigrations(this.migrationsPath);
Map<String, Version> currentVersions = getCurrentVersions(cert);
Map<String, MigrationVersion> currentVersions = getCurrentVersions(cert);
this.migrations = migrations;
return this.migrations.getMigrationsToRun(currentVersions);
}
@ -87,12 +87,12 @@ public class MigrationsHandler extends StrolchComponent {
Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), this.verbose);
migrations.parseMigrations(this.migrationsPath);
Map<String, Version> currentVersions = getCurrentVersions(cert);
Map<String, MigrationVersion> currentVersions = getCurrentVersions(cert);
this.migrations.runMigrations(cert, currentVersions);
}
public void runCodeMigrations(Certificate cert, MapOfLists<String, CodeMigration> codeMigrationsByRealm) {
Map<String, Version> currentVersions = getCurrentVersions(cert);
Map<String, MigrationVersion> currentVersions = getCurrentVersions(cert);
Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), this.verbose);
this.migrations = migrations;
migrations.runCodeMigrations(cert, currentVersions, codeMigrationsByRealm);
@ -138,7 +138,7 @@ public class MigrationsHandler extends StrolchComponent {
QueryCurrentVersionsAction queryAction = new QueryCurrentVersionsAction(query);
PrivilegeHandler privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, queryAction);
Map<String, Version> currentVersions = query.getCurrentVersions();
Map<String, MigrationVersion> currentVersions = query.getCurrentVersions();
RunMigrationsAction action = new RunMigrationsAction(this.migrations, currentVersions);
@ -185,7 +185,7 @@ public class MigrationsHandler extends StrolchComponent {
QueryCurrentVersionsAction queryAction = new QueryCurrentVersionsAction(query);
PrivilegeHandler privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, queryAction);
Map<String, Version> currentVersions = query.getCurrentVersions();
Map<String, MigrationVersion> currentVersions = query.getCurrentVersions();
MigrationsHandler.this.migrations = migrations;
if (migrations.getMigrationsToRun(currentVersions).isEmpty()) {

View File

@ -27,13 +27,13 @@ import ch.eitchnet.utils.Version;
public class RunMigrationsAction implements SystemUserAction {
private Migrations migrations;
private Map<String, Version> currentVersions;
private Map<String, MigrationVersion> currentVersions;
/**
* @param migrations
* @param currentVersions
*/
public RunMigrationsAction(Migrations migrations, Map<String, Version> currentVersions) {
public RunMigrationsAction(Migrations migrations, Map<String, MigrationVersion> currentVersions) {
this.migrations = migrations;
this.currentVersions = currentVersions;
}

View File

@ -70,10 +70,10 @@ public class MigrationsTest {
public void shouldRunMigrations() {
MigrationsHandler migrationsHandler = runtimeMock.getContainer().getComponent(MigrationsHandler.class);
Map<String, Version> currentVersions = migrationsHandler.getCurrentVersions(certificate);
Map<String, MigrationVersion> currentVersions = migrationsHandler.getCurrentVersions(certificate);
String defRealm = StrolchConstants.DEFAULT_REALM;
assertEquals("1.1.1", currentVersions.get(defRealm).toString());
assertEquals("0.0.0", currentVersions.get("other").toString());
assertEquals("1.1.1", currentVersions.get(defRealm).getDataVersion().toString());
assertEquals("0.0.0", currentVersions.get("other").getCodeVersion().toString());
MapOfLists<String, Version> lastMigrations = migrationsHandler.getLastMigrations();
List<Version> expectedMigrations = Arrays.asList(Version.valueOf("0.1.0"), Version.valueOf("0.1.1"),
@ -86,8 +86,8 @@ public class MigrationsTest {
// assert new current version
currentVersions = migrationsHandler.getCurrentVersions(certificate);
assertEquals("1.1.1", currentVersions.get(defRealm).toString());
assertEquals("0.0.0", currentVersions.get("other").toString());
assertEquals("1.1.1", currentVersions.get(defRealm).getDataVersion().toString());
assertEquals("0.0.0", currentVersions.get("other").getCodeVersion().toString());
MapOfLists<String, CodeMigration> codeMigrationsByRealm = new MapOfLists<>();
// add migrations in wrong sequence - should be fixed by migration handler
@ -98,13 +98,13 @@ public class MigrationsTest {
lastMigrations = migrationsHandler.getLastMigrations();
assertEquals(1, lastMigrations.keySet().size());
assertEquals(Arrays.asList(Version.valueOf("1.2.0"), Version.valueOf("1.2.0.a")),
assertEquals(Arrays.asList(Version.valueOf("1.0.0"),Version.valueOf("1.2.0"), Version.valueOf("1.2.0.a")),
lastMigrations.getList(defRealm));
// assert new current version
currentVersions = migrationsHandler.getCurrentVersions(certificate);
assertEquals("1.2.0.a", currentVersions.get(defRealm).toString());
assertEquals("0.0.0", currentVersions.get("other").toString());
assertEquals("1.2.0.a", currentVersions.get(defRealm).getCodeVersion().toString());
assertEquals("0.0.0", currentVersions.get("other").getDataVersion().toString());
}
private static class MyMigration0 extends CodeMigration {
@ -148,7 +148,7 @@ public class MigrationsTest {
try (StrolchTransaction tx = openTx(container, cert)) {
Order fooOrder = ModelGenerator.createOrder("foo", "Foo", "Foo");
Order fooOrder = ModelGenerator.createOrder("foo1", "Foo", "Foo");
AddOrderCommand addOrderCommand = new AddOrderCommand(container, tx);
addOrderCommand.setOrder(fooOrder);