From 9e3b12685b7f6735a4056c0544fa17aa4158ed33 Mon Sep 17 00:00:00 2001 From: "Andreas Penski (init)" Date: Thu, 7 May 2020 17:10:33 +0200 Subject: [PATCH] Support for DOMSource and other Sources --- docs/api.md | 2 +- .../validationtool/api/InputFactory.java | 9 +++- .../impl/input/SourceInput.java | 50 +++++++++++-------- .../validationtool/api/InputFactoryTest.java | 34 +++++++++++++ 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/docs/api.md b/docs/api.md index c59bc23..14add56 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4,7 +4,7 @@ The Validator offers an API which allows you to integrate Validator in your own ## Dependency Management -Currently, we *do not* deploy to Maven Central or similar. Hence you need to build and optionally deploy the Validator artifacts to your own +Currently, we *do not* deploy to Maven Central or similar. Hence, you need to build and optionally deploy the Validator artifacts to your own shared (or local) repository (see for example [Maven Documentation](https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html)). ### Maven diff --git a/src/main/java/de/kosit/validationtool/api/InputFactory.java b/src/main/java/de/kosit/validationtool/api/InputFactory.java index 8cf380f..b491cb2 100644 --- a/src/main/java/de/kosit/validationtool/api/InputFactory.java +++ b/src/main/java/de/kosit/validationtool/api/InputFactory.java @@ -164,8 +164,10 @@ public class InputFactory { } /** - * Reads a test document from a {@link Source}. - * + * Reads a test document from a {@link Source}.
+ * Note: computing the hashcode is only supported for {@link StreamSource}. You can not directly use other {@link Source + * Soures}. You need to supply the hashcode for identification then. + * * @param source source * @return an {@link Input} */ @@ -175,6 +177,9 @@ public class InputFactory { /** * Reads a test document from a {@link Source} using a specified digest algorithm. + * + * Note: computing the hashcode is only supported for {@link StreamSource}. You can not directly use other {@link Source + * Soures}. You need to supply the hashcode for identification then. * * @param source source * @param digestAlgorithm the digest algorithm diff --git a/src/main/java/de/kosit/validationtool/impl/input/SourceInput.java b/src/main/java/de/kosit/validationtool/impl/input/SourceInput.java index f11e65f..cb9f929 100644 --- a/src/main/java/de/kosit/validationtool/impl/input/SourceInput.java +++ b/src/main/java/de/kosit/validationtool/impl/input/SourceInput.java @@ -7,13 +7,25 @@ import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.input.ReaderInputStream; -import org.apache.commons.lang3.NotImplementedException; import lombok.Getter; import lombok.extern.slf4j.Slf4j; /** - * A validator {@link de.kosit.validationtool.api.Input} based an on a {@link Source}. + * A validator {@link de.kosit.validationtool.api.Input} based on a {@link Source}.
+ *

+ * Note: The various implementations of {@link Source} varies wether the can be read twice or no. This implementation + * tries to handle this with respect document identification (hashcode). + * + * This class is know to work with: + *

+ * + * Other {@link Source Sources} may work as well, please try and let us know. + *

* * @author Andreas Penski */ @@ -40,26 +52,23 @@ public class SourceInput extends AbstractInput { } private void validate() { - if (!isSupported()) { + if (!isHashcodeComputed() && !isSupported()) { throw new IllegalStateException("Unsupported source. Only StreamSource supported yet"); } - if (((StreamSource) this.source).getInputStream() == null && !isHashcodeComputed()) { + if (!isHashcodeComputed() && ((StreamSource) this.source).getInputStream() == null) { log.warn("No hashcode supplied, will wrap the reader using system default charset"); } } @Override public Source getSource() throws IOException { - if (!isSupported()) { + if (!isHashcodeComputed() && !isSupported()) { throw new IllegalStateException("Unsupported source. Only InputStream-based StreamSource supported yet"); } - if (isWrappingRequired()) { - return wrap(); - } if (isConsumed()) { throw new IllegalStateException("A SourceInput can only read once"); } - return this.source; + return isHashcodeComputed() ? this.source : wrappedSource(); } private boolean isSupported() { @@ -67,24 +76,25 @@ public class SourceInput extends AbstractInput { } private boolean isConsumed() throws IOException { - if (!isStreamSource()) { - throw new NotImplementedException("Supports only StreamSource yet"); - } - final StreamSource ss = (StreamSource) this.source; - try { - return (ss.getInputStream() != null && ss.getInputStream().available() == 0) - || (ss.getReader() != null && !ss.getReader().ready()); - } catch (final IOException e) { - log.error("Error checking consumed state", e); - return true; + if (isStreamSource()) { + + final StreamSource ss = (StreamSource) this.source; + try { + return (ss.getInputStream() != null && ss.getInputStream().available() == 0) + || (ss.getReader() != null && !ss.getReader().ready()); + } catch (final IOException e) { + log.error("Error checking consumed state", e); + return true; + } } + return false; } private boolean isStreamSource() { return this.source instanceof StreamSource; } - private Source wrap() { + private Source wrappedSource() { Source result = this.source; if (isStreamSource()) { final StreamSource ss = (StreamSource) this.source; diff --git a/src/test/java/de/kosit/validationtool/api/InputFactoryTest.java b/src/test/java/de/kosit/validationtool/api/InputFactoryTest.java index 3fc6122..aa8e6e3 100644 --- a/src/test/java/de/kosit/validationtool/api/InputFactoryTest.java +++ b/src/test/java/de/kosit/validationtool/api/InputFactoryTest.java @@ -31,14 +31,29 @@ import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Paths; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; +import de.kosit.validationtool.impl.Helper; import de.kosit.validationtool.impl.Helper.Simple; +import de.kosit.validationtool.impl.TestObjectFactory; import de.kosit.validationtool.impl.input.SourceInput; +import de.kosit.validationtool.impl.model.Result; +import de.kosit.validationtool.model.reportInput.XMLSyntaxError; + +import net.sf.saxon.dom.NodeOverNodeInfo; +import net.sf.saxon.s9api.BuildingContentHandler; +import net.sf.saxon.s9api.DocumentBuilder; +import net.sf.saxon.s9api.SaxonApiException; +import net.sf.saxon.s9api.XdmNode; /** * Testet den Hashcode-Service. @@ -163,4 +178,23 @@ public class InputFactoryTest { InputFactory.read(Simple.NOT_EXISTING); } + @Test + public void testDomSource() throws SaxonApiException, SAXException, IOException { + final DocumentBuilder builder = TestObjectFactory.createProcessor().newDocumentBuilder(); + + final BuildingContentHandler handler = builder.newBuildingContentHandler(); + handler.startDocument(); + handler.startElement("http://some.ns", "mynode", "mynode", new AttributesImpl()); + final Document dom = NodeOverNodeInfo.wrap(handler.getDocumentNode().getUnderlyingNode()).getOwnerDocument(); + final Input domInput = InputFactory.read(new DOMSource(dom), "MD5", "id".getBytes()); + assertThat(domInput).isNotNull(); + final Source source = domInput.getSource(); + assertThat(source).isNotNull(); + final Result parsed = Helper.parseDocument(domInput); + assertThat(parsed.isValid()).isTrue(); + + // read twice + assertThat(Helper.parseDocument(domInput).getObject()).isNotNull(); + } + }