[Devel] Implementing MigrationsHandler
- currently the parsing of the versions is handled - missing is the actual loading of the date into the realms - and the performing of the code migrations - and the registering of the performed migrations
This commit is contained in:
parent
2375c94dd6
commit
e741680959
|
@ -1 +1 @@
|
||||||
Subproject commit 97936b03fe86ce421bbfe61efbd51a49da1f0868
|
Subproject commit d87517e4c2a3e9507b2661cc1737031761d99b61
|
|
@ -0,0 +1,19 @@
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.Version;
|
||||||
|
|
||||||
|
public class CodeMigration extends Migration {
|
||||||
|
|
||||||
|
public CodeMigration(String realm, Version version, File dataFile) {
|
||||||
|
super(realm, version, dataFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(ComponentContainer container, Certificate certificate) {
|
||||||
|
logger.info("[" + this.realm + "] Running migration " + this.version);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
import li.strolch.agent.api.StrolchRealm;
|
||||||
|
import li.strolch.model.Resource;
|
||||||
|
import li.strolch.model.parameter.StringParameter;
|
||||||
|
import li.strolch.persistence.api.StrolchTransaction;
|
||||||
|
import li.strolch.runtime.configuration.StrolchConfigurationException;
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.Version;
|
||||||
|
|
||||||
|
public class CurrentMigrationVersionQuery {
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
private ComponentContainer container;
|
||||||
|
private Map<String, Version> currentVersions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
public CurrentMigrationVersionQuery(ComponentContainer container) {
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doQuery(Certificate cert) {
|
||||||
|
|
||||||
|
this.currentVersions = new HashMap<>();
|
||||||
|
|
||||||
|
for (String realmName : this.container.getRealmNames()) {
|
||||||
|
StrolchRealm realm = this.container.getRealm(realmName);
|
||||||
|
try (StrolchTransaction tx = realm.openTx(cert, getClass())) {
|
||||||
|
|
||||||
|
Resource migrationsRes = tx.getResourceBy(MIGRATIONS_TYPE, MIGRATIONS_ID);
|
||||||
|
if (migrationsRes == null) {
|
||||||
|
this.currentVersions.put(realmName, Version.emptyVersion);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringParameter currentVersionP = migrationsRes.getParameter(BAG_PARAMETERS, PARAM_CURRENT_VERSION);
|
||||||
|
if (currentVersionP == null) {
|
||||||
|
this.currentVersions.put(realmName, Version.emptyVersion);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
return this.currentVersions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.Version;
|
||||||
|
|
||||||
|
public class DataMigration extends Migration {
|
||||||
|
|
||||||
|
public DataMigration(String realm, Version version, File dataFile) {
|
||||||
|
super(realm, version, dataFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(ComponentContainer container, Certificate certificate) {
|
||||||
|
|
||||||
|
logger.info("[" + this.realm + "] Running migration " + this.version);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.Version;
|
||||||
|
|
||||||
|
public abstract class Migration {
|
||||||
|
|
||||||
|
protected static final Logger logger = LoggerFactory.getLogger(CodeMigration.class);
|
||||||
|
|
||||||
|
protected final String realm;
|
||||||
|
protected final Version version;
|
||||||
|
protected final File dataFile;
|
||||||
|
|
||||||
|
public Migration(String realm, Version version, File dataFile) {
|
||||||
|
this.realm = realm;
|
||||||
|
this.version = version;
|
||||||
|
this.dataFile = dataFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealm() {
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Version getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDataFile() {
|
||||||
|
return dataFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void migrate(ComponentContainer container, Certificate certificate);
|
||||||
|
}
|
|
@ -0,0 +1,207 @@
|
||||||
|
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;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.Version;
|
||||||
|
import ch.eitchnet.utils.collections.MapOfLists;
|
||||||
|
import ch.eitchnet.utils.dbc.DBC;
|
||||||
|
|
||||||
|
public class Migrations {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(Migrations.class);
|
||||||
|
|
||||||
|
private ComponentContainer container;
|
||||||
|
private Map<String, Version> currentVersions;
|
||||||
|
|
||||||
|
private SortedSet<DataMigration> dataMigrations;
|
||||||
|
private SortedSet<CodeMigration> codeMigrations;
|
||||||
|
|
||||||
|
private Map<String, Version> migrationsRan;
|
||||||
|
|
||||||
|
public Migrations(ComponentContainer container, Map<String, Version> currentVersions) {
|
||||||
|
this.container = container;
|
||||||
|
this.currentVersions = currentVersions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Version> getMigrationsRan() {
|
||||||
|
return this.migrationsRan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseMigrations(File migrationsPath) {
|
||||||
|
DBC.PRE.assertTrue("If migrations path is not a directory!", migrationsPath.isDirectory());
|
||||||
|
|
||||||
|
// data migrations
|
||||||
|
this.dataMigrations = loadDataMigrations(this.currentVersions, migrationsPath);
|
||||||
|
|
||||||
|
// code migrations
|
||||||
|
this.codeMigrations = loadCodeMigrations(this.currentVersions, migrationsPath);
|
||||||
|
|
||||||
|
// log found migrations
|
||||||
|
logDetectedMigrations(this.currentVersions, this.dataMigrations, this.codeMigrations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runMigrations(Certificate certificate) {
|
||||||
|
|
||||||
|
Map<String, Version> migrationsRan = new HashMap<>();
|
||||||
|
|
||||||
|
for (Entry<String, Version> entry : this.currentVersions.entrySet()) {
|
||||||
|
String realm = entry.getKey();
|
||||||
|
Version currentVersion = entry.getValue();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!this.codeMigrations.isEmpty()) {
|
||||||
|
for (CodeMigration migration : this.codeMigrations.tailSet(currentCodeMigration)) {
|
||||||
|
migration.migrate(container, certificate);
|
||||||
|
migrationsRan.put(realm, migration.getVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.dataMigrations.isEmpty()) {
|
||||||
|
for (DataMigration migration : this.dataMigrations.tailSet(currentDataMigration)) {
|
||||||
|
migration.migrate(container, certificate);
|
||||||
|
migrationsRan.put(realm, migration.getVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.migrationsRan = migrationsRan;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logDetectedMigrations(Map<String, Version> currentVersions,
|
||||||
|
SortedSet<DataMigration> dataMigrations, SortedSet<CodeMigration> codeMigrations) {
|
||||||
|
for (Entry<String, Version> entry : currentVersions.entrySet()) {
|
||||||
|
String realm = entry.getKey();
|
||||||
|
Version currentVersion = entry.getValue();
|
||||||
|
|
||||||
|
if (codeMigrations.isEmpty()) {
|
||||||
|
logger.info("[" + realm + "] Found no code 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataMigrations.isEmpty()) {
|
||||||
|
logger.info("[" + realm + "] Found no data 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SortedSet<DataMigration> loadDataMigrations(Map<String, Version> currentVersions, File migrationsPath) {
|
||||||
|
|
||||||
|
SortedSet<DataMigration> dataMigrations = new TreeSet<>((o1, o2) -> o1.getVersion().compareTo(o2.getVersion()));
|
||||||
|
|
||||||
|
File dataDir = new File(migrationsPath, "data");
|
||||||
|
if (dataDir.exists()) {
|
||||||
|
DBC.PRE.assertTrue("migrations/data must be a directory!", dataDir.isDirectory());
|
||||||
|
|
||||||
|
File[] realmMigrations = dataDir.listFiles();
|
||||||
|
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(
|
||||||
|
".xml"));
|
||||||
|
for (File file : migrations) {
|
||||||
|
String name = file.getName();
|
||||||
|
Version version = Version.valueOf(name.substring(0, name.length() - 4));
|
||||||
|
dataMigrations.add(new DataMigration(realm, version, file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataMigrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SortedSet<CodeMigration> loadCodeMigrations(Map<String, Version> currentVersions, File migrationsPath) {
|
||||||
|
|
||||||
|
SortedSet<CodeMigration> codeMigrations = 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();
|
||||||
|
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(
|
||||||
|
".xml"));
|
||||||
|
for (File file : migrations) {
|
||||||
|
String name = file.getName();
|
||||||
|
Version version = Version.valueOf(name.substring(0, name.length() - 4));
|
||||||
|
codeMigrations.add(new CodeMigration(realm, version, file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeMigrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapOfLists<String, Version> getMigrationsToRun() {
|
||||||
|
|
||||||
|
MapOfLists<String, Version> migrationsToRun = new MapOfLists<>();
|
||||||
|
|
||||||
|
for (Entry<String, Version> entry : this.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);
|
||||||
|
|
||||||
|
SortedSet<CodeMigration> codeMigrations = this.codeMigrations.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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return migrationsToRun;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.ComponentContainer;
|
||||||
|
import li.strolch.agent.api.RealmHandler;
|
||||||
|
import li.strolch.agent.api.StrolchComponent;
|
||||||
|
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||||
|
import li.strolch.runtime.configuration.RuntimeConfiguration;
|
||||||
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.Version;
|
||||||
|
import ch.eitchnet.utils.collections.MapOfLists;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class MigrationsHandler extends StrolchComponent {
|
||||||
|
|
||||||
|
private static final String PATH_MIGRATIONS = "migrations";
|
||||||
|
|
||||||
|
private Migrations migrations;
|
||||||
|
private Map<String, Version> lastMigrations;
|
||||||
|
private File migrationsPath;
|
||||||
|
|
||||||
|
public MigrationsHandler(ComponentContainer container, String componentName) {
|
||||||
|
super(container, componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Version> getLastMigrations() {
|
||||||
|
return this.lastMigrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Version> getCurrentVersions(Certificate cert) {
|
||||||
|
CurrentMigrationVersionQuery query = new CurrentMigrationVersionQuery(getContainer());
|
||||||
|
query.doQuery(cert);
|
||||||
|
return query.getCurrentVersions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapOfLists<String, Version> queryMigrationsToRun(Certificate cert) {
|
||||||
|
Map<String, Version> currentVersions = getCurrentVersions(cert);
|
||||||
|
Migrations migrations = new Migrations(getContainer(), currentVersions);
|
||||||
|
migrations.parseMigrations(this.migrationsPath);
|
||||||
|
|
||||||
|
this.migrations = migrations;
|
||||||
|
return this.migrations.getMigrationsToRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runMigrations(Certificate cert) {
|
||||||
|
this.lastMigrations.clear();
|
||||||
|
this.migrations.runMigrations(cert);
|
||||||
|
this.lastMigrations.putAll(this.migrations.getMigrationsRan());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(ComponentConfiguration configuration) {
|
||||||
|
|
||||||
|
this.lastMigrations = new HashMap<>();
|
||||||
|
|
||||||
|
RuntimeConfiguration runtimeConf = configuration.getRuntimeConfiguration();
|
||||||
|
this.migrationsPath = runtimeConf.getDataDir(MigrationsHandler.class.getName(), PATH_MIGRATIONS, false);
|
||||||
|
if (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<String, Version> currentVersions = query.getCurrentVersions();
|
||||||
|
|
||||||
|
Migrations migrations = new Migrations(getContainer(), currentVersions);
|
||||||
|
migrations.parseMigrations(this.migrationsPath);
|
||||||
|
|
||||||
|
this.migrations = migrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.initialize(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
|
||||||
|
if (this.migrations != null) {
|
||||||
|
|
||||||
|
PrivilegeHandler privilegeHandler = getContainer().getComponent(PrivilegeHandler.class);
|
||||||
|
RunMigrationsAction action = new RunMigrationsAction(this.migrations);
|
||||||
|
|
||||||
|
privilegeHandler.runAsSystem(RealmHandler.SYSTEM_USER_AGENT, action);
|
||||||
|
this.lastMigrations.putAll(this.migrations.getMigrationsRan());
|
||||||
|
}
|
||||||
|
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.handler.SystemUserAction;
|
||||||
|
import ch.eitchnet.privilege.model.PrivilegeContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class QueryCurrentVersionsAction implements SystemUserAction {
|
||||||
|
|
||||||
|
private CurrentMigrationVersionQuery query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
public QueryCurrentVersionsAction(CurrentMigrationVersionQuery query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(PrivilegeContext privilegeContext) {
|
||||||
|
this.query.doQuery(privilegeContext.getCertificate());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.handler.SystemUserAction;
|
||||||
|
import ch.eitchnet.privilege.model.PrivilegeContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class RunMigrationsAction implements SystemUserAction {
|
||||||
|
|
||||||
|
private Migrations migrations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param migrations
|
||||||
|
*/
|
||||||
|
public RunMigrationsAction(Migrations migrations) {
|
||||||
|
this.migrations = migrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(PrivilegeContext privilegeContext) {
|
||||||
|
this.migrations.runMigrations(privilegeContext.getCertificate());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package li.strolch.migrations;
|
||||||
|
|
||||||
|
import static li.strolch.agent.ComponentContainerTest.destroyContainer;
|
||||||
|
import static li.strolch.agent.ComponentContainerTest.logger;
|
||||||
|
import static li.strolch.agent.ComponentContainerTest.startContainer;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import li.strolch.agent.api.StrolchAgent;
|
||||||
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ch.eitchnet.privilege.model.Certificate;
|
||||||
|
import ch.eitchnet.utils.Version;
|
||||||
|
import ch.eitchnet.utils.collections.MapOfLists;
|
||||||
|
|
||||||
|
public class MigrationsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldRunMigrations() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
StrolchAgent agent = startContainer("target/MigrationsTest/", "src/test/resources/migrationstest");
|
||||||
|
|
||||||
|
PrivilegeHandler privilegeHandler = agent.getContainer().getPrivilegeHandler();
|
||||||
|
Certificate cert = privilegeHandler.authenticate("test", "test".getBytes());
|
||||||
|
|
||||||
|
MigrationsHandler migrationsHandler = agent.getContainer().getComponent(MigrationsHandler.class);
|
||||||
|
Map<String, Version> currentVersions = migrationsHandler.getCurrentVersions(cert);
|
||||||
|
for (Entry<String, Version> entry : currentVersions.entrySet()) {
|
||||||
|
logger.info("[" + entry.getKey() + "] Current version: " + entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
MapOfLists<String, Version> migrationsToRun = migrationsHandler.queryMigrationsToRun(cert);
|
||||||
|
for (String realm : migrationsToRun.keySet()) {
|
||||||
|
logger.info("[" + realm + "] Migrations to run: " + migrationsToRun.getList(realm));
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyContainer(agent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Privilege>
|
||||||
|
|
||||||
|
<Container>
|
||||||
|
|
||||||
|
<Parameters>
|
||||||
|
<!-- parameters for the container itself -->
|
||||||
|
<Parameter name="autoPersistOnPasswordChange" value="true" />
|
||||||
|
</Parameters>
|
||||||
|
|
||||||
|
<EncryptionHandler class="ch.eitchnet.privilege.handler.DefaultEncryptionHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="hashAlgorithm" value="SHA-256" />
|
||||||
|
</Parameters>
|
||||||
|
</EncryptionHandler>
|
||||||
|
|
||||||
|
<PersistenceHandler class="ch.eitchnet.privilege.handler.XmlPersistenceHandler">
|
||||||
|
<Parameters>
|
||||||
|
<Parameter name="basePath" value="target/strolchRuntime/config" />
|
||||||
|
<Parameter name="modelXmlFile" value="PrivilegeModel.xml" />
|
||||||
|
</Parameters>
|
||||||
|
</PersistenceHandler>
|
||||||
|
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Policies>
|
||||||
|
<Policy name="DefaultPrivilege" class="ch.eitchnet.privilege.policy.DefaultPrivilege" />
|
||||||
|
</Policies>
|
||||||
|
|
||||||
|
</Privilege>
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<UsersAndRoles>
|
||||||
|
|
||||||
|
<Users>
|
||||||
|
<User userId="1" username="agent">
|
||||||
|
<State>SYSTEM</State>
|
||||||
|
<Roles>
|
||||||
|
<Role>agent</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
<User userId="2" username="test" password="9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08">
|
||||||
|
<Firstname>Application</Firstname>
|
||||||
|
<Lastname>Administrator</Lastname>
|
||||||
|
<State>ENABLED</State>
|
||||||
|
<Locale>en_GB</Locale>
|
||||||
|
<Roles>
|
||||||
|
<Role>PrivilegeAdmin</Role>
|
||||||
|
<Role>AppUser</Role>
|
||||||
|
</Roles>
|
||||||
|
</User>
|
||||||
|
</Users>
|
||||||
|
|
||||||
|
<Roles>
|
||||||
|
<Role name="PrivilegeAdmin" />
|
||||||
|
<Role name="agent">
|
||||||
|
<Privilege name="li.strolch.agent.impl.StartRealms" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
<Privilege name="li.strolch.migrations.QueryCurrentVersionsAction" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
<Privilege name="li.strolch.migrations.RunMigrationsAction" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
<Role name="AppUser">
|
||||||
|
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
|
||||||
|
<AllAllowed>true</AllAllowed>
|
||||||
|
</Privilege>
|
||||||
|
</Role>
|
||||||
|
|
||||||
|
</Roles>
|
||||||
|
</UsersAndRoles>
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StrolchConfiguration>
|
||||||
|
<env id="dev">
|
||||||
|
<Runtime>
|
||||||
|
<applicationName>StrolchRuntimeTest</applicationName>
|
||||||
|
<Properties>
|
||||||
|
<dataStoreMode>TRANSIENT</dataStoreMode>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
</Properties>
|
||||||
|
</Runtime>
|
||||||
|
<Component>
|
||||||
|
<name>PrivilegeHandler</name>
|
||||||
|
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
|
||||||
|
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
|
||||||
|
<Properties>
|
||||||
|
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>RealmHandler</name>
|
||||||
|
<api>li.strolch.agent.api.RealmHandler</api>
|
||||||
|
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
|
||||||
|
<depends>PrivilegeHandler</depends>
|
||||||
|
<Properties>
|
||||||
|
<realms>defaultRealm</realms>
|
||||||
|
<dataStoreMode>TRANSIENT</dataStoreMode>
|
||||||
|
<dataStoreFile>Model.xml</dataStoreFile>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>ServiceHandler</name>
|
||||||
|
<api>li.strolch.runtime.configuration.model.ServiceHandlerTest</api>
|
||||||
|
<impl>li.strolch.runtime.configuration.model.ServiceHandlerTestImpl</impl>
|
||||||
|
<depends>RealmHandler</depends>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>MigrationsHandler</name>
|
||||||
|
<api>li.strolch.migrations.MigrationsHandler</api>
|
||||||
|
<impl>li.strolch.migrations.MigrationsHandler</impl>
|
||||||
|
<depends>ServiceHandler</depends>
|
||||||
|
</Component>
|
||||||
|
<Component>
|
||||||
|
<name>PostInitializer</name>
|
||||||
|
<api>li.strolch.runtime.configuration.model.PostInitializerTest</api>
|
||||||
|
<impl>li.strolch.runtime.configuration.model.PostInitializerTestImpl</impl>
|
||||||
|
<depends>MigrationsHandler</depends>
|
||||||
|
</Component>
|
||||||
|
</env>
|
||||||
|
</StrolchConfiguration>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<StrolchModel>
|
||||||
|
<Resource Id="TestType" Name="TestType Template" Type="Template">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Resource>
|
||||||
|
<Order Id="Template" Name="MyTestOrder Template" Type="MyTestOrder">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Order>
|
||||||
|
|
||||||
|
</StrolchModel>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<StrolchModel>
|
||||||
|
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Resource>
|
||||||
|
</StrolchModel>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<StrolchModel>
|
||||||
|
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Resource>
|
||||||
|
</StrolchModel>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<StrolchModel>
|
||||||
|
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Resource>
|
||||||
|
</StrolchModel>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<StrolchModel>
|
||||||
|
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Resource>
|
||||||
|
</StrolchModel>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<StrolchModel>
|
||||||
|
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Resource>
|
||||||
|
</StrolchModel>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<StrolchModel>
|
||||||
|
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
|
||||||
|
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||||
|
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||||
|
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||||
|
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||||
|
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||||
|
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||||
|
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||||
|
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||||
|
</ParameterBag>
|
||||||
|
</Resource>
|
||||||
|
</StrolchModel>
|
Loading…
Reference in New Issue