This is an automated email from the ASF dual-hosted git repository.

slawrence pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git


The following commit(s) were added to refs/heads/main by this push:
     new 3ae1ef479 Allow changing blob attributes when full/custom validation 
is enabled
3ae1ef479 is described below

commit 3ae1ef479f0530322ab20f0111b70c47fa5430c6
Author: Steve Lawrence <[email protected]>
AuthorDate: Fri Aug 4 11:09:03 2023 -0400

    Allow changing blob attributes when full/custom validation is enabled
    
    When full or custom validation is enabled, Daffodil creates a new
    TeeInfosetOutputter which proxies infoset events to the user provided
    InfosetOutputter and another one used for validation. This means that
    calls to getBlobDirectory, getBlobSuffix, setBlobPath, etc. go to the
    TeeInfosetOutputter, and ignore any values that a user may have set on
    their provided InfosetOutputter. This essentially means you cannot
    change the directory, suffix, or prefix of blobs if full or custom
    validation is enabled. It also means that if calling getBlobPaths on the
    user provided InfosetOutputter never returns anything, even if blobs
    were created.
    
    To fix this, if full or custom validation is enabled, we copy the blob
    attributes to the TeeInfosetOutputter used for parsing. We also ensure
    that at the end of parsing, we call setBlobPaths on the InfosetOutputter
    the user passed in instead of the TeeInfosetOutputter.
    
    DAFFODIL-2837
---
 .../org/apache/daffodil/example/TestJavaAPI.java   | 38 ++++++++++++++++++++++
 .../{blob_backtracking.dfdl.xsd => blob.dfdl.xsd}  | 20 ++++--------
 .../runtime1/processors/DataProcessor.scala        | 14 ++++++--
 .../src/test/resources/test/sapi/blob.dfdl.xsd     | 20 ++++--------
 .../org/apache/daffodil/example/TestScalaAPI.scala | 35 ++++++++++++++++++++
 5 files changed, 96 insertions(+), 31 deletions(-)

diff --git 
a/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java 
b/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java
index 9f4be4a7b..1ad39bd5c 100644
--- a/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java
+++ b/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java
@@ -35,7 +35,9 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
+import scala.collection.JavaConverters;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
@@ -1308,4 +1310,40 @@ public class TestJavaAPI {
         assertFalse(err);
         assertEquals(expect, value);
     }
+
+    @Test
+    public void testJavaAPIBlob1() throws IOException, ClassNotFoundException, 
InvalidUsageException {
+        org.apache.daffodil.japi.Compiler c = Daffodil.compiler();
+        java.io.File schemaFile = getResource("/test/japi/blob.dfdl.xsd");
+        ProcessorFactory pf = c.compileFile(schemaFile);
+        DataProcessor dp = pf.onPath("/");
+        dp = dp.withValidationMode(ValidationMode.Full);
+
+        byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 
0x04 };
+        ByteArrayInputStream bis = new ByteArrayInputStream(data);
+        InputSourceDataInputStream input = new 
InputSourceDataInputStream(data);
+
+        Path blobRoot = Paths.get(System.getProperty("java.io.tmpdir"), 
"daffodil", "japi");
+        Files.createDirectories(blobRoot);
+        Path blobDir = Files.createTempDirectory(blobRoot, "blob-");
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        XMLTextInfosetOutputter output = new XMLTextInfosetOutputter(bos, 
true);
+        output.setBlobAttributes(blobDir, "pre-", ".suf");
+
+        ParseResult res = dp.parse(input, output);
+        List<Path> blobPaths = 
JavaConverters.seqAsJavaList(output.getBlobPaths());
+
+        try {
+            assertFalse(res.isError());
+            assertTrue(blobPaths.size() == 1);
+            assertTrue(blobPaths.get(0).toString().contains("blob-"));
+            assertTrue(blobPaths.get(0).toString().contains("pre-"));
+            assertTrue(blobPaths.get(0).toString().contains(".suf"));
+        } finally {
+            Iterator<Path> pathIter = blobPaths.iterator();
+            while (pathIter.hasNext()) Files.delete(pathIter.next());
+            Files.delete(blobDir);
+        }
+    }
 }
diff --git 
a/daffodil-japi/src/test/resources/test/japi/blob_backtracking.dfdl.xsd 
b/daffodil-japi/src/test/resources/test/japi/blob.dfdl.xsd
similarity index 72%
copy from daffodil-japi/src/test/resources/test/japi/blob_backtracking.dfdl.xsd
copy to daffodil-japi/src/test/resources/test/japi/blob.dfdl.xsd
index 4bc3c2f2e..842b378ef 100644
--- a/daffodil-japi/src/test/resources/test/japi/blob_backtracking.dfdl.xsd
+++ b/daffodil-japi/src/test/resources/test/japi/blob.dfdl.xsd
@@ -27,25 +27,17 @@
   <annotation>
     <appinfo source="http://www.ogf.org/dfdl/";>
       <dfdl:format ref="tns:GeneralFormat"
-        representation="binary"
-        encodingErrorPolicy="replace" />
+        representation="binary" />
     </appinfo>
   </annotation>
 
   <xs:element name="root">
     <xs:complexType>
-      <xs:choice>
-        <xs:sequence>
-          <xs:element name="b" type="xs:anyURI"
-            dfdl:lengthKind="explicit" dfdl:length="2098176008"
-            dfdlx:objectKind="bytes" />
-          <xs:element name="a" type="xs:string"
-            dfdl:lengthKind="explicit" dfdl:length="1" />
-        </xs:sequence>
-        <xs:element name="oneGigBlob" type="xs:anyURI"
-          dfdl:lengthKind="explicit" dfdl:length="2098176008"
-          dfdlx:objectKind="bytes" />
-      </xs:choice>
+      <xs:sequence>
+        <xs:element name="length" type="xs:int" />
+        <xs:element name="blob" type="xs:anyURI" dfdlx:objectKind="bytes"
+          dfdl:lengthKind="explicit" dfdl:length="{ ../length }" />
+      </xs:sequence>
     </xs:complexType>
   </xs:element>
 
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala
index efedbdb8b..633b50054 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/DataProcessor.scala
@@ -356,6 +356,13 @@ class DataProcessor(
           val bos = new java.io.ByteArrayOutputStream()
           val xmlOutputter = new XMLTextInfosetOutputter(bos, false)
           val teeOutputter = new TeeInfosetOutputter(output, xmlOutputter)
+          // copy the blob attributes from the users outputter to the tee 
infoset outputter
+          // since Daffodil will now use that to get blob attributes
+          teeOutputter.setBlobAttributes(
+            output.getBlobDirectory(),
+            output.getBlobPrefix(),
+            output.getBlobSuffix(),
+          )
           (teeOutputter, One(bos))
         case _ =>
           (output, Nope)
@@ -387,15 +394,16 @@ class DataProcessor(
         }
         res
       }
-      state.output.setBlobPaths(state.blobPaths)
+      // copy the blob paths we created to the users infoset outputter
+      output.setBlobPaths(state.blobPaths)
       new ParseResult(state, vr)
     } else {
       // failed, so delete all blobs that were created
       state.blobPaths.foreach { path =>
         Files.delete(path)
       }
-      // ensure the blob paths are empty in case of outputter reuse
-      state.output.setBlobPaths(Seq.empty)
+      // ensure the blob paths on the users infoset outputter are empty in 
case of reuse
+      output.setBlobPaths(Seq.empty)
       new ParseResult(state, None)
     }
     val s = state
diff --git 
a/daffodil-japi/src/test/resources/test/japi/blob_backtracking.dfdl.xsd 
b/daffodil-sapi/src/test/resources/test/sapi/blob.dfdl.xsd
similarity index 72%
rename from 
daffodil-japi/src/test/resources/test/japi/blob_backtracking.dfdl.xsd
rename to daffodil-sapi/src/test/resources/test/sapi/blob.dfdl.xsd
index 4bc3c2f2e..842b378ef 100644
--- a/daffodil-japi/src/test/resources/test/japi/blob_backtracking.dfdl.xsd
+++ b/daffodil-sapi/src/test/resources/test/sapi/blob.dfdl.xsd
@@ -27,25 +27,17 @@
   <annotation>
     <appinfo source="http://www.ogf.org/dfdl/";>
       <dfdl:format ref="tns:GeneralFormat"
-        representation="binary"
-        encodingErrorPolicy="replace" />
+        representation="binary" />
     </appinfo>
   </annotation>
 
   <xs:element name="root">
     <xs:complexType>
-      <xs:choice>
-        <xs:sequence>
-          <xs:element name="b" type="xs:anyURI"
-            dfdl:lengthKind="explicit" dfdl:length="2098176008"
-            dfdlx:objectKind="bytes" />
-          <xs:element name="a" type="xs:string"
-            dfdl:lengthKind="explicit" dfdl:length="1" />
-        </xs:sequence>
-        <xs:element name="oneGigBlob" type="xs:anyURI"
-          dfdl:lengthKind="explicit" dfdl:length="2098176008"
-          dfdlx:objectKind="bytes" />
-      </xs:choice>
+      <xs:sequence>
+        <xs:element name="length" type="xs:int" />
+        <xs:element name="blob" type="xs:anyURI" dfdlx:objectKind="bytes"
+          dfdl:lengthKind="explicit" dfdl:length="{ ../length }" />
+      </xs:sequence>
     </xs:complexType>
   </xs:element>
 
diff --git 
a/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala 
b/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala
index 5e9a2092f..14b31031b 100644
--- 
a/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala
+++ 
b/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala
@@ -25,6 +25,7 @@ import java.io.ObjectOutputStream
 import java.nio.ByteBuffer
 import java.nio.channels.Channels
 import java.nio.charset.StandardCharsets
+import java.nio.file.Files
 import java.nio.file.Paths
 import javax.xml.XMLConstants
 
@@ -1290,4 +1291,38 @@ class TestScalaAPI {
     assertFalse(err)
     assertEquals(expect, value)
   }
+
+  @Test
+  def testScalaAPIBlob1(): Unit = {
+    val c = Daffodil.compiler()
+    val schemaFile = getResource("/test/sapi/blob.dfdl.xsd")
+    val pf = c.compileFile(schemaFile)
+    val dp = pf.onPath("/").withValidationMode(ValidationMode.Full)
+
+    val data = Array[Byte](0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04)
+    val bis = new ByteArrayInputStream(data)
+    val input = new InputSourceDataInputStream(data)
+
+    val blobRoot = Paths.get(System.getProperty("java.io.tmpdir"), "daffodil", 
"sapi")
+    Files.createDirectories(blobRoot)
+    val blobDir = Files.createTempDirectory(blobRoot, "blob-")
+
+    val bos = new ByteArrayOutputStream()
+    val output = new XMLTextInfosetOutputter(bos, true)
+    output.setBlobAttributes(blobDir, "pre-", ".suf")
+
+    val res = dp.parse(input, output)
+    val blobPaths = output.getBlobPaths()
+
+    try {
+      assertFalse(res.isError)
+      assertTrue(blobPaths.length == 1)
+      assertTrue(blobPaths(0).toString().contains("blob-"))
+      assertTrue(blobPaths(0).toString().contains("pre-"))
+      assertTrue(blobPaths(0).toString().contains(".suf"))
+    } finally {
+      blobPaths.foreach(Files.delete)
+      Files.delete(blobDir)
+    }
+  }
 }

Reply via email to