24.09., 9:00 - 11:00: Due to updates GitLab will be unavailable for some minutes between 09:00 and 11:00.

Commit 89572e48 authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck

refactor JoltTransformations to seperate classes.

Each JoltTransformation is create as a Singletone from the abstract
JoltTransformation class. These classes manage the transformation and
postHook processing if needed. All resource files were renamend to
automatically build resources names based on the current version alone.
parent a34323cb
Pipeline #64120 failed with stages
in 2 minutes and 57 seconds
This diff is collapsed.
......@@ -310,7 +310,7 @@
"id": "-1",
"shape": {},
"interSpawnTimeDistribution": "org.vadere.state.scenario.ConstantDistribution",
"distributionParameters": "[ 1.0 ]",
"distributionParameters": [ 1.0 ],
"spawnNumber": "1",
"maxSpawnNumberTotal": "-1",
"startTime": "0.0",
......@@ -336,4 +336,4 @@
}
}
}
]
\ No newline at end of file
]
This diff is collapsed.
package org.vadere.simulator.projects.migration;
import com.bazaarvoice.jolt.Chainr;
import com.bazaarvoice.jolt.Diffy;
import com.bazaarvoice.jolt.JsonUtils;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.log4j.Logger;
import org.vadere.simulator.entrypoints.Version;
import org.vadere.simulator.projects.migration.jolttranformation.JoltTransformation;
import org.vadere.state.util.StateJsonConverter;
import org.vadere.util.io.IOUtils;
import org.vadere.util.logging.LogBufferAppender;
......@@ -17,8 +15,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Optional;
import static org.vadere.util.io.IOUtils.LEGACY_DIR;
......@@ -29,25 +25,12 @@ import static org.vadere.util.io.IOUtils.SCENARIO_DIR;
public class JoltMigrationAssistant extends MigrationAssistant {
private final static Logger logger = Logger.getLogger(JoltMigrationAssistant.class);
private final static LogBufferAppender appender;
private final LogBufferAppender appender;
private static HashMap<Version, Chainr> identityTransformation = new LinkedHashMap<>();
private static HashMap<Version, Chainr> transformations = new LinkedHashMap<>();
static {
identityTransformation.put(Version.V0_1, Chainr.fromSpec(JsonUtils.classpathToList("/identity_v1.json")));
identityTransformation.put(Version.V0_2, Chainr.fromSpec(JsonUtils.classpathToList("/identity_v2.json")));
transformations.put(Version.V0_1, Chainr.fromSpec(JsonUtils.classpathToList("/transform_v0_to_v1.json")));
transformations.put(Version.V0_2, Chainr.fromSpec(JsonUtils.classpathToList("/transform_v1_to_v2.json")));
appender = new LogBufferAppender();
}
private Diffy transformationDiff;
public JoltMigrationAssistant(MigrationOptions options) {
super(options);
this.transformationDiff = new Diffy();
appender = new LogBufferAppender();
logger.addAppender(appender);
}
......@@ -113,32 +96,8 @@ public class JoltMigrationAssistant extends MigrationAssistant {
}
public JsonNode transform(JsonNode currentJson, Version targetVersion) throws MigrationException {
return transform(StateJsonConverter.convertJsonNodeToObject(currentJson), targetVersion);
}
private JsonNode transform(Object currentJson, Version targetVersion) throws MigrationException {
Chainr t = transformations.get(targetVersion);
if (t == null) {
logger.error("No Transformation defined for Version " + targetVersion.toString());
throw new MigrationException("No Transformation defined for Version " + targetVersion.toString());
}
Object scenarioTransformed = t.transform(currentJson);
Chainr identity = identityTransformation.get(targetVersion);
if (identity == null) {
logger.error("No IdentityTransformation defined for Version " + targetVersion.toString());
throw new MigrationException("No IdentityTransformation definde for Version " + targetVersion.toString());
}
Object scenarioTransformedTest = identity.transform(scenarioTransformed);
Diffy.Result diffResult = transformationDiff.diff(scenarioTransformed, scenarioTransformedTest);
if (diffResult.isEmpty()) {
return StateJsonConverter.deserializeToNode(scenarioTransformed);
} else {
logger.error("Error in Transformation " + diffResult.toString());
throw new MigrationException("Error in Transformation " + diffResult.toString());
}
JoltTransformation t = JoltTransformation.get(targetVersion.previousVersion());
return t.applyTransformation(currentJson);
}
private boolean analyzeScenario(Path scenarioFilePath, Path legacyDir, String dirName)
......@@ -178,8 +137,8 @@ public class JoltMigrationAssistant extends MigrationAssistant {
return false;
}
} else {
logger.error("Version is unknown");
throw new MigrationException("Version is unknown");
logger.warn("Version is unknown of scenario <" + parentPath + node.get("name").asText() + ">! Try to use " + Version.NOT_A_RELEASE.label() + " as Version for transformation.");
version = Version.NOT_A_RELEASE;
}
JsonNode transformedNode = node;
......
package org.vadere.simulator.projects.migration.jolttranformation;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.vadere.simulator.entrypoints.Version;
......@@ -17,13 +18,15 @@ import org.vadere.state.attributes.models.AttributesOSM;
import org.vadere.state.attributes.models.AttributesPotentialCompact;
import org.vadere.state.attributes.models.AttributesPotentialOSM;
import org.vadere.state.attributes.scenario.AttributesSource;
import org.vadere.state.util.StateJsonConverter;
import java.util.Iterator;
import java.util.LinkedHashMap;
public class JoltTransformV0toV1 extends JoltTransformation {
JoltTransformV0toV1(String transformation, String identity, Version version) {
JoltTransformV0toV1(String transformation, String identity, Version version) throws MigrationException {
super(transformation, identity, version);
}
......@@ -32,29 +35,46 @@ public class JoltTransformV0toV1 extends JoltTransformation {
postTransformHooks.add(this::findMainModel);
postTransformHooks.add(this::attributesPotentialCompactVSosmIncident);
postTransformHooks.add(this::moveSpawnDelayIntoDistributionParametersIncident);
postTransformHooks.add(this::sort);
}
//post Hooks
@SuppressWarnings("unchecked")
public JsonNode sort (JsonNode node) throws MigrationException{
LinkedHashMap source = (LinkedHashMap) StateJsonConverter.convertJsonNodeToObject(node);
LinkedHashMap<Object, Object> sortedRoot = new LinkedHashMap<>();
putObject(sortedRoot, source, "name");
putObject(sortedRoot, source, "description");
putObject(sortedRoot, source, "release");
putObject(sortedRoot, source, "commithash");
putObject(sortedRoot, source, "processWriters", "files", "processors", "isTimestamped");
putObject(sortedRoot, source, "vadere", "mainModel", "attributesModel", "attributesSimulation", "topography");
return StateJsonConverter.deserializeToNode(sortedRoot);
}
private JsonNode findMainModel(JsonNode node) throws MigrationException {
JsonNode scenario = node.path("scenario");
JsonNode scenario = node.path("vadere");
if (scenario.isMissingNode()){
logger.error("There must be scenario Node");
throw new MigrationException("There must be scenario Node");
throw new MigrationException("There must be vadere Node");
}
// Possible Main Models
String mainModelValue = "";
if (! node.path("scenario").path("attributesModel").path(AttributesOSM.class.getName()).isMissingNode()){
if (! node.path("vadere").path("attributesModel").path(AttributesOSM.class.getName()).isMissingNode()){
mainModelValue = OptimalStepsModel.class.getName();
}
if (! node.path("scenario").path("attributesModel").path(AttributesGNM.class.getName()).isMissingNode()){
if (! node.path("vadere").path("attributesModel").path(AttributesGNM.class.getName()).isMissingNode()){
if (!mainModelValue.equals("")){
throw new MigrationException("can't automatically determine the mainModel - more than one mainModel-suitable model is present");
}
mainModelValue = GradientNavigationModel.class.getName();
}
if (! node.path("scenario").path("attributesModel").path(AttributesGNM.class.getName()).isMissingNode()){
if (! node.path("vadere").path("attributesModel").path(AttributesGNM.class.getName()).isMissingNode()){
if (!mainModelValue.equals("")){
throw new MigrationException("can't automatically determine the mainModel - more than one mainModel-suitable model is present");
}
......@@ -76,12 +96,12 @@ public class JoltTransformV0toV1 extends JoltTransformation {
* Jolt transformation
*/
private JsonNode attributesPotentialCompactVSosmIncident (JsonNode node) throws MigrationException {
JsonNode osmAttr = node.path("scenario").path("attributesModel").path(AttributesOSM.class.getCanonicalName());
JsonNode osmAttr = node.path("vadere").path("attributesModel").path(AttributesOSM.class.getCanonicalName());
if (osmAttr.isMissingNode())
return node;
JsonNode potentialCompactAttr = node.path("scenario").path("attributesModel").path(AttributesPotentialCompact.class.getCanonicalName());
JsonNode potentialOSMAttr = node.path("scenario").path("attributesModel").path(AttributesPotentialOSM.class.getCanonicalName());
JsonNode potentialCompactAttr = node.path("vadere").path("attributesModel").path(AttributesPotentialCompact.class.getCanonicalName());
JsonNode potentialOSMAttr = node.path("vadere").path("attributesModel").path(AttributesPotentialOSM.class.getCanonicalName());
if (!potentialCompactAttr.isMissingNode() && !potentialOSMAttr.isMissingNode()){
throw new MigrationException("[AttributesPotentialCompact] and [AttributesPotentialOSM] are both present, that is not allowed.");
......@@ -115,7 +135,7 @@ public class JoltTransformV0toV1 extends JoltTransformation {
* If the interSpawnTimeDistribution is set within one source rebuild the distributionParameters
*/
private JsonNode moveSpawnDelayIntoDistributionParametersIncident (JsonNode node) {
JsonNode sources = node.path("scenario").path("topography").path("sources");
JsonNode sources = node.path("vadere").path("topography").path("sources");
if (sources.isMissingNode())
return node;
......@@ -129,7 +149,8 @@ public class JoltTransformV0toV1 extends JoltTransformation {
if (spawnDelay != -1.0 && (!distribution.isMissingNode() ||
distribution.asText().equals(AttributesSource.CONSTANT_DISTRIBUTION))){
setDoubelArray(source, "distributionParameters", spawnDelay);
ArrayNode arrayNode = ((ObjectNode)source).putArray("distributionParameters");
arrayNode.add(spawnDelay);
}
((ObjectNode)source).remove("spawnDelay");
......
package org.vadere.simulator.projects.migration.jolttranformation;
import com.fasterxml.jackson.databind.JsonNode;
import org.vadere.simulator.entrypoints.Version;
import org.vadere.simulator.projects.migration.MigrationException;
import org.vadere.state.util.StateJsonConverter;
import java.util.LinkedHashMap;
public class JoltTransformV1toV2 extends JoltTransformation {
public JoltTransformV1toV2(String transformation, String identity, Version version) {
public JoltTransformV1toV2(String transformation, String identity, Version version) throws MigrationException {
super(transformation, identity, version);
}
@Override
protected void initPostHooks() {
postTransformHooks.add(this::sort);
}
@SuppressWarnings("unchecked")
public JsonNode sort (JsonNode node) throws MigrationException{
LinkedHashMap source = (LinkedHashMap) StateJsonConverter.convertJsonNodeToObject(node);
LinkedHashMap<Object, Object> sortedRoot = new LinkedHashMap<>();
putObject(sortedRoot, source, "name");
putObject(sortedRoot, source, "description");
putObject(sortedRoot, source, "release");
putObject(sortedRoot, source, "commithash");
putObject(sortedRoot, source, "processWriters", "files", "processors", "isTimestamped");
putObject(sortedRoot, source, "scenario", "mainModel", "attributesModel", "attributesSimulation", "topography");
return StateJsonConverter.deserializeToNode(sortedRoot);
}
}
package org.vadere.simulator.projects.migration.jolttranformation;
import org.vadere.simulator.entrypoints.Version;
import org.vadere.simulator.projects.migration.MigrationException;
public class JoltTransformV2toV3 extends JoltTransformation {
public JoltTransformV2toV3(String transformation, String identity, Version version) {
public JoltTransformV2toV3(String transformation, String identity, Version version) throws MigrationException {
super(transformation, identity, version);
}
@Override
protected void initPostHooks() {
protected void initPostHooks() throws MigrationException {
// postTransformHooks.add(this::postHook1);
}
// public JsonNode postHook1 (JsonNode node){
// // implement
// return node;
// }
}
......@@ -9,58 +9,59 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.log4j.Logger;
import org.vadere.simulator.entrypoints.Version;
import org.vadere.simulator.projects.migration.MigrationException;
import org.vadere.simulator.projects.migration.incidents.VersionBumpIncident;
import org.vadere.state.util.StateJsonConverter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap;
public abstract class JoltTransformation {
protected final static Logger logger = Logger.getLogger(JoltTransformation.class);
private static ConcurrentHashMap<Version, JoltTransformation> transformations = new ConcurrentHashMap<>();
private final Chainr chainr; // Transformation from (version -1) to version
private final Chainr identity; // Identity of version
private final Version version; // Output of Transformation
private final Diffy diffy;
protected ArrayList<PostTransformHook> postTransformHooks;
public static JoltTransformation get(Version v) throws MigrationException {
if (v.equalOrSamller(Version.UNDEFINED))
public static JoltTransformation get(Version currentVersion) throws MigrationException {
if (currentVersion.equalOrSamller(Version.UNDEFINED))
throw new MigrationException("There is now Transformation for Version " + Version.UNDEFINED.toString());
if (v.equals(Version.latest()))
if (currentVersion.equals(Version.latest()))
throw new MigrationException("No Transformation needed. Already latest Version!");
String transformationResource = "transform_v" + v.label('-').toUpperCase() + "_to_v" + v.nextVersion().label('-').toUpperCase() + ".json";
String identityResource = "identity_v" + v.nextVersion().label('-').toUpperCase() + ".json";
JoltTransformation ret = null;
switch (v) {
case NOT_A_RELEASE:
ret = new JoltTransformV0toV1(transformationResource, identityResource, v);
break;
case V0_1:
ret = new JoltTransformV1toV2(transformationResource, identityResource, v);
break;
case V0_2:
ret = new JoltTransformV2toV3(transformationResource, identityResource, v);
break;
String transformationResource = "/transform_v" + currentVersion.label('-').toUpperCase() + "_to_v" + currentVersion.nextVersion().label('-').toUpperCase() + ".json";
String identityResource = "/identity_v" + currentVersion.nextVersion().label('-').toUpperCase() + ".json";
JoltTransformation ret = transformations.getOrDefault(currentVersion, null);
if ( ret == null) {
switch (currentVersion) {
case NOT_A_RELEASE:
ret = new JoltTransformV0toV1(transformationResource, identityResource, currentVersion);
break;
case V0_1:
ret = new JoltTransformV1toV2(transformationResource, identityResource, currentVersion);
break;
case V0_2:
ret = new JoltTransformV2toV3(transformationResource, identityResource, currentVersion);
break;
default:
throw new MigrationException("No Transformation defined for Verson " + currentVersion.toString());
}
transformations.put(currentVersion, ret);
}
if (ret == null)
throw new MigrationException("No Transformation defined for Verson " + v.toString());
return ret;
}
public JoltTransformation(String transformation, String identity, Version version){
public JoltTransformation(String transformation, String identity, Version version) throws MigrationException {
this.chainr = Chainr.fromSpec(JsonUtils.classpathToList(transformation));
this.identity = Chainr.fromSpec(JsonUtils.classpathToList(identity));
this.version = version;
// Output of Transformation
this.postTransformHooks = new ArrayList<>();
this.diffy = new Diffy();
initPostHooks();
......@@ -86,7 +87,7 @@ public abstract class JoltTransformation {
}
}
private JsonNode applyPostHooks(JsonNode root) throws MigrationException{
public JsonNode applyPostHooks(JsonNode root) throws MigrationException{
JsonNode ret = root;
for (PostTransformHook hook : postTransformHooks) {
ret = hook.applyHook(ret);
......@@ -97,15 +98,13 @@ public abstract class JoltTransformation {
/**
* add PostHooks in the correct order.
*/
protected abstract void initPostHooks();
protected abstract void initPostHooks() throws MigrationException;
protected void addToObjectNode(JsonNode node, String key, String value){
((ObjectNode)node).put(key, value);
}
protected void setDoubelArray(JsonNode node, String key, Double value){
((ObjectNode)node).set(key, StateJsonConverter.toJsonNode(new Double[] {value}));
}
public ArrayList<PostTransformHook> getPostTransformHooks() {
return postTransformHooks;
......@@ -114,4 +113,35 @@ public abstract class JoltTransformation {
public void setPostTransformHooks(ArrayList<PostTransformHook> postTransformHooks) {
this.postTransformHooks = postTransformHooks;
}
/**
* Create a Copy of Json and put nodes in user specified order
* @param target new LinkedHashMap with wherer to put nodes
* @param source source
* @param key key to add to new HashMap
* @param children Specify Order on second level
*/
protected void putObject(LinkedHashMap<Object, Object> target,
LinkedHashMap<Object, Object> source,
String key, String... children) throws MigrationException {
Object obj = source.get(key);
if (obj == null) {
throw new MigrationException("Scenario must contain Key: " + key);
}
if (children.length > 0){
LinkedHashMap<Object, Object> node = new LinkedHashMap<>();
LinkedHashMap<Object, Object> parent = (LinkedHashMap<Object, Object>) obj;
for (String childKey : children){
Object childObj = parent.get(childKey);
if (childObj == null){
throw new MigrationException("Object with Key " + key + " does not has child with key" + childKey);
}
node.put(childKey, childObj);
}
obj = node;
}
target.put(key, obj);
}
}
{
"topographyhash": "4cd0fdc685fc51e4ae57d0514b3d325d4f2e1340",
"name": "Test1",
"processWriters": [],
"attributeshash": "af732ad440af7f01cd0cc12608657058fd55f8a8",
"vadere": {
"attributesModel": {
"OPTIMAL_STEPS_MODEL": {
"stepCircleResolution": 18.0,
"numberOfCircles": 1.0,
"varyStepDirection": false,
"stepLengthIntercept": 0.4625,
"stepLengthSlopeSpeed": 0.2345,
"stepLengthSD": 0.036,
"movementThreshold": 0.0,
"optimizationType": "DISCRETE",
"movementType": "ARBITRARY",
"dynamicStepLength": false,
"updateType": "EVENT_DRIVEN",
"seeSmallWalls": false
},
"FLOORFIELD": {
"createMethod": "HIGH_ACCURACY_FAST_MARCHING",
"potentialFieldResolution": 0.1,
"obstacleGridPenalty": 0.1,
"targetAttractionStrength": 1.0,
"timeCostAttributes": {
"standardDerivation": 0.7,
"pedestrianTorso": 0.4,
"meanSpeed": 1.34,
"type": "UNIT",
"obstacleDensityWeight": 3.5,
"pedestrianSameTargetDensityWeight": 3.5,
"pedestrianOtherTargetDensityWeight": 3.5,
"pedestrianWeight": 3.5,
"queueWidthLoading": 1.0,
"pedestrianDynamicWeight": 6.0,
"loadingType": "CONSTANT"
}
},
"POTENTIAL_COMPACT_SUPPORT": {
"pedPotentialWidth": 0.5,
"pedPotentialHeight": 12.6,
"obstPotentialWidth": 0.25,
"obstPotentialHeight": 20.1,
"visionFieldAngle": 1.8849555921538759,
"visionFieldRadius": 5.0,
"numPedConsidered": 5.0
}
},
"attributesPedestrian": {
"radius": 0.195,
"densityDependentSpeed": false,
"speedDistributionMean": 1.34,
"speedDistributionStandardDeviation": 0.0,
"minimumSpeed": 0.3,
"maximumSpeed": 3.0,
"acceleration": 2.0,
"id": -1
},
"attributesSimulation": {
"simTimeStepLength": 0.4,
"realTimeSimTimeRatio": 0.1,
"writeSimulationData": true,
"visualizationEnabled": true,
"printFPS": false,
"needsBoundary": false,
"digitsPerCoordinate": 2,
"useRandomSeed": true,
"randomSeed": 1
},
"topography": {
"attributes": {
"finishTime": 60.0,
"bounds": {
"x": 0.0,
"y": 0.0,
"width": 10.0,
"height": 10.0
},
"boundingBoxWidth": 0.5,
"bounded": true
},
"obstacles": [
{
"shape": {
"x": 3.9,
"y": 8.0,
"width": 2.2,
"height": 1.1,
"type": "RECTANGLE"
},
"id": -1
},
{
"shape": {
"type": "POLYGON",
"points": [
{
"x": -1.0E-4,
"y": 0.5001
},
{
"x": -1.0E-4,
"y": -1.0E-4
},
{
"x": 10.0001,
"y": -1.0E-4
},
{
"x": 10.0001,
"y": 0.5001
}
]
},
"id": -1
},
{
"shape": {
"type": "POLYGON",
"points": [
{
"x": 9.4999,
"y": -1.0E-4
},
{
"x": 10.0001,
"y": -1.0E-4
},
{
"x": 10.0001,
"y": 10.0001
},
{
"x": 9.4999,
"y": 10.0001
}
]
},
"id": -1
},
{
"shape": {
"type": "POLYGON",
"points": [
{
"x": 10.0001,
"y": 9.4999
},
{
"x": 10.0001,
"y": 10.0001
},
{
"x": -1.0E-4,
"y": 10.0001
},
{
"x": -1.0E-4,
"y": 9.4999