Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.powsybl.iidm.serde.IidmSerDeConstants.ITESLA_DOMAIN;
import static com.powsybl.iidm.serde.IidmSerDeConstants.POWSYBL_DOMAIN;
import static com.powsybl.iidm.serde.IidmSerDeConstants.*;

/**
* @author Miora Ralambotiana {@literal <miora.ralambotiana at rte-france.com>}
Expand Down Expand Up @@ -82,6 +81,15 @@ public String getXsd(boolean valid) {
return "iidm_equipment_V" + toString("_") + ".xsd";
}

public static IidmVersion of(String version, String separator) {
Objects.requireNonNull(version);
return Stream.of(IidmVersion.values())
.filter(v -> version.equals(v.toString(separator)))
.findFirst() // there can only be 0 or exactly 1 match
.orElseThrow(() -> new PowsyblException("IIDM Version " + version + " is not supported. Max supported version: "
+ CURRENT_IIDM_VERSION.toString(".")));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
+ CURRENT_IIDM_VERSION.toString(".")));
+ CURRENT_IIDM_VERSION.toString(separator)));

}

public static IidmVersion fromNamespaceURI(String namespaceURI) {
String version = namespaceURI.substring(namespaceURI.lastIndexOf('/') + 1);
IidmVersion v = of(version, "_");
Expand All @@ -96,11 +104,4 @@ public static IidmVersion fromNamespaceURI(String namespaceURI) {
return v;
}

public static IidmVersion of(String version, String separator) {
Objects.requireNonNull(version);
return Stream.of(IidmVersion.values())
.filter(v -> version.equals(v.toString(separator)))
.findFirst() // there can only be 0 or exactly 1 match
.orElseThrow(() -> new PowsyblException("Version " + version + " is not supported."));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,32 +58,44 @@ public String getComment() {
}

protected boolean exists(ReadOnlyDataSource dataSource, String ext) throws IOException {
try {
if (ext != null) {
try (InputStream is = dataSource.newInputStream(null, ext)) {
// check the first root element is network and namespace is IIDM
XMLStreamReader xmlsr = getXMLInputFactory().createXMLStreamReader(is);
try {
while (xmlsr.hasNext()) {
int eventType = xmlsr.next();
if (eventType == XMLStreamConstants.START_ELEMENT) {
String name = xmlsr.getLocalName();
String ns = xmlsr.getNamespaceURI();
return NetworkSerDe.NETWORK_ROOT_ELEMENT_NAME.equals(name)
&& (Stream.of(IidmVersion.values()).anyMatch(v -> v.getNamespaceURI().equals(ns))
|| Stream.of(IidmVersion.values()).filter(v -> v.compareTo(IidmVersion.V_1_7) >= 0).anyMatch(v -> v.getNamespaceURI(false).equals(ns)));
}
}
} finally {
cleanClose(xmlsr);
if (ext == null) {
return false;
}

try (InputStream is = dataSource.newInputStream(null, ext)) {
XMLStreamReader xmlsr = getXMLInputFactory().createXMLStreamReader(is);
try {
return isValidNetworkRoot(xmlsr);
} finally {
cleanClose(xmlsr);
}
} catch (XMLStreamException e) {
return false; // not a valid XML file
}
}

private boolean isValidNetworkRoot(XMLStreamReader xmlsr) throws XMLStreamException {
while (xmlsr.hasNext()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment that previously existed was useful:

Suggested change
while (xmlsr.hasNext()) {
// check the first root element is network and namespace is IIDM
while (xmlsr.hasNext()) {

if (xmlsr.next() == XMLStreamConstants.START_ELEMENT) {
String name = xmlsr.getLocalName();
String ns = xmlsr.getNamespaceURI();

if (!NetworkSerDe.NETWORK_ROOT_ELEMENT_NAME.equals(name)) {
return false;
}

if (!ns.isEmpty()) {
String version = ns.substring(ns.lastIndexOf('/') + 1);
if (!version.isEmpty()) {
IidmVersion.fromNamespaceURI(ns);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • It would be better to use IidmVersion.of(...).
  • Comments should be added to explain the purpose of this line.
Suggested change
IidmVersion.fromNamespaceURI(ns);
// Try to load an IidmVersion from the version number.
// If it is not supported, this will throw an exception giving details on the encountered version
// and the maximum supported version.
IidmVersion.of(version, "_");

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another problem here. You could not throw a exception here without a minimum of checks.

When a file is imported, in Importer.find(...), all the importer present in the class loader will be tested to see if one of them support the file format. I think that you can reach this line each time you import an XML file whose extension is .xml and whose first root element is network.
If you have a custom network file format with these characteristics, you may encountered the unsupported IIDM version exception depending on the order the importers are tested.

One control that can be added is on the known namespace prefixes. I suggest that you loop on IidmVersion.values() to retrieve their namespace prefixes (by this, I mean the part before the last'/') and to check that the one of the current namespace is equal to one of them. If it is indeed, you can check the version and raise an exception if it is unknown. Else, you'll have to ignore the check.

return Stream.of(IidmVersion.values()).anyMatch(v -> v.getNamespaceURI().equals(ns))
|| Stream.of(IidmVersion.values()).filter(v -> v.compareTo(IidmVersion.V_1_7) >= 0)
.anyMatch(v -> v.getNamespaceURI(false).equals(ns));
}
}
}
return false;
} catch (XMLStreamException e) {
// not a valid xml file
return false;
}
return false;
}

private void cleanClose(XMLStreamReader xmlStreamReader) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.powsybl.iidm.serde;

import com.google.common.io.ByteStreams;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.datasource.*;
import com.powsybl.commons.report.PowsyblCoreReportResourceBundle;
import com.powsybl.commons.test.PowsyblTestReportResourceBundle;
Expand All @@ -23,6 +24,7 @@
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
Expand Down Expand Up @@ -90,6 +92,20 @@ private void writeNetworkWithComment(String fileName) throws IOException {
}
}

private void writeNetworkUnsupportedIidmVersion(String fileName) throws IOException {
writeNetwork(fileName, unsupportedIidmVersionNamespaceURI(), false);
}

private String unsupportedIidmVersionNamespaceURI() {
String currentIidmVersion = CURRENT_IIDM_VERSION.toString();
String currentIidmNamespaceURI = CURRENT_IIDM_VERSION.getNamespaceURI();
String[] currentIidmVersionSplit = currentIidmVersion.split("_");
int currentVersionMajor = Integer.parseInt(currentIidmVersionSplit[1]);
int currentVersionMinor = Integer.parseInt(currentIidmVersionSplit[2]);
String unsupportedIidmVersion = String.format("%d_%d", currentVersionMajor, currentVersionMinor + 1);
return currentIidmNamespaceURI.substring(0, currentIidmNamespaceURI.lastIndexOf("/") + 1) + unsupportedIidmVersion;
}

@BeforeEach
public void setUp() throws IOException {
super.setUp();
Expand All @@ -116,6 +132,7 @@ public void setUp() throws IOException {
}
writeNetworkWithComment("/test7.xiidm");
writeNetworkWithExtension("/test8.xiidm", CURRENT_IIDM_VERSION.getNamespaceURI());
writeNetworkUnsupportedIidmVersion("/test9.xiidm");

importer = new XMLImporter();
}
Expand Down Expand Up @@ -154,6 +171,19 @@ void exists() {
assertFalse(importer.exists(new DirectoryDataSource(fileSystem.getPath("/"), "testDummy"))); // namespace URI is not defined
}

@Test
void testUnsupportedIidmVersion() {
String[] currentIidmVersionSplit = CURRENT_IIDM_VERSION.toString().split("_");
int unsupportedIidmVersionMajor = Integer.parseInt(currentIidmVersionSplit[1]);
int unsupportedIidmVersionMinor = Integer.parseInt(currentIidmVersionSplit[2]) + 1;
String unsupportedIidmVersion = String.format("%d.%d", unsupportedIidmVersionMajor, unsupportedIidmVersionMinor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code could be extracted in a private static method to be reused by unsupportedIidmVersionNamespaceURI().

Path dir = fileSystem.getPath("/");
ReadOnlyDataSource dataSource = new DirectoryDataSource(dir, "test9");
String expectedError = "IIDM Version " + unsupportedIidmVersion + "is not supported. Max supported version: "
+ CURRENT_IIDM_VERSION.toString(".");
assertThrows(PowsyblException.class, () -> importer.exists(dataSource), expectedError);
}

@Test
void copy() throws Exception {
importer.copy(new DirectoryDataSource(fileSystem.getPath("/"), "test0"), new DirectoryDataSource(fileSystem.getPath("/"), "test0_copy"));
Expand Down