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:
+ *
+ * - {@link StreamSource} - both {@link java.io.InputStream} based and {@link java.io.Reader} based
+ * - {@link javax.xml.transform.dom.DOMSource}
+ * - {@link javax.xml.bind.util.JAXBSource}
+ *
+ *
+ * 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();
+ }
+
}