You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2022/10/31 19:00:35 UTC

[camel-quarkus] 04/19: Fix #3904 to increase the xslt tests and support the schemas in JVM mode (#4018)

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch 2.13.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 12f2cca481c76dce50ee8a043d6b743e79a5887c
Author: Zheng Feng <zh...@gmail.com>
AuthorDate: Tue Oct 25 10:24:00 2022 +0800

    Fix #3904 to increase the xslt tests and support the schemas in JVM mode (#4018)
---
 .../ROOT/pages/reference/extensions/xslt.adoc      |  22 +++--
 .../xslt/runtime/src/main/doc/configuration.adoc   |  22 +++--
 .../quarkus/component/xslt/CamelXsltRecorder.java  |  54 +++++++----
 .../quarkus/component/xslt/RuntimeUriResolver.java |   9 +-
 integration-tests/xml/pom.xml                      |  38 ++++++++
 .../quarkus/component/xml/it/XmlResource.java      |  86 +++++++++++++++++-
 .../quarkus/component/xml/it/XmlRouteBuilder.java  |  17 ++++
 .../quarkus/component/xml/it/XsltProducers.java    |  84 +++++++++++++++++
 .../xml/src/main/resources/application.properties  |   4 +-
 .../xml/src/main/resources/xslt/aggregate.xsl      |  34 +++++++
 .../xml/src/main/resources/xslt/include.xsl        |  26 ++++++
 .../xslt/include_not_existing_resource.xsl         |  31 +++++++
 .../xml/src/main/resources/xslt/terminate.xsl      |  36 ++++++++
 .../camel/quarkus/component/xml/it/XmlTest.java    | 100 +++++++++++++++++++--
 .../quarkus/component/xml/it/XmlTestResource.java  |  60 +++++++++++++
 integration-tests/xml/src/test/resources/data1.xml |  20 +++++
 integration-tests/xml/src/test/resources/data2.xml |  20 +++++
 integration-tests/xml/src/test/resources/data3.xml |  20 +++++
 18 files changed, 641 insertions(+), 42 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/extensions/xslt.adoc b/docs/modules/ROOT/pages/reference/extensions/xslt.adoc
index 458f0def29..5d06e0057d 100644
--- a/docs/modules/ROOT/pages/reference/extensions/xslt.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/xslt.adoc
@@ -59,7 +59,22 @@ quarkus.camel.xslt.sources = transform.xsl, classpath:path/to/my/file.xsl
 
 Scheme-less URIs are interpreted as `classpath:` URIs.
 
-Only `classpath:` URIs are supported on Quarkus. `file:`, `http:` and other kinds of URIs do not work by design.
+Only `classpath:` URIs are supported on Quarkus native mode. `file:`, `http:` and other kinds of URIs can be used on JVM mode only.
+
+`<xsl:include>` and `<xsl:messaging>` XSLT elements are also supported in JVM mode only right now.
+
+If `aggregate` DSL is used, `XsltSaxonAggregationStrategy` has to be used such as
+[source,java]
+----
+from("file:src/test/resources?noop=true&sortBy=file:name&antInclude=*.xml")
+   .routeId("aggregate").noAutoStartup()
+   .aggregate(new XsltSaxonAggregationStrategy("xslt/aggregate.xsl"))
+   .constant(true)
+   .completionFromBatchConsumer()
+   .log("after aggregate body: ${body}")
+   .to("mock:transformed");
+----
+Also, it's only supported on JVM mode.
 
 [id="extensions-xslt-configuration-configuration"]
 === Configuration
@@ -89,11 +104,6 @@ The content of the XSLT source URIs is parsed and compiled into Java classes at
 only source of XSLT information at runtime. The XSLT source files may not be included in the application archive at all.
 ====
 
-[WARNING]
-====
-the extension does not yet support Java 11.
-====
-
 
 [width="100%",cols="80,5,15",options="header"]
 |===
diff --git a/extensions/xslt/runtime/src/main/doc/configuration.adoc b/extensions/xslt/runtime/src/main/doc/configuration.adoc
index d8783fa0b0..85262d3b42 100644
--- a/extensions/xslt/runtime/src/main/doc/configuration.adoc
+++ b/extensions/xslt/runtime/src/main/doc/configuration.adoc
@@ -9,7 +9,22 @@ quarkus.camel.xslt.sources = transform.xsl, classpath:path/to/my/file.xsl
 
 Scheme-less URIs are interpreted as `classpath:` URIs.
 
-Only `classpath:` URIs are supported on Quarkus. `file:`, `http:` and other kinds of URIs do not work by design.
+Only `classpath:` URIs are supported on Quarkus native mode. `file:`, `http:` and other kinds of URIs can be used on JVM mode only.
+
+`<xsl:include>` and `<xsl:messaging>` XSLT elements are also supported in JVM mode only right now.
+
+If `aggregate` DSL is used, `XsltSaxonAggregationStrategy` has to be used such as
+[source,java]
+----
+from("file:src/test/resources?noop=true&sortBy=file:name&antInclude=*.xml")
+   .routeId("aggregate").noAutoStartup()
+   .aggregate(new XsltSaxonAggregationStrategy("xslt/aggregate.xsl"))
+   .constant(true)
+   .completionFromBatchConsumer()
+   .log("after aggregate body: ${body}")
+   .to("mock:transformed");
+----
+Also, it's only supported on JVM mode.
 
 === Configuration
 TransformerFactory features can be configured using following property:
@@ -35,9 +50,4 @@ public class FunctionsConfiguration {
 ====
 The content of the XSLT source URIs is parsed and compiled into Java classes at build time. These Java classes are the
 only source of XSLT information at runtime. The XSLT source files may not be included in the application archive at all.
-====
-
-[WARNING]
-====
-the extension does not yet support Java 11.
 ====
\ No newline at end of file
diff --git a/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/CamelXsltRecorder.java b/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/CamelXsltRecorder.java
index 67f85cf0a3..af551b3e7d 100644
--- a/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/CamelXsltRecorder.java
+++ b/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/CamelXsltRecorder.java
@@ -20,9 +20,12 @@ import java.util.Map;
 
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
 
 import io.quarkus.runtime.RuntimeValue;
 import io.quarkus.runtime.annotations.Recorder;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.xslt.DefaultXsltUriResolverFactory;
 import org.apache.camel.component.xslt.TransformerFactoryConfigurationStrategy;
 import org.apache.camel.component.xslt.XsltComponent;
 import org.apache.camel.component.xslt.XsltEndpoint;
@@ -37,7 +40,7 @@ public class CamelXsltRecorder {
         final QuarkusTransformerFactoryConfigurationStrategy strategy = new QuarkusTransformerFactoryConfigurationStrategy(
                 config.packageName, config.features, uriResolver);
         final XsltComponent component = new XsltComponent();
-        component.setUriResolver(uriResolver);
+        component.setUriResolverFactory(new QuarkusXsltUriResolverFactory(uriResolver));
         component.setTransformerFactoryConfigurationStrategy(strategy);
         component.setTransformerFactoryClass(XalanTransformerFactory.class.getName());
         return new RuntimeValue<>(component);
@@ -52,6 +55,27 @@ public class CamelXsltRecorder {
         builder.getValue().entry(templateUri, transletClassName);
     }
 
+    static class QuarkusXsltUriResolverFactory extends DefaultXsltUriResolverFactory {
+        private final RuntimeUriResolver uriResolver;
+
+        public QuarkusXsltUriResolverFactory(RuntimeUriResolver uriResolver) {
+            this.uriResolver = uriResolver;
+        }
+
+        @Override
+        public URIResolver createUriResolver(CamelContext camelContext, String resourceUri) {
+            // It is supposed to catch cases where we compile the translet at build time which is for classpath: XSLT
+            // resources in both JVM and native mode.
+            // Otherwise, all other cases will be handled by the default XsltUriResolver which is able to load a resource
+            // at runtime. So it is only supported in JVM mode.
+            if (uriResolver.getTransletClassName(resourceUri) != null) {
+                return uriResolver;
+            } else {
+                return super.createUriResolver(camelContext, resourceUri);
+            }
+        }
+    }
+
     static class QuarkusTransformerFactoryConfigurationStrategy implements TransformerFactoryConfigurationStrategy {
 
         private final String packageName;
@@ -68,23 +92,23 @@ public class CamelXsltRecorder {
         @Override
         public void configure(TransformerFactory tf, XsltEndpoint endpoint) {
             final String className = uriResolver.getTransletClassName(endpoint.getResourceUri());
-
-            for (Map.Entry<String, Boolean> entry : features.entrySet()) {
-                try {
-                    tf.setFeature(entry.getKey(), entry.getValue());
-                } catch (TransformerException e) {
-                    throw new RuntimeException("Could not set TransformerFactory feature '"
-                            + entry.getKey() + "' = " + entry.getValue(), e);
+            if (className != null) {
+                for (Map.Entry<String, Boolean> entry : features.entrySet()) {
+                    try {
+                        tf.setFeature(entry.getKey(), entry.getValue());
+                    } catch (TransformerException e) {
+                        throw new RuntimeException("Could not set TransformerFactory feature '"
+                                + entry.getKey() + "' = " + entry.getValue(), e);
+                    }
                 }
-            }
 
-            tf.setAttribute("use-classpath", true);
-            tf.setAttribute("translet-name", className);
-            tf.setAttribute("package-name", packageName);
-            tf.setErrorListener(new CamelXsltErrorListener());
+                tf.setAttribute("use-classpath", true);
+                tf.setAttribute("translet-name", className);
+                tf.setAttribute("package-name", packageName);
+                tf.setErrorListener(new CamelXsltErrorListener());
 
-            endpoint.setTransformerFactory(tf);
+                endpoint.setTransformerFactory(tf);
+            }
         }
-
     }
 }
diff --git a/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/RuntimeUriResolver.java b/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/RuntimeUriResolver.java
index bcc7cc381b..b9251be4e8 100644
--- a/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/RuntimeUriResolver.java
+++ b/extensions/xslt/runtime/src/main/java/org/apache/camel/quarkus/component/xslt/RuntimeUriResolver.java
@@ -57,14 +57,11 @@ public class RuntimeUriResolver implements URIResolver {
 
     /**
      * @param  uri the URI whose translet is seeked
-     * @return     the unqualified translet name associated with the given {@code uri}
+     * @return     the unqualified translet name associated with the given {@code uri} or
+     *             {@code null} if the given XSLT resource was not compiled to a translet at build time.
      */
     public String getTransletClassName(String uri) {
-        final String transletClassName = uriToTransletName.get(uri);
-        if (transletClassName == null) {
-            throw new RuntimeException("Could not resolve " + uri);
-        }
-        return transletClassName;
+        return uriToTransletName.get(uri);
     }
 
     /**
diff --git a/integration-tests/xml/pom.xml b/integration-tests/xml/pom.xml
index 886eba16df..658d0719b3 100644
--- a/integration-tests/xml/pom.xml
+++ b/integration-tests/xml/pom.xml
@@ -35,14 +35,34 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-xslt</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-xslt-saxon</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-xpath</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-stax</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-bean</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-direct</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-file</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-mock</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-seda</artifactId>
@@ -71,6 +91,11 @@
             <artifactId>rest-assured</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-integration-wiremock-support</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 
@@ -137,6 +162,19 @@
                         </exclusion>
                     </exclusions>
                 </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-stax-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
                 <dependency>
                     <groupId>org.apache.camel.quarkus</groupId>
                     <artifactId>camel-quarkus-support-stax-deployment</artifactId>
diff --git a/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlResource.java b/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlResource.java
index 328851a6b8..cb70629924 100644
--- a/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlResource.java
+++ b/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlResource.java
@@ -21,13 +21,20 @@ import java.util.StringJoiner;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
+import org.apache.camel.CamelContext;
 import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.Exchange;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.eclipse.microprofile.config.ConfigProvider;
 import org.jboss.logging.Logger;
 
 @Path("/xml")
@@ -42,11 +49,34 @@ public class XmlResource {
     @Inject
     ConsumerTemplate consumerTemplate;
 
+    @Inject
+    CamelContext camelContext;
+
     @Path("/xslt")
     @POST
     @Produces(MediaType.TEXT_PLAIN)
-    public String classpath(String body) {
-        return producerTemplate.requestBody("xslt:xslt/classpath-transform.xsl", body, String.class);
+    public String classpath(@QueryParam("output") @DefaultValue("string") String output, String body) {
+        if (output.equals("file")) {
+            return producerTemplate.requestBodyAndHeader("xslt:xslt/classpath-transform.xsl?output=file",
+                    body, Exchange.XSLT_FILE_NAME, "target/xsltme.xml", String.class);
+        }
+        return producerTemplate.requestBody("xslt:xslt/classpath-transform.xsl?output=" + output, body, String.class);
+    }
+
+    @Path("/xslt_include")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String xsltInclude(String body) {
+        return producerTemplate.requestBody("xslt:xslt/include.xsl", body, String.class);
+    }
+
+    @Path("/xslt_terminate")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String xsltTerminate(String body) {
+        Exchange out = producerTemplate.request("xslt:xslt/terminate.xsl", exchange -> exchange.getIn().setBody(body));
+        Exception warning = out.getProperty(Exchange.XSLT_WARNING, Exception.class);
+        return warning.getMessage();
     }
 
     @Path("/xslt-extension-function")
@@ -56,6 +86,58 @@ public class XmlResource {
         return producerTemplate.requestBody("xslt:xslt/extension-function.xsl", body, String.class);
     }
 
+    @Path("/xslt-custom-uri-resolver")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String customURIResolver(String body) {
+        return producerTemplate.requestBody("xslt:xslt/include_not_existing_resource.xsl?uriResolver=#customURIResolver", body,
+                String.class);
+    }
+
+    @Path("/xslt-ref")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String xsltRef(String body) {
+        return producerTemplate.requestBody("xslt:ref:xslt_resource", body, String.class);
+    }
+
+    @Path("/xslt-bean")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String xsltBean(String body) {
+        return producerTemplate.requestBody("xslt:bean:xslt_bean.getXsltResource", body, String.class);
+    }
+
+    @Path("/xslt-file")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String xsltFile(String body) {
+        return producerTemplate.requestBody("xslt:file:src/main/resources/xslt/classpath-transform.xsl", body, String.class);
+    }
+
+    @Path("/xslt-http")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String xsltHttp(String body) {
+        String serverURL = ConfigProvider.getConfig()
+                .getConfigValue("xslt.server-url")
+                .getRawValue();
+        return producerTemplate.requestBody("xslt:" + serverURL + "/xslt", body, String.class);
+    }
+
+    @Path("/aggregate")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String aggregate() throws Exception {
+        MockEndpoint mock = camelContext.getEndpoint("mock:transformed", MockEndpoint.class);
+        mock.expectedMessageCount(1);
+        camelContext.getRouteController().startRoute("aggregate");
+
+        mock.assertIsSatisfied();
+        return mock.getExchanges().get(0).getIn().getBody(String.class);
+
+    }
+
     @Path("/html-transform")
     @POST
     @Consumes(MediaType.TEXT_HTML)
diff --git a/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlRouteBuilder.java b/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlRouteBuilder.java
index 702552ecb3..160efcc5cb 100644
--- a/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlRouteBuilder.java
+++ b/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XmlRouteBuilder.java
@@ -18,9 +18,18 @@ package org.apache.camel.quarkus.component.xml.it;
 
 import org.w3c.dom.Document;
 
+import io.quarkus.runtime.annotations.RegisterForReflection;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.xslt.saxon.XsltSaxonAggregationStrategy;
 import org.apache.camel.support.builder.Namespaces;
 
+// These reflections registrations should be removed with fixing https://github.com/apache/camel-quarkus/issues/1615
+@RegisterForReflection(classNames = {
+        "net.sf.saxon.Configuration",
+        "net.sf.saxon.functions.String_1",
+        "net.sf.saxon.functions.Tokenize_1",
+        "net.sf.saxon.functions.StringJoin",
+        "org.apache.camel.component.xslt.saxon.XsltSaxonBuilder" })
 public class XmlRouteBuilder extends RouteBuilder {
     public static final String DIRECT_HTML_TRANSFORM = "direct:html-transform";
     public static final String DIRECT_HTML_TO_TEXT = "direct:html-to-text";
@@ -48,5 +57,13 @@ public class XmlRouteBuilder extends RouteBuilder {
                 .split()
                 .xtokenize("//C:child", new Namespaces("C", "urn:c"))
                 .to("seda:xtokenize-result");
+
+        from("file:src/test/resources?noop=true&sortBy=file:name&antInclude=*.xml")
+                .routeId("aggregate").noAutoStartup()
+                .aggregate(new XsltSaxonAggregationStrategy("xslt/aggregate.xsl"))
+                .constant(true)
+                .completionFromBatchConsumer()
+                .log("after aggregate body: ${body}")
+                .to("mock:transformed");
     }
 }
diff --git a/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XsltProducers.java b/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XsltProducers.java
new file mode 100644
index 0000000000..35147bbaa0
--- /dev/null
+++ b/integration-tests/xml/src/main/java/org/apache/camel/quarkus/component/xml/it/XsltProducers.java
@@ -0,0 +1,84 @@
+/*
+ * 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.component.xml.it;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.support.ResourceHelper;
+
+@Dependent
+public class XsltProducers {
+    public static final String EXPECTED_XML_CONSTANT = "<data>FOO DATA</data>";
+    @Inject
+    CamelContext context;
+
+    @Named("customURIResolver")
+    public URIResolver getCustomURIResolver() {
+        return new URIResolver() {
+
+            @Override
+            public Source resolve(String href, String base) throws TransformerException {
+                if (href.equals("xslt/include_not_existing_resource.xsl")) {
+                    try {
+                        InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(context, href);
+                        return new StreamSource(is);
+                    } catch (Exception e) {
+                        throw new TransformerException(e);
+                    }
+                }
+
+                Source constantResult = new StreamSource(new ByteArrayInputStream(EXPECTED_XML_CONSTANT.getBytes()));
+                return constantResult;
+            }
+        };
+    }
+
+    @Named("xslt_resource")
+    public String getXsltResource() throws Exception {
+        return getXsltContent();
+    }
+
+    @Named("xslt_bean")
+    public XsltBean getXsltBean() {
+        return new XsltBean();
+    }
+
+    public static class XsltBean {
+        public String getXsltResource() throws Exception {
+            return getXsltContent();
+        }
+    }
+
+    private static String getXsltContent() throws Exception {
+        try (InputStream in = Thread.currentThread().getContextClassLoader()
+                .getResourceAsStream("xslt/classpath-transform.xsl")) {
+            return new String(in.readAllBytes(), StandardCharsets.UTF_8);
+        }
+    }
+}
diff --git a/integration-tests/xml/src/main/resources/application.properties b/integration-tests/xml/src/main/resources/application.properties
index 472d5bc393..e3c54d8308 100644
--- a/integration-tests/xml/src/main/resources/application.properties
+++ b/integration-tests/xml/src/main/resources/application.properties
@@ -23,5 +23,5 @@ quarkus.log.category."org.apache.camel.quarkus.core.deployment".level = INFO
 #
 # Quarkus - Camel
 #
-quarkus.camel.xslt.sources = xslt/classpath-transform.xsl,xslt/html-transform.xsl,xslt/html-to-text.xsl,xslt/extension-function.xsl
-quarkus.camel.xslt.features."http\://javax.xml.XMLConstants/feature/secure-processing" = false
\ No newline at end of file
+quarkus.camel.xslt.sources = xslt/classpath-transform.xsl,xslt/html-transform.xsl,xslt/html-to-text.xsl,xslt/extension-function.xsl,xslt/include_not_existing_resource.xsl,xslt/aggregate.xsl,xslt/terminate.xsl
+quarkus.camel.xslt.features."http\://javax.xml.XMLConstants/feature/secure-processing" = false
diff --git a/integration-tests/xml/src/main/resources/xslt/aggregate.xsl b/integration-tests/xml/src/main/resources/xslt/aggregate.xsl
new file mode 100644
index 0000000000..91a8b918f1
--- /dev/null
+++ b/integration-tests/xml/src/main/resources/xslt/aggregate.xsl
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+    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.
+
+-->
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+    <xsl:output method="xml" indent="no"/>
+    <xsl:strip-space elements="*"/>
+
+    <xsl:param name="new-exchange" />
+
+    <xsl:template match="/">
+        <item>
+            <xsl:value-of select="."/>
+            <xsl:value-of select="$new-exchange/item"/>
+        </item>
+    </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/integration-tests/xml/src/main/resources/xslt/include.xsl b/integration-tests/xml/src/main/resources/xslt/include.xsl
new file mode 100644
index 0000000000..a9544da6fa
--- /dev/null
+++ b/integration-tests/xml/src/main/resources/xslt/include.xsl
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+
+    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.
+
+-->
+<xsl:stylesheet
+        xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+        version='1.0'>
+
+    <xsl:include href="classpath-transform.xsl"/>
+
+</xsl:stylesheet>
diff --git a/integration-tests/xml/src/main/resources/xslt/include_not_existing_resource.xsl b/integration-tests/xml/src/main/resources/xslt/include_not_existing_resource.xsl
new file mode 100644
index 0000000000..99c5b35bc6
--- /dev/null
+++ b/integration-tests/xml/src/main/resources/xslt/include_not_existing_resource.xsl
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+
+    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.
+
+-->
+
+<xsl:stylesheet
+        xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+        version='1.0'>
+
+    <xsl:output method="xml" indent="yes" encoding="ISO-8859-1"/>
+
+    <xsl:template match="/">
+        <xsl:copy-of select="document('notExistingExternalFile.xml')"/>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/integration-tests/xml/src/main/resources/xslt/terminate.xsl b/integration-tests/xml/src/main/resources/xslt/terminate.xsl
new file mode 100644
index 0000000000..4e9892d5ae
--- /dev/null
+++ b/integration-tests/xml/src/main/resources/xslt/terminate.xsl
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:template match="/">
+    <html>
+      <body>
+        <xsl:for-each select="staff/programmer">
+          <p>Name: <xsl:value-of select="name"/><br />
+            <xsl:if test="dob=''">
+              <xsl:message terminate="yes">Error: DOB is an empty string!</xsl:message>
+            </xsl:if>
+          </p>
+        </xsl:for-each>
+      </body>
+    </html>
+  </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/integration-tests/xml/src/test/java/org/apache/camel/quarkus/component/xml/it/XmlTest.java b/integration-tests/xml/src/test/java/org/apache/camel/quarkus/component/xml/it/XmlTest.java
index 4633c8e4f3..b629e6117f 100644
--- a/integration-tests/xml/src/test/java/org/apache/camel/quarkus/component/xml/it/XmlTest.java
+++ b/integration-tests/xml/src/test/java/org/apache/camel/quarkus/component/xml/it/XmlTest.java
@@ -17,25 +17,90 @@
 package org.apache.camel.quarkus.component.xml.it;
 
 import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.DisabledOnIntegrationTest;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
 import org.apache.commons.io.IOUtils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import static org.hamcrest.Matchers.is;
 
 @QuarkusTest
+@QuarkusTestResource(XmlTestResource.class)
 class XmlTest {
     private static final String BODY = "<mail><subject>Hey</subject><body>Hello world!</body></mail>";
 
+    @ParameterizedTest
+    @ValueSource(strings = { "string", "bytes", "dom", "file" })
+    public void xslt(String output) throws Exception {
+        final String actual = RestAssured.given()
+                .body(BODY)
+                .post("/xml/xslt?output=" + output)
+                .then()
+                .statusCode(200)
+                .extract().body().asString().trim().replaceAll(">\\s+<", "><");
+
+        if (output.equals("dom")) {
+            Assertions.assertEquals(
+                    "<classpath-xsl subject=\"Hey\"><cheese><mail><subject>Hey</subject><body>Hello world!</body></mail></cheese></classpath-xsl>",
+                    actual);
+        } else {
+            Assertions.assertEquals(
+                    "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><classpath-xsl subject=\"Hey\"><cheese><mail><subject>Hey</subject><body>Hello world!</body></mail></cheese></classpath-xsl>",
+                    actual);
+        }
+
+        if (output.equals("file")) {
+            Assertions.assertEquals(
+                    "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><classpath-xsl subject=\"Hey\"><cheese><mail><subject>Hey</subject><body>Hello world!</body></mail></cheese></classpath-xsl>",
+                    Files.readString(Path.of("target/xsltme.xml"), Charset.forName("ISO-8859-1")).replaceAll(">\\s+<", "><")
+                            .replaceAll("[\\n\\r]", ""));
+        }
+    }
+
+    @Test
+    public void xsltExtensionFunction() {
+        final String actual = RestAssured.given()
+                .body(BODY)
+                .post("/xml/xslt-extension-function")
+                .then()
+                .statusCode(200)
+                .extract().body().asString().trim().replaceAll(">\\s+<", "><");
+
+        Assertions.assertEquals(
+                "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><extension-function-xsl>Hey-Hello world!</extension-function-xsl>",
+                actual);
+    }
+
     @Test
-    public void xslt() {
+    public void xsltCustomURIResolver() {
         final String actual = RestAssured.given()
                 .body(BODY)
-                .post("/xml/xslt")
+                .post("/xml/xslt-custom-uri-resolver")
+                .then()
+                .statusCode(200)
+                .extract().body().asString().trim().replaceAll(">\\s+<", "><");
+
+        Assertions.assertEquals(
+                "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + XsltProducers.EXPECTED_XML_CONSTANT,
+                actual);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "ref", "bean", "http", "file" })
+    @DisabledOnIntegrationTest("Generating xslt templates dynamically does not be supported in native mode")
+    public void xsltSchemas(String schema) {
+        final String actual = RestAssured.given()
+                .body(BODY)
+                .post("/xml/xslt-{schema}", schema)
                 .then()
                 .statusCode(200)
                 .extract().body().asString().trim().replaceAll(">\\s+<", "><");
@@ -46,19 +111,44 @@ class XmlTest {
     }
 
     @Test
-    public void xsltExtensionFunction() {
+    @DisabledOnIntegrationTest("Generating xslt templates dynamically does not be supported in native mode")
+    public void aggregate() {
+        final String actual = RestAssured.given()
+                .accept(ContentType.TEXT)
+                .get("/xml/aggregate")
+                .then()
+                .statusCode(200)
+                .extract().body().asString().trim().replaceAll(">\\s+<", "><");
+
+        Assertions.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><item>ABC</item>", actual);
+    }
+
+    @Test
+    @DisabledOnIntegrationTest("Generating xslt templates dynamically does not be supported in native mode")
+    public void xsltInclude() {
         final String actual = RestAssured.given()
                 .body(BODY)
-                .post("/xml/xslt-extension-function")
+                .post("/xml/xslt_include")
                 .then()
                 .statusCode(200)
                 .extract().body().asString().trim().replaceAll(">\\s+<", "><");
 
         Assertions.assertEquals(
-                "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><extension-function-xsl>Hey-Hello world!</extension-function-xsl>",
+                "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><classpath-xsl subject=\"Hey\"><cheese><mail><subject>Hey</subject><body>Hello world!</body></mail></cheese></classpath-xsl>",
                 actual);
     }
 
+    @Test
+    @DisabledOnIntegrationTest("forwarding xslt error and warn messages does not be supported in native mode")
+    public void xsltTerminate() {
+        RestAssured.given()
+                .body("<staff><programmer><name>Daisy Duck</name><dob></dob></programmer></staff>")
+                .post("/xml/xslt_terminate")
+                .then()
+                .statusCode(200)
+                .body(is("Error: DOB is an empty string!"));
+    }
+
     @Test
     public void htmlTransform() throws Exception {
         String html = IOUtils.toString(getClass().getResourceAsStream("/test.html"), Charset.forName("UTF-8"));
diff --git a/integration-tests/xml/src/test/java/org/apache/camel/quarkus/component/xml/it/XmlTestResource.java b/integration-tests/xml/src/test/java/org/apache/camel/quarkus/component/xml/it/XmlTestResource.java
new file mode 100644
index 0000000000..a22599edb3
--- /dev/null
+++ b/integration-tests/xml/src/test/java/org/apache/camel/quarkus/component/xml/it/XmlTestResource.java
@@ -0,0 +1,60 @@
+/*
+ * 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.component.xml.it;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+
+public class XmlTestResource implements QuarkusTestResourceLifecycleManager {
+    private WireMockServer server;
+
+    @Override
+    public Map<String, String> start() {
+        try (InputStream in = Thread.currentThread().getContextClassLoader()
+                .getResourceAsStream("xslt/classpath-transform.xsl")) {
+            server = new WireMockServer(WireMockConfiguration.DYNAMIC_PORT);
+            server.start();
+            server.stubFor(
+                    get(urlEqualTo("/xslt"))
+                            .willReturn(aResponse()
+                                    .withHeader("Content-Type", "application/XML")
+                                    .withBody(new String(in.readAllBytes(), StandardCharsets.UTF_8))));
+            Map<String, String> conf = new HashMap<>();
+            conf.put("xslt.server-url", server.baseUrl());
+            return conf;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void stop() {
+        if (server != null) {
+            server.stop();
+        }
+    }
+}
diff --git a/integration-tests/xml/src/test/resources/data1.xml b/integration-tests/xml/src/test/resources/data1.xml
new file mode 100644
index 0000000000..ab271eff66
--- /dev/null
+++ b/integration-tests/xml/src/test/resources/data1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<item>A</item>
\ No newline at end of file
diff --git a/integration-tests/xml/src/test/resources/data2.xml b/integration-tests/xml/src/test/resources/data2.xml
new file mode 100644
index 0000000000..ff5eca1e90
--- /dev/null
+++ b/integration-tests/xml/src/test/resources/data2.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<item>B</item>
diff --git a/integration-tests/xml/src/test/resources/data3.xml b/integration-tests/xml/src/test/resources/data3.xml
new file mode 100644
index 0000000000..b447fb9edd
--- /dev/null
+++ b/integration-tests/xml/src/test/resources/data3.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<item>C</item>