Validation Logic#
The Test Orchestrator validates submodels in three main steps:
1. Event-driven Submodel Processing#
The MqttSubscriber listens for submodel creation, update, and deletion events:
client.subscribe(TOPIC_NEW);
client.subscribe(TOPIC_UPDATE);
client.subscribe(TOPIC_DELETE);
On creation/update:
Deserializes the submodel
Checks the AASX version
Validates presence of
SemanticId
On deletion:
Cleans up related test results in the repository.
2. Validation Logic#
Validation Sequence#
The validation process is illustrated in the sequence diagram below, showing the interactions between the Submodel Repository, Deserializer, Comparator, Recursion Function, SMEComparator, and MQTT/Web UI interface.
Deserialization:
Parses all input submodels and templates using IDTA-compatible JSON:
Environment inputEnv = Deserializer.deserializejsonFile(jsonString);
Comparison Logic:
Each input submodel is compared to schema submodels by matching SemanticId:
ComparisonResult result = Comparator.compare(schemaSubmodel, inputSubmodel);
Recursive Validation:
Main logic for comparing submodel elements recursively:
RecursionFunc.compareSubmodelElements(
schemaSubmodel.getSubmodelElements(),
inputSubmodel.getSubmodelElements(),
result
);
This function:
Checks multiplicity (One, ZeroToOne, etc.)
Verifies qualifiers (required/optional)
Compares type, value, and semanticId
Recurses into nested
SubmodelElementCollections
Multiplicity Checks Example:
if ("One".equals(multiplicity)) {
SMEComparator.checkMultiplicityOne(schemaElement, inputElementMap, result);
}
All four multiplicity types are supported:
OneZeroToOneOneToManyZeroToMany
3. Test Results & Reporting#
All validation results are written as Submodels in the repository:
ResultSubmodelFactory.addResultToSubmodel(comparisonResult, inputSubmodel);
Example structure of a result:
{
"ComparedSubmodelId": "...",
"SemanticId": "...",
"Errors": "...",
"Warnings": "...",
"Differences": "...",
"Infos": "..."
}
Handling Edge Cases:#
Unsupported AASX Versions#
ResultSubmodelFactory.addUnsupportedVersionResult(rawJson);
Missing SemanticId#
if (submodel.getSemanticId() == null) {
ResultSubmodelFactory.addUnsuccessfulResultToSubmodel(submodel);
return;
}
Full Comparison Function Example#
public static ComparisonResult compare(Submodel schemaSubmodel, Submodel inputSubmodel) {
ComparisonResult result = new ComparisonResult();
RecursionFunc.compareSubmodelElements(
schemaSubmodel.getSubmodelElements(),
inputSubmodel.getSubmodelElements(),
result
);
return result;
}
Handling New Submodel Event#
private void processSubmodel(String submodelJson) {
if (!isAASXv3Format(submodelJson)) {
ResultSubmodelFactory.addUnsupportedVersionResult(submodelJson);
return;
}
Submodel submodel = deserializer.read(submodelJson, Submodel.class);
if (submodel.getSemanticId() == null) {
ResultSubmodelFactory.addUnsuccessfulResultToSubmodel(submodel);
return;
}
SubmodelFactory.processReceivedSubmodel(submodel);
}