[New] added MigrationsHandler.runCodeMigrations()
- this allows a project to add migrations to be run in a post initializer etc.
This commit is contained in:
parent
cfb30486e0
commit
cf807edd7a
|
@ -26,9 +26,6 @@ public class StrolchTypeNavigation implements Navigation {
|
|||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,12 @@ public class CodeMigration extends Migration {
|
|||
super(realm, version, dataFile);
|
||||
}
|
||||
|
||||
public CodeMigration(String realm, Version version) {
|
||||
super(realm, version, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(ComponentContainer container, Certificate certificate) {
|
||||
logger.info("[" + this.realm + "] Running migration " + this.version);
|
||||
logger.info("[" + this.realm + "] Running no-op migration " + this.version);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public class DataMigration extends Migration {
|
|||
public void migrate(ComponentContainer container, Certificate certificate) {
|
||||
|
||||
XmlImportModelCommand command;
|
||||
try (StrolchTransaction tx = container.getRealm(getRealm()).openTx(certificate, DataMigration.class)) {
|
||||
try (StrolchTransaction tx = openTx(container, certificate)) {
|
||||
|
||||
command = new XmlImportModelCommand(container, tx);
|
||||
command.setModelFile(getDataFile());
|
||||
|
|
|
@ -48,6 +48,10 @@ public abstract class Migration {
|
|||
return dataFile;
|
||||
}
|
||||
|
||||
protected StrolchTransaction openTx(ComponentContainer container, Certificate cert) {
|
||||
return container.getRealm(getRealm()).openTx(cert, getClass());
|
||||
}
|
||||
|
||||
protected Command buildMigrationVersionChangeCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
|
||||
Resource migrationsRes = tx.getResourceBy(MIGRATIONS_TYPE, MIGRATIONS_ID);
|
||||
|
|
|
@ -3,6 +3,7 @@ package li.strolch.migrations;
|
|||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.SortedSet;
|
||||
|
@ -103,6 +104,45 @@ public class Migrations {
|
|||
this.migrationsRan = migrationsRan;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cert
|
||||
* @param codeMigrationsByRealm
|
||||
*/
|
||||
public void runCodeMigrations(Certificate cert, MapOfLists<String, CodeMigration> codeMigrationsByRealm) {
|
||||
|
||||
MapOfLists<String, Version> migrationsRan = new MapOfLists<>();
|
||||
|
||||
for (String realm : codeMigrationsByRealm.keySet()) {
|
||||
Version currentVersion = this.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);
|
||||
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,
|
||||
isLaterMigration);
|
||||
|
||||
migration.migrate(this.container, cert);
|
||||
migrationsRan.addElement(realm, migration.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
if (migrationsRan.isEmpty()) {
|
||||
logger.info("There were no migrations required!");
|
||||
} else {
|
||||
logger.info("Migrated " + migrationsRan.size() + " realms!");
|
||||
}
|
||||
this.migrationsRan = migrationsRan;
|
||||
}
|
||||
|
||||
private static void logDetectedMigrations(Map<String, Version> currentVersions,
|
||||
Map<String, SortedSet<DataMigration>> allDataMigrations,
|
||||
Map<String, SortedSet<CodeMigration>> allCodeMigrations) {
|
||||
|
|
|
@ -46,7 +46,6 @@ public class MigrationsHandler extends StrolchComponent {
|
|||
private boolean verbose;
|
||||
|
||||
private Migrations migrations;
|
||||
private MapOfLists<String, Version> lastMigrations;
|
||||
private File migrationsPath;
|
||||
|
||||
private Timer migrationTimer;
|
||||
|
@ -58,9 +57,9 @@ public class MigrationsHandler extends StrolchComponent {
|
|||
}
|
||||
|
||||
public MapOfLists<String, Version> getLastMigrations() {
|
||||
if (this.lastMigrations == null)
|
||||
if (this.migrations == null)
|
||||
return new MapOfLists<>();
|
||||
return this.lastMigrations;
|
||||
return this.migrations.getMigrationsRan();
|
||||
}
|
||||
|
||||
public Map<String, Version> getCurrentVersions(Certificate cert) {
|
||||
|
@ -70,9 +69,8 @@ public class MigrationsHandler extends StrolchComponent {
|
|||
}
|
||||
|
||||
public MapOfLists<String, Version> queryMigrationsToRun(Certificate cert) {
|
||||
if (!this.migrationsPath.isDirectory()) {
|
||||
if (!this.migrationsPath.isDirectory())
|
||||
return new MapOfLists<>();
|
||||
}
|
||||
|
||||
Map<String, Version> currentVersions = getCurrentVersions(cert);
|
||||
Migrations migrations = new Migrations(getContainer(), currentVersions, this.verbose);
|
||||
|
@ -85,7 +83,13 @@ public class MigrationsHandler extends StrolchComponent {
|
|||
public void runMigrations(Certificate cert) {
|
||||
queryMigrationsToRun(cert);
|
||||
this.migrations.runMigrations(cert);
|
||||
this.lastMigrations = this.migrations.getMigrationsRan();
|
||||
}
|
||||
|
||||
public void runCodeMigrations(Certificate cert, MapOfLists<String, CodeMigration> codeMigrationsByRealm) {
|
||||
Map<String, Version> currentVersions = getCurrentVersions(cert);
|
||||
Migrations migrations = new Migrations(getContainer(), currentVersions, this.verbose);
|
||||
this.migrations = migrations;
|
||||
migrations.runCodeMigrations(cert, codeMigrationsByRealm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,7 +134,6 @@ public class MigrationsHandler extends StrolchComponent {
|
|||
RunMigrationsAction action = new RunMigrationsAction(this.migrations);
|
||||
|
||||
privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, action);
|
||||
this.lastMigrations = this.migrations.getMigrationsRan();
|
||||
}
|
||||
|
||||
super.start();
|
||||
|
@ -180,7 +183,6 @@ public class MigrationsHandler extends StrolchComponent {
|
|||
} else {
|
||||
RunMigrationsAction runMigrationsAction = new RunMigrationsAction(MigrationsHandler.this.migrations);
|
||||
privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, runMigrationsAction);
|
||||
MigrationsHandler.this.lastMigrations = MigrationsHandler.this.migrations.getMigrationsRan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,13 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.command.AddOrderCommand;
|
||||
import li.strolch.command.RemoveOrderCommand;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.runtime.StrolchConstants;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
import li.strolch.testbase.runtime.RuntimeMock;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
|
@ -49,21 +54,122 @@ public class MigrationsTest {
|
|||
@Test
|
||||
public void shouldRunMigrations() {
|
||||
|
||||
PrivilegeHandler privilegeHandler = runtimeMock.getPrivilegeHandler();
|
||||
Certificate cert = privilegeHandler.authenticate("test", "test".getBytes());
|
||||
|
||||
MigrationsHandler migrationsHandler = runtimeMock.getContainer().getComponent(MigrationsHandler.class);
|
||||
Map<String, Version> currentVersions = migrationsHandler.getCurrentVersions(cert);
|
||||
assertEquals("1.1.1", currentVersions.get(StrolchConstants.DEFAULT_REALM).toString());
|
||||
Map<String, Version> 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());
|
||||
|
||||
MapOfLists<String, Version> lastMigrations = migrationsHandler.getLastMigrations();
|
||||
List<Version> expectedMigrations = Arrays.asList(Version.valueOf("0.1.0"), Version.valueOf("0.1.1"),
|
||||
Version.valueOf("0.5.2"), Version.valueOf("1.0.0"), Version.valueOf("1.0.5"), Version.valueOf("1.1.1"));
|
||||
assertEquals(expectedMigrations, lastMigrations.getList(StrolchConstants.DEFAULT_REALM));
|
||||
assertEquals(expectedMigrations, lastMigrations.getList(defRealm));
|
||||
assertEquals(null, lastMigrations.getList("other"));
|
||||
|
||||
MapOfLists<String, Version> migrationsToRun = migrationsHandler.queryMigrationsToRun(cert);
|
||||
MapOfLists<String, Version> migrationsToRun = migrationsHandler.queryMigrationsToRun(certificate);
|
||||
assertTrue("Expected to have all migrations run", migrationsToRun.isEmpty());
|
||||
|
||||
// assert new current version
|
||||
currentVersions = migrationsHandler.getCurrentVersions(certificate);
|
||||
assertEquals("1.1.1", currentVersions.get(defRealm).toString());
|
||||
assertEquals("0.0.0", currentVersions.get("other").toString());
|
||||
|
||||
MapOfLists<String, CodeMigration> codeMigrationsByRealm = new MapOfLists<>();
|
||||
// add migrations in wrong sequence - should be fixed by migration handler
|
||||
codeMigrationsByRealm.addElement(defRealm, new MyMigration2(defRealm));
|
||||
codeMigrationsByRealm.addElement(defRealm, new MyMigration1(defRealm));
|
||||
codeMigrationsByRealm.addElement(defRealm, new MyMigration0(defRealm));
|
||||
migrationsHandler.runCodeMigrations(certificate, codeMigrationsByRealm);
|
||||
|
||||
lastMigrations = migrationsHandler.getLastMigrations();
|
||||
assertEquals(1, lastMigrations.keySet().size());
|
||||
assertEquals(Arrays.asList(Version.valueOf("1.2.0"), Version.valueOf("1.3.0")),
|
||||
lastMigrations.getList(defRealm));
|
||||
|
||||
// assert new current version
|
||||
currentVersions = migrationsHandler.getCurrentVersions(certificate);
|
||||
assertEquals("1.3.0", currentVersions.get(defRealm).toString());
|
||||
assertEquals("0.0.0", currentVersions.get("other").toString());
|
||||
}
|
||||
|
||||
private static class MyMigration0 extends CodeMigration {
|
||||
|
||||
private static final Version version = Version.valueOf("1.0.0");
|
||||
|
||||
public MyMigration0(String realm) {
|
||||
super(realm, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(ComponentContainer container, Certificate cert) {
|
||||
logger.info("[" + this.realm + "] Running migration " + this.getVersion());
|
||||
|
||||
try (StrolchTransaction tx = openTx(container, cert)) {
|
||||
|
||||
Order fooOrder = ModelGenerator.createOrder("foo", "Foo", "Foo");
|
||||
|
||||
AddOrderCommand addOrderCommand = new AddOrderCommand(container, tx);
|
||||
addOrderCommand.setOrder(fooOrder);
|
||||
tx.addCommand(addOrderCommand);
|
||||
|
||||
tx.addCommand(buildMigrationVersionChangeCommand(container, tx));
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyMigration1 extends CodeMigration {
|
||||
|
||||
private static final Version version = Version.valueOf("1.2.0");
|
||||
|
||||
public MyMigration1(String realm) {
|
||||
super(realm, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(ComponentContainer container, Certificate cert) {
|
||||
logger.info("[" + this.realm + "] Running migration " + this.getVersion());
|
||||
|
||||
try (StrolchTransaction tx = openTx(container, cert)) {
|
||||
|
||||
Order fooOrder = ModelGenerator.createOrder("foo", "Foo", "Foo");
|
||||
|
||||
AddOrderCommand addOrderCommand = new AddOrderCommand(container, tx);
|
||||
addOrderCommand.setOrder(fooOrder);
|
||||
tx.addCommand(addOrderCommand);
|
||||
|
||||
tx.addCommand(buildMigrationVersionChangeCommand(container, tx));
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyMigration2 extends CodeMigration {
|
||||
|
||||
private static final Version version = Version.valueOf("1.3.0");
|
||||
|
||||
public MyMigration2(String realm) {
|
||||
super(realm, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(ComponentContainer container, Certificate cert) {
|
||||
logger.info("[" + this.realm + "] Running migration " + this.getVersion());
|
||||
|
||||
try (StrolchTransaction tx = openTx(container, cert)) {
|
||||
|
||||
Order fooOrder = tx.getOrderBy("Foo", "foo");
|
||||
|
||||
RemoveOrderCommand removeOrderCommand = new RemoveOrderCommand(container, tx);
|
||||
removeOrderCommand.setOrder(fooOrder);
|
||||
tx.addCommand(removeOrderCommand);
|
||||
|
||||
tx.addCommand(buildMigrationVersionChangeCommand(container, tx));
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue