stevedlawrence commented on code in PR #1112:
URL: https://github.com/apache/daffodil/pull/1112#discussion_r1391117119


##########
daffodil-core/src/test/scala/org/apache/daffodil/core/api/TestMetadataWalking.scala:
##########
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.core.api
+
+import scala.collection.mutable.ArrayBuffer
+import scala.xml.Elem
+
+import org.apache.daffodil.core.util.TestUtils
+import org.apache.daffodil.io.InputSourceDataInputStream
+import org.apache.daffodil.lib.util._
+import org.apache.daffodil.runtime1.api.ChoiceMetadata
+import org.apache.daffodil.runtime1.api.ComplexElementMetadata
+import org.apache.daffodil.runtime1.api.DFDL.ParseResult
+import org.apache.daffodil.runtime1.api.ElementMetadata
+import org.apache.daffodil.runtime1.api.InfosetArray
+import org.apache.daffodil.runtime1.api.InfosetComplexElement
+import org.apache.daffodil.runtime1.api.InfosetElement
+import org.apache.daffodil.runtime1.api.InfosetItem
+import org.apache.daffodil.runtime1.api.InfosetSimpleElement
+import org.apache.daffodil.runtime1.api.Metadata
+import org.apache.daffodil.runtime1.api.MetadataHandler
+import org.apache.daffodil.runtime1.api.SequenceMetadata
+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
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class TestMetadataWalking {
+
+  def compileAndWalkMetadata(schema: Elem, mh: MetadataHandler): DataProcessor 
= {
+    val dp = TestUtils.compileSchema(schema)
+    assertTrue(!dp.isError)
+    dp.walkMetadata(mh)
+    dp
+  }
+
+  def parseAndWalkData(dp: DataProcessor, infosetOutputter: InfosetOutputter)(
+    data: Array[Byte],
+  ): ParseResult = {
+    val isdis = InputSourceDataInputStream(data)
+    val res = dp.parse(isdis, infosetOutputter)
+    res
+  }
+
+  class GatherMetadata extends MetadataHandler {
+
+    private val buf = new ArrayBuffer[Metadata]();
+
+    def getResult: Seq[Metadata] = {
+      val res: Seq[Metadata] = buf.toVector // makes a copy
+      buf.clear()
+      res
+    }
+
+    override def simpleElementMetadata(m: SimpleElementMetadata): Unit = buf 
+= m
+
+    override def startComplexElementMetadata(m: ComplexElementMetadata): Unit 
= buf += m
+
+    override def endComplexElementMetadata(m: ComplexElementMetadata): Unit = 
buf += m
+
+    override def startSequenceMetadata(m: SequenceMetadata): Unit = buf += m
+
+    override def endSequenceMetadata(m: SequenceMetadata): Unit = buf += m
+
+    override def startChoiceMetadata(m: ChoiceMetadata): Unit = buf += m
+
+    override def endChoiceMetadata(m: ChoiceMetadata): Unit = buf += m
+  }
+
+  class GatherData
+    extends InfosetOutputterImpl
+    with InfosetOutputter
+    with ExceptionOccurredMixin {
+
+    private val buf = new ArrayBuffer[InfosetItem]
+
+    def getResult: Seq[InfosetItem] = {
+      val res = buf.toVector
+      reset()
+      res
+    }
+
+    override def reset(): Unit = { buf.clear() }
+
+    override def startDocument(): Unit = {}
+
+    override def endDocument(): Unit = {}
+
+    override def startSimple(diSimple: InfosetSimpleElement): Unit = { buf += 
diSimple }
+
+    override def endSimple(diSimple: InfosetSimpleElement): Unit = {}

Review Comment:
   This is slightly different for the MetaDataHandler, which just has a 
"simpleElement" function, instead of separate start/endSimple functions. Having 
start/end events for simple in the InfosetOutputter API maybe have been a 
mistake. In fact, most implementations make endSimple be a no-op. The only one 
that doesn't is the saxInfosetOutputter, which could do all it's logic in 
startSimple.
   
   We are already breaking backwards compatibility pretty heavily here, maybe 
we should also drop endSimple and just have a single method for handling simple 
elements in the InfosetOutputter?



##########
daffodil-japi/src/test/java/org/apache/daffodil/example/TestInfosetOutputter.java:
##########
@@ -51,45 +50,50 @@ public void endDocument() {
     }
 
     @Override
-    public void startSimple(DISimple diSimple) {
+    public void startSimple(InfosetSimpleElement diSimple) {
         events.add(
             TestInfosetEvent.startSimple(
-                diSimple.erd().name(),
-                diSimple.erd().namedQName().namespace().toString(),
+                diSimple.metadata().name(),
+                diSimple.metadata().namespace(),
                 diSimple.dataValueAsString(),
-                diSimple.erd().isNillable() ? diSimple.isNilled() : null));
+                diSimple.metadata().isNillable() ? diSimple.isNilled() : 
null));

Review Comment:
   Rename `diSimple` to just `simple`? Same with other tests.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.daffodil.runtime1.api
+
+import scala.xml.NamespaceBinding
+
+/**
+ * This is the supportable API for access to the RuntimeData structures
+ * which provide access to static information about a given .
+ *
+ * This is used to interface other data processing fabrics to Daffodil
+ * data and metadata, by mapping to/from these metadata objects.
+ */
+trait Metadata {
+
+  /**
+   * Provides the file context of a metadata component. This refers to the 
specific
+   * DFDL schema file where the corresponding DFDL schema text resides 
corresponding
+   * to this metadata object.
+   * <p/>
+   * This is for use in diagnostic messaging. It is not the actual file URI, 
because
+   * those may contain personal-identifying information about the 
person/acccount and
+   * system that compiled the schema. It will provide enough content about the 
file URI that
+   * a user will be able to identify which file, but some prefix of the path
+   * components trimmed to make it of a manageable length.
+   * <p/>
+   * Used along with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]]
+   * and 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineColumnNumber]],
+   * this can give a precise location in the DFDL schema file.
+   * @return a string containing the file information, or null if unknown.
+   */
+  def schemaFileInfo: String
+
+  /**
+   * Provides the line number to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileInfo]].
+   * @return the line number as a string, or null if unknown.
+   */
+  def schemaFileLineNumber: String
+
+  /**
+   * Provides the column number within the text line, to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]].
+   * @return the column number within the text line, as a string, or null if 
unknown.
+   */
+  def schemaFileLineColumnNumber: String

Review Comment:
   Can line/column be Long's instead? Or does Daffodil internally represent 
these as strings so it's just easier to pass that through? If we need the 
`null` to mean for no-information, they can be boxed java longs so we can still 
return null?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala:
##########
@@ -84,75 +85,98 @@ trait InfosetOutputter {
    *                 value, nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endSimple(diSimple: DISimple): Unit
+  def endSimple(diSimple: InfosetSimpleElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of a complex 
element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is started. Various fields of
+   * @param complex the complex element that is started. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def startComplex(diComplex: DIComplex): Unit
+  def startComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the end of a complex element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is ended. Various fields of
+   * @param complex the complex element that is ended. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endComplex(diComplex: DIComplex): Unit
+  def endComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of an array of 
elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is started. Various fields of
+   * @param array the array that is started. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def startArray(diArray: DIArray): Unit
+  def startArray(array: InfosetArray): Unit
 
   /**
    * Called by Daffodil internals to signify the end of an array of elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is ended. Various fields of
+   * @param array the array that is ended. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def endArray(diArray: DIArray): Unit
+  def endArray(array: InfosetArray): Unit
 
-  def getStatus(): Status = {
-    // Done, Ready (Not started), Visiting (part way done - can retry to visit 
more)...
-    status
-  }
+  def getStatus(): Status
 
   /**
-   * Helper function to determine if an element is nilled or not, taking into
-   * account whether or not the nilled state has been set yet.
+   * 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.
    *
-   * @param diElement the element to check the nilled state of
+   * This saves the user of the API from having to wrap try/catch around their
+   * start/end method bodies.
    *
-   * @return true if the nilled state has been set and is true. false if the
-   *         nilled state is false or if the nilled state has not been set yet
-   *         (e.g. during debugging)
+   * @param e the exception thrown by one of the other methods.
    */
-  final def isNilled(diElement: DIElement): Boolean = {
-    val maybeIsNilled = diElement.maybeIsNilled
-    maybeIsNilled.isDefined && maybeIsNilled.get == true
-  }
+  def exceptionOccurred(e: Exception): Unit
+
+}
+
+/**
+ * Methods that provide Blob (Binary Large Object) support.
+ *
+ * FIXME: Scaladoc
+ */
+trait BlobMethodsMixin {
+
+  def setBlobAttributes(blobDir: Path, blobPrefix: String, blobSuffix: 
String): Unit
+  def setBlobPaths(empty: Seq[Path]): Unit
+  def getBlobDirectory(): Path
+  def getBlobPrefix(): String
+  def getBlobSuffix(): String
+
+}
+
+/**
+ * An available basic implementation of the BLOB methods.
+ * Stores blobs in files in directory identified by Java system property
+ * `java.io.tempdir`.
+ *
+ * FIXME: Unclear if Daffodil implements blob copying based on these
+ *   alone or not, and what else people have to do for BLOB support
+ *   than mixin this to their InfosetOutputter. 

Review Comment:
   Nothing needs to be done to support blobs. These functions are just a way to 
configure where blobs get written to. That information is set on the infoset 
outputter because there isn't really a good other place to do it. This also 
provides a way to get paths to all blobs wihtout having to traverse the infoset.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/JsonInfosetOutputter.scala:
##########
@@ -112,11 +116,12 @@ class JsonInfosetOutputter private (writer: 
java.io.Writer, pretty: Boolean)
     }
   }
 
-  override def endSimple(simple: DISimple): Unit = {
+  override def endSimple(se: InfosetSimpleElement): Unit = {
     // nothing to do
   }
 
-  override def startComplex(complex: DIComplex): Unit = {
+  override def startComplex(ce: InfosetComplexElement): Unit = {
+    val complex = ce.asInstanceOf[DIComplex]

Review Comment:
   Can this asInstanceOf go away? Same with others in the class. Or is that 
planned for a later PR?



##########
daffodil-core/src/test/scala/org/apache/daffodil/core/api/TestMetadataWalking.scala:
##########
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.core.api
+
+import scala.collection.mutable.ArrayBuffer
+import scala.xml.Elem
+
+import org.apache.daffodil.core.util.TestUtils
+import org.apache.daffodil.io.InputSourceDataInputStream
+import org.apache.daffodil.lib.util._
+import org.apache.daffodil.runtime1.api.ChoiceMetadata
+import org.apache.daffodil.runtime1.api.ComplexElementMetadata
+import org.apache.daffodil.runtime1.api.DFDL.ParseResult
+import org.apache.daffodil.runtime1.api.ElementMetadata
+import org.apache.daffodil.runtime1.api.InfosetArray
+import org.apache.daffodil.runtime1.api.InfosetComplexElement
+import org.apache.daffodil.runtime1.api.InfosetElement
+import org.apache.daffodil.runtime1.api.InfosetItem
+import org.apache.daffodil.runtime1.api.InfosetSimpleElement
+import org.apache.daffodil.runtime1.api.Metadata
+import org.apache.daffodil.runtime1.api.MetadataHandler
+import org.apache.daffodil.runtime1.api.SequenceMetadata
+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
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class TestMetadataWalking {
+
+  def compileAndWalkMetadata(schema: Elem, mh: MetadataHandler): DataProcessor 
= {
+    val dp = TestUtils.compileSchema(schema)
+    assertTrue(!dp.isError)
+    dp.walkMetadata(mh)
+    dp
+  }
+
+  def parseAndWalkData(dp: DataProcessor, infosetOutputter: InfosetOutputter)(
+    data: Array[Byte],
+  ): ParseResult = {
+    val isdis = InputSourceDataInputStream(data)
+    val res = dp.parse(isdis, infosetOutputter)
+    res
+  }
+
+  class GatherMetadata extends MetadataHandler {
+
+    private val buf = new ArrayBuffer[Metadata]();
+
+    def getResult: Seq[Metadata] = {
+      val res: Seq[Metadata] = buf.toVector // makes a copy
+      buf.clear()
+      res
+    }
+
+    override def simpleElementMetadata(m: SimpleElementMetadata): Unit = buf 
+= m
+
+    override def startComplexElementMetadata(m: ComplexElementMetadata): Unit 
= buf += m
+
+    override def endComplexElementMetadata(m: ComplexElementMetadata): Unit = 
buf += m
+
+    override def startSequenceMetadata(m: SequenceMetadata): Unit = buf += m
+
+    override def endSequenceMetadata(m: SequenceMetadata): Unit = buf += m
+
+    override def startChoiceMetadata(m: ChoiceMetadata): Unit = buf += m
+
+    override def endChoiceMetadata(m: ChoiceMetadata): Unit = buf += m
+  }
+
+  class GatherData
+    extends InfosetOutputterImpl
+    with InfosetOutputter
+    with ExceptionOccurredMixin {
+
+    private val buf = new ArrayBuffer[InfosetItem]
+
+    def getResult: Seq[InfosetItem] = {
+      val res = buf.toVector
+      reset()
+      res
+    }
+
+    override def reset(): Unit = { buf.clear() }
+
+    override def startDocument(): Unit = {}
+
+    override def endDocument(): Unit = {}

Review Comment:
   Does a MetadatHandler not  of a start/endDocument like an InfosetOutputter 
does?



##########
daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/SequenceTermRuntime1Mixin.scala:
##########
@@ -82,6 +83,7 @@ trait ChoiceBranchImpliedSequenceRuntime1Mixin { self: 
ChoiceBranchImpliedSequen
       FillByteUseNotAllowedEv,
       Maybe.Nope,
       Maybe.Nope,
+      false,

Review Comment:
   Suggest `isHidden = false` like in other places?



##########
daffodil-core/src/test/scala/org/apache/daffodil/core/api/TestMetadataWalking.scala:
##########
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.core.api
+
+import scala.collection.mutable.ArrayBuffer
+import scala.xml.Elem
+
+import org.apache.daffodil.core.util.TestUtils
+import org.apache.daffodil.io.InputSourceDataInputStream
+import org.apache.daffodil.lib.util._
+import org.apache.daffodil.runtime1.api.ChoiceMetadata
+import org.apache.daffodil.runtime1.api.ComplexElementMetadata
+import org.apache.daffodil.runtime1.api.DFDL.ParseResult
+import org.apache.daffodil.runtime1.api.ElementMetadata
+import org.apache.daffodil.runtime1.api.InfosetArray
+import org.apache.daffodil.runtime1.api.InfosetComplexElement
+import org.apache.daffodil.runtime1.api.InfosetElement
+import org.apache.daffodil.runtime1.api.InfosetItem
+import org.apache.daffodil.runtime1.api.InfosetSimpleElement
+import org.apache.daffodil.runtime1.api.Metadata
+import org.apache.daffodil.runtime1.api.MetadataHandler
+import org.apache.daffodil.runtime1.api.SequenceMetadata
+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
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class TestMetadataWalking {
+
+  def compileAndWalkMetadata(schema: Elem, mh: MetadataHandler): DataProcessor 
= {
+    val dp = TestUtils.compileSchema(schema)
+    assertTrue(!dp.isError)
+    dp.walkMetadata(mh)
+    dp
+  }
+
+  def parseAndWalkData(dp: DataProcessor, infosetOutputter: InfosetOutputter)(
+    data: Array[Byte],
+  ): ParseResult = {
+    val isdis = InputSourceDataInputStream(data)
+    val res = dp.parse(isdis, infosetOutputter)
+    res
+  }
+
+  class GatherMetadata extends MetadataHandler {
+
+    private val buf = new ArrayBuffer[Metadata]();
+
+    def getResult: Seq[Metadata] = {
+      val res: Seq[Metadata] = buf.toVector // makes a copy
+      buf.clear()
+      res
+    }
+
+    override def simpleElementMetadata(m: SimpleElementMetadata): Unit = buf 
+= m
+
+    override def startComplexElementMetadata(m: ComplexElementMetadata): Unit 
= buf += m
+
+    override def endComplexElementMetadata(m: ComplexElementMetadata): Unit = 
buf += m
+
+    override def startSequenceMetadata(m: SequenceMetadata): Unit = buf += m
+
+    override def endSequenceMetadata(m: SequenceMetadata): Unit = buf += m
+
+    override def startChoiceMetadata(m: ChoiceMetadata): Unit = buf += m
+
+    override def endChoiceMetadata(m: ChoiceMetadata): Unit = buf += m

Review Comment:
   Do we need `Metadata` in all the names of these functions? Seems 
unnecessarily verbose since we're already in a Metaata handler?



##########
daffodil-japi/src/main/scala/org/apache/daffodil/japi/Daffodil.scala:
##########
@@ -514,6 +515,20 @@ class DataProcessor private[japi] (private var dp: 
SDataProcessor)
    */
   def save(output: WritableByteChannel): Unit = dp.save(output)
 
+  /**
+   * Walks the handler over the runtime 
[[org.apache.daffodil.runtime1.api.Metadata]] structures.
+   * These provide information about name, namespace, type, simple/complex, 
etc.
+   *
+   * This is used to interface Daffodil runtime1 metadata to the metadata 
structures
+   * of other software systems.
+   *
+   * See [[org.apache.daffodil.runtime1.api.MetadataHandler]] for more 
motivating materials about
+   * runtime1 metadata walking.
+   *
+   * @param handler - the handler is called-back during the walk as each 
metadata structure is encountered.
+   */
+  def walkMetadata(handler: MetadataHandler): Unit = dp.walkMetadata(handler)

Review Comment:
   We should implement tests in TestJavaAPI.java to get coverage from this and 
make sure everything is easily accessible using reasonable Java without any 
weird scala-isms.



##########
daffodil-japi/src/main/scala/org/apache/daffodil/japi/infoset/Infoset.scala:
##########
@@ -154,69 +153,69 @@ abstract class InfosetOutputter extends SInfosetOutputter 
{
   /**
    * Called by Daffodil internals to signify the beginning of a simple element.
    *
-   * @param diSimple the simple element that is started. Various fields of
+   * @param simple the simple element that is started. Various fields of
    *                 DISimple can be accessed to determine things like the
    *                 value, nil, name, namespace, etc.
    * @throws Exception if there was an error and Daffodil should stop parsing
    */
 
   @throws[Exception]
-  def startSimple(diSimple: DISimple): Unit
+  def startSimple(simple: InfosetSimpleElement): Unit

Review Comment:
   When we look at java doc, we need to make sure to see what this looks like. 
InfosetSimpleElement and the others are not in the daffodil-japi project, so I 
dont' think will have any java doc associated with them. Maybe we should 
consider options to make that available? I really don't like our the proxy 
kinof thing we've been doing in past, I'm not sure if there are other 
alternatives though.



##########
daffodil-japi/src/main/scala/org/apache/daffodil/japi/infoset/Infoset.scala:
##########
@@ -154,69 +153,69 @@ abstract class InfosetOutputter extends SInfosetOutputter 
{
   /**
    * Called by Daffodil internals to signify the beginning of a simple element.
    *
-   * @param diSimple the simple element that is started. Various fields of
+   * @param simple the simple element that is started. Various fields of
    *                 DISimple can be accessed to determine things like the
    *                 value, nil, name, namespace, etc.
    * @throws Exception if there was an error and Daffodil should stop parsing
    */
 
   @throws[Exception]
-  def startSimple(diSimple: DISimple): Unit
+  def startSimple(simple: InfosetSimpleElement): Unit
 
   /**
    * Called by Daffodil internals to signify the end of a simple element.
    *
-   * @param diSimple the simple element that is ended. Various fields of
+   * @param simple the simple element that is ended. Various fields of
    *                 DISimple can be accessed to determine things like the
    *                 value, nil, name, namespace, etc.
    * @throws Exception if there was an error and Daffodil should stop parsing
    */
   @throws[Exception]
-  def endSimple(diSimple: DISimple): Unit
+  def endSimple(simple: InfosetSimpleElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of a complex 
element.
    *
-   * @param diComplex the complex element that is started. Various fields of
+   * @param complex the complex element that is started. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    * @throws Exception if there was an error and Daffodil should stop parsing
    */
   @throws[Exception]
-  def startComplex(diComplex: DIComplex): Unit
+  def startComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the end of a complex element.
    *
-   * @param diComplex the complex element that is ended. Various fields of
+   * @param complex the complex element that is ended. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    * @throws Exception if there was an error and Daffodil should stop parsing
    */
   @throws[Exception]
-  def endComplex(diComplex: DIComplex): Unit
+  def endComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of an array of 
elements.
    *
-   * @param diArray the array that is started. Various fields of
+   * @param array the array that is started. Various fields of
    *                DIArray can be accessed to determine things like the
    *                name, namespace, etc.
    * @throws Exception if there was an error and Daffodil should stop parsing
    */
   @throws[Exception]
-  def startArray(diArray: DIArray): Unit
+  def startArray(array: InfosetArray): Unit
 
   /**
    * Called by Daffodil internals to signify the end of an array of elements.
    *
-   * @param diArray the array that is ended. Various fields of
+   * @param array the array that is ended. Various fields of
    *                DIArray can be accessed to determine things like the
    *                name, namespace, etc.
    * @throws Exception if there was an error and Daffodil should stop parsing
    */
   @throws[Exception]
-  def endArray(diArray: DIArray): Unit
+  def endArray(array: InfosetArray): Unit

Review Comment:
   This is all a pretty big backwards-icompabitle change. Maybe that's fine and 
will just be another thing that warrants the next version being 4.0.0.
   
   We could maybe do somthing where this API has both variants of functions, 
and the new one calls the old one, e.g.
   ```scala
   def endArray(diArray: DIArray): Unit
   def endArray(array: InfosetAray): Unit = 
endArray(array.asInstanceOf[DIArray])
   ```
   This way old infoset outputters still work, but new infoset ouputters can be 
written with the new API. Not sure the extra complication is worth it, 
especially if we go to 4.0.0.
   
   We should add a `Deprecation/Compatibility` section to the commit message 
though so we remember to mention this in the release notes.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import com.ibm.icu.util.Calendar
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+
+  /**
+   * @return the metadata of the element that is an array
+   */
+  override def metadata: ElementMetadata
+
+  /**
+   * @return the number of items in the array.
+   */
+  def length: Long
+
+  /**
+   * Access to an infoset element of the array.
+   * @param occursIndex1b the one-based index of the element to be accessed
+   * @return the infoset element located at the given index
+   */
+  def apply(occursIndex1b: Long): InfosetElement
+}
+
+/**
+ * API access to elements of the DFDL Infoset of both
+ * complex and simple type.
+ */
+trait InfosetElement extends InfosetItem {
+
+  /**
+   * In DFDL both simple and complex type elements can be
+   * nilled.
+   *
+   * @return true if the element is nilled, false otherwise.
+   */
+  def isNilled: Boolean
+
+  /**
+   * @return true if the element is a string or hexBinary of length 0, false 
otherwise.

Review Comment:
   Seems an odd special case to support. Can't the user just get the string or 
byte array and ask if that is empty? What are the cases where users would even 
care if they are empty? For example, empty string often isn't a special case.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import com.ibm.icu.util.Calendar
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+
+  /**
+   * @return the metadata of the element that is an array
+   */
+  override def metadata: ElementMetadata
+
+  /**
+   * @return the number of items in the array.
+   */
+  def length: Long
+
+  /**
+   * Access to an infoset element of the array.
+   * @param occursIndex1b the one-based index of the element to be accessed
+   * @return the infoset element located at the given index
+   */
+  def apply(occursIndex1b: Long): InfosetElement

Review Comment:
   What are array `length` add `apply` used for? My concern is when an 
`InfosetWalker` walks an array, the full length might not be known at that 
time. I don't remember if we wait for an array to be completely finished before 
walking into it (I would guess we don't?), but if we don't this could cause 
weird behavior. Can we get away with removing these?



##########
daffodil-japi/src/test/java/org/apache/daffodil/example/TestInfosetOutputter.java:
##########
@@ -51,45 +50,50 @@ public void endDocument() {
     }
 
     @Override
-    public void startSimple(DISimple diSimple) {
+    public void startSimple(InfosetSimpleElement diSimple) {
         events.add(
             TestInfosetEvent.startSimple(
-                diSimple.erd().name(),
-                diSimple.erd().namedQName().namespace().toString(),
+                diSimple.metadata().name(),
+                diSimple.metadata().namespace(),
                 diSimple.dataValueAsString(),
-                diSimple.erd().isNillable() ? diSimple.isNilled() : null));
+                diSimple.metadata().isNillable() ? diSimple.isNilled() : 
null));
     }
 
     @Override
-    public void endSimple(DISimple diSimple) {
+    public void endSimple(InfosetSimpleElement diSimple) {
         events.add(
             TestInfosetEvent.endSimple(
-                diSimple.erd().name(),
-                diSimple.erd().namedQName().namespace().toString()));
+                diSimple.metadata().name(),
+                diSimple.metadata().namespace()));
     }
 
     @Override
-    public void startComplex(DIComplex diComplex) {
+    public void startComplex(InfosetComplexElement complex) {
         events.add(
             TestInfosetEvent.startComplex(
-                diComplex.erd().name(),
-                diComplex.erd().namedQName().namespace().toString(),
-                diComplex.erd().isNillable() ? diComplex.isNilled() : null));
+                complex.metadata().name(),
+                complex.metadata().namespace(),
+                complex.metadata().isNillable() ? complex.isNilled() : null));

Review Comment:
   Unrlated to this PR, but do you know if we must call `isNillabled` before 
asking `isNilled`? Seems odd if so. It would be nice if isNilled just returns 
false if something isn't nillable. But maybe this test infoset outputter just 
doing something fancy and wants differentiable nillable but not nil vs not 
nillable.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import com.ibm.icu.util.Calendar
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+
+  /**
+   * @return the metadata of the element that is an array
+   */
+  override def metadata: ElementMetadata
+
+  /**
+   * @return the number of items in the array.
+   */
+  def length: Long
+
+  /**
+   * Access to an infoset element of the array.
+   * @param occursIndex1b the one-based index of the element to be accessed
+   * @return the infoset element located at the given index
+   */
+  def apply(occursIndex1b: Long): InfosetElement
+}
+
+/**
+ * API access to elements of the DFDL Infoset of both
+ * complex and simple type.
+ */
+trait InfosetElement extends InfosetItem {
+
+  /**
+   * In DFDL both simple and complex type elements can be
+   * nilled.
+   *
+   * @return true if the element is nilled, false otherwise.
+   */
+  def isNilled: Boolean
+
+  /**
+   * @return true if the element is a string or hexBinary of length 0, false 
otherwise.
+   */
+  def isEmpty: Boolean
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ElementMetadata]]
+   */
+  def metadata: ElementMetadata
+
+}
+
+/**
+ * Methods specific complex elements in the infoset
+ */
+trait InfosetComplexElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ComplexElementMetadata]]
+   */
+  override def metadata: ComplexElementMetadata
+}
+
+/**
+ * Methods specific to simple elements in the infoset
+ */
+trait InfosetSimpleElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[SimpleElementMetadata]]
+   */
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * @return true if the element has a value, false for a nilled element.
+   */
+  def hasValue: Boolean

Review Comment:
   How is this different from the `isNilled` method inherited from 
`InfosetElement`. Seems if isNilled is false, then the element must have a 
value. Can we drop this to simplify the API?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import com.ibm.icu.util.Calendar
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+
+  /**
+   * @return the metadata of the element that is an array
+   */
+  override def metadata: ElementMetadata
+
+  /**
+   * @return the number of items in the array.
+   */
+  def length: Long
+
+  /**
+   * Access to an infoset element of the array.
+   * @param occursIndex1b the one-based index of the element to be accessed
+   * @return the infoset element located at the given index
+   */
+  def apply(occursIndex1b: Long): InfosetElement
+}
+
+/**
+ * API access to elements of the DFDL Infoset of both
+ * complex and simple type.
+ */
+trait InfosetElement extends InfosetItem {
+
+  /**
+   * In DFDL both simple and complex type elements can be
+   * nilled.
+   *
+   * @return true if the element is nilled, false otherwise.
+   */
+  def isNilled: Boolean
+
+  /**
+   * @return true if the element is a string or hexBinary of length 0, false 
otherwise.
+   */
+  def isEmpty: Boolean
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ElementMetadata]]
+   */
+  def metadata: ElementMetadata
+
+}
+
+/**
+ * Methods specific complex elements in the infoset
+ */
+trait InfosetComplexElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ComplexElementMetadata]]
+   */
+  override def metadata: ComplexElementMetadata
+}
+
+/**
+ * Methods specific to simple elements in the infoset
+ */
+trait InfosetSimpleElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[SimpleElementMetadata]]
+   */
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * @return true if the element has a value, false for a nilled element.
+   */
+  def hasValue: Boolean
+
+  /**
+   * Obtains the value, then converts it to a string.
+   * Caches the string so we're not allocating strings repeatedly
+   */
+  def dataValueAsString: String

Review Comment:
   Thoughts on something like `getText` instead? This follows the `getXYZ` 
convention of the other functions, but maybe makes it clear that it is getting 
a textual representation of the underlying value?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import com.ibm.icu.util.Calendar
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+
+  /**
+   * @return the metadata of the element that is an array
+   */
+  override def metadata: ElementMetadata
+
+  /**
+   * @return the number of items in the array.
+   */
+  def length: Long
+
+  /**
+   * Access to an infoset element of the array.
+   * @param occursIndex1b the one-based index of the element to be accessed
+   * @return the infoset element located at the given index
+   */
+  def apply(occursIndex1b: Long): InfosetElement
+}
+
+/**
+ * API access to elements of the DFDL Infoset of both
+ * complex and simple type.
+ */
+trait InfosetElement extends InfosetItem {
+
+  /**
+   * In DFDL both simple and complex type elements can be
+   * nilled.
+   *
+   * @return true if the element is nilled, false otherwise.
+   */
+  def isNilled: Boolean
+
+  /**
+   * @return true if the element is a string or hexBinary of length 0, false 
otherwise.
+   */
+  def isEmpty: Boolean
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ElementMetadata]]
+   */
+  def metadata: ElementMetadata
+
+}
+
+/**
+ * Methods specific complex elements in the infoset
+ */
+trait InfosetComplexElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ComplexElementMetadata]]
+   */
+  override def metadata: ComplexElementMetadata
+}
+
+/**
+ * Methods specific to simple elements in the infoset
+ */
+trait InfosetSimpleElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[SimpleElementMetadata]]
+   */
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * @return true if the element has a value, false for a nilled element.
+   */
+  def hasValue: Boolean
+
+  /**
+   * Obtains the value, then converts it to a string.
+   * Caches the string so we're not allocating strings repeatedly
+   */
+  def dataValueAsString: String
+
+  /*
+   * These are so that API users don't have to know about our
+   * very Scala-oriented DataValue type system.
+   */
+
+  /**
+   * @return the value of this simple element as a Scala AnyRef, which is
+   *         equivalent to a Java Object.
+   */
+  def getAnyRef: AnyRef
+
+  /**
+   * @return the value of this simple element as an Object (java.lang.Object),
+   *         which is equivalent to Scala AnyRef.
+   */
+  final def getObject: java.lang.Object = getAnyRef
+
+  // Note: I could not get @throws in scaladoc to work right.
+  // Complains "Could not find any member to link for ... and I tried various 
formulations of
+  // ClassCastException, with package, with and without [[..]].
+  // So I've just converted it to plain text.
+
+  /**
+   * @return Casts the value of this simple element as a java.math.BigDecimal.
+   * <p/>throws `ClassCastException` if the element value is not of type 
Decimal.
+   */
+  def getBigDecimal: JBigDecimal
+
+  /**
+   * @return Casts the value of this Date, Time, or DateTime simple element as 
a
+   *         `com.ibm.icu.util.Calendar`
+   * <p/>throws `ClassCastException` if the element value is not of type Date, 
Time, or DateTime
+   */
+  def getCalendar: Calendar
+
+  /**
+   * @return the value of this simple element cast to 
`com.ibm.icu.util.Calendar`.
+   * <p/>throws `ClassCastException` if the element value is not of the 
required type.
+   */
+  def getDate: Calendar
+
+  /**
+   * @return the value of this simple element cast to 
`com.ibm.icu.util.Calendar`.
+   * <p/>throws `ClassCastException` if the element value is not of the 
required type.
+   */
+  def getTime: Calendar
+
+  /**
+   * @return the value of this simple element cast to 
`com.ibm.icu.util.Calendar`.
+   * <p/>throws `ClassCastException` if the element value is not of the 
required type.
+   */
+  def getDateTime: Calendar
+
+  /**
+   * @return the value of this simple element of HexBinary type cast to 
`Array[Byte]`.
+   * <p/>throws `ClassCastException` if the element value is not of HexBinary 
type.
+   */
+  def getByteArray: Array[Byte]
+
+  /**
+   * @return the value of this simple element of Boolean type cast to 
java.lang.Boolean.
+   * <p/>throws `ClassCastException` if the element value is not of Boolean 
type.
+   */
+  def getBoolean: JBoolean
+
+  /**
+   * @return the value of this simple element of numeric type cast to 
java.lang.Number.
+   * <p/>throws `ClassCastException` if the element value is not of numeric 
type.
+   */
+  def getNumber: JNumber

Review Comment:
   Suggest we remove getNumber? The only useful functions provided by Number 
ways to get the number as a byte, short, int, long, float, or double. 
Presumably users are going to need to know which type of number they need 
anyways and call the right getXZY function?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.daffodil.runtime1.api
+
+import scala.xml.NamespaceBinding
+
+/**
+ * This is the supportable API for access to the RuntimeData structures
+ * which provide access to static information about a given .
+ *
+ * This is used to interface other data processing fabrics to Daffodil
+ * data and metadata, by mapping to/from these metadata objects.
+ */
+trait Metadata {
+
+  /**
+   * Provides the file context of a metadata component. This refers to the 
specific
+   * DFDL schema file where the corresponding DFDL schema text resides 
corresponding
+   * to this metadata object.
+   * <p/>
+   * This is for use in diagnostic messaging. It is not the actual file URI, 
because
+   * those may contain personal-identifying information about the 
person/acccount and
+   * system that compiled the schema. It will provide enough content about the 
file URI that
+   * a user will be able to identify which file, but some prefix of the path
+   * components trimmed to make it of a manageable length.
+   * <p/>
+   * Used along with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]]
+   * and 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineColumnNumber]],
+   * this can give a precise location in the DFDL schema file.
+   * @return a string containing the file information, or null if unknown.
+   */
+  def schemaFileInfo: String
+
+  /**
+   * Provides the line number to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileInfo]].
+   * @return the line number as a string, or null if unknown.
+   */
+  def schemaFileLineNumber: String
+
+  /**
+   * Provides the column number within the text line, to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]].
+   * @return the column number within the text line, as a string, or null if 
unknown.
+   */
+  def schemaFileLineColumnNumber: String
+
+  /**
+   * The name of the schema component, in a form suitable for diagnostic 
messages.
+   * Unnamed components like sequence or choice groups have a 
diagnosticDebugName, despite not having
+   * any actual name.
+   * @return the name of the component, suitable for use in diagnostic 
messages.
+   */
+  def diagnosticDebugName: String
+
+  /**
+   * The standard conversion of the metadata component to a string.
+   * Unless overridden this uses the 
[[org.apache.daffodil.runtime1.api.Metadata.diagnosticDebugName]].
+   * @return string representation of this metadata component.
+   */
+  override def toString = diagnosticDebugName
+}
+
+/*
+ * Provides metadata access that is common to all Terms, which include
+ * Elements of simple or complex type, as well as the Sequence and Choice 
groups.
+ */
+trait TermMetadata extends Metadata {
+  // nothing here
+}
+
+/**
+ * Common metadata access for all elements, of simple or complex type.
+ */
+trait ElementMetadata extends TermMetadata {
+
+  /**
+   * @return the name of this element. In the case of a global/qualified name, 
this is only the local
+   *         part of the QName.
+   */
+  def name: String
+
+  /**
+   * @return the namespace URI as a string, or null if no namespace.
+   */
+  def namespace: String
+
+  /**
+   * @return the namespace bindings needed to construct an XML element from a 
Daffodil infoset
+   *         element of simple or complex type.
+   */
+  def minimizedScope: NamespaceBinding
+
+  /**
+   * @return the namespace prefix part of the XML QName of this component, or 
null if there
+   *         is no prefix defined or no namespace.
+   */
+  def prefix: String
+
+  /**
+   *  @return true if two or more occurrences are possible.
+   *          Note that having only 0 or 1 occurrence is not considered an 
array,
+   *          but rather an optional element.
+   */
+  def isArray: Boolean
+
+  /**
+   * @return true if only 0 or 1 occurrence are possible.
+   */
+  def isOptional: Boolean
+
+  /**
+   * @return the QName string for this element.
+   */
+  def toQName: String
+
+  /**
+   * @return true if the element is declared to be nillable.
+   */
+  def isNillable: Boolean
+
+  /**
+   * Provides access to the runtime properties. This is an extended collection 
of
+   * name-value pairs which are associated with a schema component.
+   * <p/>
+   * Runtime properties are intended to use for new ad-hoc property extensions 
to
+   * DFDL. These name-value pairs are visible to infoset outputters as well.
+   *
+   * @return a java-compatible map of name-value pairs.
+   */
+  def runtimeProperties: java.util.Map[String, String]
+
+}
+
+/**
+ * Access to metadata values exclusive to elements of complex type.
+ */
+trait ComplexElementMetadata extends ElementMetadata {
+
+  /**
+   * @return an ordered sequence of the child elements within this complex 
type regardless
+   *         of their nesting within sequence and choice groups.
+   */
+  def childMetadata: Seq[ElementMetadata]
+}
+
+/**
+ * Access to metadata values exclusive to elements of simple type.
+ */
+trait SimpleElementMetadata extends ElementMetadata {
+
+  /**
+   * The primitive type of this element as a string.
+   *
+   * @return one of boolean, double, float, date, time, dateTime, string, 
anyURI, hexBinary, decimal,
+   *         integer, nonNegativeInteger, byte, short, int, long, 
unsignedByte, unsignedShort,
+   *         unsignedInt, unsignedLong as a string. Note the initial 
lower-case letter in all these
+   *         type names.
+   */
+  def primTypeName: String

Review Comment:
   Why not use a enum for this? If java it would allow you to swich on it since 
you can't switch on a string. I think it would also give warnings if a 
match/case didn't cover all enum values. Maybe it's a bit annoying to convert 
from the internal primType objects to enum values?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Infoset.scala:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.api
+
+import java.lang.{ Boolean => JBoolean }
+import java.lang.{ Byte => JByte }
+import java.lang.{ Double => JDouble }
+import java.lang.{ Float => JFloat }
+import java.lang.{ Integer => JInt }
+import java.lang.{ Long => JLong }
+import java.lang.{ Number => JNumber }
+import java.lang.{ Short => JShort }
+import java.lang.{ String => JString }
+import java.math.{ BigDecimal => JBigDecimal }
+import java.math.{ BigInteger => JBigInt }
+import java.net.URI
+
+import com.ibm.icu.util.Calendar
+
+/**
+ * API access to array objects in the DFDL Infoset
+ */
+trait InfosetArray extends InfosetItem {
+
+  /**
+   * @return the metadata of the element that is an array
+   */
+  override def metadata: ElementMetadata
+
+  /**
+   * @return the number of items in the array.
+   */
+  def length: Long
+
+  /**
+   * Access to an infoset element of the array.
+   * @param occursIndex1b the one-based index of the element to be accessed
+   * @return the infoset element located at the given index
+   */
+  def apply(occursIndex1b: Long): InfosetElement
+}
+
+/**
+ * API access to elements of the DFDL Infoset of both
+ * complex and simple type.
+ */
+trait InfosetElement extends InfosetItem {
+
+  /**
+   * In DFDL both simple and complex type elements can be
+   * nilled.
+   *
+   * @return true if the element is nilled, false otherwise.
+   */
+  def isNilled: Boolean
+
+  /**
+   * @return true if the element is a string or hexBinary of length 0, false 
otherwise.
+   */
+  def isEmpty: Boolean
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ElementMetadata]]
+   */
+  def metadata: ElementMetadata
+
+}
+
+/**
+ * Methods specific complex elements in the infoset
+ */
+trait InfosetComplexElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[ComplexElementMetadata]]
+   */
+  override def metadata: ComplexElementMetadata
+}
+
+/**
+ * Methods specific to simple elements in the infoset
+ */
+trait InfosetSimpleElement extends InfosetElement {
+
+  /*
+   * Access to the metadata information about this element.
+   * See [[SimpleElementMetadata]]
+   */
+  override def metadata: SimpleElementMetadata
+
+  /**
+   * @return true if the element has a value, false for a nilled element.
+   */
+  def hasValue: Boolean
+
+  /**
+   * Obtains the value, then converts it to a string.
+   * Caches the string so we're not allocating strings repeatedly
+   */
+  def dataValueAsString: String
+
+  /*
+   * These are so that API users don't have to know about our
+   * very Scala-oriented DataValue type system.
+   */
+
+  /**
+   * @return the value of this simple element as a Scala AnyRef, which is
+   *         equivalent to a Java Object.
+   */
+  def getAnyRef: AnyRef
+
+  /**
+   * @return the value of this simple element as an Object (java.lang.Object),
+   *         which is equivalent to Scala AnyRef.
+   */
+  final def getObject: java.lang.Object = getAnyRef
+
+  // Note: I could not get @throws in scaladoc to work right.
+  // Complains "Could not find any member to link for ... and I tried various 
formulations of
+  // ClassCastException, with package, with and without [[..]].
+  // So I've just converted it to plain text.
+
+  /**
+   * @return Casts the value of this simple element as a java.math.BigDecimal.
+   * <p/>throws `ClassCastException` if the element value is not of type 
Decimal.
+   */
+  def getBigDecimal: JBigDecimal

Review Comment:
   A thought about all these getXYZ function is that they sortof leak internal 
implementation details and require infoset outputter implementations to know 
how daffodil internally represents the primitive types.
   
   For example, if `metadata.primTypeName` returns `unsignedInt`, then infoset 
outputters need to know to use `getLong` since we implement `unsignedInt` as a 
`Long`. It also means we can't easily change thing in the future. For example, 
maybe one day we decide to implement all signed integergs (byte, short, int, 
long) as `Long`s to simply things. That change would then leak into infoset 
walkers and potentially break them
   
   I'm not sure of a good way to deal with this though. Maybe the primTypeName 
returns the underlying type? That would mean primTypeNames would never have 
unsigned types, since Java has no concept of that.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala:
##########
@@ -1575,9 +1617,12 @@ sealed class DIComplex(override val erd: 
ElementRuntimeData)
   with DIComplexSharedImplMixin
   with InfosetComplexElement { diComplex =>
 
+  override def metadata: ComplexElementMetadata = erd
+
   final override def isSimple = false
   final override def isComplex = true
   final override def isArray = false
+  // final override def optArray: Option[DIArray] = None

Review Comment:
   Delete comment?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.daffodil.runtime1.api
+
+import scala.xml.NamespaceBinding
+
+/**
+ * This is the supportable API for access to the RuntimeData structures
+ * which provide access to static information about a given .
+ *
+ * This is used to interface other data processing fabrics to Daffodil
+ * data and metadata, by mapping to/from these metadata objects.
+ */
+trait Metadata {
+
+  /**
+   * Provides the file context of a metadata component. This refers to the 
specific
+   * DFDL schema file where the corresponding DFDL schema text resides 
corresponding
+   * to this metadata object.
+   * <p/>
+   * This is for use in diagnostic messaging. It is not the actual file URI, 
because
+   * those may contain personal-identifying information about the 
person/acccount and
+   * system that compiled the schema. It will provide enough content about the 
file URI that
+   * a user will be able to identify which file, but some prefix of the path
+   * components trimmed to make it of a manageable length.
+   * <p/>
+   * Used along with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]]
+   * and 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineColumnNumber]],
+   * this can give a precise location in the DFDL schema file.
+   * @return a string containing the file information, or null if unknown.
+   */
+  def schemaFileInfo: String
+
+  /**
+   * Provides the line number to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileInfo]].
+   * @return the line number as a string, or null if unknown.
+   */
+  def schemaFileLineNumber: String
+
+  /**
+   * Provides the column number within the text line, to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]].
+   * @return the column number within the text line, as a string, or null if 
unknown.
+   */
+  def schemaFileLineColumnNumber: String
+
+  /**
+   * The name of the schema component, in a form suitable for diagnostic 
messages.
+   * Unnamed components like sequence or choice groups have a 
diagnosticDebugName, despite not having
+   * any actual name.
+   * @return the name of the component, suitable for use in diagnostic 
messages.
+   */
+  def diagnosticDebugName: String
+
+  /**
+   * The standard conversion of the metadata component to a string.
+   * Unless overridden this uses the 
[[org.apache.daffodil.runtime1.api.Metadata.diagnosticDebugName]].
+   * @return string representation of this metadata component.
+   */
+  override def toString = diagnosticDebugName
+}
+
+/*
+ * Provides metadata access that is common to all Terms, which include
+ * Elements of simple or complex type, as well as the Sequence and Choice 
groups.
+ */
+trait TermMetadata extends Metadata {
+  // nothing here
+}
+
+/**
+ * Common metadata access for all elements, of simple or complex type.
+ */
+trait ElementMetadata extends TermMetadata {
+
+  /**
+   * @return the name of this element. In the case of a global/qualified name, 
this is only the local
+   *         part of the QName.
+   */
+  def name: String
+
+  /**
+   * @return the namespace URI as a string, or null if no namespace.
+   */
+  def namespace: String
+
+  /**
+   * @return the namespace bindings needed to construct an XML element from a 
Daffodil infoset
+   *         element of simple or complex type.
+   */
+  def minimizedScope: NamespaceBinding
+
+  /**
+   * @return the namespace prefix part of the XML QName of this component, or 
null if there
+   *         is no prefix defined or no namespace.
+   */
+  def prefix: String
+
+  /**
+   *  @return true if two or more occurrences are possible.
+   *          Note that having only 0 or 1 occurrence is not considered an 
array,
+   *          but rather an optional element.
+   */
+  def isArray: Boolean
+
+  /**
+   * @return true if only 0 or 1 occurrence are possible.
+   */
+  def isOptional: Boolean
+
+  /**
+   * @return the QName string for this element.
+   */
+  def toQName: String
+
+  /**
+   * @return true if the element is declared to be nillable.
+   */
+  def isNillable: Boolean
+
+  /**
+   * Provides access to the runtime properties. This is an extended collection 
of
+   * name-value pairs which are associated with a schema component.
+   * <p/>
+   * Runtime properties are intended to use for new ad-hoc property extensions 
to
+   * DFDL. These name-value pairs are visible to infoset outputters as well.
+   *
+   * @return a java-compatible map of name-value pairs.
+   */
+  def runtimeProperties: java.util.Map[String, String]
+
+}
+
+/**
+ * Access to metadata values exclusive to elements of complex type.
+ */
+trait ComplexElementMetadata extends ElementMetadata {
+
+  /**
+   * @return an ordered sequence of the child elements within this complex 
type regardless
+   *         of their nesting within sequence and choice groups.
+   */
+  def childMetadata: Seq[ElementMetadata]
+}
+
+/**
+ * Access to metadata values exclusive to elements of simple type.
+ */
+trait SimpleElementMetadata extends ElementMetadata {
+
+  /**
+   * The primitive type of this element as a string.
+   *
+   * @return one of boolean, double, float, date, time, dateTime, string, 
anyURI, hexBinary, decimal,
+   *         integer, nonNegativeInteger, byte, short, int, long, 
unsignedByte, unsignedShort,
+   *         unsignedInt, unsignedLong as a string. Note the initial 
lower-case letter in all these
+   *         type names.
+   */
+  def primTypeName: String
+}
+
+/**
+ * Access to metadata values shared by both sequences and choices
+ * which are known collectively as Model Groups.
+ */
+trait ModelGroupMetadata extends TermMetadata {}

Review Comment:
   Should ModelGroupMetaData include childMetadata like we do with complex 
elements?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala:
##########
@@ -84,75 +85,98 @@ trait InfosetOutputter {
    *                 value, nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endSimple(diSimple: DISimple): Unit
+  def endSimple(diSimple: InfosetSimpleElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of a complex 
element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is started. Various fields of
+   * @param complex the complex element that is started. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def startComplex(diComplex: DIComplex): Unit
+  def startComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the end of a complex element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is ended. Various fields of
+   * @param complex the complex element that is ended. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endComplex(diComplex: DIComplex): Unit
+  def endComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of an array of 
elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is started. Various fields of
+   * @param array the array that is started. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def startArray(diArray: DIArray): Unit
+  def startArray(array: InfosetArray): Unit
 
   /**
    * Called by Daffodil internals to signify the end of an array of elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is ended. Various fields of
+   * @param array the array that is ended. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def endArray(diArray: DIArray): Unit
+  def endArray(array: InfosetArray): Unit
 
-  def getStatus(): Status = {
-    // Done, Ready (Not started), Visiting (part way done - can retry to visit 
more)...
-    status
-  }
+  def getStatus(): Status
 
   /**
-   * Helper function to determine if an element is nilled or not, taking into
-   * account whether or not the nilled state has been set yet.
+   * 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.
    *
-   * @param diElement the element to check the nilled state of
+   * This saves the user of the API from having to wrap try/catch around their
+   * start/end method bodies.

Review Comment:
   Personally, I'm not really a huge fan of this. As annoying as wrapping 
function in try/catch blocks is, it's kindof the way it's done. And really, 
users should be handling exceptions individually instead of wrapping an entire 
function. That's probably bad practice.
   
   I'm also wondering if it many cases it's even too late to do anything about 
it and debugging wouldn't be that useful. The code and variables where the 
exception was thrown are out of scope, so important information might be lost. 
If an exception is thrown, it seems the best course of action is to look at the 
stack trace and point a breakpoint in the right spot. If our SDE isn't making 
that stacktrace available, maybe we should do that instead?
   
   That said, if we do keep this, we need to specify what a user should do with 
this exception in this funtion. In most cases most cases that's should probably 
be nothing. But I also assume they shouldn't rethrow or do anything that might 
cause another exception to be thrown, not sure if we handle that case.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.daffodil.runtime1.api
+
+import scala.xml.NamespaceBinding
+
+/**
+ * This is the supportable API for access to the RuntimeData structures
+ * which provide access to static information about a given .
+ *
+ * This is used to interface other data processing fabrics to Daffodil
+ * data and metadata, by mapping to/from these metadata objects.
+ */
+trait Metadata {
+
+  /**
+   * Provides the file context of a metadata component. This refers to the 
specific
+   * DFDL schema file where the corresponding DFDL schema text resides 
corresponding
+   * to this metadata object.
+   * <p/>
+   * This is for use in diagnostic messaging. It is not the actual file URI, 
because
+   * those may contain personal-identifying information about the 
person/acccount and
+   * system that compiled the schema. It will provide enough content about the 
file URI that
+   * a user will be able to identify which file, but some prefix of the path
+   * components trimmed to make it of a manageable length.
+   * <p/>
+   * Used along with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]]
+   * and 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineColumnNumber]],
+   * this can give a precise location in the DFDL schema file.
+   * @return a string containing the file information, or null if unknown.
+   */
+  def schemaFileInfo: String
+
+  /**
+   * Provides the line number to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileInfo]].
+   * @return the line number as a string, or null if unknown.
+   */
+  def schemaFileLineNumber: String
+
+  /**
+   * Provides the column number within the text line, to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]].
+   * @return the column number within the text line, as a string, or null if 
unknown.
+   */
+  def schemaFileLineColumnNumber: String
+
+  /**
+   * The name of the schema component, in a form suitable for diagnostic 
messages.
+   * Unnamed components like sequence or choice groups have a 
diagnosticDebugName, despite not having
+   * any actual name.
+   * @return the name of the component, suitable for use in diagnostic 
messages.
+   */
+  def diagnosticDebugName: String
+
+  /**
+   * The standard conversion of the metadata component to a string.
+   * Unless overridden this uses the 
[[org.apache.daffodil.runtime1.api.Metadata.diagnosticDebugName]].
+   * @return string representation of this metadata component.
+   */
+  override def toString = diagnosticDebugName
+}
+
+/*
+ * Provides metadata access that is common to all Terms, which include
+ * Elements of simple or complex type, as well as the Sequence and Choice 
groups.
+ */
+trait TermMetadata extends Metadata {
+  // nothing here
+}
+
+/**
+ * Common metadata access for all elements, of simple or complex type.
+ */
+trait ElementMetadata extends TermMetadata {
+
+  /**
+   * @return the name of this element. In the case of a global/qualified name, 
this is only the local
+   *         part of the QName.
+   */
+  def name: String
+
+  /**
+   * @return the namespace URI as a string, or null if no namespace.
+   */
+  def namespace: String
+
+  /**
+   * @return the namespace bindings needed to construct an XML element from a 
Daffodil infoset
+   *         element of simple or complex type.
+   */
+  def minimizedScope: NamespaceBinding
+
+  /**
+   * @return the namespace prefix part of the XML QName of this component, or 
null if there
+   *         is no prefix defined or no namespace.
+   */
+  def prefix: String
+
+  /**
+   *  @return true if two or more occurrences are possible.
+   *          Note that having only 0 or 1 occurrence is not considered an 
array,
+   *          but rather an optional element.
+   */
+  def isArray: Boolean
+
+  /**
+   * @return true if only 0 or 1 occurrence are possible.
+   */
+  def isOptional: Boolean
+
+  /**
+   * @return the QName string for this element.
+   */
+  def toQName: String
+
+  /**
+   * @return true if the element is declared to be nillable.
+   */
+  def isNillable: Boolean
+
+  /**
+   * Provides access to the runtime properties. This is an extended collection 
of
+   * name-value pairs which are associated with a schema component.
+   * <p/>
+   * Runtime properties are intended to use for new ad-hoc property extensions 
to
+   * DFDL. These name-value pairs are visible to infoset outputters as well.
+   *
+   * @return a java-compatible map of name-value pairs.
+   */
+  def runtimeProperties: java.util.Map[String, String]
+
+}
+
+/**
+ * Access to metadata values exclusive to elements of complex type.
+ */
+trait ComplexElementMetadata extends ElementMetadata {
+
+  /**
+   * @return an ordered sequence of the child elements within this complex 
type regardless
+   *         of their nesting within sequence and choice groups.
+   */
+  def childMetadata: Seq[ElementMetadata]

Review Comment:
   Why does this not include sequence and choice metadata? If we're granted 
access to children, it seems important to also grant access to know if those 
children are in hidden sequences or are in choices/unions. Personally I would 
prefere it we didn't grant child access at all.
   
   Can the use case of a docRoot having one complex repeating child not be 
figured out using the walker?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala:
##########
@@ -84,75 +85,98 @@ trait InfosetOutputter {
    *                 value, nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endSimple(diSimple: DISimple): Unit
+  def endSimple(diSimple: InfosetSimpleElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of a complex 
element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is started. Various fields of
+   * @param complex the complex element that is started. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def startComplex(diComplex: DIComplex): Unit
+  def startComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the end of a complex element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is ended. Various fields of
+   * @param complex the complex element that is ended. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endComplex(diComplex: DIComplex): Unit
+  def endComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of an array of 
elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is started. Various fields of
+   * @param array the array that is started. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def startArray(diArray: DIArray): Unit
+  def startArray(array: InfosetArray): Unit
 
   /**
    * Called by Daffodil internals to signify the end of an array of elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is ended. Various fields of
+   * @param array the array that is ended. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def endArray(diArray: DIArray): Unit
+  def endArray(array: InfosetArray): Unit
 
-  def getStatus(): Status = {
-    // Done, Ready (Not started), Visiting (part way done - can retry to visit 
more)...
-    status
-  }
+  def getStatus(): Status
 
   /**
-   * Helper function to determine if an element is nilled or not, taking into
-   * account whether or not the nilled state has been set yet.
+   * 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.
    *
-   * @param diElement the element to check the nilled state of
+   * This saves the user of the API from having to wrap try/catch around their
+   * start/end method bodies.
    *
-   * @return true if the nilled state has been set and is true. false if the
-   *         nilled state is false or if the nilled state has not been set yet
-   *         (e.g. during debugging)
+   * @param e the exception thrown by one of the other methods.
    */
-  final def isNilled(diElement: DIElement): Boolean = {
-    val maybeIsNilled = diElement.maybeIsNilled
-    maybeIsNilled.isDefined && maybeIsNilled.get == true
-  }
+  def exceptionOccurred(e: Exception): Unit

Review Comment:
   Sould this have a default implementation of `{}` so that infoset outputters 
aren't forced to implement it?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/api/Metadata.scala:
##########
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.daffodil.runtime1.api
+
+import scala.xml.NamespaceBinding
+
+/**
+ * This is the supportable API for access to the RuntimeData structures
+ * which provide access to static information about a given .
+ *
+ * This is used to interface other data processing fabrics to Daffodil
+ * data and metadata, by mapping to/from these metadata objects.
+ */
+trait Metadata {
+
+  /**
+   * Provides the file context of a metadata component. This refers to the 
specific
+   * DFDL schema file where the corresponding DFDL schema text resides 
corresponding
+   * to this metadata object.
+   * <p/>
+   * This is for use in diagnostic messaging. It is not the actual file URI, 
because
+   * those may contain personal-identifying information about the 
person/acccount and
+   * system that compiled the schema. It will provide enough content about the 
file URI that
+   * a user will be able to identify which file, but some prefix of the path
+   * components trimmed to make it of a manageable length.
+   * <p/>
+   * Used along with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]]
+   * and 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineColumnNumber]],
+   * this can give a precise location in the DFDL schema file.
+   * @return a string containing the file information, or null if unknown.
+   */
+  def schemaFileInfo: String
+
+  /**
+   * Provides the line number to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileInfo]].
+   * @return the line number as a string, or null if unknown.
+   */
+  def schemaFileLineNumber: String
+
+  /**
+   * Provides the column number within the text line, to go with 
[[org.apache.daffodil.runtime1.api.Metadata.schemaFileLineNumber]].
+   * @return the column number within the text line, as a string, or null if 
unknown.
+   */
+  def schemaFileLineColumnNumber: String
+
+  /**
+   * The name of the schema component, in a form suitable for diagnostic 
messages.
+   * Unnamed components like sequence or choice groups have a 
diagnosticDebugName, despite not having
+   * any actual name.
+   * @return the name of the component, suitable for use in diagnostic 
messages.
+   */
+  def diagnosticDebugName: String

Review Comment:
   Seems odd to provide a debug thing in a public API. Should we remove this?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala:
##########
@@ -190,3 +213,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

Review Comment:
   > // because sometimes the debugger won't show the exception
   
   Is this the Daffodil CLI debugger, or an IDE debugger? The InfosetWalker 
will convert any exceptions thrown by an InfosetOutputter to an SDE, maybe that 
is what is making it hard to see the exceptions? Maybe that should include the 
stack trace?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputterImpl.scala:
##########
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.infoset
+
+import org.apache.daffodil.runtime1.api.InfosetElement
+
+abstract class InfosetOutputterImpl() extends BlobMethodsImpl with 
InfosetOutputter {
+
+  import Status._
+
+  private def status: Status = READY
+
+  override def getStatus(): Status = {
+    // Done, Ready (Not started), Visiting (part way done - can retry to visit 
more)...
+    status
+  }

Review Comment:
   This staus stuff doesn't even seem to be use? Can we remove it? I dont' 
remember what it was originally for.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/JsonInfosetOutputter.scala:
##########
@@ -92,12 +96,12 @@ class JsonInfosetOutputter private (writer: java.io.Writer, 
pretty: Boolean)
     if (pretty) outputIndentation(writer)
   }
 
-  override def startSimple(simple: DISimple): Unit = {
+  override def startSimple(simple: InfosetSimpleElement): Unit = {
     startNode()
     startElement(simple)
-    if (!isNilled(simple) && simple.hasValue) {
+    if (!simple.isNilled && simple.hasValue) {

Review Comment:
   I asked elsewhere if `hasValue` could be removed. Now that I look at this 
code, I think maybe the answer is "no", but has nothing to with nillables. I 
*think* it is because an infoset outputter could be use by the CLI debugger, 
which configures the walker to walk in places where it normally wouldn't, and 
so parts of an infoset might not actually have a value. So most normal infoset 
outputters (e.g. one uses in Drill) should never need to use `hasValue`. It's 
only those that could be used by the CLI debugger. I wonder if there's a better 
way we can handle this so that infoset outputters don't ever have to be 
concerned with possibly not having a value if used during debugging, and we can 
move that logic somewhere else?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputter.scala:
##########
@@ -84,75 +85,98 @@ trait InfosetOutputter {
    *                 value, nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endSimple(diSimple: DISimple): Unit
+  def endSimple(diSimple: InfosetSimpleElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of a complex 
element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is started. Various fields of
+   * @param complex the complex element that is started. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def startComplex(diComplex: DIComplex): Unit
+  def startComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the end of a complex element.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the complex element that is ended. Various fields of
+   * @param complex the complex element that is ended. Various fields of
    *                  DIComplex can be accessed to determine things like the
    *                  nil, name, namespace, etc.
    */
   @throws[Exception]
-  def endComplex(diComplex: DIComplex): Unit
+  def endComplex(complex: InfosetComplexElement): Unit
 
   /**
    * Called by Daffodil internals to signify the beginning of an array of 
elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is started. Various fields of
+   * @param array the array that is started. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def startArray(diArray: DIArray): Unit
+  def startArray(array: InfosetArray): Unit
 
   /**
    * Called by Daffodil internals to signify the end of an array of elements.
    *
    * Throws java.lang.Exception if there was an error and Daffodil should stop 
parsing
    *
-   * @param diComplex the array that is ended. Various fields of
+   * @param array the array that is ended. Various fields of
    *                  DIArray can be accessed to determine things like the
    *                  name, namespace, etc.
    */
   @throws[Exception]
-  def endArray(diArray: DIArray): Unit
+  def endArray(array: InfosetArray): Unit
 
-  def getStatus(): Status = {
-    // Done, Ready (Not started), Visiting (part way done - can retry to visit 
more)...
-    status
-  }
+  def getStatus(): Status
 
   /**
-   * Helper function to determine if an element is nilled or not, taking into
-   * account whether or not the nilled state has been set yet.
+   * 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.
    *
-   * @param diElement the element to check the nilled state of
+   * This saves the user of the API from having to wrap try/catch around their
+   * start/end method bodies.
    *
-   * @return true if the nilled state has been set and is true. false if the
-   *         nilled state is false or if the nilled state has not been set yet
-   *         (e.g. during debugging)
+   * @param e the exception thrown by one of the other methods.
    */
-  final def isNilled(diElement: DIElement): Boolean = {
-    val maybeIsNilled = diElement.maybeIsNilled
-    maybeIsNilled.isDefined && maybeIsNilled.get == true
-  }
+  def exceptionOccurred(e: Exception): Unit
+
+}
+
+/**
+ * Methods that provide Blob (Binary Large Object) support.
+ *
+ * FIXME: Scaladoc
+ */
+trait BlobMethodsMixin {
+
+  def setBlobAttributes(blobDir: Path, blobPrefix: String, blobSuffix: 
String): Unit
+  def setBlobPaths(empty: Seq[Path]): Unit
+  def getBlobDirectory(): Path
+  def getBlobPrefix(): String
+  def getBlobSuffix(): String
+
+}

Review Comment:
   I think I asked in the other review, but I can't find the quesiton or answer 
if it was answered. What is the goal of splitting BlobMethodsMixin into a 
separate trait instead of staying on the InofsetOutputter trait?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetOutputterImpl.scala:
##########
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.runtime1.infoset
+
+import org.apache.daffodil.runtime1.api.InfosetElement
+
+abstract class InfosetOutputterImpl() extends BlobMethodsImpl with 
InfosetOutputter {
+
+  import Status._
+
+  private def status: Status = READY
+
+  override def getStatus(): Status = {
+    // Done, Ready (Not started), Visiting (part way done - can retry to visit 
more)...
+    status
+  }
+
+  /**
+   * Helper function to determine if an element is nilled or not, taking into
+   * account whether or not the nilled state has been set yet.
+   *
+   * @param elem the element to check the nilled state of
+   * @return true if the nilled state has been set and is true. false if the
+   *         nilled state is false or if the nilled state has not been set yet
+   *         (e.g. during debugging)
+   */
+  final def isNilled(elem: InfosetElement): Boolean = {
+    val diElement = elem.asInstanceOf[DIElement]
+    val maybeIsNilled = diElement.maybeIsNilled
+    maybeIsNilled.isDefined && maybeIsNilled.get == true
+  }

Review Comment:
   Can this live on the InfosetOutputter trait? It would be nice if we didn't 
need to have a separate InfosetOutputter and InfosetOutputterImpl classes. 
Seems like this is the only real differentiator.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala:
##########
@@ -665,14 +675,29 @@ sealed class ElementRuntimeData(
     fillByteEvArg,
     maybeCheckByteAndBitOrderEvArg,
     maybeCheckBitOrderAndCharsetEvArg,
-  ) {
+  )
+  with ElementMetadata
+  with SimpleElementMetadata
+  with ComplexElementMetadata {
+
+  override def toQName: String = namedQName.toQNameString
 
   override def isRequiredScalar = !isArray && isRequiredInUnparseInfoset
 
   final def childERDs = children
 
+  final override def childMetadata: Seq[ElementRuntimeData] = childERDs

Review Comment:
   Not covered, I think this is only used by the drill walker? Any chance this 
could be remove and the walker could figure out what this is needed without 
direct access to children metadata? Maybe it's a bit more complicated, but it 
would be nice to minimize the API.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/unparsers/UState.scala:
##########
@@ -168,7 +168,7 @@ abstract class UState(
     Assert.invariant(Maybe.WithNulls.isDefined(currentInfosetNode))
     currentInfosetNode match {
       case a: DIArray => {
-        a.getOccurrence(arrayIterationPos)
+        a(arrayIterationPos)

Review Comment:
   Is this line not possible to hit? Is the currentInfosetNode alway a 
DIElement? I think it is? Can we remove this case?



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/RuntimeData.scala:
##########
@@ -871,10 +901,11 @@ sealed abstract class ModelGroupRuntimeData(
     fillByteEvArg,
     maybeCheckByteAndBitOrderEvArg,
     maybeCheckBitOrderAndCharsetEvArg,
-  ) {
+  )
+  with ModelGroupMetadata {
 
   final override def isRequiredScalar = true
-  final override def isArray = false
+  final def isArray = false

Review Comment:
   Can we remove this if does override anything and isn't used?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to