Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,49 +22,36 @@ import java.net.URI
import java.nio.channels.ReadableByteChannel
import java.nio.channels.WritableByteChannel
import scala.collection.JavaConverters._

import org.apache.daffodil.core.compiler.{ Compiler => SCompiler }
import org.apache.daffodil.core.compiler.{ InvalidParserException => SInvalidParserException }
import org.apache.daffodil.core.compiler.{ ProcessorFactory => SProcessorFactory }
import org.apache.daffodil.core.compiler.{Compiler => SCompiler}
import org.apache.daffodil.core.compiler.{InvalidParserException => SInvalidParserException}
import org.apache.daffodil.core.compiler.{ProcessorFactory => SProcessorFactory}
import org.apache.daffodil.core.dsom.ExpressionCompilers
import org.apache.daffodil.core.dsom.walker.RootView
import org.apache.daffodil.japi.debugger._
import org.apache.daffodil.japi.infoset._
import org.apache.daffodil.japi.io.InputSourceDataInputStream
import org.apache.daffodil.japi.packageprivate._
import org.apache.daffodil.japi.schema.{RuntimeSchemaHandler, RuntimeSchemaWalker}
import org.apache.daffodil.lib.api.URISchemaSource
import org.apache.daffodil.lib.api.Validator
import org.apache.daffodil.lib.api.{ DataLocation => SDataLocation }
import org.apache.daffodil.lib.api.{ Diagnostic => SDiagnostic }
import org.apache.daffodil.lib.api.{ LocationInSchemaFile => SLocationInSchemaFile }
import org.apache.daffodil.lib.api.{ WithDiagnostics => SWithDiagnostics }
import org.apache.daffodil.lib.api.{DataLocation => SDataLocation}
import org.apache.daffodil.lib.api.{Diagnostic => SDiagnostic}
import org.apache.daffodil.lib.api.{LocationInSchemaFile => SLocationInSchemaFile}
import org.apache.daffodil.lib.api.{WithDiagnostics => SWithDiagnostics}
import org.apache.daffodil.lib.xml.DFDLCatalogResolver
import org.apache.daffodil.lib.xml.XMLUtils
import org.apache.daffodil.runtime1.api.DFDL.{
DaffodilUnhandledSAXException => SDaffodilUnhandledSAXException,
}
import org.apache.daffodil.runtime1.api.DFDL.{
DaffodilUnparseContentHandler => SDaffodilUnparseContentHandler,
}
import org.apache.daffodil.runtime1.api.DFDL.{
DaffodilUnparseErrorSAXException => SDaffodilUnparseErrorSAXException,
}
import org.apache.daffodil.runtime1.api.DFDL.{DaffodilUnhandledSAXException => SDaffodilUnhandledSAXException}
import org.apache.daffodil.runtime1.api.DFDL.{DaffodilUnparseContentHandler => SDaffodilUnparseContentHandler}
import org.apache.daffodil.runtime1.api.DFDL.{DaffodilUnparseErrorSAXException => SDaffodilUnparseErrorSAXException}
import org.apache.daffodil.runtime1.debugger.Debugger
import org.apache.daffodil.runtime1.debugger.{ InteractiveDebugger => SInteractiveDebugger }
import org.apache.daffodil.runtime1.debugger.{ TraceDebuggerRunner => STraceDebuggerRunner }
import org.apache.daffodil.runtime1.processors.{
DaffodilParseXMLReader => SDaffodilParseXMLReader,
}
import org.apache.daffodil.runtime1.processors.{ DataProcessor => SDataProcessor }
import org.apache.daffodil.runtime1.processors.{
ExternalVariableException => SExternalVariableException,
}
import org.apache.daffodil.runtime1.processors.{
InvalidUsageException => SInvalidUsageException,
}
import org.apache.daffodil.runtime1.processors.{ ParseResult => SParseResult }
import org.apache.daffodil.runtime1.processors.{ UnparseResult => SUnparseResult }

import org.apache.daffodil.runtime1.debugger.{InteractiveDebugger => SInteractiveDebugger}
import org.apache.daffodil.runtime1.debugger.{TraceDebuggerRunner => STraceDebuggerRunner}
import org.apache.daffodil.runtime1.processors.{DaffodilParseXMLReader => SDaffodilParseXMLReader}
import org.apache.daffodil.runtime1.processors.{DataProcessor => SDataProcessor}
import org.apache.daffodil.runtime1.processors.{ExternalVariableException => SExternalVariableException}
import org.apache.daffodil.runtime1.processors.{InvalidUsageException => SInvalidUsageException}
import org.apache.daffodil.runtime1.processors.{ParseResult => SParseResult}
import org.apache.daffodil.runtime1.processors.{UnparseResult => SUnparseResult}
import org.xml.sax.Attributes
import org.xml.sax.ContentHandler
import org.xml.sax.DTDHandler
Expand Down Expand Up @@ -401,6 +388,12 @@ class DataProcessor private[japi] (private var dp: SDataProcessor)
extends WithDiagnostics(dp)
with Serializable {

/**
* For use by the JAPI implementation only.
* @return the underlying data processor
*/
private [japi] def getUnderlyingDataProcessor = dp

private def copy(dp: SDataProcessor = dp) = new DataProcessor(dp)

/**
Expand Down Expand Up @@ -514,6 +507,11 @@ class DataProcessor private[japi] (private var dp: SDataProcessor)
*/
def save(output: WritableByteChannel): Unit = dp.save(output)

def walkRuntimeSchema(handler: RuntimeSchemaHandler): Unit = {
val walker = new RuntimeSchemaWalker(dp)
walker.walk(handler)
}

/**
* Obtain a new [[DaffodilParseXMLReader]] from the current [[DataProcessor]].
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package org.apache.daffodil.japi.schema

import org.apache.daffodil.japi.{ DataProcessor => JDataProcessor }
import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.runtime1.dpath.NodeInfo.PrimType
import org.apache.daffodil.runtime1.processors.{
ChoiceRuntimeData,
DataProcessor => SDataProcessor,
ElementRuntimeData,
ErrorERD,
SequenceRuntimeData,
TermRuntimeData,
}

/**
* Base class used by japi clients who want to walk the runtime schema information.
*/
abstract class RuntimeSchemaHandler() {

/**
* Called for simple type element declarations.
*
* @param qnameString
* @param primTypeName
* @param isArray only true if more than one occurrence is possible. Disjoint with isOptional
* @param isOptional true if 0 or 1 occurrence only. Allows for a different representation of optional from a 0..1 array
*/
def elementSimple(
qnameString: String,
primTypeName: String,
isArray: Boolean,
isOptional: Boolean,
): Unit

/**
* Called for complex type element declarations
*
* Subsequent calls will be for the model group making up the content
* of the element.
*
* @param qnameString
*/
def startElementComplex(qnameString: String, isArray: Boolean, isOptional: Boolean): Unit
def endElementComplex(qnameString: String, isArray: Boolean, isOptional: Boolean): Unit

def startSequence(): Unit

def endSequence(): Unit

def startChoice(): Unit

def endChoice(): Unit

}

/**
* Walks the schema, but not the DSOM schema, it walks the RuntimeData objects that
* represent the DFDL schema at runtime.
*
* @param dp
*/
class RuntimeSchemaWalker(private val dp: SDataProcessor) {

// provided so that people can write various tests from JAPI only.
// we wouldn't need this otherwise.
def this(jdp: JDataProcessor) = this(jdp.getUnderlyingDataProcessor)

private lazy val rootERD = dp.ssrd.elementRuntimeData

def walk(handler: RuntimeSchemaHandler): Unit = {
walkTerm(handler, rootERD)
}

private def walkTerm(handler: RuntimeSchemaHandler, trd: TermRuntimeData): Unit = {
trd match {
case err: ErrorERD => Assert.invariantFailed("should not get ErrorERDs")
case erd: ElementRuntimeData => walkElement(handler, erd)
case srd: SequenceRuntimeData => walkSequence(handler, srd)
case crd: ChoiceRuntimeData => walkChoice(handler, crd)
case _ => Assert.invariantFailed(s"unrecognized TermRuntimeData subtype: $trd")
}
}

private def walkElement(handler: RuntimeSchemaHandler, erd: ElementRuntimeData): Unit = {
if (erd.optComplexTypeModelGroupRuntimeData.isDefined)
walkComplexElement(handler, erd)
else
walkSimpleElement(handler, erd)
}

private def walkComplexElement(
handler: RuntimeSchemaHandler,
erd: ElementRuntimeData,
): Unit = {
val qname = erd.namedQName.toQNameString
val isArray = erd.isArray
val isOptional = erd.isOptional
val mgrd = erd.optComplexTypeModelGroupRuntimeData.getOrElse {
Assert.invariantFailed("not a complex type element")
}
handler.startElementComplex(qname, isArray, isOptional)
walkTerm(handler, mgrd)
handler.endElementComplex(qname, isArray, isOptional)
}

private def walkSimpleElement(
handler: RuntimeSchemaHandler,
erd: ElementRuntimeData,
): Unit = {
val qname = erd.namedQName.toQNameString
val isArray = erd.isArray
val isOptional = erd.isOptional
val primType: PrimType = erd.optPrimType.getOrElse {
erd.optSimpleTypeRuntimeData.map { _.primType }.get
}
handler.elementSimple(qname, primType.toString, isArray, isOptional)
}

private def walkSequence(handler: RuntimeSchemaHandler, srd: SequenceRuntimeData): Unit = {
handler.startSequence()
srd.groupMembers.map { trd =>
walkTerm(handler, trd)
}
handler.endSequence()
}

private def walkChoice(handler: RuntimeSchemaHandler, crd: ChoiceRuntimeData): Unit = {
handler.startChoice()
crd.groupMembers.map { trd =>
walkTerm(handler, trd)
}
handler.endChoice()
}

}