From da704216204a177c16d1a4b4be0804bff057114b Mon Sep 17 00:00:00 2001 From: "Andreas Penski (init)" Date: Mon, 6 Jan 2020 09:10:45 +0100 Subject: [PATCH] #40 Fix NPE in Result.getReportDocument for malformed xml input --- pom.xml | 9 +----- .../validationtool/impl/DefaultCheck.java | 7 ----- .../impl/model/BaseScenario.java | 2 +- .../impl/tasks/CreateReportAction.java | 23 +++++++++------ .../impl/tasks/ScenarioSelectionAction.java | 28 ++++++++++++------- .../impl/tasks/SchemaValidationAction.java | 18 ++++++------ .../tasks/SchematronValidationAction.java | 6 +++- .../validationtool/impl/DefaultCheckTest.java | 3 ++ .../de/kosit/validationtool/impl/Helper.java | 22 +++++++++++++++ 9 files changed, 74 insertions(+), 44 deletions(-) diff --git a/pom.xml b/pom.xml index 67bf426..04e0cde 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ KoSIT XML Prüftool Implementierung de.kosit - 1.1.1 + 1.1.2-SNAPSHOT validationtool KoSIT XML Validator against XSD and Schematron based on defined scenarios. @@ -19,7 +19,6 @@ http://www.xoev.de - renzo.kottmann Renzo Kottmann KoSIT @@ -37,12 +36,6 @@ developer - - fabian.buettner - Fabian Büttner - KoSIT - http://www.xoev.de - UTF-8 diff --git a/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java b/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java index 8610347..f47d84c 100644 --- a/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java +++ b/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java @@ -43,7 +43,6 @@ import de.kosit.validationtool.impl.tasks.SchematronValidationAction; import de.kosit.validationtool.impl.tasks.ValidateReportInputAction; import de.kosit.validationtool.model.reportInput.CreateReportInput; import de.kosit.validationtool.model.reportInput.EngineType; -import de.kosit.validationtool.model.reportInput.ProcessingError; import de.kosit.validationtool.model.reportInput.XMLSyntaxError; import net.sf.saxon.s9api.Processor; @@ -116,12 +115,6 @@ public class DefaultCheck implements Check { action.check(t); } log.debug("Step {} finished in {}ms", action.getClass().getSimpleName(), System.currentTimeMillis() - start); - if (t.isStopped()) { - final ProcessingError processingError = t.getReportInput().getProcessingError(); - log.error("Error processing input {}: {}", t.getInput().getName(), - processingError != null ? String.join("\n", processingError.getError()) : ""); - break; - } } t.setFinished(true); log.info("Finished check of {} in {}ms\n", t.getInput().getName(), System.currentTimeMillis() - started); diff --git a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java index be32ca9..71c723f 100644 --- a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java +++ b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java @@ -94,7 +94,7 @@ public abstract class BaseScenario { * @return das passende Schema */ public Schema getSchema() { - if (this.schema == null) { + if (this.schema == null && getValidateWithXmlSchema() != null) { final List schemaResources = getValidateWithXmlSchema().getResource().stream().map(ResourceType::getLocation) .collect(Collectors.toList()); this.schema = this.repository.createSchema(schemaResources); diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java index 87d0256..b8bab3d 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java @@ -22,6 +22,7 @@ package de.kosit.validationtool.impl.tasks; import javax.xml.transform.dom.DOMSource; import org.w3c.dom.Document; +import org.xml.sax.SAXException; import lombok.RequiredArgsConstructor; @@ -31,9 +32,9 @@ import de.kosit.validationtool.impl.ConversionService; import de.kosit.validationtool.impl.ObjectFactory; import de.kosit.validationtool.impl.RelativeUriResolver; import de.kosit.validationtool.impl.ScenarioRepository; -import de.kosit.validationtool.impl.model.Result; import de.kosit.validationtool.model.scenarios.ScenarioType; +import net.sf.saxon.s9api.BuildingContentHandler; import net.sf.saxon.s9api.DocumentBuilder; import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.QName; @@ -70,7 +71,7 @@ public class CreateReportAction implements CheckAction { try { final XdmNode parsedDocument = results.getParserResult().isValid() ? results.getParserResult().getObject() - : ObjectFactory.createProcessor().newDocumentBuilder().newBuildingContentHandler().getDocumentNode(); + : createEmpty(); final Document reportInput = this.conversionService.writeDocument(results.getReportInput()); final XdmNode root = documentBuilder.build(new DOMSource(reportInput)); @@ -81,21 +82,27 @@ public class CreateReportAction implements CheckAction { transformer.setMessageListener(e); transformer.setURIResolver(resolver); transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver); - transformer.setParameter(new QName("input-document"), parsedDocument); + if (parsedDocument != null) { + transformer.setParameter(new QName("input-document"), parsedDocument); + } final XdmDestination destination = new XdmDestination(); transformer.setDestination(destination); transformer.transform(); results.setReport(destination.getXdmNode()); - } catch (final SaxonApiException e) { + } catch (final SaxonApiException | SAXException e) { throw new IllegalStateException("Can not create final report", e); } } - private XsltExecutable getTransformation(final Bag results) { - final Result scenario = results.getScenarioSelectionResult(); - final ScenarioType reportScenario = scenario.isValid() ? scenario.getObject() : this.scenarioRepository.getFallbackScenario(); - return loadFromScenario(reportScenario); + private static XdmNode createEmpty() throws SaxonApiException, SAXException { + final BuildingContentHandler contentHandler = ObjectFactory.createProcessor().newDocumentBuilder().newBuildingContentHandler(); + contentHandler.startDocument(); + return contentHandler.getDocumentNode(); + } + + private static XsltExecutable getTransformation(final Bag results) { + return loadFromScenario(results.getScenarioSelectionResult().getObject()); } } diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java index 10a7bbd..c66eead 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java @@ -26,8 +26,11 @@ import de.kosit.validationtool.impl.model.Result; import de.kosit.validationtool.model.reportInput.CreateReportInput; import de.kosit.validationtool.model.scenarios.ScenarioType; +import net.sf.saxon.s9api.XdmNode; + /** - * Identifiziert das der Eingabe entsprechende Szenario, sofern eines konfiguriert ist. + * Identifiziert das der Eingabe entsprechende Szenario, sofern eines konfiguriert ist. Setzt das Fallback-Szenario, + * wenn keines identifiziert werden konnte. * * @author Andreas Penski */ @@ -39,18 +42,23 @@ public class ScenarioSelectionAction implements CheckAction { @Override public void check(final Bag results) { final CreateReportInput report = results.getReportInput(); - final Result scenarioTypeResult = this.repository.selectScenario(results.getParserResult().getObject()); - results.setScenarioSelectionResult(scenarioTypeResult); - if (scenarioTypeResult.isValid()) { - final ScenarioType scenario = scenarioTypeResult.getObject(); - report.setScenario(scenario); + final Result scenarioTypeResult; + + if (results.getParserResult().isValid()) { + scenarioTypeResult = determineScenario(results.getParserResult().getObject()); } else { - results.stopProcessing(scenarioTypeResult.getErrors()); + scenarioTypeResult = new Result<>(repository.getFallbackScenario()); } + results.setScenarioSelectionResult(scenarioTypeResult); + report.setScenario(scenarioTypeResult.getObject()); } - @Override - public boolean isSkipped(final Bag results) { - return results.getParserResult().isInvalid(); + private Result determineScenario(final XdmNode document) { + final Result result = this.repository.selectScenario(document); + if (result.isInvalid()) { + return new Result<>(repository.getFallbackScenario()); + } + return result; } + } diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java index f43afbd..3efdfc5 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java @@ -46,26 +46,26 @@ import de.kosit.validationtool.model.scenarios.ScenarioType; @Slf4j public class SchemaValidationAction implements CheckAction { - private Result validate(byte[] document, ScenarioType scenarioType) { + private static Result validate(final byte[] document, final ScenarioType scenarioType) { log.debug("Validating document using scenario {}", scenarioType.getName()); final CollectingErrorEventHandler errorHandler = new CollectingErrorEventHandler(); - try ( InputStream input = new ByteArrayInputStream(document) ) { + try ( final InputStream input = new ByteArrayInputStream(document) ) { final Validator validator = ObjectFactory.createValidator(scenarioType.getSchema()); validator.setErrorHandler(errorHandler); validator.validate(new StreamSource(input)); return new Result<>(!errorHandler.hasErrors(), errorHandler.getErrors()); - } catch (SAXException | IOException e) { + } catch (final SAXException | IOException e) { throw new IllegalStateException("Error validating document", e); } } @Override - public void check(Bag results) { + public void check(final Bag results) { final CreateReportInput report = results.getReportInput(); final ScenarioType scenario = results.getScenarioSelectionResult().getObject(); final Result validateResult = validate(results.getInput().getContent(), scenario); results.setSchemaValidationResult(validateResult); - ValidationResultsXmlSchema result = new ValidationResultsXmlSchema(); + final ValidationResultsXmlSchema result = new ValidationResultsXmlSchema(); report.setValidationResultsXmlSchema(result); result.getResource().addAll(scenario.getValidateWithXmlSchema().getResource()); if (!validateResult.isValid()) { @@ -76,11 +76,11 @@ public class SchemaValidationAction implements CheckAction { @Override - public boolean isSkipped(Bag results) { - return hasNoScenario(results); + public boolean isSkipped(final Bag results) { + return hasNoSchema(results); } - private static boolean hasNoScenario(Bag results) { - return results.getScenarioSelectionResult() == null || results.getScenarioSelectionResult().isInvalid(); + private static boolean hasNoSchema(final Bag results) { + return results.getScenarioSelectionResult() == null || results.getScenarioSelectionResult().getObject().getSchema() == null; } } diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java index 2fe271a..0063da7 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java @@ -95,6 +95,10 @@ public class SchematronValidationAction implements CheckAction { @Override public boolean isSkipped(final Bag results) { - return results.getSchemaValidationResult() == null || results.getSchemaValidationResult().isInvalid(); + return hasNoSchematrons(results.getScenarioSelectionResult().getObject()); + } + + private static boolean hasNoSchematrons(final ScenarioType object) { + return object.getValidateWithSchematron() == null || object.getValidateWithSchematron().size() == 0; } } diff --git a/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java b/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java index 421ea10..0e7af12 100644 --- a/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java +++ b/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java @@ -121,6 +121,9 @@ public class DefaultCheckTest { assertThat(result.isWellformed()).isFalse(); assertThat(result.isSchemaValid()).isFalse(); assertThat(result.isProcessingSuccessful()).isFalse(); + assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.REJECT); + assertThat(result.getReport()).isNotNull(); + assertThat(result.getReportDocument()).isNotNull(); } } diff --git a/src/test/java/de/kosit/validationtool/impl/Helper.java b/src/test/java/de/kosit/validationtool/impl/Helper.java index cf183a8..196b431 100644 --- a/src/test/java/de/kosit/validationtool/impl/Helper.java +++ b/src/test/java/de/kosit/validationtool/impl/Helper.java @@ -22,13 +22,21 @@ package de.kosit.validationtool.impl; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Paths; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.w3c.dom.Document; + +import net.sf.saxon.dom.NodeOverNodeInfo; import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.XdmNode; @@ -123,4 +131,18 @@ public class Helper { return new ContentRepository(ObjectFactory.createProcessor(), new File("src/test/resources/examples/repository").toURI()); } + public static String serialize(final Document doc) { + try ( final StringWriter writer = new StringWriter() ) { + final Transformer transformer = ObjectFactory.createTransformer(true); + transformer.transform(new DOMSource(doc), new StreamResult(writer)); + return writer.toString(); + } catch (final IOException | TransformerException e) { + throw new IllegalStateException("Can not serialize document", e); + } + } + + public static String serialize(final XdmNode node) { + return serialize((Document) NodeOverNodeInfo.wrap(node.getUnderlyingNode())); + } + }