Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SRMD validation and schema support #1417

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0ec574d
Add SRMD validation and schema support
just-amin Jan 10, 2025
d5e3275
Fix SRMD validation to use generic string representation of the path
just-amin Jan 10, 2025
e295315
Trigger build
just-amin Jan 10, 2025
1018c27
Refactor XercesValidator namespace usage and remove outdated TODO com…
just-amin Jan 10, 2025
345912c
Use namespace for XercesValidator to simplify code in Model.cpp
just-amin Jan 10, 2025
c816e76
Add invalid SRMD test resources
just-amin Jan 10, 2025
f1406fb
fix xerces namespace conflicts in mingw
arun3688 Jan 16, 2025
ff2630a
add test to Makefile
arun3688 Jan 16, 2025
60330ff
add invalidSRMD target to Makefile
just-amin Jan 16, 2025
7cd8300
add testsuite/validate/validateSRMD.lua
arun3688 Jan 16, 2025
16fd25c
update validateSRMD tests to include Lua script and adjust error hand…
just-amin Jan 16, 2025
fe580b7
update teardown commands in validateSRMD tests
just-amin Jan 16, 2025
a970ad5
add validate.log target to Makefile for validation tests
just-amin Jan 16, 2025
a471479
remove unnecessary model deletion in validateSRMD.py
just-amin Jan 16, 2025
e62637e
fix: correct warning message formatting in validateSSD.py
just-amin Jan 16, 2025
0902b92
return as warning when SRMD validation failed
arun3688 Jan 17, 2025
323e2b4
update SRMD validation error messages
just-amin Jan 17, 2025
7f2f708
update SRMD validation output for
just-amin Jan 17, 2025
de588d3
fix test
arun3688 Jan 17, 2025
8de4a62
fix path
arun3688 Jan 17, 2025
f987790
update SRMD validation output and warnings in test scripts
just-amin Jan 17, 2025
bf17b44
update validation output formatting in SRMD test script
just-amin Jan 17, 2025
740aa72
fix SRMD validation warning message path in validateSRMD.py
just-amin Jan 17, 2025
995cba1
fix missing dependencies "xlink.xsd" when validating srmd
arun3688 Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
896 changes: 896 additions & 0 deletions schema/ssp/SSPTraceabilityCommon.xsd

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions schema/ssp/SimulationResourceMetaData.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.0"
xmlns:srmd="http://ssp-standard.org/SSPTraceability1/SimulationResourceMetaData"
xmlns:stc="http://ssp-standard.org/SSPTraceability1/SSPTraceabilityCommon"
xmlns:ssc="http://ssp-standard.org/SSP1/SystemStructureCommon"
xmlns="http://ssp-standard.org/SSPTraceability1/SimulationResourceMetaData"
targetNamespace="http://ssp-standard.org/SSPTraceability1/SimulationResourceMetaData"
elementFormDefault="qualified">

<xs:import namespace="http://ssp-standard.org/SSP1/SystemStructureCommon" schemaLocation="SystemStructureCommon.xsd"/>
<xs:import namespace="http://ssp-standard.org/SSPTraceability1/SSPTraceabilityCommon" schemaLocation="SSPTraceabilityCommon.xsd"/>

<xs:element name="SimulationResourceMetaData">
<xs:annotation>
<xs:documentation xml:lang="en">
This element specifies the structure of a Simulation Resource Meta Data file.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:group ref="stc:GElementCommon"/>
<xs:attribute name="version" use="required">
<xs:annotation>
<xs:documentation xml:lang="en">
Version of SRMD format, 1.0.0 for this release.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:normalizedString">
<xs:pattern value="[0-9]+[.][0-9]+([.][0-9]+)?(-.*)?"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
<xs:documentation xml:lang="en">
This attribute gives the simulation resource meta data a name,
which can be used for purposes of presenting the simulation resource
meta data to the user.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="data" type="xs:anyURI" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">
This optional attribute gives a URI to the data item this
resource meta data applies to. If this attribute is not
present, then the data this resource meta data applies to
is provided outside of the meta data (e.g. by embedding
SRMD into the data format, or providing it as meta data in
an STMD file).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="checksum" type="xs:hexBinary" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">
This attribute gives the checksum over the data item this meta data
applies to. This is optional information to allow the identification
of the data item and the precise algorithm
specifying
The checksum is calculated using the algorithm indicated by the checksumType attribute.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="checksumType" type="xs:string" use="optional" default="SHA3-256">
<xs:annotation>
<xs:documentation xml:lang="en">
This attribute gives the algorithm for the calculation of the checksum attribute. MUST be
SHA3-256 for now, indicating a SHA3 256bit secure hash algorithm, as specified in FIPS 202.
In the future other checksum algorithms might be supported.
</xs:documentation>
</xs:annotation>
</xs:attribute>

<xs:attributeGroup ref="ssc:ABaseElement"/>
<xs:attributeGroup ref="ssc:ATopLevelMetaData"/>
</xs:complexType>
</xs:element>
</xs:schema>
16 changes: 16 additions & 0 deletions src/OMSimulatorLib/Model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "Scope.h"
#include "ssd/Tags.h"
#include "System.h"
#include "XercesValidator.h"

#include "minizip.h"
#include <thread>
Expand Down Expand Up @@ -678,6 +679,21 @@ oms_status_enu_t oms::Model::addResources(const oms::ComRef& cref, const std::st
fileName = path_.filename().generic_string();
}

// TODO: this is a temporary workaround, we need a proper helper function to get the extension, .srmd is bigger that 4 so the old check is not valid
std::string extension = filesystem::path(fileName).extension().generic_string();

// initialize validator
oms::XercesValidator validator;

// validate the srmd file
if (extension == ".srmd")
{
oms_status_enu_t status = validator.validateSRMD(path_);
just-amin marked this conversation as resolved.
Show resolved Hide resolved
if (status != oms_status_ok)
logError("SRMD format validation of \"" + path + "\" failed");
return status;
}

// copy the file to temp directory
filesystem::path temp_root(getTempDirectory());
filesystem::path temp_temp = temp_root / "temp";
Expand Down
21 changes: 18 additions & 3 deletions src/OMSimulatorLib/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,12 @@ oms_status_enu_t oms::Scope::importModel(const std::string& filename, char** _cr
if (_cref)
*_cref = NULL;

std::string extension = "";
if (filename.length() > 4)
extension = filename.substr(filename.length() - 4);
// TODO: this is a temporary workaround, we need a proper helper function to get the extension, .srmd is bigger that 4 so the old check is not valid
std::string extension = filesystem::path(filename).extension().generic_string();

// std::string extension = "";
// if (filename.length() > 4)
// extension = filename.substr(filename.length() - 4);

if (extension != ".ssp")
return logError("filename extension must be \".ssp\"; no other formats are supported");
Expand All @@ -197,6 +200,7 @@ oms_status_enu_t oms::Scope::importModel(const std::string& filename, char** _cr
if (!systemStructure)
return logError("failed to extract \"SystemStructure.ssd\" from \"" + std::string(filename) + "\"");

// TODO: check this out. this validate ssp file.
XercesValidator xercesValidator;
xercesValidator.validateSSP(systemStructure, filename);

Expand Down Expand Up @@ -260,6 +264,17 @@ oms_status_enu_t oms::Scope::importModel(const std::string& filename, char** _cr
model->importedResources.push_back(entry.path().filename().generic_string());
snapshot.importResourceFile(naive_uncomplete(entry.path(), model->getTempDirectory()), model->getTempDirectory());
}

if (".srmd" == entry.path().extension())
{
oms_status_enu_t status = xercesValidator.validateSRMD(entry.path().generic_string());
if (status != oms_status_ok)
logError("SRMD format validation of \"" + entry.path().generic_string() + "\" failed");
return status;

model->importedResources.push_back(entry.path().filename().generic_string());
snapshot.importResourceFile(naive_uncomplete(entry.path(), model->getTempDirectory()), model->getTempDirectory());
}
}
// snapshot.debugPrintAll();

Expand Down
149 changes: 149 additions & 0 deletions src/OMSimulatorLib/XercesValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "Logging.h"
#include "OMSFileSystem.h"
#include "OMSString.h"
#include <algorithm>
#include <unordered_map>
#include <iostream>

#include <xercesc/parsers/XercesDOMParser.hpp>
Expand Down Expand Up @@ -303,3 +305,150 @@ oms_status_enu_t oms::XercesValidator::validateFMU(const char *modeldescription,

return oms_status_ok;
}

oms_status_enu_t oms::XercesValidator::validateSRMD(const std::string &filePath) {
// Validate file extension
oms_status_enu_t status = isSupportedExtension(filePath, {".srmd"});
if (status != oms_status_ok)
return status;

// Initialize Xerces
status = initializeXerces();
if (status != oms_status_ok)
return status;

// Retrieve schema paths
std::map<std::string, std::string> schemaPaths;
const std::vector<std::tuple<std::string, std::string, std::string>> schemaFiles = {
{"SystemStructureCommon.xsd","http://ssp-standard.org/SSP1/SystemStructureCommon", "ssp"},
{"SSPTraceabilityCommon.xsd","http://ssp-standard.org/SSPTraceability1/SSPTraceabilityCommon", "ssp"},
{"SimulationResourceMetaData.xsd","http://ssp-standard.org/SSPTraceability1/SimulationResourceMetaData", "ssp"},
};
status = resolveSchemaPaths(schemaPaths, schemaFiles);
if (status != oms_status_ok)
return status;

// Configure the parser
XercesDOMParser domParser;

ParserErrorHandler parserErrorHandler("SimulationResourceMetaData", filePath.c_str());
domParser.setErrorHandler(&parserErrorHandler);

status = loadSchema(domParser, schemaPaths);
if (status != oms_status_ok)
return status;

//iterate and print all

// Parse the provided XML
status = parseXML(domParser, filePath);
if (status != oms_status_ok)
return status;

return oms_status_ok;
}

oms_status_enu_t oms::XercesValidator::isSupportedExtension(const std::string &filePath, const std::vector<std::string> &validExtensions) {
std::string extension = filesystem::path(filePath).extension().generic_string();
if (std::find(validExtensions.begin(), validExtensions.end(), extension) == validExtensions.end()) {
logWarning("Unsupported file extension: " + extension);
return oms_status_warning;
}
return oms_status_ok;
}

oms_status_enu_t oms::XercesValidator::initializeXerces() {
static bool initialized = false; // Tracks if Xerces has already been initialized
if (initialized) {
return oms_status_ok;
}

try {
XMLPlatformUtils::Initialize();
initialized = true; // Mark Xerces as initialized
return oms_status_ok;
} catch (const XMLException &toCatch) {
char *message = XMLString::transcode(toCatch.getMessage());
logError("Xerces initialization error: " + std::string(message));
XMLString::release(&message);
return oms_status_error;
}
}

oms_status_enu_t oms::XercesValidator::resolveSchemaPaths(std::map<std::string, std::string> &paths, const std::vector<std::tuple<std::string, std::string, std::string>> &schemaFiles) {
std::string basePath = getExecutablePath();
if (basePath.empty()) {
logError("Executable path could not be found.");
return oms_status_error;
}

for (const auto& [file, ns, dir] : schemaFiles) {
const std::vector<std::string> potentialRoots = {
"../share/OMSimulator/schema/" + dir,
"../../share/OMSimulator/schema/" + dir,
"../../../share/OMSimulator/schema/" + dir,
"schema/" + dir
};

for (const auto &root : potentialRoots) {
filesystem::path path = filesystem::path(basePath) / root / file;
if (filesystem::exists(path)) {
paths[ns] = path.generic_string();
}
}

if (paths.find(ns) == paths.end()) {
logWarning("Schema file not found: " + file);
return oms_status_warning;
}
}

return oms_status_ok;
}

oms_status_enu_t oms::XercesValidator::loadSchema(XercesDOMParser &parser, const std::map<std::string, std::string> &schemaPaths) {
for (const auto &[namespaceUri, path] : schemaPaths) {
if (parser.loadGrammar(path.c_str(), Grammar::SchemaGrammarType, true) == nullptr) {
logWarning("Could not load schema file: " + path);
return oms_status_warning;
}
}

std::string schemaLocation;
for (const auto &[namespaceUri, path] : schemaPaths) {
schemaLocation += namespaceUri + " " + path + " ";
}

parser.setExternalSchemaLocation(schemaLocation.c_str());
parser.cacheGrammarFromParse(true);
parser.setValidationScheme(XercesDOMParser::Val_Always);
parser.setDoNamespaces(true);
parser.setDoSchema(true);
parser.setValidationSchemaFullChecking(true);
parser.setValidationConstraintFatal(true);

return oms_status_ok;
}

oms_status_enu_t oms::XercesValidator::parseXML(XercesDOMParser &parser, const std::string &filePath) {
try {
parser.parse(filePath.c_str());

if (parser.getErrorCount() > 0) {
logWarning("XML parse error: validation failed.");
return oms_status_warning;
}

return oms_status_ok;
} catch (const XMLException &e) {
char *message = XMLString::transcode(e.getMessage());
logError("Xerces parse error: " + std::string(message));
XMLString::release(&message);
return oms_status_error;
} catch (const DOMException &e) {
char *message = XMLString::transcode(e.msg);
logError("DOM parse error: " + std::string(message));
XMLString::release(&message);
return oms_status_error;
}
}
11 changes: 11 additions & 0 deletions src/OMSimulatorLib/XercesValidator.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
#include "OMSimulator/Types.h"

#include <map>
#include <xercesc/parsers/XercesDOMParser.hpp>

XERCES_CPP_NAMESPACE_USE

namespace oms
{
Expand All @@ -49,6 +52,14 @@ namespace oms
oms_status_enu_t validateSSP(const char * ssd, const std::string& filePath);
oms_status_enu_t validateFMU(const char * modeldescription, const std::string& filePath);
std::string getExecutablePath();
oms_status_enu_t validateSRMD(const std::string &filePath);

private:
oms_status_enu_t isSupportedExtension(const std::string &filePath, const std::vector<std::string> &validExtensions);
oms_status_enu_t initializeXerces();
oms_status_enu_t resolveSchemaPaths(std::map<std::string, std::string> &paths, const std::vector<std::tuple<std::string, std::string, std::string>> &schemaFiles);
oms_status_enu_t loadSchema(XercesDOMParser &parser, const std::map<std::string, std::string> &schemaPaths);
oms_status_enu_t parseXML(XercesDOMParser &parser, const std::string &filePath);
};
}

Expand Down
23 changes: 23 additions & 0 deletions testsuite/validate/validateSRMD.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## status: correct
## teardown_command: rm -rf validateSSV-py/
## linux: yes
## mac: no
## mingw32: no
## mingw64: yes
## win: yes

import OMSimulator as oms

oms.setCommandLineOption('--suppressPath=true')
oms.setTempDirectory('./validateSRMD-py/')

model = oms.importFile('../resources/invalidSRMD.ssp')

model.delete()

## Result:
## warning: invalid "SystemStructureParameterValues" detected in file "resources/System1.ssv" at line: 4 column: 48, attribute 'type' is not declared for element 'Parameter'
## warning: "SystemStructureParameterValues" does not conform to the SSP standard schema
## info: 2 warnings
## info: 0 errors
## endResult