def main()

in src/main/scala/org/apache/daffodil/DaffodilSaver.scala [41:159]


  def main(args: Array[String]): Unit = {

    assert(
      args.length == 5,
      "DaffodilPlugin did not provide the correct number of arguments when forking DaffodilSaver"
    )

    // the "version" of the Daffodil API to use. Note that this is not the same as the Daffodil
    // version, but is related. See the "daffodilInternalAPIVersionMapping" in the plugin code
    // for an explanation of why we have this and what version of Daffodil it represents.
    val apiVersion = args(0).toInt

    val schemaResource = args(1)
    val schemaUrl = this.getClass.getResource(schemaResource)
    if (schemaUrl == null) {
      System.err.println(s"failed to find schema resource: $schemaResource")
      System.exit(1)
    }
    val output = FileChannel.open(
      Paths.get(args(2)),
      StandardOpenOption.CREATE,
      StandardOpenOption.WRITE
    )
    val root = if (args(3) != "") args(3) else null
    val config = if (args(4) != "") args(4) else null

    // parameter types
    val cURI = classOf[URI]
    val cString = classOf[String]
    val cWritableByteChannel = classOf[WritableByteChannel]

    // get the Compiler, ProcessorFactory, and DataProcessor classes and the functions we need
    // to invoke on those classes. Note that we use JAPI because its easier to use via
    // reflection than the Scala API and it is much smaller and easier to use then the lib API
    val daffodilClass = Class.forName("org.apache.daffodil.japi.Daffodil")
    val daffodilCompiler = daffodilClass.getMethod("compiler")

    val compilerClass = Class.forName("org.apache.daffodil.japi.Compiler")
    val compilerWithTunable = compilerClass.getMethod("withTunable", cString, cString)
    // the compileResource method added in Daffodil 3.9.0 allows for depersonalized diagnostics
    // and better reproducibility of saved parsers--use it instead of compileSource for newer
    // versions of Daffodil
    val compilerCompile = apiVersion match {
      case 1 => compilerClass.getMethod("compileSource", cURI, cString, cString)
      case 2 => compilerClass.getMethod("compileResource", cString, cString, cString)
    }

    val processorFactoryClass = Class.forName("org.apache.daffodil.japi.ProcessorFactory")
    val processorFactoryIsError = processorFactoryClass.getMethod("isError")
    val processorFactoryOnPath = processorFactoryClass.getMethod("onPath", cString)
    val processorFactoryGetDiagnostics = processorFactoryClass.getMethod("getDiagnostics")

    val dataProcessorClass = Class.forName("org.apache.daffodil.japi.DataProcessor")
    val dataProcessorIsError = dataProcessorClass.getMethod("isError")
    val dataProcessorSave = dataProcessorClass.getMethod("save", cWritableByteChannel)
    val dataProcessorGetDiagnostics = processorFactoryClass.getMethod("getDiagnostics")

    val diagnosticClass = Class.forName("org.apache.daffodil.japi.Diagnostic")
    val diagnosticIsError = diagnosticClass.getMethod("isError")
    val diagnosticToString = diagnosticClass.getMethod("toString")

    def printDiagnostics(diags: java.util.List[Object]): Unit = {
      diags.asScala.foreach { d =>
        // val msg = d.toString
        val msg = diagnosticToString.invoke(d).asInstanceOf[String]
        // val isError = d.isError
        val isError = diagnosticIsError.invoke(d).asInstanceOf[Boolean]
        val level = if (isError) "error" else "warning"
        System.err.println(s"[$level] $msg")
      }
    }

    // val compiler = Daffodil.compiler()
    var compiler = daffodilCompiler.invoke(null)

    // compiler = compiler.withTunable(...)
    if (config != null) {
      val configXml = scala.xml.Utility.trim(scala.xml.XML.loadFile(config))
      (configXml \ "tunables").foreach { tunablesNode =>
        tunablesNode.child.foreach { node =>
          compiler = compilerWithTunable.invoke(compiler, node.label, node.text)
        }
      }
    }

    // val processorFactory = compiler.compileSource(schemaUrl.toURI, root, None)  // < 3.9.0
    // val processorFactory = compiler.compileResource(name, root, None)           // >= 3.9.0
    val schemaArg = apiVersion match {
      case 1 => schemaUrl.toURI
      case 2 => schemaResource
    }
    val processorFactory = compilerCompile.invoke(compiler, schemaArg, root, null)

    // val processorFactoryDiags = processorFactory.getDiagnostics()
    val processorFactoryDiags = processorFactoryGetDiagnostics
      .invoke(processorFactory)
      .asInstanceOf[java.util.List[Object]]
    printDiagnostics(processorFactoryDiags)

    // if (processorFactory.isError) System.exit(1)
    if (processorFactoryIsError.invoke(processorFactory).asInstanceOf[Boolean]) System.exit(1)

    // val dataProcessor= processorFactory.onPath("/")
    val dataProcessor = processorFactoryOnPath.invoke(processorFactory, "/")

    // val dataProcessorDiags = dataProcessor.getDiagnostics()
    val dataProcessorDiags = dataProcessorGetDiagnostics
      .invoke(dataProcessor)
      .asInstanceOf[java.util.List[Object]]
    printDiagnostics(dataProcessorDiags)

    // if (dataProcessor.isError) System.exit(1)
    if (dataProcessorIsError.invoke(dataProcessor).asInstanceOf[Boolean]) System.exit(1)

    // dataProcessor.save(output)
    dataProcessorSave.invoke(dataProcessor, output)

    System.exit(0)
  }