diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java b/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java index 942aa408f..e9c5c657d 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/Migrations.java @@ -2,6 +2,7 @@ package li.strolch.migrations; import java.io.File; import java.io.FileFilter; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.SortedSet; @@ -25,14 +26,15 @@ public class Migrations { private Map currentVersions; private boolean verbose; - private SortedSet dataMigrations; - private SortedSet codeMigrations; + private Map> dataMigrations; + private Map> codeMigrations; private MapOfLists migrationsRan; - public Migrations(ComponentContainer container, Map currentVersions) { + public Migrations(ComponentContainer container, Map currentVersions, boolean verbose) { this.container = container; this.currentVersions = currentVersions; + this.verbose = verbose; } public void setVerbose(boolean verbose) { @@ -75,15 +77,17 @@ public class Migrations { CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleVersion, null); DataMigration currentDataMigration = new DataMigration(realm, nextPossibleVersion, null); - if (!this.codeMigrations.isEmpty()) { - for (CodeMigration migration : this.codeMigrations.tailSet(currentCodeMigration)) { + SortedSet codeMigrations = this.codeMigrations.get(realm); + if (codeMigrations != null && !codeMigrations.isEmpty()) { + for (CodeMigration migration : codeMigrations.tailSet(currentCodeMigration)) { migration.migrate(container, certificate); migrationsRan.addElement(realm, migration.getVersion()); } } - if (!this.dataMigrations.isEmpty()) { - for (DataMigration migration : this.dataMigrations.tailSet(currentDataMigration)) { + SortedSet dataMigrations = this.dataMigrations.get(realm); + if (dataMigrations != null && !dataMigrations.isEmpty()) { + for (DataMigration migration : dataMigrations.tailSet(currentDataMigration)) { migration.migrate(container, certificate); migrationsRan.addElement(realm, migration.getVersion()); } @@ -100,12 +104,14 @@ public class Migrations { } private static void logDetectedMigrations(Map currentVersions, - SortedSet dataMigrations, SortedSet codeMigrations) { + Map> allDataMigrations, + Map> allCodeMigrations) { for (Entry entry : currentVersions.entrySet()) { String realm = entry.getKey(); Version currentVersion = entry.getValue(); - if (codeMigrations.isEmpty()) { + SortedSet codeMigrations = allCodeMigrations.get(realm); + if (codeMigrations == null || codeMigrations.isEmpty()) { logger.info("[" + realm + "] Found no code migrations."); } else { logger.info("[" + realm + "] Found " + codeMigrations.size() + " code migrations"); @@ -117,7 +123,8 @@ public class Migrations { } } - if (dataMigrations.isEmpty()) { + SortedSet dataMigrations = allDataMigrations.get(realm); + if (dataMigrations == null || dataMigrations.isEmpty()) { logger.info("[" + realm + "] Found no data migrations."); } else { logger.info("[" + realm + "] Found " + dataMigrations.size() + " data migrations"); @@ -131,68 +138,68 @@ public class Migrations { } } - private static SortedSet loadDataMigrations(Map currentVersions, File migrationsPath) { + private static Map> loadDataMigrations(Map currentVersions, + File migrationsPath) { - SortedSet dataMigrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion())); + Map> migrationsByRealm = new HashMap<>(); File dataDir = new File(migrationsPath, "data"); if (dataDir.exists()) { DBC.PRE.assertTrue("migrations/data must be a directory!", dataDir.isDirectory()); - File[] realmMigrations = dataDir.listFiles(); + // only list directories where name is a realmName + File[] realmMigrations = dataDir + .listFiles((FileFilter) path -> currentVersions.containsKey(path.getName())); + for (File realmMigration : realmMigrations) { - - DBC.PRE.assertTrue("found non directory in migrations path: " + realmMigration.getAbsolutePath(), - realmMigration.isDirectory()); String realm = realmMigration.getName(); - if (!currentVersions.containsKey(realm)) { - logger.warn("Found non realm migration directory: " + realmMigration.getAbsolutePath()); - continue; - } - File[] migrations = realmMigration.listFiles((FileFilter) pathname -> pathname.getName().endsWith( + SortedSet migrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo( + o2.getVersion())); + migrationsByRealm.put(realm, migrations); + + File[] migrationFiles = realmMigration.listFiles((FileFilter) pathname -> pathname.getName().endsWith( ".xml")); - for (File file : migrations) { + for (File file : migrationFiles) { String name = file.getName(); Version version = Version.valueOf(name.substring(0, name.length() - 4)); - dataMigrations.add(new DataMigration(realm, version, file)); + migrations.add(new DataMigration(realm, version, file)); } } } - return dataMigrations; + return migrationsByRealm; } - private static SortedSet loadCodeMigrations(Map currentVersions, File migrationsPath) { + private static Map> loadCodeMigrations(Map currentVersions, + File migrationsPath) { - SortedSet codeMigrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion())); + Map> migrationsByRealm = new HashMap<>(); //new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion())); File codeDir = new File(migrationsPath, "code"); if (codeDir.exists()) { DBC.PRE.assertTrue("migrations/code must be a directory!", codeDir.isDirectory()); - File[] realmMigrations = codeDir.listFiles(); + File[] realmMigrations = codeDir + .listFiles((FileFilter) path -> currentVersions.containsKey(path.getName())); for (File realmMigration : realmMigrations) { - - DBC.PRE.assertTrue("found non directory in migrations path: " + realmMigration.getAbsolutePath(), - realmMigration.isDirectory()); String realm = realmMigration.getName(); - if (!currentVersions.containsKey(realm)) { - logger.warn("Found non realm migration directory: " + realmMigration.getAbsolutePath()); - continue; - } - File[] migrations = realmMigration.listFiles((FileFilter) pathname -> pathname.getName().endsWith( + SortedSet migrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo( + o2.getVersion())); + migrationsByRealm.put(realm, migrations); + + File[] migrationFiles = realmMigration.listFiles((FileFilter) pathname -> pathname.getName().endsWith( ".xml")); - for (File file : migrations) { + for (File file : migrationFiles) { String name = file.getName(); Version version = Version.valueOf(name.substring(0, name.length() - 4)); - codeMigrations.add(new CodeMigration(realm, version, file)); + migrations.add(new CodeMigration(realm, version, file)); } } } - return codeMigrations; + return migrationsByRealm; } public MapOfLists getMigrationsToRun() { @@ -205,15 +212,22 @@ public class Migrations { CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleVersion, null); DataMigration currentDataMigration = new DataMigration(realm, nextPossibleVersion, null); - SortedSet codeMigrations = this.codeMigrations.tailSet(currentCodeMigration); - for (CodeMigration codeMigration : codeMigrations) { - if (!migrationsToRun.containsElement(realm, codeMigration.getVersion())) - migrationsToRun.addElement(realm, codeMigration.getVersion()); + SortedSet allCodeMigrations = this.codeMigrations.get(realm); + if (allCodeMigrations != null) { + SortedSet codeMigrations = allCodeMigrations.tailSet(currentCodeMigration); + for (CodeMigration codeMigration : codeMigrations) { + if (!migrationsToRun.containsElement(realm, codeMigration.getVersion())) + migrationsToRun.addElement(realm, codeMigration.getVersion()); + } } - SortedSet dataMigrations = this.dataMigrations.tailSet(currentDataMigration); - for (DataMigration dataMigration : dataMigrations) { - if (!migrationsToRun.containsElement(realm, dataMigration.getVersion())) - migrationsToRun.addElement(realm, dataMigration.getVersion()); + + SortedSet allDataMigrations = this.dataMigrations.get(realm); + if (allDataMigrations != null) { + SortedSet dataMigrations = allDataMigrations.tailSet(currentDataMigration); + for (DataMigration dataMigration : dataMigrations) { + if (!migrationsToRun.containsElement(realm, dataMigration.getVersion())) + migrationsToRun.addElement(realm, dataMigration.getVersion()); + } } } diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java b/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java index 6b8d6efa3..45f465fa4 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/MigrationsHandler.java @@ -75,9 +75,8 @@ public class MigrationsHandler extends StrolchComponent { } Map currentVersions = getCurrentVersions(cert); - Migrations migrations = new Migrations(getContainer(), currentVersions); + Migrations migrations = new Migrations(getContainer(), currentVersions, this.verbose); migrations.parseMigrations(this.migrationsPath); - migrations.setVerbose(this.verbose); this.migrations = migrations; return this.migrations.getMigrationsToRun(); @@ -107,9 +106,8 @@ public class MigrationsHandler extends StrolchComponent { privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, action); Map currentVersions = query.getCurrentVersions(); - Migrations migrations = new Migrations(getContainer(), currentVersions); + Migrations migrations = new Migrations(getContainer(), currentVersions, this.verbose); migrations.parseMigrations(this.migrationsPath); - migrations.setVerbose(this.verbose); this.migrations = migrations; } @@ -172,9 +170,8 @@ public class MigrationsHandler extends StrolchComponent { privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, queryAction); Map currentVersions = query.getCurrentVersions(); - Migrations migrations = new Migrations(getContainer(), currentVersions); + Migrations migrations = new Migrations(getContainer(), currentVersions, MigrationsHandler.this.verbose); migrations.parseMigrations(MigrationsHandler.this.migrationsPath); - migrations.setVerbose(MigrationsHandler.this.verbose); MigrationsHandler.this.migrations = migrations; diff --git a/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java b/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java index 094e141f9..e03fc25e0 100644 --- a/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java +++ b/li.strolch.service/src/test/java/li/strolch/migrations/MigrationsTest.java @@ -55,11 +55,13 @@ public class MigrationsTest { MigrationsHandler migrationsHandler = runtimeMock.getContainer().getComponent(MigrationsHandler.class); Map currentVersions = migrationsHandler.getCurrentVersions(cert); assertEquals("1.1.1", currentVersions.get(StrolchConstants.DEFAULT_REALM).toString()); + assertEquals("0.0.0", currentVersions.get("other").toString()); MapOfLists lastMigrations = migrationsHandler.getLastMigrations(); List 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(null, lastMigrations.getList("other")); MapOfLists migrationsToRun = migrationsHandler.queryMigrationsToRun(cert); assertTrue("Expected to have all migrations run", migrationsToRun.isEmpty()); diff --git a/li.strolch.service/src/test/resources/migrationstest/config/StrolchConfiguration.xml b/li.strolch.service/src/test/resources/migrationstest/config/StrolchConfiguration.xml index 747412834..ce97ce9a9 100644 --- a/li.strolch.service/src/test/resources/migrationstest/config/StrolchConfiguration.xml +++ b/li.strolch.service/src/test/resources/migrationstest/config/StrolchConfiguration.xml @@ -21,9 +21,11 @@ li.strolch.agent.impl.DefaultRealmHandler PrivilegeHandler - defaultRealm + defaultRealm, other TRANSIENT StrolchModel.xml + TRANSIENT + StrolchModel.xml