[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:
Robert von Burg 2015-02-07 23:56:59 +01:00
parent 2375c94dd6
commit e741680959
20 changed files with 810 additions and 1 deletions

@ -1 +1 @@
Subproject commit 97936b03fe86ce421bbfe61efbd51a49da1f0868
Subproject commit d87517e4c2a3e9507b2661cc1737031761d99b61

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>