You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pp...@apache.org on 2020/04/03 12:52:44 UTC
[camel-quarkus] branch master updated: Revisit #1017 Be even less
intrusive when registering our TransformerFactory
This is an automated email from the ASF dual-hosted git repository.
ppalaga pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/master by this push:
new d668d45 Revisit #1017 Be even less intrusive when registering our TransformerFactory
d668d45 is described below
commit d668d45cfa64926ef3289e04b15ad53ecf703283
Author: Peter Palaga <pp...@redhat.com>
AuthorDate: Fri Apr 3 11:00:00 2020 +0200
Revisit #1017 Be even less intrusive when registering our TransformerFactory
---
.../camel/quarkus/core/graal/ResourceUtils.java | 46 ++++++++++++++
extensions-support/xalan/deployment/pom.xml | 4 ++
.../deployment/CamelXalanBuildTimeConfig.java | 50 ---------------
.../deployment/XalanNativeImageProcessor.java | 71 ++++++++++++++++------
extensions-support/xalan/runtime/pom.xml | 4 ++
.../javax.xml.transform.TransformerFactory | 1 -
6 files changed, 106 insertions(+), 70 deletions(-)
diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/graal/ResourceUtils.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/graal/ResourceUtils.java
new file mode 100644
index 0000000..5a6d886
--- /dev/null
+++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/graal/ResourceUtils.java
@@ -0,0 +1,46 @@
+/*
+ * 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.camel.quarkus.core.graal;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import com.oracle.svm.core.jdk.Resources;
+
+/**
+ * Helper methods invoked from generated bytecode during image processing
+ */
+public class ResourceUtils {
+
+ /**
+ * Write a string resource into the native image.
+ *
+ * @param resourcePath the path under which the given {@code content} should be stored
+ * @param content the content that will be serialized using {@code UTF-8}
+ */
+ public static void registerResources(String resourcePath, String content) {
+ try {
+ try (InputStream in = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))) {
+ Resources.registerResource(resourcePath, in);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to store resource " + resourcePath, e);
+ }
+ }
+
+}
diff --git a/extensions-support/xalan/deployment/pom.xml b/extensions-support/xalan/deployment/pom.xml
index e7fb841..3e05d05 100644
--- a/extensions-support/xalan/deployment/pom.xml
+++ b/extensions-support/xalan/deployment/pom.xml
@@ -47,6 +47,10 @@
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-core-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-support-xalan</artifactId>
</dependency>
</dependencies>
diff --git a/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/CamelXalanBuildTimeConfig.java b/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/CamelXalanBuildTimeConfig.java
deleted file mode 100644
index 8180a5f..0000000
--- a/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/CamelXalanBuildTimeConfig.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.camel.quarkus.support.xalan.deployment;
-
-import java.util.Optional;
-
-import io.quarkus.runtime.annotations.ConfigItem;
-import io.quarkus.runtime.annotations.ConfigPhase;
-import io.quarkus.runtime.annotations.ConfigRoot;
-
-@ConfigRoot(name = "camel.xalan", phase = ConfigPhase.BUILD_TIME)
-public class CamelXalanBuildTimeConfig {
-
- /**
- * A fully qualified class name to set as the {@code javax.xml.transform.TransformerFactory} system property early
- * at the application startup.
- * <p>
- * The system property effectively overrides any service providers defined in
- * {@code META-INF/services/javax.xml.transform.TransformerFactory} files available in the class path. If the option
- * is not present in your {@code application.properties}, the default value is used and the service providers are
- * overridden anyway. To avoid overriding the service providers, set it to an empty value in
- * {@code application.properties}:
- *
- * <pre>
- * quarkus.camel.xalan.transformer-factory =
- * </pre>
- * <p>
- * Note that any custom transformer factory you pass will only work in native mode if all necessary classes are
- * registered for reflection and all necessary resources are included in the native image. This may already be the
- * case for {@code com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl} if you depend on
- * {@code io.quarkus:quarkus-jaxb} or {@code org.apache.xalan.xsltc.trax.TransformerFactoryImpl} if you depend on
- * {@code org.apache.camel.quarkus:camel-quarkus-support-xalan}.
- */
- @ConfigItem(defaultValue = "org.apache.camel.quarkus.support.xalan.XalanTransformerFactory")
- public Optional<String> transformerFactory;
-}
diff --git a/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/XalanNativeImageProcessor.java b/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/XalanNativeImageProcessor.java
index b412e7c..4311694 100644
--- a/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/XalanNativeImageProcessor.java
+++ b/extensions-support/xalan/deployment/src/main/java/org/apache/camel/quarkus/support/xalan/deployment/XalanNativeImageProcessor.java
@@ -16,18 +16,31 @@
*/
package org.apache.camel.quarkus.support.xalan.deployment;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.builditem.SystemPropertyBuildItem;
+import io.quarkus.deployment.builditem.GeneratedNativeImageClassBuildItem;
+import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
-import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
+import io.quarkus.gizmo.CatchBlockCreator;
+import io.quarkus.gizmo.ClassCreator;
+import io.quarkus.gizmo.ClassOutput;
+import io.quarkus.gizmo.MethodCreator;
+import io.quarkus.gizmo.TryBlock;
+import org.apache.camel.quarkus.core.graal.ResourceUtils;
+import org.apache.camel.quarkus.support.xalan.XalanTransformerFactory;
+import org.graalvm.nativeimage.hosted.Feature;
+
+import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
class XalanNativeImageProcessor {
+ private static final String TRANSFORMER_FACTORY_SERVICE_FILE_PATH = "META-INF/services/javax.xml.transform.TransformerFactory";
+
@BuildStep
ReflectiveClassBuildItem reflectiveClasses() {
return new ReflectiveClassBuildItem(
@@ -58,26 +71,46 @@ class XalanNativeImageProcessor {
@BuildStep
void installTransformerFactory(
- CamelXalanBuildTimeConfig config,
- BuildProducer<SystemPropertyBuildItem> properties,
- BuildProducer<ServiceProviderBuildItem> serviceProviders,
- BuildProducer<NativeImageResourceBuildItem> nativeResources) {
+ BuildProducer<GeneratedNativeImageClassBuildItem> nativeImageClass,
+ BuildProducer<GeneratedResourceBuildItem> generatedResources) {
+
+ final String serviceProviderFileContent = XalanTransformerFactory.class.getName() + "\n";
+
+ /* This is primarily for the JVM mode */
+ generatedResources.produce(
+ new GeneratedResourceBuildItem(TRANSFORMER_FACTORY_SERVICE_FILE_PATH,
+ serviceProviderFileContent.getBytes(StandardCharsets.UTF_8)));
+
+ /* A low level way to embed only our service file in the native image.
+ * There are at least two META-INF/services/javax.xml.transform.TransformerFactory files
+ * in the class path: ours and the one from xalan.jar. As of GraalVM 19.3.1-java8, 19.3.1-java11,
+ * 20.0.0-java8 and 20.0.0-java11, there is no way to ensure that ServiceProviderBuildItem
+ * or NativeImageResourceBuildItem will pick the service file preferred by us.
+ * We are thus forced to use this low level mechanism to ensure that.
+ */
+ final ClassCreator file = new ClassCreator(new ClassOutput() {
+ @Override
+ public void write(String s, byte[] bytes) {
+ nativeImageClass.produce(new GeneratedNativeImageClassBuildItem(s, bytes));
+ }
+ }, getClass().getName() + "AutoFeature", null,
+ Object.class.getName(), Feature.class.getName());
+ file.addAnnotation("com.oracle.svm.core.annotate.AutomaticFeature");
+ final MethodCreator beforeAn = file.getMethodCreator("beforeAnalysis", "V",
+ Feature.BeforeAnalysisAccess.class.getName());
+ final TryBlock overallCatch = beforeAn.tryBlock();
+ overallCatch.invokeStaticMethod(
+ ofMethod(ResourceUtils.class, "registerResources", void.class,
+ String.class, String.class),
+ overallCatch.load(TRANSFORMER_FACTORY_SERVICE_FILE_PATH),
+ overallCatch.load(serviceProviderFileContent));
- config.transformerFactory
- .ifPresent(val -> properties.produce(
- /*
- * If we do not do this, the service provider defined in xalan.jar's
- * META-INF/services/javax.xml.transform.TransformerFactory
- * wins over our factory on Java 11+ native
- * I any case, the user has an option to pass his preferred factory instead of ours
- */
- new SystemPropertyBuildItem("javax.xml.transform.TransformerFactory", val)));
+ final CatchBlockCreator print = overallCatch.addCatch(Throwable.class);
+ print.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), print.getCaughtException());
- serviceProviders.produce(
- new ServiceProviderBuildItem("javax.xml.transform.TransformerFactory",
- "org.apache.camel.quarkus.support.xalan.XalanTransformerFactory"));
+ beforeAn.returnValue(null);
+ file.close();
- nativeResources.produce(new NativeImageResourceBuildItem("META-INF/services/javax.xml.transform.TransformerFactory"));
}
}
diff --git a/extensions-support/xalan/runtime/pom.xml b/extensions-support/xalan/runtime/pom.xml
index 9942545..2e0aeef 100644
--- a/extensions-support/xalan/runtime/pom.xml
+++ b/extensions-support/xalan/runtime/pom.xml
@@ -46,6 +46,10 @@
<artifactId>quarkus-core</artifactId>
</dependency>
<dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-core</artifactId>
+ </dependency>
+ <dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
</dependency>
diff --git a/extensions-support/xalan/runtime/src/main/resources/META-INF/services/javax.xml.transform.TransformerFactory b/extensions-support/xalan/runtime/src/main/resources/META-INF/services/javax.xml.transform.TransformerFactory
deleted file mode 100644
index 202f3ae..0000000
--- a/extensions-support/xalan/runtime/src/main/resources/META-INF/services/javax.xml.transform.TransformerFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.apache.camel.quarkus.support.xalan.XalanTransformerFactory