diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/core/api/TestMetadataWalking.scala b/daffodil-core/src/test/scala/org/apache/daffodil/core/api/TestMetadataWalking.scala index cb2d4f8747..90c4beb2f4 100644 --- a/daffodil-core/src/test/scala/org/apache/daffodil/core/api/TestMetadataWalking.scala +++ b/daffodil-core/src/test/scala/org/apache/daffodil/core/api/TestMetadataWalking.scala @@ -30,6 +30,7 @@ import org.apache.daffodil.runtime1.api.InfosetItem import org.apache.daffodil.runtime1.api.InfosetSimpleElement import org.apache.daffodil.runtime1.api.MetadataHandler import org.apache.daffodil.runtime1.api.SimpleElementMetadata +import org.apache.daffodil.runtime1.infoset.ExceptionOccurredMixin import org.apache.daffodil.runtime1.infoset.InfosetOutputter import org.apache.daffodil.runtime1.infoset.InfosetOutputterImpl import org.apache.daffodil.runtime1.processors.DataProcessor @@ -72,7 +73,7 @@ class TestMetadataWalking { override def endComplexElementMetadata(m: ComplexElementMetadata): Unit = buf += m } - class GatherData extends InfosetOutputterImpl with InfosetOutputter { + class GatherData extends InfosetOutputterImpl with InfosetOutputter with ExceptionOccurredMixin { private val buf = new ArrayBuffer[InfosetItem] diff --git a/daffodil-japi/src/main/scala/org/apache/daffodil/japi/infoset/Infoset.scala b/daffodil-japi/src/main/scala/org/apache/daffodil/japi/infoset/Infoset.scala index 9395b34887..800ec5a41b 100644 --- a/daffodil-japi/src/main/scala/org/apache/daffodil/japi/infoset/Infoset.scala +++ b/daffodil-japi/src/main/scala/org/apache/daffodil/japi/infoset/Infoset.scala @@ -470,4 +470,5 @@ abstract class InfosetOutputterProxy extends InfosetOutputter { override def endComplex(diComplex: InfosetComplexElement): Unit = infosetOutputter.endComplex(diComplex) override def startArray(diArray: InfosetArray): Unit = infosetOutputter.startArray(diArray) override def endArray(diArray: InfosetArray): Unit = infosetOutputter.endArray(diArray) + override def exceptionOccurred(e: Exception): Unit = infosetOutputter.exceptionOccurred(e) } diff --git a/daffodil-japi/src/test/java/org/apache/daffodil/example/TestInfosetOutputter.java b/daffodil-japi/src/test/java/org/apache/daffodil/example/TestInfosetOutputter.java index 25c29f28be..063e947cfa 100644 --- a/daffodil-japi/src/test/java/org/apache/daffodil/example/TestInfosetOutputter.java +++ b/daffodil-japi/src/test/java/org/apache/daffodil/example/TestInfosetOutputter.java @@ -91,4 +91,9 @@ public void startArray(InfosetArray diArray) { @Override public void endArray(InfosetArray diArray) { } + + @Override + public void exceptionOccurred(Exception e) { + // do nothing + } } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala index db899cc15d..c70f2b4c5d 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala @@ -120,6 +120,18 @@ trait InfosetOutputter extends BlobMethodsMixin { def endArray(diArray: InfosetArray): Unit def getStatus(): Status + + /** + * Override this to be fed any exceptions thrown by the start/end methods of this class. + * This is mostly to facilitate users debugging their code that uses the API. + * + * This saves the user of the API from having to wrap try/catch around their + * start/end method bodies. + * + * @param e the exception thrown by one of the other methods. + */ + def exceptionOccurred(e: Exception): Unit + } /** @@ -185,3 +197,10 @@ object Status extends Enumeration { type Status = Value val DONE, READY, VISITING = Value } + +trait ExceptionOccurredMixin { + def exceptionOccurred(e: Exception): Unit = { + val ex = e // because sometimes the debugger won't show the exception + ex.getCause() // good place for a breakpoint + } +} \ No newline at end of file diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetWalker.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetWalker.scala index c091327b73..1265004475 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetWalker.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetWalker.scala @@ -453,6 +453,7 @@ class InfosetWalker private ( outputterFunc } catch { case e: Exception => { + outputter.exceptionOccurred(e) // debugging hook for the user. val cause = e.getCause val msg = if (cause == null) e.toString else cause.toString context.SDE("Failed to %s: %s", desc, msg) diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/JsonInfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/JsonInfosetOutputter.scala index c7d7fae67f..fae4c9924c 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/JsonInfosetOutputter.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/JsonInfosetOutputter.scala @@ -29,6 +29,7 @@ import java.nio.charset.StandardCharsets class JsonInfosetOutputter private (writer: java.io.Writer, pretty: Boolean) extends InfosetOutputterImpl + with ExceptionOccurredMixin with Indentable { def this(os: java.io.OutputStream, pretty: Boolean) = { diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/NullInfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/NullInfosetOutputter.scala index 4626b55c1d..34917b66aa 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/NullInfosetOutputter.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/NullInfosetOutputter.scala @@ -24,7 +24,8 @@ import org.apache.daffodil.runtime1.api.InfosetSimpleElement /** * Ignores all infoset events, outputting nothing */ -class NullInfosetOutputter() extends InfosetOutputterImpl { +class NullInfosetOutputter() extends InfosetOutputterImpl +with ExceptionOccurredMixin { override def reset(): Unit = {} diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/TeeInfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/TeeInfosetOutputter.scala index d5c4d3f393..b721064865 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/TeeInfosetOutputter.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/TeeInfosetOutputter.scala @@ -30,7 +30,8 @@ import org.apache.daffodil.runtime1.api.InfosetSimpleElement * * InfosetOutputters to send all events */ -class TeeInfosetOutputter(outputters: InfosetOutputter*) extends InfosetOutputterImpl { +class TeeInfosetOutputter(outputters: InfosetOutputter*) extends InfosetOutputterImpl +with ExceptionOccurredMixin { override def reset(): Unit = { outputters.foreach { _.reset() } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/XMLInfosetOutputterMixin.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/XMLInfosetOutputterMixin.scala index 662a1e08fa..8af71530f4 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/XMLInfosetOutputterMixin.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/XMLInfosetOutputterMixin.scala @@ -21,7 +21,7 @@ import org.apache.daffodil.lib.equality._ import org.apache.daffodil.lib.util.Maybe import org.apache.daffodil.lib.xml.XMLUtils -trait XMLInfosetOutputterMixin { +trait XMLInfosetOutputterMixin extends ExceptionOccurredMixin { def remapped(dataValueAsString: String) = XMLUtils.remapXMLIllegalCharactersToPUA(dataValueAsString) @@ -58,5 +58,4 @@ trait XMLInfosetOutputterMixin { } res } - } diff --git a/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/infoset/Infoset.scala b/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/infoset/Infoset.scala index 3b747f3221..5b690293d0 100644 --- a/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/infoset/Infoset.scala +++ b/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/infoset/Infoset.scala @@ -459,4 +459,5 @@ abstract class InfosetInputterProxy extends InfosetInputter { override def endComplex(diComplex: InfosetComplexElement): Unit = infosetOutputter.endComplex(diComplex) override def startArray(diArray: InfosetArray): Unit = infosetOutputter.startArray(diArray) override def endArray(diArray: InfosetArray): Unit = infosetOutputter.endArray(diArray) + override def exceptionOccurred(e: Exception): Unit = infosetOutputter.exceptionOccurred(e) } diff --git a/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestInfosetInputterOutputter.scala b/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestInfosetInputterOutputter.scala index f4c814c3ca..e4615a2017 100644 --- a/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestInfosetInputterOutputter.scala +++ b/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestInfosetInputterOutputter.scala @@ -139,4 +139,6 @@ case class TestInfosetOutputter() extends InfosetOutputter { override def startArray(diArray: InfosetArray): Unit = {} override def endArray(diArray: InfosetArray): Unit = {} + + override def exceptionOccurred(e: Exception): Unit = {} }