Skip to content

Commit

Permalink
improve XSLTC usage
Browse files Browse the repository at this point in the history
  • Loading branch information
sboeckelmann committed Jun 16, 2024
1 parent 163be31 commit 5f8daa7
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 383 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/maven-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
- name: checkout from git
uses: actions/checkout@v3

- name: Set up GraalVM 17
- name: Set up GraalVM 21
uses: graalvm/setup-graalvm@v1
with:
java-version: '17'
java-version: '21'
distribution: 'graalvm'

- id: run_sonarqube
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/maven-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ jobs:
build-quarkus-native-container-images:
if: false
name: "Build Native Container Image"
needs: [ build-vue-js-job ]

strategy:
matrix:
Expand Down Expand Up @@ -223,10 +222,10 @@ jobs:
username: ${{github.actor}}
password: ${{secrets.GITHUB_TOKEN}}

- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
cache: maven

Expand Down
1 change: 0 additions & 1 deletion .mvn/jvm.config

This file was deleted.

71 changes: 66 additions & 5 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,6 @@
<groupId>io.smallrye.reactive</groupId>
<artifactId>mutiny</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>utils</artifactId>
</dependency>

<dependency>
<groupId>jakarta.enterprise</groupId>
Expand Down Expand Up @@ -145,7 +141,16 @@
<version>${project.parent.version}</version>
</dependency>

<!-- Add constants as dependencies -->
<!-- external xalan is required to support class generation from xsl in native builds -->
<dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
</dependency>
<dependency>
<groupId>xalan</groupId>
<artifactId>serializer</artifactId>
</dependency>

<dependency>
<groupId>io.openepcis</groupId>
<artifactId>openepcis-test-resources</artifactId>
Expand Down Expand Up @@ -183,6 +188,62 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>

<!--
PRE-COMPILE XSL Translets
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>convert-2.0-to-1.2</id>
<phase>compile</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.apache.xalan.xsltc.cmdline.Compile</mainClass>
<arguments>
<argument>-o</argument>
<argument>From20To12</argument>
<argument>-d</argument>
<argument>${build.directory}/classes</argument>
<argument>-p</argument>
<argument>io.openepcis.converter.translet</argument>
<argument>-n</argument>
<argument>-x</argument>
<argument>-u</argument>
<argument>file:${project.basedir}/src/main/resources/xalan-conversion/convert-2.0-to-1.2.xsl</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>convert-1.2-to-2.0</id>
<phase>compile</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.apache.xalan.xsltc.cmdline.Compile</mainClass>
<arguments>
<argument>-o</argument>
<argument>From12To20</argument>
<argument>-d</argument>
<argument>${build.directory}/classes</argument>
<argument>-p</argument>
<argument>io.openepcis.converter.translet</argument>
<argument>-n</argument>
<argument>-x</argument>
<argument>-u</argument>
<argument>file:${project.basedir}/src/main/resources/xalan-conversion/convert-1.2-to-2.0.xsl</argument>
</arguments>
</configuration>
</execution>
</executions>

</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
import io.openepcis.converter.Conversion;
import io.openepcis.converter.VersionTransformerFeature;
import io.openepcis.converter.exception.FormatConverterException;
import org.reactivestreams.FlowAdapters;
import software.amazon.awssdk.utils.async.InputStreamSubscriber;
import software.amazon.awssdk.utils.async.OutputStreamPublisher;

import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
Expand All @@ -30,10 +27,9 @@
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.ByteBuffer;
import java.net.URL;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Flow;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;

Expand All @@ -45,35 +41,40 @@
*/
public class DefaultXmlVersionTransformer implements XmlVersionTransformer {

private static Templates FROM_12_TO_20;
private static Templates FROM_20_TO_12;
private static final TransformerFactory TRANSFORMER_FACTORY = createTransformerFactory();
private ExecutorService executorService;

public DefaultXmlVersionTransformer(final ExecutorService executorService) {
this.executorService = executorService;
}
/**
* !!!
*
* static TransformerFactory instances and Templates
* required for registering classes for native
*
* !!!
*/
private final Templates from12To20;
private final Templates from20To12;
private final ExecutorService executorService;

public void setExecutorService(final ExecutorService executorService) {
public static final String TRANSLET_PACKAGE_NAME = "io.openepcis.converter.generated.translet";
public DefaultXmlVersionTransformer(final ExecutorService executorService) {
this.executorService = executorService;
}

private static TransformerFactory createTransformerFactory() {

final TransformerFactory transformerFactory = TransformerFactory.newInstance();
try {
FROM_12_TO_20 = transformerFactory.newTemplates(
new StreamSource(DefaultXmlVersionTransformer.class
.getClassLoader()
.getResourceAsStream("xalan-conversion/convert-1.2-to-2.0.xsl"), "urn:openepcis:converter:xsl:convert-1.2-to-2.0"));
FROM_20_TO_12 = transformerFactory.newTemplates(
new StreamSource(DefaultXmlVersionTransformer.class.getClassLoader()
.getResourceAsStream("xalan-conversion/convert-2.0-to-1.2.xsl"), "urn:openepcis:converter:xsl:convert-2.0-to-1.2"));
TransformerFactory transformerFactory = TransformerFactory.newInstance("org.apache.xalan.xsltc.trax.TransformerFactoryImpl", Thread.currentThread().getContextClassLoader());
transformerFactory.setAttribute("package-name", "io.openepcis.converter.translet");
transformerFactory.setAttribute("translet-name", "From20To12");
transformerFactory.setAttribute("use-classpath", true);
from20To12 = transformerFactory.newTemplates(
new StreamSource(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("xalan-conversion/convert-2.0-to-1.2.xsl")));

transformerFactory = TransformerFactory.newInstance("org.apache.xalan.xsltc.trax.TransformerFactoryImpl", Thread.currentThread().getContextClassLoader());
transformerFactory.setAttribute("package-name", "io.openepcis.converter.translet");
transformerFactory.setAttribute("translet-name", "From12To20");
transformerFactory.setAttribute("use-classpath", true);
from12To20 = transformerFactory.newTemplates(
new StreamSource(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("xalan-conversion/convert-1.2-to-2.0.xsl")));
} catch (Exception e) {
throw new RuntimeException(e);
throw new RuntimeException(e.getMessage(), e);
}

return transformerFactory;
}

@Override
Expand Down Expand Up @@ -117,43 +118,14 @@ public final InputStream xmlConverter(
}
}

/**
* Convert EPCIS 1.2 XML document to EPCIS 2.0 XML document
*
* @param publisher EPCIS 1.2 XML document as a ByteBuffer Publisher
* @return converted EPCIS 2.0 XML document as a ByteBuffer Publisher
* @throws IOException If any exception occur during the conversion then throw the error
*/
public Flow.Publisher<ByteBuffer> convert12To20(final Flow.Publisher<ByteBuffer> publisher) {
final OutputStreamPublisher outTransform = new OutputStreamPublisher();
final InputStreamSubscriber inputDocument = new InputStreamSubscriber();
FlowAdapters.toPublisher(publisher).subscribe(inputDocument);
executorService.submit(() -> {
try (inputDocument) {
FROM_12_TO_20.newTransformer().transform(
new StreamSource(inputDocument),
new StreamResult(new BufferedOutputStream(outTransform)));
} catch (Exception e) {
outTransform.write(e.getMessage().getBytes());
final FormatConverterException ex = new FormatConverterException(
"Exception occurred during conversion of EPCIS XML document from 1.2 to 2.0 : "
+ e.getMessage(),
e);
inputDocument.onError(ex);
throw ex;
}
});
return FlowAdapters.toFlowPublisher(outTransform);
}

/**
* Convert EPCIS 1.2 XML document to EPCIS 2.0 XML document
*
* @param inputDocument EPCIS 1.2 XML document as a InputStream
* @return converted EPCIS 2.0 XML document as a InputStream
* @throws IOException If any exception occur during the conversion then throw the error
*/
public InputStream convert12To20(final InputStream inputDocument) {
private InputStream convert12To20(final InputStream inputDocument) {
final PipedInputStream convertedDocument = new PipedInputStream();
final AtomicBoolean pipeConnected = new AtomicBoolean(false);

Expand All @@ -163,7 +135,7 @@ public InputStream convert12To20(final InputStream inputDocument) {
try (outTransform) {
outTransform.connect(convertedDocument);
pipeConnected.set(true);
FROM_12_TO_20.newTransformer().transform(
from12To20.newTransformer().transform(
new StreamSource(inputDocument),
new StreamResult(new BufferedOutputStream(outTransform)));
} catch (Exception e) {
Expand Down Expand Up @@ -196,21 +168,21 @@ public InputStream convert12To20(final InputStream inputDocument) {
private InputStream convert20To12(final InputStream inputDocument, final List<VersionTransformerFeature> enabledFeatures) throws TransformerConfigurationException {
final PipedInputStream convertedDocument = new PipedInputStream();
final AtomicBoolean pipeConnected = new AtomicBoolean(false);
final Transformer from20T012 = FROM_20_TO_12.newTransformer();
from20T012.setParameter("includeAssociationEvent", enabledFeatures.contains(VersionTransformerFeature.EPCIS_1_2_0_INCLUDE_ASSOCIATION_EVENT) ? "yes" : "no");
from20T012.setParameter("includePersistentDisposition", enabledFeatures.contains(VersionTransformerFeature.EPCIS_1_2_0_INCLUDE_PERSISTENT_DISPOSITION) ? "yes" : "no");
from20T012.setParameter("includeSensorElementList", enabledFeatures.contains(VersionTransformerFeature.EPCIS_1_2_0_INCLUDE_SENSOR_ELEMENT_LIST) ? "yes" : "no");

executorService.execute(
() -> {
final PipedOutputStream outTransform = new PipedOutputStream();
try (outTransform) {
outTransform.connect(convertedDocument);
pipeConnected.set(true);
from20T012.transform(
final Transformer from20T012Transformer = from20To12.newTransformer();
from20T012Transformer.setParameter("includeAssociationEvent", enabledFeatures.contains(VersionTransformerFeature.EPCIS_1_2_0_INCLUDE_ASSOCIATION_EVENT) ? "yes" : "no");
from20T012Transformer.setParameter("includePersistentDisposition", enabledFeatures.contains(VersionTransformerFeature.EPCIS_1_2_0_INCLUDE_PERSISTENT_DISPOSITION) ? "yes" : "no");
from20T012Transformer.setParameter("includeSensorElementList", enabledFeatures.contains(VersionTransformerFeature.EPCIS_1_2_0_INCLUDE_SENSOR_ELEMENT_LIST) ? "yes" : "no");
from20T012Transformer.transform(
new StreamSource(inputDocument),
new StreamResult(new BufferedOutputStream(outTransform)));
} catch (Exception e) {
} catch (Throwable e) {
try {
outTransform.write(e.getMessage().getBytes());
} catch (IOException ioException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourcePatternsBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.steps.NativeImageSerializationConfigStep;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;

import java.util.stream.Stream;
Expand Down Expand Up @@ -55,31 +56,80 @@ HealthBuildItem addHealthCheck(OpenEPCISBuildTimeConfig buildTimeConfig) {
@BuildStep
NativeImageConfigBuildItem addNativeImageConfig() {
final NativeImageConfigBuildItem.Builder builder = NativeImageConfigBuildItem.builder();

// as resource bundles
Stream.of(
"org.apache.xml.res.XMLErrorResources",
"org.apache.xml.serializer.utils.SerializerMessages"
"org.apache.xml.serializer.utils.SerializerMessages",
"org.apache.xalan.xsltc.compiler.util.ErrorMessages"
).forEach(builder::addResourceBundle);

// set runtime initialized classes
Stream.of(
"io.openepcis.converter.xml.DefaultXmlVersionTransformer",
"org.apache.xalan.xsltc.trax.TransformerFactoryImpl",
"org.apache.bcel.util.SyntheticRepository",
"org.apache.bcel.util.ClassPath"
).forEach(builder::addRuntimeInitializedClass);
return builder.build();
}

@BuildStep
ReflectiveClassBuildItem addReflectiveClassBuildItem() {
return ReflectiveClassBuildItem.builder(
VersionTransformerProducer.class,
VersionTransformer.class,
DefaultXmlVersionTransformer.class,
org.apache.xml.dtm.ref.DTMManagerDefault.class,
org.apache.xml.serializer.AttributesImplSerializer.class,
org.apache.xml.serializer.DOM3Serializer.class,
org.apache.xml.serializer.DOMSerializer.class,
org.apache.xml.serializer.ExtendedContentHandler.class,
org.apache.xml.serializer.ExtendedLexicalHandler.class,
org.apache.xml.serializer.ToXMLStream.class
)

// OpenEPCIS classes
"io.openepcis.converter.VersionTransformer",
"io.openepcis.converter.xml.DefaultXmlVersionTransformer",
"io.openepcis.quarkus.converter.runtime.OpenEPCISConverterHealthCheck",
"io.openepcis.quarkus.converter.runtime.VersionTransformerProducer",

// Apache Xalan related classes
"org.apache.xalan.xsltc.trax.TransformerFactoryImpl",
"org.apache.xalan.xsltc.trax.SmartTransformerFactoryImpl",
"org.apache.xalan.xsltc.dom.XSLTCDTMManager"

// Apache Xalan related internal class
/*
"com.sun.org.apache.xalan.internal.xsltc.compiler.ApplyTemplates",
"com.sun.org.apache.xalan.internal.xsltc.compiler.CallTemplate",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Choose",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Copy",
"com.sun.org.apache.xalan.internal.xsltc.compiler.CopyOf",
"com.sun.org.apache.xalan.internal.xsltc.compiler.ForEach",
"com.sun.org.apache.xalan.internal.xsltc.compiler.If",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Otherwise",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Output",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Param",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Stylesheet",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Template",
"com.sun.org.apache.xalan.internal.xsltc.compiler.ValueOf",
"com.sun.org.apache.xalan.internal.xsltc.compiler.When",
"com.sun.org.apache.xalan.internal.xsltc.compiler.Whitespace",
"com.sun.org.apache.xalan.internal.xsltc.compiler.XslAttribute",
"com.sun.org.apache.xalan.internal.xsltc.compiler.XslElement",
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl",
"com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl",
"com.sun.org.apache.xml.internal.serializer.SerializationHandler",
"com.sun.org.apache.xml.internal.dtm.DTMAxisIterator",
"com.sun.org.apache.xml.internal.serializer.SerializationHandler"
*/
)
.unsafeAllocated()
.serialization().methods().fields().constructors()
.build();
}
@BuildStep
ReflectiveClassBuildItem addReflectiveClassConstructorBuildItem() {
return ReflectiveClassBuildItem.builder(
// predefined generated classes from XML Stylesheets
"io.openepcis.converter.translet.From12To20",
"io.openepcis.converter.translet.From20To12"
).constructors().methods().fields().build();
}



@BuildStep
Expand Down
Loading

0 comments on commit 5f8daa7

Please sign in to comment.