From 174e5bd37f6a7e83385defd4c8d413a95d61477c Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Thu, 12 Feb 2015 17:25:59 +0100 Subject: [PATCH] [Major] refactored MigrationsHandler - now the currentVersions are queried later, because only after the realm handler is started, can we query the current version. - this lead to only parsing the migrations at initialize - and thus in start querying the versions and performing the required migrations --- .../li/strolch/migrations/Migrations.java | 77 +++++++++---------- .../strolch/migrations/MigrationsHandler.java | 50 ++++++------ .../migrations/RunMigrationsAction.java | 10 ++- 3 files changed, 73 insertions(+), 64 deletions(-) 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 459e1ad4f..77c8a762a 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 @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -25,7 +26,7 @@ public class Migrations { private static final Logger logger = LoggerFactory.getLogger(Migrations.class); private ComponentContainer container; - private Map currentVersions; + private Set realmNames; private boolean verbose; private Map> dataMigrations; @@ -33,9 +34,9 @@ public class Migrations { private MapOfLists migrationsRan; - public Migrations(ComponentContainer container, Map currentVersions, boolean verbose) { + public Migrations(ComponentContainer container, Set realmNames, boolean verbose) { this.container = container; - this.currentVersions = currentVersions; + this.realmNames = realmNames; this.verbose = verbose; } @@ -55,41 +56,46 @@ public class Migrations { DBC.PRE.assertTrue("If migrations path is not a directory!", migrationsPath.isDirectory()); // data migrations - this.dataMigrations = loadDataMigrations(this.currentVersions, migrationsPath); + this.dataMigrations = loadDataMigrations(this.realmNames, migrationsPath); // code migrations - this.codeMigrations = loadCodeMigrations(this.currentVersions, migrationsPath); + this.codeMigrations = loadCodeMigrations(this.realmNames, migrationsPath); // log found migrations if (this.verbose) - logDetectedMigrations(this.currentVersions, this.dataMigrations, this.codeMigrations); + logDetectedMigrations(this.realmNames, this.dataMigrations, this.codeMigrations); } - public void runMigrations(Certificate certificate) { + public void runMigrations(Certificate certificate, Map currentVersions) { MapOfLists migrationsRan = new MapOfLists<>(); - for (Entry entry : this.currentVersions.entrySet()) { + for (Entry entry : currentVersions.entrySet()) { String realm = entry.getKey(); Version currentVersion = entry.getValue(); - logger.info("[" + realm + "] Performing all migrations after " + currentVersion); + 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); - SortedSet codeMigrations = this.codeMigrations.get(realm); - if (codeMigrations != null && !codeMigrations.isEmpty()) { - for (CodeMigration migration : codeMigrations.tailSet(currentCodeMigration)) { + SortedSet dataMigrations = this.dataMigrations.get(realm); + if (dataMigrations != null && !dataMigrations.isEmpty()) { + for (DataMigration migration : dataMigrations.tailSet(currentDataMigration)) { + String msg = "[{0}] Running data migration {1}"; + logger.info(MessageFormat.format(msg, realm, migration.getVersion())); migration.migrate(container, certificate); migrationsRan.addElement(realm, migration.getVersion()); } } - SortedSet dataMigrations = this.dataMigrations.get(realm); - if (dataMigrations != null && !dataMigrations.isEmpty()) { - for (DataMigration migration : dataMigrations.tailSet(currentDataMigration)) { + SortedSet codeMigrations = this.codeMigrations.get(realm); + if (codeMigrations != null && !codeMigrations.isEmpty()) { + for (CodeMigration migration : codeMigrations.tailSet(currentCodeMigration)) { + String msg = "[{0}] Running code migration {1} {2}"; + logger.info(MessageFormat.format(msg, realm, migration.getVersion(), migration.getClass().getName())); migration.migrate(container, certificate); migrationsRan.addElement(realm, migration.getVersion()); } @@ -110,17 +116,18 @@ public class Migrations { * @param cert * @param codeMigrationsByRealm */ - public void runCodeMigrations(Certificate cert, MapOfLists codeMigrationsByRealm) { + public void runCodeMigrations(Certificate cert, Map currentVersions, + MapOfLists codeMigrationsByRealm) { MapOfLists migrationsRan = new MapOfLists<>(); for (String realm : codeMigrationsByRealm.keySet()) { // ignore if no such realm - if (!this.currentVersions.containsKey(realm)) + if (!this.realmNames.contains(realm)) continue; - Version currentVersion = this.currentVersions.get(realm); + Version currentVersion = currentVersions.get(realm); List listOfMigrations = codeMigrationsByRealm.getList(realm); SortedSet migrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion())); @@ -153,12 +160,11 @@ public class Migrations { this.migrationsRan = migrationsRan; } - private static void logDetectedMigrations(Map currentVersions, + private static void logDetectedMigrations(Set realmNames, Map> allDataMigrations, Map> allCodeMigrations) { - for (Entry entry : currentVersions.entrySet()) { - String realm = entry.getKey(); - Version currentVersion = entry.getValue(); + + for (String realm : realmNames) { SortedSet codeMigrations = allCodeMigrations.get(realm); if (codeMigrations == null || codeMigrations.isEmpty()) { @@ -166,10 +172,7 @@ public class Migrations { } else { logger.info("[" + realm + "] Found " + codeMigrations.size() + " code migrations"); for (CodeMigration codeMigration : codeMigrations) { - if (codeMigration.getVersion().compareTo(currentVersion) > 0) - logger.info("[" + realm + "] + " + codeMigration.getVersion().toString()); - else - logger.info("[" + realm + "] - " + codeMigration.getVersion().toString()); + logger.info("[" + realm + "] " + codeMigration.getVersion().toString()); } } @@ -179,17 +182,13 @@ public class Migrations { } else { logger.info("[" + realm + "] Found " + dataMigrations.size() + " data migrations"); for (DataMigration dataMigration : dataMigrations) { - if (dataMigration.getVersion().compareTo(currentVersion) > 0) - logger.info("[" + realm + "] + " + dataMigration.getVersion().toString()); - else - logger.info("[" + realm + "] - " + dataMigration.getVersion().toString()); + logger.info("[" + realm + "] " + dataMigration.getVersion().toString()); } } } } - private static Map> loadDataMigrations(Map currentVersions, - File migrationsPath) { + private static Map> loadDataMigrations(Set realmNames, File migrationsPath) { Map> migrationsByRealm = new HashMap<>(); @@ -198,8 +197,7 @@ public class Migrations { DBC.PRE.assertTrue("migrations/data must be a directory!", dataDir.isDirectory()); // only list directories where name is a realmName - File[] realmMigrations = dataDir - .listFiles((FileFilter) path -> currentVersions.containsKey(path.getName())); + File[] realmMigrations = dataDir.listFiles((FileFilter) path -> realmNames.contains(path.getName())); for (File realmMigration : realmMigrations) { String realm = realmMigration.getName(); @@ -221,8 +219,7 @@ public class Migrations { return migrationsByRealm; } - private static Map> loadCodeMigrations(Map currentVersions, - File migrationsPath) { + private static Map> loadCodeMigrations(Set realmNames, File migrationsPath) { Map> migrationsByRealm = new HashMap<>(); //new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion())); @@ -230,8 +227,8 @@ public class Migrations { if (codeDir.exists()) { DBC.PRE.assertTrue("migrations/code must be a directory!", codeDir.isDirectory()); - File[] realmMigrations = codeDir - .listFiles((FileFilter) path -> currentVersions.containsKey(path.getName())); + File[] realmMigrations = codeDir.listFiles((FileFilter) path -> realmNames.contains(path.getName())); + for (File realmMigration : realmMigrations) { String realm = realmMigration.getName(); @@ -252,11 +249,11 @@ public class Migrations { return migrationsByRealm; } - public MapOfLists getMigrationsToRun() { + public MapOfLists getMigrationsToRun(Map currentVersions) { MapOfLists migrationsToRun = new MapOfLists<>(); - for (Entry entry : this.currentVersions.entrySet()) { + for (Entry entry : currentVersions.entrySet()) { String realm = entry.getKey(); Version nextPossibleVersion = entry.getValue().add(0, 0, 1); CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleVersion, null); 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 93c03af2a..62233497f 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 @@ -72,24 +72,30 @@ public class MigrationsHandler extends StrolchComponent { if (!this.migrationsPath.isDirectory()) return new MapOfLists<>(); - Map currentVersions = getCurrentVersions(cert); - Migrations migrations = new Migrations(getContainer(), currentVersions, this.verbose); + Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), this.verbose); migrations.parseMigrations(this.migrationsPath); + Map currentVersions = getCurrentVersions(cert); this.migrations = migrations; - return this.migrations.getMigrationsToRun(); + return this.migrations.getMigrationsToRun(currentVersions); } public void runMigrations(Certificate cert) { - queryMigrationsToRun(cert); - this.migrations.runMigrations(cert); + if (!this.migrationsPath.isDirectory()) + return; + + Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), this.verbose); + migrations.parseMigrations(this.migrationsPath); + + Map currentVersions = getCurrentVersions(cert); + this.migrations.runMigrations(cert, currentVersions); } public void runCodeMigrations(Certificate cert, MapOfLists codeMigrationsByRealm) { Map currentVersions = getCurrentVersions(cert); - Migrations migrations = new Migrations(getContainer(), currentVersions, this.verbose); + Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), this.verbose); this.migrations = migrations; - migrations.runCodeMigrations(cert, codeMigrationsByRealm); + migrations.runCodeMigrations(cert, currentVersions, codeMigrationsByRealm); } public boolean isVerbose() { @@ -108,13 +114,7 @@ public class MigrationsHandler extends StrolchComponent { this.migrationsPath = runtimeConf.getDataDir(MigrationsHandler.class.getName(), PATH_MIGRATIONS, false); if (this.runMigrationsOnStart && this.migrationsPath.exists()) { - CurrentMigrationVersionQuery query = new CurrentMigrationVersionQuery(getContainer()); - PrivilegeHandler privilegeHandler = getContainer().getComponent(PrivilegeHandler.class); - QueryCurrentVersionsAction action = new QueryCurrentVersionsAction(query); - privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, action); - Map currentVersions = query.getCurrentVersions(); - - Migrations migrations = new Migrations(getContainer(), currentVersions, this.verbose); + Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), this.verbose); migrations.parseMigrations(this.migrationsPath); this.migrations = migrations; @@ -134,8 +134,13 @@ public class MigrationsHandler extends StrolchComponent { if (this.runMigrationsOnStart && this.migrations != null) { + CurrentMigrationVersionQuery query = new CurrentMigrationVersionQuery(getContainer()); + QueryCurrentVersionsAction queryAction = new QueryCurrentVersionsAction(query); PrivilegeHandler privilegeHandler = getContainer().getComponent(PrivilegeHandler.class); - RunMigrationsAction action = new RunMigrationsAction(this.migrations); + privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, queryAction); + Map currentVersions = query.getCurrentVersions(); + + RunMigrationsAction action = new RunMigrationsAction(this.migrations, currentVersions); privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, action); } @@ -172,22 +177,23 @@ public class MigrationsHandler extends StrolchComponent { return; } + Migrations migrations = new Migrations(getContainer(), getContainer().getRealmNames(), + MigrationsHandler.this.verbose); + migrations.parseMigrations(MigrationsHandler.this.migrationsPath); + CurrentMigrationVersionQuery query = new CurrentMigrationVersionQuery(getContainer()); - PrivilegeHandler privilegeHandler = getContainer().getComponent(PrivilegeHandler.class); QueryCurrentVersionsAction queryAction = new QueryCurrentVersionsAction(query); + PrivilegeHandler privilegeHandler = getContainer().getComponent(PrivilegeHandler.class); privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, queryAction); Map currentVersions = query.getCurrentVersions(); - Migrations migrations = new Migrations(getContainer(), currentVersions, MigrationsHandler.this.verbose); - migrations.parseMigrations(MigrationsHandler.this.migrationsPath); - MigrationsHandler.this.migrations = migrations; - - if (migrations.getMigrationsToRun().isEmpty()) { + if (migrations.getMigrationsToRun(currentVersions).isEmpty()) { if (verbose) logger.info("There are no migrations required at the moment!"); } else { - RunMigrationsAction runMigrationsAction = new RunMigrationsAction(MigrationsHandler.this.migrations); + RunMigrationsAction runMigrationsAction = new RunMigrationsAction(MigrationsHandler.this.migrations, + currentVersions); privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, runMigrationsAction); } } diff --git a/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java b/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java index ba8536963..d9d4e4732 100644 --- a/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java +++ b/li.strolch.service/src/main/java/li/strolch/migrations/RunMigrationsAction.java @@ -1,7 +1,10 @@ package li.strolch.migrations; +import java.util.Map; + import ch.eitchnet.privilege.handler.SystemUserAction; import ch.eitchnet.privilege.model.PrivilegeContext; +import ch.eitchnet.utils.Version; /** * @author Robert von Burg @@ -9,16 +12,19 @@ import ch.eitchnet.privilege.model.PrivilegeContext; public class RunMigrationsAction implements SystemUserAction { private Migrations migrations; + private Map currentVersions; /** * @param migrations + * @param currentVersions */ - public RunMigrationsAction(Migrations migrations) { + public RunMigrationsAction(Migrations migrations, Map currentVersions) { this.migrations = migrations; + this.currentVersions = currentVersions; } @Override public void execute(PrivilegeContext privilegeContext) { - this.migrations.runMigrations(privilegeContext.getCertificate()); + this.migrations.runMigrations(privilegeContext.getCertificate(), currentVersions); } }