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/09/15 10:25:13 UTC

[camel-quarkus] branch master updated: Disruptor native support #1597

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 9a4655d  Disruptor native support #1597
9a4655d is described below

commit 9a4655d3c166ddbddf5b9854b13862d07e5250cd
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Mon Sep 14 19:21:03 2020 +0200

    Disruptor native support #1597
---
 docs/modules/ROOT/pages/reference/components.adoc  |   4 +-
 .../ROOT/pages/reference/extensions/disruptor.adoc |   7 +-
 docs/modules/ROOT/pages/reference/index.adoc       |   4 +-
 .../disruptor/deployment/DisruptorProcessor.java   |  46 ------
 extensions-jvm/disruptor/integration-test/pom.xml  |  95 ------------
 .../component/disruptor/it/DisruptorResource.java  |  64 ---------
 extensions-jvm/pom.xml                             |   1 -
 .../disruptor/deployment/pom.xml                   |   0
 .../disruptor/deployment/DisruptorProcessor.java   |  75 ++++++++++
 {extensions-jvm => extensions}/disruptor/pom.xml   |   1 -
 .../disruptor/runtime/pom.xml                      |   5 +
 .../runtime/src/main/doc/limitations.adoc          |   1 +
 .../disruptor/graal/ThreadHintsSubstitutions.java  |  64 +++++++++
 .../main/resources/META-INF/quarkus-extension.yaml |   3 +-
 extensions/pom.xml                                 |   1 +
 integration-tests/disruptor/pom.xml                | 160 +++++++++++++++++++++
 .../component/disruptor/it/DisruptorResource.java  |  85 +++++++++++
 .../component/disruptor/it/DisruptorIT.java        |  24 +---
 .../component/disruptor/it/DisruptorTest.java      |  81 +++++++++++
 integration-tests/pom.xml                          |   1 +
 tooling/scripts/test-categories.yaml               |   1 +
 21 files changed, 488 insertions(+), 235 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/components.adoc b/docs/modules/ROOT/pages/reference/components.adoc
index a2a14f1..49111d7 100644
--- a/docs/modules/ROOT/pages/reference/components.adoc
+++ b/docs/modules/ROOT/pages/reference/components.adoc
@@ -271,8 +271,8 @@ Preview | 1.1.0 | Manage Droplets and resources within the DigitalOcean cloud.
 | xref:reference/extensions/direct.adoc[Direct] | [.camel-element-artifact]##camel-quarkus-direct## | [.camel-element-Native]##Native## +
 Stable | 0.2.0 | Call another endpoint from the same Camel Context synchronously.
 
-| xref:reference/extensions/disruptor.adoc[Disruptor] | [.camel-element-artifact]##camel-quarkus-disruptor## | [.camel-element-JVM]##JVM## +
-Preview | 1.1.0 | Provides asynchronous SEDA behavior using LMAX Disruptor.
+| xref:reference/extensions/disruptor.adoc[Disruptor] | [.camel-element-artifact]##camel-quarkus-disruptor## | [.camel-element-Native]##Native## +
+Stable | 1.1.0 | Provides asynchronous SEDA behavior using LMAX Disruptor.
 
 | xref:reference/extensions/dns.adoc[DNS] | [.camel-element-artifact]##camel-quarkus-dns## | [.camel-element-JVM]##JVM## +
 Preview | 1.1.0 | Perform DNS queries using DNSJava.
diff --git a/docs/modules/ROOT/pages/reference/extensions/disruptor.adoc b/docs/modules/ROOT/pages/reference/extensions/disruptor.adoc
index 7d1204a..bd6cd04 100644
--- a/docs/modules/ROOT/pages/reference/extensions/disruptor.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/disruptor.adoc
@@ -6,7 +6,7 @@
 :page-aliases: extensions/disruptor.adoc
 
 [.badges]
-[.badge-key]##Since Camel Quarkus##[.badge-version]##1.1.0## [.badge-key]##JVM##[.badge-supported]##supported## [.badge-key]##Native##[.badge-unsupported]##unsupported##
+[.badge-key]##Since Camel Quarkus##[.badge-version]##1.1.0## [.badge-key]##JVM##[.badge-supported]##supported## [.badge-key]##Native##[.badge-supported]##supported##
 
 Provides asynchronous SEDA behavior using LMAX Disruptor.
 
@@ -28,3 +28,8 @@ Please refer to the above links for usage and configuration details.
 ----
 
 Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
+
+== Camel Quarkus limitations
+
+The `disruptor-vm` component is not available on Camel Quarkus. This is because it is supposed to provide support for communication across multiple CamelContext instances within a single JVM, but by design, there is always just a single `CamelContext` on Camel Quarkus. Therefore `disruptor-vm` would make no sense.
+
diff --git a/docs/modules/ROOT/pages/reference/index.adoc b/docs/modules/ROOT/pages/reference/index.adoc
index 12f19d6..0bcc973 100644
--- a/docs/modules/ROOT/pages/reference/index.adoc
+++ b/docs/modules/ROOT/pages/reference/index.adoc
@@ -290,8 +290,8 @@ Preview | 1.1.0 | Manage Droplets and resources within the DigitalOcean cloud.
 |  xref:reference/extensions/direct.adoc[Direct]  | camel-quarkus-direct | [.camel-element-Native]##Native## +
 Stable | 0.2.0 | Call another endpoint from the same Camel Context synchronously.
 
-|  xref:reference/extensions/disruptor.adoc[Disruptor]  | camel-quarkus-disruptor | [.camel-element-JVM]##JVM## +
-Preview | 1.1.0 | Provides asynchronous SEDA behavior using LMAX Disruptor.
+|  xref:reference/extensions/disruptor.adoc[Disruptor]  | camel-quarkus-disruptor | [.camel-element-Native]##Native## +
+Stable | 1.1.0 | Provides asynchronous SEDA behavior using LMAX Disruptor.
 
 |  xref:reference/extensions/dns.adoc[DNS]  | camel-quarkus-dns | [.camel-element-JVM]##JVM## +
 Preview | 1.1.0 | Perform DNS queries using DNSJava.
diff --git a/extensions-jvm/disruptor/deployment/src/main/java/org/apache/camel/quarkus/component/disruptor/deployment/DisruptorProcessor.java b/extensions-jvm/disruptor/deployment/src/main/java/org/apache/camel/quarkus/component/disruptor/deployment/DisruptorProcessor.java
deleted file mode 100644
index 626c75b..0000000
--- a/extensions-jvm/disruptor/deployment/src/main/java/org/apache/camel/quarkus/component/disruptor/deployment/DisruptorProcessor.java
+++ /dev/null
@@ -1,46 +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.component.disruptor.deployment;
-
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.ExecutionTime;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.pkg.steps.NativeBuild;
-import org.apache.camel.quarkus.core.JvmOnlyRecorder;
-import org.jboss.logging.Logger;
-
-class DisruptorProcessor {
-
-    private static final Logger LOG = Logger.getLogger(DisruptorProcessor.class);
-    private static final String FEATURE = "camel-disruptor";
-
-    @BuildStep
-    FeatureBuildItem feature() {
-        return new FeatureBuildItem(FEATURE);
-    }
-
-    /**
-     * Remove this once this extension starts supporting the native mode.
-     */
-    @BuildStep(onlyIf = NativeBuild.class)
-    @Record(value = ExecutionTime.RUNTIME_INIT)
-    void warnJvmInNative(JvmOnlyRecorder recorder) {
-        JvmOnlyRecorder.warnJvmInNative(LOG, FEATURE); // warn at build time
-        recorder.warnJvmInNative(FEATURE); // warn at runtime
-    }
-}
diff --git a/extensions-jvm/disruptor/integration-test/pom.xml b/extensions-jvm/disruptor/integration-test/pom.xml
deleted file mode 100644
index fd05e02..0000000
--- a/extensions-jvm/disruptor/integration-test/pom.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.camel.quarkus</groupId>
-        <artifactId>camel-quarkus-build-parent-it</artifactId>
-        <version>1.2.0-SNAPSHOT</version>
-        <relativePath>../../../poms/build-parent-it/pom.xml</relativePath>
-    </parent>
-
-    <artifactId>camel-quarkus-disruptor-integration-test</artifactId>
-    <name>Camel Quarkus :: Disruptor :: Integration Test</name>
-    <description>Integration tests for Camel Quarkus Disruptor extension</description>
-
-    <properties>
-        <!-- mvnd, a.k.a. Maven Daemon: https://github.com/mvndaemon/mvnd -->
-        <!-- The following rule tells mvnd to build the listed deployment modules before this module. -->
-        <!-- This is important because mvnd builds modules in parallel by default. The deployment modules are not -->
-        <!-- explicit dependencies of this module in the Maven sense, although they are required by the Quarkus Maven plugin. -->
-        <!-- Please update the rule whenever you change the dependencies of this module by running -->
-        <!--     mvn process-resources -Pformat    from the root directory -->
-        <mvnd.builder.rule>camel-quarkus-disruptor-deployment,camel-quarkus-support-policy-deployment</mvnd.builder.rule>
-    </properties>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.apache.camel.quarkus</groupId>
-                <artifactId>camel-quarkus-bom-test</artifactId>
-                <version>${project.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.camel.quarkus</groupId>
-            <artifactId>camel-quarkus-disruptor</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy</artifactId>
-        </dependency>
-
-        <!-- test dependencies -->
-        <dependency>
-            <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-junit5</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>io.rest-assured</groupId>
-            <artifactId>rest-assured</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>io.quarkus</groupId>
-                <artifactId>quarkus-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>build</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-</project>
diff --git a/extensions-jvm/disruptor/integration-test/src/main/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorResource.java b/extensions-jvm/disruptor/integration-test/src/main/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorResource.java
deleted file mode 100644
index d8636e2..0000000
--- a/extensions-jvm/disruptor/integration-test/src/main/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorResource.java
+++ /dev/null
@@ -1,64 +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.component.disruptor.it;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.apache.camel.CamelContext;
-import org.jboss.logging.Logger;
-
-@Path("/disruptor")
-@ApplicationScoped
-public class DisruptorResource {
-
-    private static final Logger LOG = Logger.getLogger(DisruptorResource.class);
-
-    private static final String COMPONENT_DISRUPTOR = "disruptor";
-    private static final String COMPONENT_DISRUPTOR_VM = "disruptor-vm";
-    @Inject
-    CamelContext context;
-
-    @Path("/load/component/disruptor")
-    @GET
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response loadComponentDisruptor() throws Exception {
-        /* This is an autogenerated test */
-        if (context.getComponent(COMPONENT_DISRUPTOR) != null) {
-            return Response.ok().build();
-        }
-        LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_DISRUPTOR);
-        return Response.status(500, COMPONENT_DISRUPTOR + " could not be loaded from the Camel context").build();
-    }
-
-    @Path("/load/component/disruptor-vm")
-    @GET
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response loadComponentDisruptorVm() throws Exception {
-        /* This is an autogenerated test */
-        if (context.getComponent(COMPONENT_DISRUPTOR_VM) != null) {
-            return Response.ok().build();
-        }
-        LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_DISRUPTOR_VM);
-        return Response.status(500, COMPONENT_DISRUPTOR_VM + " could not be loaded from the Camel context").build();
-    }
-}
diff --git a/extensions-jvm/pom.xml b/extensions-jvm/pom.xml
index 64c6a1b..c38ec4a 100644
--- a/extensions-jvm/pom.xml
+++ b/extensions-jvm/pom.xml
@@ -62,7 +62,6 @@
         <module>crypto</module>
         <module>debezium-mongodb</module>
         <module>digitalocean</module>
-        <module>disruptor</module>
         <module>djl</module>
         <module>dns</module>
         <module>drill</module>
diff --git a/extensions-jvm/disruptor/deployment/pom.xml b/extensions/disruptor/deployment/pom.xml
similarity index 100%
rename from extensions-jvm/disruptor/deployment/pom.xml
rename to extensions/disruptor/deployment/pom.xml
diff --git a/extensions/disruptor/deployment/src/main/java/org/apache/camel/quarkus/component/disruptor/deployment/DisruptorProcessor.java b/extensions/disruptor/deployment/src/main/java/org/apache/camel/quarkus/component/disruptor/deployment/DisruptorProcessor.java
new file mode 100644
index 0000000..0afade1
--- /dev/null
+++ b/extensions/disruptor/deployment/src/main/java/org/apache/camel/quarkus/component/disruptor/deployment/DisruptorProcessor.java
@@ -0,0 +1,75 @@
+/*
+ * 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.disruptor.deployment;
+
+import com.lmax.disruptor.BlockingWaitStrategy;
+import com.lmax.disruptor.BusySpinWaitStrategy;
+import com.lmax.disruptor.SleepingWaitStrategy;
+import com.lmax.disruptor.YieldingWaitStrategy;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem;
+import org.apache.camel.quarkus.core.deployment.spi.CamelServiceFilter;
+import org.apache.camel.quarkus.core.deployment.spi.CamelServiceFilterBuildItem;
+
+class DisruptorProcessor {
+    private static final String FEATURE = "camel-disruptor";
+
+    @BuildStep
+    FeatureBuildItem feature() {
+        return new FeatureBuildItem(FEATURE);
+    }
+
+    @BuildStep
+    CamelServiceFilterBuildItem excludeDisruptorVM() {
+        // The disruptor-vm provide support for communication across CamelContext instances but
+        // since camel-quarkus support a single CamelContext, the component does not make sense.
+        return new CamelServiceFilterBuildItem(CamelServiceFilter.forComponent("disruptor-vm"));
+    }
+
+    @BuildStep
+    ReflectiveClassBuildItem reflectiveClasses(CombinedIndexBuildItem index) {
+        // Note: this should be kept in sink with org.apache.camel.component.disruptor.DisruptorWaitStrategy
+        return new ReflectiveClassBuildItem(
+                true,
+                false,
+                BlockingWaitStrategy.class,
+                SleepingWaitStrategy.class,
+                BusySpinWaitStrategy.class,
+                YieldingWaitStrategy.class);
+    }
+
+    @BuildStep
+    RuntimeReinitializedClassBuildItem reinitializedRingBufferFields() {
+        // The `com.lmax.disruptor.RingBufferFields` class uses sun.misc.Unsafe behind the scenes to compute some static
+        // fields and that confuses graalvm which emits warnings like:
+        //
+        //   Warning: RecomputeFieldValue.ArrayBaseOffset automatic substitution failed. The automatic substitution
+        //   registration was attempted because a call to jdk.internal.misc.Unsafe.arrayBaseOffset(Class) was detected
+        //   in the static initializer of com.lmax.disruptor.RingBufferFields. Detailed failure reason(s): Could not
+        //   determine the field where the value produced by the call to jdk.internal.misc.Unsafe.arrayBaseOffset(Class)
+        //   for the array base offset computation is stored. The call is not directly followed by a field store or by
+        //   a sign extend node followed directly by a field store.
+        //
+        // Even if this is reported as a warning and the native compilation succeed, some static field are not computed
+        // properly which result in weird result as runtime. For such reason, the static init method need to re-run at
+        // runtime.
+        return new RuntimeReinitializedClassBuildItem("com.lmax.disruptor.RingBufferFields");
+    }
+}
diff --git a/extensions-jvm/disruptor/pom.xml b/extensions/disruptor/pom.xml
similarity index 97%
rename from extensions-jvm/disruptor/pom.xml
rename to extensions/disruptor/pom.xml
index 064a759..d44aa8c 100644
--- a/extensions-jvm/disruptor/pom.xml
+++ b/extensions/disruptor/pom.xml
@@ -35,6 +35,5 @@
     <modules>
         <module>deployment</module>
         <module>runtime</module>
-        <module>integration-test</module>
     </modules>
 </project>
diff --git a/extensions-jvm/disruptor/runtime/pom.xml b/extensions/disruptor/runtime/pom.xml
similarity index 95%
rename from extensions-jvm/disruptor/runtime/pom.xml
rename to extensions/disruptor/runtime/pom.xml
index 1f504ed..82fd4f3 100644
--- a/extensions-jvm/disruptor/runtime/pom.xml
+++ b/extensions/disruptor/runtime/pom.xml
@@ -57,6 +57,11 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-disruptor</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.graalvm.nativeimage</groupId>
+            <artifactId>svm</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/extensions/disruptor/runtime/src/main/doc/limitations.adoc b/extensions/disruptor/runtime/src/main/doc/limitations.adoc
new file mode 100644
index 0000000..8b7b02d
--- /dev/null
+++ b/extensions/disruptor/runtime/src/main/doc/limitations.adoc
@@ -0,0 +1 @@
+The `disruptor-vm` component is not available on Camel Quarkus. This is because it is supposed to provide support for communication across multiple CamelContext instances within a single JVM, but by design, there is always just a single `CamelContext` on Camel Quarkus. Therefore `disruptor-vm` would make no sense.
\ No newline at end of file
diff --git a/extensions/disruptor/runtime/src/main/java/org/apache/camel/quarkus/component/disruptor/graal/ThreadHintsSubstitutions.java b/extensions/disruptor/runtime/src/main/java/org/apache/camel/quarkus/component/disruptor/graal/ThreadHintsSubstitutions.java
new file mode 100644
index 0000000..b91cd89
--- /dev/null
+++ b/extensions/disruptor/runtime/src/main/java/org/apache/camel/quarkus/component/disruptor/graal/ThreadHintsSubstitutions.java
@@ -0,0 +1,64 @@
+/*
+ * 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.disruptor.graal;
+
+import java.lang.reflect.Method;
+
+import com.lmax.disruptor.util.ThreadHints;
+import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.annotate.TargetClass;
+import com.oracle.svm.core.jdk.JDK11OrLater;
+import com.oracle.svm.core.jdk.JDK8OrEarlier;
+
+public final class ThreadHintsSubstitutions {
+
+    @TargetClass(value = ThreadHints.class, onlyWith = JDK8OrEarlier.class)
+    @Substitute
+    public final static class ThreadHints_JDK8OrEarlier {
+        @Substitute
+        public static void onSpinWait() {
+            // do nothing since onSpinWait is available in Java >= 9
+        }
+    }
+
+    @TargetClass(value = ThreadHints.class, onlyWith = JDK11OrLater.class)
+    @Substitute
+    public final static class ThreadHints_JDK11OrLater {
+        private static final Method ON_SPIN_WAIT_METHOD = lookupOnSpinWait();
+
+        @Substitute
+        public static void onSpinWait() {
+            if (null != ON_SPIN_WAIT_METHOD) {
+                try {
+                    ON_SPIN_WAIT_METHOD.invoke(null);
+                } catch (final Throwable ignore) {
+                }
+            }
+        }
+
+        public static Method lookupOnSpinWait() {
+            try {
+                // use old good Class.getMethod as the method handle technique used by
+                // ThreadHints seems to be one of the cases not covered by SubstrateVM
+                return Thread.class.getMethod("onSpinWait");
+            } catch (Exception ignore) {
+            }
+
+            return null;
+        }
+    }
+}
diff --git a/extensions-jvm/disruptor/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/disruptor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
similarity index 97%
rename from extensions-jvm/disruptor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
rename to extensions/disruptor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
index 148c4f2..abfc318 100644
--- a/extensions-jvm/disruptor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
+++ b/extensions/disruptor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -24,9 +24,8 @@
 name: "Camel Disruptor"
 description: "Provides asynchronous SEDA behavior using LMAX Disruptor"
 metadata:
-  unlisted: true
   guide: "https://camel.apache.org/camel-quarkus/latest/reference/extensions/disruptor.html"
   categories:
   - "integration"
   status:
-  - "preview"
+  - "stable"
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 3508ead..57248b3 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -90,6 +90,7 @@
         <module>debezium-postgres</module>
         <module>debezium-sqlserver</module>
         <module>direct</module>
+        <module>disruptor</module>
         <module>dozer</module>
         <module>dropbox</module>
         <module>elasticsearch-rest</module>
diff --git a/integration-tests/disruptor/pom.xml b/integration-tests/disruptor/pom.xml
new file mode 100644
index 0000000..8b7d9dd
--- /dev/null
+++ b/integration-tests/disruptor/pom.xml
@@ -0,0 +1,160 @@
+<?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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-integration-tests</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-quarkus-integration-test-disruptor</artifactId>
+    <name>Camel Quarkus :: Integration Tests :: Disruptor</name>
+    <description>Integration tests for Camel Quarkus Disruptor extension</description>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.camel.quarkus</groupId>
+                <artifactId>camel-quarkus-bom-test</artifactId>
+                <version>${project.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-direct</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-disruptor</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-resteasy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-jsonb</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-resteasy-jsonb</artifactId>
+        </dependency>
+
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit5</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-direct-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-disruptor-deployment</artifactId>
+            <version>${project.version}</version>
+            <type>pom</type>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.quarkus</groupId>
+                <artifactId>quarkus-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>build</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>native</id>
+            <activation>
+                <property>
+                    <name>native</name>
+                </property>
+            </activation>
+            <properties>
+                <quarkus.package.type>native</quarkus.package.type>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/integration-tests/disruptor/src/main/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorResource.java b/integration-tests/disruptor/src/main/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorResource.java
new file mode 100644
index 0000000..f923e88
--- /dev/null
+++ b/integration-tests/disruptor/src/main/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorResource.java
@@ -0,0 +1,85 @@
+/*
+ * 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.disruptor.it;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.disruptor.DisruptorEndpoint;
+import org.apache.camel.component.disruptor.DisruptorNotStartedException;
+
+@Path("/disruptor")
+@ApplicationScoped
+public class DisruptorResource {
+    public static final String DISRUPTOR = "disruptor";
+    public static final String DISRUPTOR_VM = "disruptor-vm";
+
+    @Inject
+    CamelContext context;
+    @Inject
+    ProducerTemplate producerTemplate;
+    @Inject
+    ConsumerTemplate consumerTemplate;
+
+    @Path("/component/{componentName}")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response loadComponent(@PathParam("componentName") String componentName) {
+        return context.getComponent(componentName) != null
+                ? Response.ok().build()
+                : Response.status(404, componentName + " could not be loaded from the Camel context").build();
+    }
+
+    @Path("/buffer/{name}")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    public void request(@PathParam("name") String name, String value) {
+        producerTemplate.sendBody(DISRUPTOR + ":" + name, value);
+    }
+
+    @Path("/buffer/{name}")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String request(@PathParam("name") String name) {
+        return consumerTemplate.receiveBody(DISRUPTOR + ":" + name, String.class);
+    }
+
+    @Path("/buffer/{name}/inspect")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject size(@PathParam("name") String name) throws DisruptorNotStartedException {
+        DisruptorEndpoint endpoint = context.getEndpoint(DISRUPTOR + ":" + name, DisruptorEndpoint.class);
+
+        return Json.createObjectBuilder()
+                .add("pendingExchangeCount", endpoint.getPendingExchangeCount())
+                .add("size", endpoint.getSize())
+                .build();
+    }
+}
diff --git a/extensions-jvm/disruptor/integration-test/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorTest.java b/integration-tests/disruptor/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorIT.java
similarity index 59%
rename from extensions-jvm/disruptor/integration-test/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorTest.java
rename to integration-tests/disruptor/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorIT.java
index 4735ecf..90c0488 100644
--- a/extensions-jvm/disruptor/integration-test/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorTest.java
+++ b/integration-tests/disruptor/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorIT.java
@@ -16,27 +16,9 @@
  */
 package org.apache.camel.quarkus.component.disruptor.it;
 
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import org.junit.jupiter.api.Test;
+import io.quarkus.test.junit.NativeImageTest;
 
-@QuarkusTest
-class DisruptorTest {
-
-    @Test
-    public void loadComponentDisruptor() {
-        /* A simple autogenerated test */
-        RestAssured.get("/disruptor/load/component/disruptor")
-                .then()
-                .statusCode(200);
-    }
-
-    @Test
-    public void loadComponentDisruptorVm() {
-        /* A simple autogenerated test */
-        RestAssured.get("/disruptor/load/component/disruptor-vm")
-                .then()
-                .statusCode(200);
-    }
+@NativeImageTest
+class DisruptorIT extends DisruptorTest {
 
 }
diff --git a/integration-tests/disruptor/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorTest.java b/integration-tests/disruptor/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorTest.java
new file mode 100644
index 0000000..922c5c0
--- /dev/null
+++ b/integration-tests/disruptor/src/test/java/org/apache/camel/quarkus/component/disruptor/it/DisruptorTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.disruptor.it;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.core.MediaType;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.awaitility.Awaitility.await;
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+class DisruptorTest {
+
+    @Test
+    public void loadComponent() {
+        RestAssured.get("/disruptor/component/{componentName}", DisruptorResource.DISRUPTOR)
+                .then()
+                .statusCode(200);
+        RestAssured.get("/disruptor/component/{componentName}", DisruptorResource.DISRUPTOR_VM)
+                .then()
+                .statusCode(404);
+    }
+
+    @Test
+    public void putAndTake() {
+        final String id = "the-id";
+        final String value = UUID.randomUUID().toString();
+
+        RestAssured.given()
+                .body(value)
+                .post("/disruptor/buffer/{name}", id)
+                .then()
+                .statusCode(204);
+
+        await().atMost(10L, TimeUnit.SECONDS).until(
+                () -> {
+                    int count = RestAssured.given()
+                            .accept(MediaType.APPLICATION_JSON)
+                            .when()
+                            .get("/disruptor/buffer/{name}/inspect", id)
+                            .then()
+                            .statusCode(200)
+                            .extract().path("pendingExchangeCount");
+
+                    return count == 1;
+                });
+
+        RestAssured.get("/disruptor/buffer/{name}", id)
+                .then()
+                .statusCode(200)
+                .body(is(value));
+
+        RestAssured.given()
+                .accept(MediaType.APPLICATION_JSON)
+                .when()
+                .get("/disruptor/buffer/{name}/inspect", id)
+                .then()
+                .statusCode(200)
+                .body("pendingExchangeCount", is(0), "size", is(0));
+    }
+}
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 8440a0a..1e5c5dc 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -81,6 +81,7 @@
         <module>dataformat</module>
         <module>dataformats-json</module>
         <module>debezium</module>
+        <module>disruptor</module>
         <module>dozer</module>
         <module>dropbox</module>
         <module>elasticsearch-rest</module>
diff --git a/tooling/scripts/test-categories.yaml b/tooling/scripts/test-categories.yaml
index c64791b..300605c 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -103,6 +103,7 @@ misc:
   - tika
   - as2
   - kotlin
+  - disruptor
 networking2-dataformats:
   - git
   - mail