Create schema specific to the version to validate#3801
Create schema specific to the version to validate#3801samirromdhani wants to merge 12 commits intomainfrom
Conversation
33132c3 to
65f0051
Compare
c76619e to
a2cfa27
Compare
ccfe442 to
b356226
Compare
b356226 to
fe0aa21
Compare
fdea43a to
0180fc2
Compare
f4d0545 to
e44b19b
Compare
e44b19b to
59d72cb
Compare
59d72cb to
5dce9ad
Compare
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
…eation in XmlUtil Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com> review: centralize SchemaFactory creation in XmlUtil Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
…schema cache Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com> fixes sonar
Signed-off-by: Samir Romdhani <samir.romdhani_externe@rte-france.com>
5dce9ad to
c4dafdb
Compare
|
| try { | ||
| factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); | ||
| } catch (SAXException e) { | ||
| LOGGER.info("- Property unsupported by SchemaFactory implementation: {}", XMLConstants.ACCESS_EXTERNAL_SCHEMA); | ||
| } |
There was a problem hiding this comment.
you can factorise this code in a small utility method used for the two properties
| return initializeWriter(indent, indentString, xmlWriter); | ||
| } | ||
|
|
||
| public static SchemaFactory newSchemaFactory() { |
There was a problem hiding this comment.
Rename to createSchemaFactoryInstance to mirror createXMLInputFactoryInstance
| } | ||
| } | ||
|
|
||
| public static void validate(InputStream is, IidmVersion version, ExtensionsSupplier extensionsSupplier) { |
There was a problem hiding this comment.
Add Javadoc for this method to explain its specificities.
Also, add a warning that it loads the full network file in memory.
| String actualNs = readRootNamespace(xmlBytes); | ||
| boolean matches = actualNs.equals(validationVersion.getNamespaceURI()) | ||
| || validationVersion.supportEquipmentValidationLevel() && actualNs.equals(validationVersion.getNamespaceURI(false)); | ||
| if (!matches) { | ||
| throw new PowsyblException("Namespace mismatch: expected validation version " + validationVersion.toString(".") + ", found namespace " + actualNs); |
There was a problem hiding this comment.
| String actualNs = readRootNamespace(xmlBytes); | |
| boolean matches = actualNs.equals(validationVersion.getNamespaceURI()) | |
| || validationVersion.supportEquipmentValidationLevel() && actualNs.equals(validationVersion.getNamespaceURI(false)); | |
| if (!matches) { | |
| throw new PowsyblException("Namespace mismatch: expected validation version " + validationVersion.toString(".") + ", found namespace " + actualNs); | |
| String actualNamespace = readRootNamespace(xmlBytes); | |
| boolean matches = actualNamespace.equals(validationVersion.getNamespaceURI()) | |
| || validationVersion.supportEquipmentValidationLevel() && actualNamespace.equals(validationVersion.getNamespaceURI(false)); | |
| if (!matches) { | |
| throw new PowsyblException("Namespace mismatch: expected validation version " + validationVersion.toString(".") + ", found namespace " + actualNamespace); |
| * <p>XSD document snippet:</p> | ||
| * <pre>{@code | ||
| * ... | ||
| * targetNamespace="http://www.powsybl.org/schema/iidm/ext/extension-name/1_0" | ||
| * xmlns:iidm="http://www.powsybl.org/schema/iidm/1_10"> | ||
| * <xs:import namespace="http://www.powsybl.org/schema/iidm/1_10" schemaLocation="iidm_V1_10.xsd"/> | ||
| * </xs:schema> | ||
| * }</pre> |
There was a problem hiding this comment.
Good idea to illustrate with a small example!
Could you do the same with the other methods (when possible and useful)?
| byte[] xmlBytes; | ||
| try { | ||
| xmlBytes = is.readAllBytes(); | ||
| checkNamespace(xmlBytes, version); |
There was a problem hiding this comment.
This does could be outside the try/catch as it does not throw an IOException
| // XSD validation | ||
| Schema schema; | ||
| if (extensionsSupplier == DefaultExtensionsSupplier.getInstance()) { | ||
| schema = DEFAULT_SCHEMAS_SUPPLIER.get().computeIfAbsent(version, v -> createSchema(DefaultExtensionsSupplier.getInstance(), v)); | ||
| } else { | ||
| schema = createSchema(extensionsSupplier, version); | ||
| } |
There was a problem hiding this comment.
| // XSD validation | |
| Schema schema; | |
| if (extensionsSupplier == DefaultExtensionsSupplier.getInstance()) { | |
| schema = DEFAULT_SCHEMAS_SUPPLIER.get().computeIfAbsent(version, v -> createSchema(DefaultExtensionsSupplier.getInstance(), v)); | |
| } else { | |
| schema = createSchema(extensionsSupplier, version); | |
| } | |
| // XSD validation | |
| Schema schema = extensionsSupplier == DefaultExtensionsSupplier.getInstance() ? | |
| DEFAULT_SCHEMAS_SUPPLIER.get().computeIfAbsent(version, v -> createSchema(DefaultExtensionsSupplier.getInstance(), v)) : | |
| createSchema(extensionsSupplier, version); |
| } | ||
| } | ||
|
|
||
| private static Schema createSchema(ExtensionsSupplier extensionsSupplier, IidmVersion version) { |
There was a problem hiding this comment.
This method could be factorized with the existing one.
You might want to keep working on arrays instead of lists for efficiency (to be tested if possible)
| byte[] xmlBytes; | ||
| try { | ||
| xmlBytes = is.readAllBytes(); | ||
| checkNamespace(xmlBytes, version); |
There was a problem hiding this comment.
Is this check even necessary? There might be a better way to do this, avoiding loading the whole file in memory (which you are doing by creating the array of bytes).
For example something like this:
public static void validate(InputStream is, IidmVersion version, ExtensionsSupplier extensionsSupplier) {
Objects.requireNonNull(is);
Objects.requireNonNull(version);
Objects.requireNonNull(extensionsSupplier);
// XSD validation
Schema schema = extensionsSupplier == DefaultExtensionsSupplier.getInstance() ?
DEFAULT_SCHEMAS_SUPPLIER.get().computeIfAbsent(version, v -> createSchema(DefaultExtensionsSupplier.getInstance(), v)) :
createSchema(extensionsSupplier, version);
try {
XMLFilter xmlFilter = getXMLFilter(version);
SAXSource saxSource = new SAXSource(xmlFilter, new InputSource(is));
schema.newValidator().validate(saxSource);
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (SAXException e) {
throw new UncheckedSaxException(e);
} catch (ParserConfigurationException e) {
throw new UncheckedParserConfigurationException(e);
}
}
private static XMLFilter getXMLFilter(IidmVersion validationVersion) throws ParserConfigurationException, SAXException {
XMLFilter filter = new XMLFilterImpl() {
private boolean rootSeen = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes atts)
throws SAXException {
if (!rootSeen) {
checkNamespace(uri, validationVersion);
rootSeen = true;
}
super.startElement(uri, localName, qName, atts);
}
};
XMLReader xmlReader = SAXParserFactory.newNSInstance().newSAXParser().getXMLReader();
filter.setParent(xmlReader);
return filter;
}
private static void checkNamespace(String actualNamespace, IidmVersion validationVersion) {
boolean matches = actualNamespace.equals(validationVersion.getNamespaceURI())
|| validationVersion.supportEquipmentValidationLevel() && actualNamespace.equals(validationVersion.getNamespaceURI(false));
if (!matches) {
throw new PowsyblException("Namespace mismatch: expected validation version " + validationVersion.toString(".") + ", found namespace " + actualNamespace);
}
}Note: this is an example, this has to be checked/improved/validated!



Please check if the PR fulfills these requirements
Does this PR already have an issue describing the problem?
Fixes #2818
What kind of change does this PR introduce?
What is the current behavior?
What is the new behavior (if this is a feature change)?
Does this PR introduce a breaking change or deprecate an API?
If yes, please check if the following requirements are fulfilled
What changes might users need to make in their application due to this PR? (migration steps)
Other information:
xs:import+schemaLocation), which can impact schema resolution . To handle this,extractSchemaLocationsandgetSupportedExtensionsByIIdmVersionwere added.readRootNamespaceandcheckNamespace