[Bugfix] fixed broken migrations in multiple realms

This commit is contained in:
Robert von Burg 2015-02-09 21:13:24 +01:00
parent f43088d680
commit cfb30486e0
4 changed files with 68 additions and 53 deletions

View File

@ -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<String, Version> currentVersions;
private boolean verbose;
private SortedSet<DataMigration> dataMigrations;
private SortedSet<CodeMigration> codeMigrations;
private Map<String, SortedSet<DataMigration>> dataMigrations;
private Map<String, SortedSet<CodeMigration>> codeMigrations;
private MapOfLists<String, Version> migrationsRan;
public Migrations(ComponentContainer container, Map<String, Version> currentVersions) {
public Migrations(ComponentContainer container, Map<String, Version> 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<CodeMigration> 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<DataMigration> 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<String, Version> currentVersions,
SortedSet<DataMigration> dataMigrations, SortedSet<CodeMigration> codeMigrations) {
Map<String, SortedSet<DataMigration>> allDataMigrations,
Map<String, SortedSet<CodeMigration>> allCodeMigrations) {
for (Entry<String, Version> entry : currentVersions.entrySet()) {
String realm = entry.getKey();
Version currentVersion = entry.getValue();
if (codeMigrations.isEmpty()) {
SortedSet<CodeMigration> 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<DataMigration> 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<DataMigration> loadDataMigrations(Map<String, Version> currentVersions, File migrationsPath) {
private static Map<String, SortedSet<DataMigration>> loadDataMigrations(Map<String, Version> currentVersions,
File migrationsPath) {
SortedSet<DataMigration> dataMigrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion()));
Map<String, SortedSet<DataMigration>> 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<DataMigration> 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<CodeMigration> loadCodeMigrations(Map<String, Version> currentVersions, File migrationsPath) {
private static Map<String, SortedSet<CodeMigration>> loadCodeMigrations(Map<String, Version> currentVersions,
File migrationsPath) {
SortedSet<CodeMigration> codeMigrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion()));
Map<String, SortedSet<CodeMigration>> 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<CodeMigration> 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<String, Version> getMigrationsToRun() {
@ -205,15 +212,22 @@ public class Migrations {
CodeMigration currentCodeMigration = new CodeMigration(realm, nextPossibleVersion, null);
DataMigration currentDataMigration = new DataMigration(realm, nextPossibleVersion, null);
SortedSet<CodeMigration> codeMigrations = this.codeMigrations.tailSet(currentCodeMigration);
for (CodeMigration codeMigration : codeMigrations) {
if (!migrationsToRun.containsElement(realm, codeMigration.getVersion()))
migrationsToRun.addElement(realm, codeMigration.getVersion());
SortedSet<CodeMigration> allCodeMigrations = this.codeMigrations.get(realm);
if (allCodeMigrations != null) {
SortedSet<CodeMigration> codeMigrations = allCodeMigrations.tailSet(currentCodeMigration);
for (CodeMigration codeMigration : codeMigrations) {
if (!migrationsToRun.containsElement(realm, codeMigration.getVersion()))
migrationsToRun.addElement(realm, codeMigration.getVersion());
}
}
SortedSet<DataMigration> dataMigrations = this.dataMigrations.tailSet(currentDataMigration);
for (DataMigration dataMigration : dataMigrations) {
if (!migrationsToRun.containsElement(realm, dataMigration.getVersion()))
migrationsToRun.addElement(realm, dataMigration.getVersion());
SortedSet<DataMigration> allDataMigrations = this.dataMigrations.get(realm);
if (allDataMigrations != null) {
SortedSet<DataMigration> dataMigrations = allDataMigrations.tailSet(currentDataMigration);
for (DataMigration dataMigration : dataMigrations) {
if (!migrationsToRun.containsElement(realm, dataMigration.getVersion()))
migrationsToRun.addElement(realm, dataMigration.getVersion());
}
}
}

View File

@ -75,9 +75,8 @@ public class MigrationsHandler extends StrolchComponent {
}
Map<String, Version> 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<String, Version> 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<String, Version> 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;

View File

@ -55,11 +55,13 @@ public class MigrationsTest {
MigrationsHandler migrationsHandler = runtimeMock.getContainer().getComponent(MigrationsHandler.class);
Map<String, Version> currentVersions = migrationsHandler.getCurrentVersions(cert);
assertEquals("1.1.1", currentVersions.get(StrolchConstants.DEFAULT_REALM).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(null, lastMigrations.getList("other"));
MapOfLists<String, Version> migrationsToRun = migrationsHandler.queryMigrationsToRun(cert);
assertTrue("Expected to have all migrations run", migrationsToRun.isEmpty());

View File

@ -21,9 +21,11 @@
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<realms>defaultRealm</realms>
<realms>defaultRealm, other</realms>
<dataStoreMode>TRANSIENT</dataStoreMode>
<dataStoreFile>StrolchModel.xml</dataStoreFile>
<dataStoreMode.other>TRANSIENT</dataStoreMode.other>
<dataStoreFile.other>StrolchModel.xml</dataStoreFile.other>
</Properties>
</Component>
<Component>