[entsoe] Fix XML error handling (#19867)

* sax error handler

Signed-off-by: Bernd Weymann <bernd.weymann@gmail.com>
This commit is contained in:
Bernd Weymann
2025-12-23 20:36:26 +01:00
committed by GitHub
parent 7962f9ad6d
commit 1163f4ce11
4 changed files with 42 additions and 6 deletions
@@ -3,15 +3,11 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>5.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.entsoe</artifactId>
<name>openHAB Add-ons :: Bundles :: ENTSO-E Binding</name>
</project>
@@ -36,14 +36,16 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class EntsoeDocumentParser {
public class EntsoeDocumentParser implements ErrorHandler {
private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
private final Logger logger = LoggerFactory.getLogger(EntsoeDocumentParser.class);
private final TreeMap<String, String> sequenceDurationMap = new TreeMap<>();
@@ -51,6 +53,10 @@ public class EntsoeDocumentParser {
private @Nullable String failureReason;
private @Nullable Document document;
public EntsoeDocumentParser() {
failureReason = "Parser not initialized with response";
}
/**
* Constructor. Parses the given XML response string.
* Errors during parsing are captured and can be retrieved via {@link #isValid()} and {@link #getFailureReason()}.
@@ -284,6 +290,7 @@ public class EntsoeDocumentParser {
private @Nullable Document parseDocument(String response)
throws ParserConfigurationException, SAXException, IOException {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
documentBuilder.setErrorHandler(this);
Document document = documentBuilder.parse(new InputSource(new StringReader(response)));
document.getDocumentElement().normalize();
return document;
@@ -301,4 +308,27 @@ public class EntsoeDocumentParser {
Duration d = Duration.parse(resolution).multipliedBy(iteration);
return start.plus(d);
}
@Override
public void warning(@Nullable SAXParseException exception) throws SAXException {
throwParserException("Unknown warning", exception);
}
@Override
public void error(@Nullable SAXParseException exception) throws SAXException {
throwParserException("Unknown error", exception);
}
@Override
public void fatalError(@Nullable SAXParseException exception) throws SAXException {
throwParserException("Unknown fatal error", exception);
}
private void throwParserException(String message, @Nullable SAXParseException exception) throws SAXException {
if (exception != null) {
throw exception;
} else {
throw new SAXException(message);
}
}
}
@@ -67,7 +67,7 @@ public class EntsoeHandler extends BaseThingHandler {
private final CronScheduler cron;
private EntsoeConfiguration config = new EntsoeConfiguration();
private EntsoeDocumentParser parser = new EntsoeDocumentParser("");
private EntsoeDocumentParser parser = new EntsoeDocumentParser();
private TreeMap<Instant, SpotPrice> priceMap = new TreeMap<>();
private @Nullable ScheduledCompletableFuture<?> cronDaily;
private @Nullable ScheduledFuture<?> retryJob;
@@ -232,6 +232,16 @@ public class TestResponse {
}
}
@Test
void testEmptyParser() {
EntsoeDocumentParser standardParser = new EntsoeDocumentParser();
assertNotNull(standardParser);
assertNotNull(standardParser.getFailureReason());
EntsoeDocumentParser emptyParser = new EntsoeDocumentParser("");
assertNotNull(emptyParser);
assertNotNull(emptyParser.getFailureReason());
}
private void verifySpotPrice(Map<Instant, SpotPrice> map, String timestamp, double expectedValue) {
SpotPrice testPrice = map.get(Instant.parse(timestamp));
assertNotNull(testPrice, "No spot price at " + timestamp);