I'm currently having trouble trying to integrate Daffodil into a linux native executable produced with Quarkus.
The project is available here on github : .
What I did :
- Created a Quarkus REST project following the getting started guide : .
- Added these files from a Daffodil examples github into the project : .
- Created the native executable following this guide : .
The main class HelloWorld.java is provided here :
package .acme;
import .apache.daffodil.japi.*;
import .apache.daffodil.japi.infoset.JDOMInfosetOutputter;
import .apache.daffodil.japi.infoset.JsonInfosetOutputter;
import .apache.daffodil.japi.io.InputSourceDataInputStream;
import .jdom2.Content;
import .jdom2.Document;
import .jdom2.Namespace;
import .jdom2.filter.ContentFilter;
import .jdom2.output.XMLOutputter;
import .jdom2.transform.XSLTransformException;
import .jdom2.xpath.XPathExpression;
import .jdom2.xpath.XPathFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.URI;
import java.URISyntaxException;
import java.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Demonstrates using the Daffodil DFDL processor to
* <ul>
* <li>compile a DFDL schema
* <li>parse non-XML data into XML,
* <li>access the data it using XPath,
* <li>transform the data using XSLT
* <li>unparse the transformed data back to non-XML form.
* </ul>
*/
public class HelloWorld {
public void start() throws IOException, XSLTransformException, URISyntaxException {
try(FileOutputStream outputStream = new FileOutputStream("test.txt")) {
URI schemaFileURI = new File("files/helloWorld.dfdl.xsd").toURI();
URI dataFileURI = new File("files/helloWorld.dat").toURI();
URI xsltFileURI = new File("files/helloWorld.xslt").toURI();
outputStream.write(("Schema : " + schemaFileURI + "\n").getBytes());
outputStream.write(("Data : " + dataFileURI + "\n").getBytes());
outputStream.write(("XSLT : " + xsltFileURI + "\n").getBytes());
String fileToLoad = System.getProperty("test.file.toload");
outputStream.write(("Property : " + fileToLoad + "\n").getBytes());
//
// Run the executable with -Dtest.file.toload=path/to/resource/file to test if the file is included in the executable
//
if(fileToLoad != null) {
URL resourceURL = HelloWorld.class.getResource(fileToLoad);
if(resourceURL != null) {
outputStream.write(("Found resource URL : " + resourceURL + "\n").getBytes());
outputStream.write(("Found resource URI : " + resourceURL.toURI() + "\n").getBytes());
try(InputStream inputStream = resourceURL.openStream()) {
outputStream.write(inputStream.readAllBytes());
}
}
}
//
// First compile the DFDL Schema
//
Compiler c = Daffodilpiler();
ProcessorFactory pf = cpileSource(schemaFileURI);
outputStream.write("XSD compiled\n".getBytes());
List<Diagnostic> diags1 = pf.getDiagnostics();
outputStream.write("Diagnostics : \n".getBytes());
for(Diagnostic d : diags1) {
outputStream.write(d.getSomeMessage().getBytes());
outputStream.write("\n".getBytes());
}
if(pf.isError()) {
// didn't compile schema. Must be diagnostic of some sort.
List<Diagnostic> diags = pf.getDiagnostics();
for(Diagnostic d : diags) {
outputStream.write(d.getSomeMessage().getBytes());
outputStream.write("\n".getBytes());
}
}
DataProcessor dp = pf.onPath("/");
if(dp.isError()) {
// didn't compile schema. Must be diagnostic of some sort.
List<Diagnostic> diags = dp.getDiagnostics();
for(Diagnostic d : diags) {
outputStream.write(d.getSomeMessage().getBytes());
outputStream.write("\n".getBytes());
}
}
//
// Parse - parse data to XML
//
outputStream.write("**** Parsing data into XML *****".getBytes());
outputStream.write("\n".getBytes());
java.io.InputStream is = dataFileURI.toURL().openStream();
InputSourceDataInputStream dis = new InputSourceDataInputStream(is);
//
// Setup JDOM outputter
//
JDOMInfosetOutputter outputter = new JDOMInfosetOutputter();
// Do the parse
//
ParseResult res = dp.parse(dis, outputter);
// Check for errors
//
boolean err = res.isError();
if(err) {
// didn't parse the data. Must be diagnostic of some sort.
List<Diagnostic> diags = res.getDiagnostics();
for(Diagnostic d : diags) {
outputStream.write(d.getSomeMessage().getBytes());
outputStream.write("\n".getBytes());
}
}
Document doc = outputter.getResult();
//
// if we get here, we have a parsed infoset result!
// Let's print the XML infoset.
//
// Note that if we had only wanted this text, we could have used
// a different outputter to create XML text directly,
// but below we're going to transform this JDOM tree.
//
XMLOutputter xo = new XMLOutputter(.jdom2.output.Format.getPrettyFormat());
xo.output(doc, outputStream);
outputStream.write("\n".getBytes());
// If all you need to do is parse things to XML, then that's it.
// Let's display it as JSON also for those that need or prefer JSON
{
outputStream.write("**** Parsing data into JSON ****".getBytes());
outputStream.write("\n".getBytes());
java.io.InputStream is2 = dataFileURI.toURL().openStream();
InputSourceDataInputStream dis2 = new InputSourceDataInputStream(is2);
JsonInfosetOutputter jo = new JsonInfosetOutputter(outputStream, true);
outputStream.write("\n".getBytes());
ParseResult res2 = dp.parse(dis2, jo);
boolean err2 = res2.isError();
if(err2) {
// didn't parse the data. Must be diagnostic of some sort.
List<Diagnostic> diags = res.getDiagnostics();
for(Diagnostic d : diags) {
outputStream.write(d.getSomeMessage().getBytes());
outputStream.write("\n".getBytes());
}
}
}
//
// XPATH - use it to access the data
//
outputStream.write("**** Access with XPath *****".getBytes());
outputStream.write("\n".getBytes());
XPathExpression<Content> xexp = setupXPath("/hw:helloWorld/word[2]/text()");
List<Content> clist = xexp.evaluate(doc);
if(clist.isEmpty()) {
outputStream.write("XPath produced nothing.".getBytes());
outputStream.write("\n".getBytes());
} else {
Content content = clist.getFirst();
String txt = content.getValue();
outputStream.write(String.format("XPath says we said hello to %s%n", txt).getBytes());
outputStream.write("\n".getBytes());
}
outputStream.write("End hello world".getBytes());
}
}
/**
* Does the boilerplate stuff needed for xpath expression setup
*
* @return the compiled XPathExpression object which can be evaluated to run it.
*/
private static XPathExpression<Content> setupXPath(String xpath) {
// Need this namespace definition since the schema defines the root
// element in this namespace.
//
// A real application would hoist this boilerplate all out so it's done
// once, not each time we need to evaluate an XPath expression.
//
Namespace[] nss = {Namespace.getNamespace("hw", "/")};
XPathFactory xfactory = XPathFactory.instance();
ContentFilter cf = new ContentFilter(ContentFilter.TEXT);
Map<String, Object> variables = Collections.emptyMap();
return xfactorypile(xpath, cf, variables, nss);
}
}
Everything is compiled and executed inside a virutal machine running Alma Linux 8.10 as the root user.
As explained in this guide, I had to use the application.properties file to add XSD files from the daffodil-lib dependency as resources for the native executable. I also needed to register some classes for reflection with the ReflectionConfiguration class.
I get the expected behavior running the project as a Java project. However trying to stimulate the endpoint of the native executable throws the following error :
Schema Definition Error: Error loading schema due to Invalid or unsupported schemaLocation URI: Unrecognized URI type: resource://apache/daffodil/xsd/XMLSchema_for_DFDL.xsd
Schema context: Location in /root/Documents/quarkus/getting-started-dfdl/files/helloWorld.dfdl.xsd
at .apache.daffodil.core.dsom.DFDLSchemaFileLoadErrorHandler.$anonfun$loaderSDEs$1(DFDLSchemaFile.scala:60)
at scala.collection.immutable.List.map(List.scala:293)
at .apache.daffodil.core.dsom.DFDLSchemaFileLoadErrorHandler.loaderSDEs(DFDLSchemaFile.scala:51)
at .apache.daffodil.core.dsom.DFDLSchemaFileLoadErrorHandler.handleLoadErrors(DFDLSchemaFile.scala:99)
at .apache.daffodil.core.dsom.DFDLSchemaFile.$anonfun$iiXMLSchemaDocument$1(DFDLSchemaFile.scala:236)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.DFDLSchemaFile.iiXMLSchemaDocument$lzycompute(DFDLSchemaFile.scala:220)
at .apache.daffodil.core.dsom.DFDLSchemaFile.iiXMLSchemaDocument(DFDLSchemaFile.scala:220)
at .apache.daffodil.core.dsom.Import.$anonfun$mapPair$3(Import.scala:68)
at scala.Option.getOrElse(Option.scala:189)
at .apache.daffodil.core.dsom.Import.$anonfun$mapPair$1(Import.scala:47)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.Import.mapPair$lzycompute(Import.scala:45)
at .apache.daffodil.core.dsom.Import.mapPair(Import.scala:45)
at .apache.daffodil.core.dsom.IIBase.$anonfun$notSeenThisBefore$1(IIBase.scala:149)
at scala.runtime.java8.JFunction0$mcZ$sp.apply(JFunction0$mcZ$sp.java:23)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.IIBase.notSeenThisBefore$lzycompute(IIBase.scala:148)
at .apache.daffodil.core.dsom.IIBase.notSeenThisBefore(IIBase.scala:148)
at .apache.daffodil.core.dsom.IIBase.$anonfun$iiSchemaFileMaybe$1(IIBase.scala:255)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.IIBase.iiSchemaFileMaybe$lzycompute(IIBase.scala:254)
at .apache.daffodil.core.dsom.IIBase.iiSchemaFileMaybe(IIBase.scala:254)
at .apache.daffodil.core.dsom.IIBase.$anonfun$seenAfter$1(IIBase.scala:178)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.IIBase.seenAfter$lzycompute(IIBase.scala:177)
at .apache.daffodil.core.dsom.IIBase.seenAfter(IIBase.scala:177)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.$anonfun$getImportsOrIncludes$1(SchemaDocIncludesAndImportsMixin.scala:214)
at scala.collection.TraversableOnce$folder$1.apply(TraversableOnce.scala:196)
at scala.collection.TraversableOnce$folder$1.apply(TraversableOnce.scala:194)
at scala.collection.Iterator.foreach(Iterator.scala:943)
at scala.collection.Iterator.foreach$(Iterator.scala:943)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1431)
at scala.collection.IterableLike.foreach(IterableLike.scala:74)
at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
at scala.collection.TraversableOnce.foldLeft(TraversableOnce.scala:199)
at scala.collection.TraversableOnce.foldLeft$(TraversableOnce.scala:192)
at scala.collection.AbstractTraversable.foldLeft(Traversable.scala:108)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.getImportsOrIncludes(SchemaDocIncludesAndImportsMixin.scala:211)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.getImportsOrIncludes$(SchemaDocIncludesAndImportsMixin.scala:206)
at .apache.daffodil.core.dsom.XMLSchemaDocument.getImportsOrIncludes(SchemaDocument.scala:68)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.$anonfun$ismli_$1(SchemaDocIncludesAndImportsMixin.scala:225)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$ismli_(SchemaDocIncludesAndImportsMixin.scala:224)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$ismli_$(SchemaDocIncludesAndImportsMixin.scala:224)
at .apache.daffodil.core.dsom.XMLSchemaDocument$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$ismli_$lzycompute(SchemaDocument.scala:68)
at .apache.daffodil.core.dsom.XMLSchemaDocument$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$ismli_(SchemaDocument.scala:68)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.importStatementsMap(SchemaDocIncludesAndImportsMixin.scala:222)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.importStatementsMap$(SchemaDocIncludesAndImportsMixin.scala:222)
at .apache.daffodil.core.dsom.XMLSchemaDocument.importStatementsMap(SchemaDocument.scala:68)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.$anonfun$sali_$1(SchemaDocIncludesAndImportsMixin.scala:232)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$sali_(SchemaDocIncludesAndImportsMixin.scala:231)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$sali_$(SchemaDocIncludesAndImportsMixin.scala:231)
at .apache.daffodil.core.dsom.XMLSchemaDocument$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$sali_$lzycompute(SchemaDocument.scala:68)
at .apache.daffodil.core.dsom.XMLSchemaDocument$apache$daffodil$core$dsom$SchemaDocIncludesAndImportsMixin$$sali_(SchemaDocument.scala:68)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.seenAfter(SchemaDocIncludesAndImportsMixin.scala:229)
at .apache.daffodil.core.dsom.SchemaDocIncludesAndImportsMixin.seenAfter$(SchemaDocIncludesAndImportsMixin.scala:229)
at .apache.daffodil.core.dsom.XMLSchemaDocument.seenAfter(SchemaDocument.scala:68)
at .apache.daffodil.core.dsom.SchemaSetIncludesAndImportsMixin.$anonfun$allSchemaFiles$1(SchemaSetIncludesAndImportsMixins.scala:66)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body$lzycompute(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.body(OOLAG.scala:520)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.liftedTree1$1(OOLAG.scala:707)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny$lzycompute(OOLAG.scala:705)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValueBase.valueAsAny(OOLAG.scala:699)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value$lzycompute(OOLAG.scala:754)
at .apache.daffodil.lib.oolag.OOLAG$OOLAGValue.value(OOLAG.scala:754)
at .apache.daffodil.core.dsom.SchemaSetIncludesAndImportsMixin.allSchemaFiles(SchemaSetIncludesAndImportsMixins.scala:64)
at .apache.daffodil.core.dsom.SchemaSetIncludesAndImportsMixin.allSchemaFiles$(SchemaSetIncludesAndImportsMixins.scala:64)
at .apache.daffodil.core.dsom.SchemaSet.allSchemaFiles$lzycompute(SchemaSet.scala:92)
at .apache.daffodil.core.dsom.SchemaSet.allSchemaFiles(SchemaSet.scala:92)
at .apache.daffodil.core.dsom.SchemaSet.$anonfun$isValid$2(SchemaSet.scala:181)
at scala.runtime.java8.JFunction0$mcZ$sp.apply(JFunction0$mcZ$sp.java:23)
at .apache.daffodil.lib.oolag.OOLAG$.keepGoing(OOLAG.scala:65)
at .apache.daffodil.core.dsom.SchemaSet.isValid$lzycompute(SchemaSet.scala:180)
at .apache.daffodil.core.dsom.SchemaSet.isValid(SchemaSet.scala:172)
at .apache.daffodil.core.dsom.SchemaSet.isError$lzycompute(SchemaSet.scala:567)
at .apache.daffodil.core.dsom.SchemaSet.isError(SchemaSet.scala:566)
at .apache.daffodil.corepiler.ProcessorFactory.isError$lzycompute(Compiler.scala:147)
at .apache.daffodil.corepiler.ProcessorFactory.isError(Compiler.scala:147)
at .apache.daffodil.corepiler.Compiler$$apache$daffodil$core$compiler$Compiler$$compileSourceSynchronizer(Compiler.scala:426)
at .apache.daffodil.corepiler.CompilerpileSource(Compiler.scala:359)
at .apache.daffodil.japi.CompilerpileSource(Daffodil.scala:170)
at .apache.daffodil.japi.CompilerpileSource(Daffodil.scala:156)
at .acme.HelloWorld.start(HelloWorld.java:72)
At first glance, It seems like this XSD file isn't included in the native executable.
In order to test that, I added some code into the HelloWorld class that is stimulated with a property given to the native executable : -Dtest.file.toload=//apache/daffodil/xsd/XMLSchema_for_DFDL.xsd. This code block just opens the file given as property, and prints its content into a text file located in the execution directory. This works as intended and URI used is the exact same as the one we can see in the error thrown by Daffodil.
I can't figure out why I'm able to open the file via the HelloWorld class but Daffodil classes are not.
I would greatly appreciate some help as I'm currently out of ideas.
Thank you for reading.