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

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 43fbb94db520 CAMEL-23647: Use Vert.x APIs that exist in Vert.x 5 for 
Camel Quarkus supported components
43fbb94db520 is described below

commit 43fbb94db5205948599def333f8b6380bc39e399
Author: James Netherton <[email protected]>
AuthorDate: Mon Oct 5 15:38:41 2026 +0100

    CAMEL-23647: Use Vert.x APIs that exist in Vert.x 5 for Camel Quarkus 
supported components
    
    * CAMEL-23647: Use Vert.x APIs that exist in Vert.x 5 for Camel Quarkus 
supported components
    
    Co-Authored-By: Claude Fable 5.1 <[email protected]>
    
    * CAMEL-23647: upgrade guide - put the camel-vertx section after the 
camel-vertx-http section
    
    The section was inserted before the last paragraph of the camel-vertx-http
    section, so that paragraph rendered under the camel-vertx heading.
    
    Co-Authored-By: Claude Fable 5.1 <[email protected]>
    
    * CAMEL-23647: remove the unused keyManagerMapper override, test a custom 
vertxFactory
    
    KeyManagerFactoryOptions.keyManagerMapper had no caller left: Vert.x 4 only
    calls keyManagerFactoryMapper, whose default was the only thing that used 
it,
    and that default is now overridden. The Vert.x 5 interface has no such 
method.
    
    VertxFactoryTest sets a VertxBuilder on the vertx component and checks that
    the Vert.x instance is built by it.
    
    Co-Authored-By: Claude Fable 5.1 <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Fable 5.1 <[email protected]>
---
 .../org/apache/camel/catalog/components/vertx.json |   2 +-
 .../knative/http/KnativeHttpProducer.java          |   3 +-
 .../http/vertx/VertxPlatformHttpServer.java        |  39 ++++----
 .../vertx/common/KeyManagerFactoryOptions.java     |  11 +--
 .../component/vertx/http/VertxHttpProducer.java    |  22 ++---
 .../vertx/websocket/VertxWebsocketHelper.java      | 102 ++++++++++++++++++++-
 .../vertx/websocket/VertxWebsocketHost.java        |   6 +-
 .../vertx/websocket/VertxWebsocketProducer.java    |   6 +-
 .../vertx/websocket/VertxWebsocketHelperTest.java  |  71 ++++++++++++++
 .../vertx/websocket/VertxWebsocketSSLTest.java     |  50 ++++++++++
 .../component/vertx/VertxComponentConfigurer.java  |   4 +-
 .../org/apache/camel/component/vertx/vertx.json    |   2 +-
 .../camel/component/vertx/VertxComponent.java      |   9 +-
 .../camel/component/vertx/VertxProducer.java       |   2 +-
 .../camel/component/vertx/VertxFactoryTest.java    |  73 +++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  19 ++++
 .../dsl/VertxComponentBuilderFactory.java          |   8 +-
 17 files changed, 367 insertions(+), 62 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx.json
index b7795dc51c07..acea0b0eab45 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx.json
@@ -32,7 +32,7 @@
     "bridgeErrorHandler": { "index": 5, "kind": "property", "displayName": 
"Bridge Error Handler", "group": "consumer", "label": "consumer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Allows for bridging the consumer to the Camel routing Error Handler, which 
mean any exceptions (if possible) occurred while the Camel consumer is trying 
to pickup incoming messages, or the like [...]
     "lazyStartProducer": { "index": 6, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
     "autowiredEnabled": { "index": 7, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
-    "vertxFactory": { "index": 8, "kind": "property", "displayName": "Vertx 
Factory", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "io.vertx.core.impl.VertxBuilder", "deprecated": false, 
"autowired": false, "secret": false, "description": "To use a custom 
VertxFactory implementation" }
+    "vertxFactory": { "index": 8, "kind": "property", "displayName": "Vertx 
Factory", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "io.vertx.core.VertxBuilder", "deprecated": false, 
"autowired": false, "secret": false, "description": "To use a custom 
VertxFactory implementation" }
   },
   "properties": {
     "address": { "index": 0, "kind": "path", "displayName": "Address", 
"group": "common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Sets the event bus address used to 
communicate" },
diff --git 
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
 
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
index afa2c4ee96c5..292cca041aa0 100644
--- 
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
+++ 
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpProducer.java
@@ -110,7 +110,8 @@ public class KnativeHttpProducer extends 
DefaultAsyncProducer {
 
         client.postAbs(this.uri)
                 .putHeaders(headers)
-                .sendBuffer(Buffer.buffer(payload), response -> {
+                .sendBuffer(Buffer.buffer(payload))
+                .onComplete(response -> {
                     if (response.succeeded()) {
                         HttpResponse<Buffer> result = response.result();
                         Message answer = exchange.getMessage();
diff --git 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
index 62650db1781e..9a03036a69d6 100644
--- 
a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
+++ 
b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpServer.java
@@ -227,23 +227,24 @@ public class VertxPlatformHttpServer extends 
ServiceSupport implements CamelCont
         CompletableFuture.runAsync(
                 () -> {
                     CountDownLatch latch = new CountDownLatch(1);
-                    
server.requestHandler(router).listen(configuration.getBindPort(), 
configuration.getBindHost(), result -> {
-                        try {
-                            if (result.failed()) {
-                                LOGGER.warn("Failed to start Vert.x HttpServer 
on {}:{}, reason: {}",
-                                        configuration.getBindHost(),
-                                        configuration.getBindPort(),
-                                        result.cause().getMessage());
-
-                                throw new RuntimeException(result.cause());
-                            }
-
-                            LOGGER.info("Vert.x HttpServer started on {}:{}", 
configuration.getBindHost(),
-                                    server.actualPort());
-                        } finally {
-                            latch.countDown();
-                        }
-                    });
+                    
server.requestHandler(router).listen(configuration.getBindPort(), 
configuration.getBindHost())
+                            .onComplete(result -> {
+                                try {
+                                    if (result.failed()) {
+                                        LOGGER.warn("Failed to start Vert.x 
HttpServer on {}:{}, reason: {}",
+                                                configuration.getBindHost(),
+                                                configuration.getBindPort(),
+                                                result.cause().getMessage());
+
+                                        throw new 
RuntimeException(result.cause());
+                                    }
+
+                                    LOGGER.info("Vert.x HttpServer started on 
{}:{}", configuration.getBindHost(),
+                                            server.actualPort());
+                                } finally {
+                                    latch.countDown();
+                                }
+                            });
 
                     try {
                         latch.await();
@@ -268,7 +269,7 @@ public class VertxPlatformHttpServer extends ServiceSupport 
implements CamelCont
                         // remove the platform-http component
                         
context.removeComponent(PlatformHttpConstants.PLATFORM_HTTP_COMPONENT_NAME);
 
-                        server.close(result -> {
+                        server.close().onComplete(result -> {
                             try {
                                 if (result.failed()) {
                                     LOGGER.warn("Failed to close Vert.x 
HttpServer reason: {}",
@@ -306,7 +307,7 @@ public class VertxPlatformHttpServer extends ServiceSupport 
implements CamelCont
                     () -> {
                         CountDownLatch latch = new CountDownLatch(1);
 
-                        vertx.close(result -> {
+                        vertx.close().onComplete(result -> {
                             try {
                                 if (result.failed()) {
                                     LOGGER.warn("Failed to close Vert.x 
reason: {}",
diff --git 
a/components/camel-vertx/camel-vertx-common/src/main/java/org/apache/camel/component/vertx/common/KeyManagerFactoryOptions.java
 
b/components/camel-vertx/camel-vertx-common/src/main/java/org/apache/camel/component/vertx/common/KeyManagerFactoryOptions.java
index 86f652382480..97adce129b68 100644
--- 
a/components/camel-vertx/camel-vertx-common/src/main/java/org/apache/camel/component/vertx/common/KeyManagerFactoryOptions.java
+++ 
b/components/camel-vertx/camel-vertx-common/src/main/java/org/apache/camel/component/vertx/common/KeyManagerFactoryOptions.java
@@ -19,7 +19,6 @@ package org.apache.camel.component.vertx.common;
 import java.util.function.Function;
 
 import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.X509KeyManager;
 
 import io.vertx.core.Vertx;
 import io.vertx.core.net.KeyCertOptions;
@@ -46,12 +45,8 @@ public class KeyManagerFactoryOptions implements 
KeyCertOptions {
     }
 
     @Override
-    public Function<String, X509KeyManager> keyManagerMapper(Vertx vertx) {
-        if (keyManagerFactory == null || keyManagerFactory.getKeyManagers() == 
null
-                || keyManagerFactory.getKeyManagers().length == 0) {
-            return null;
-        }
-        return keyManagerFactory.getKeyManagers()[0] instanceof X509KeyManager
-                ? serverName -> (X509KeyManager) 
keyManagerFactory.getKeyManagers()[0] : null;
+    public Function<String, KeyManagerFactory> keyManagerFactoryMapper(Vertx 
vertx) {
+        // There is no key material per server name, so Vert.x falls back to 
getKeyManagerFactory(Vertx)
+        return serverName -> null;
     }
 }
diff --git 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java
 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java
index d3ba891e0c12..1bce789e634a 100644
--- 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java
+++ 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java
@@ -74,7 +74,7 @@ public class VertxHttpProducer extends DefaultAsyncProducer {
 
             Object body = message.getBody();
             if (body == null) {
-                request.send(resultHandler);
+                request.send().onComplete(resultHandler);
             } else {
                 String contentType = MessageHelper.getContentType(message);
                 boolean multipart = 
getEndpoint().getConfiguration().isMultipartUpload();
@@ -82,16 +82,16 @@ public class VertxHttpProducer extends DefaultAsyncProducer 
{
 
                 // Handle vertx specific body first
                 if (body instanceof MultiMap mm) {
-                    request.sendForm(mm, resultHandler);
+                    request.sendForm(mm).onComplete(resultHandler);
                     return false;
                 } else if (body instanceof MultipartForm mf) {
-                    request.sendMultipartForm(mf, resultHandler);
+                    request.sendMultipartForm(mf).onComplete(resultHandler);
                     return false;
                 } else if (body instanceof ReadStream rs) {
-                    request.sendStream(rs, resultHandler);
+                    request.sendStream(rs).onComplete(resultHandler);
                     return false;
                 } else if (body instanceof Buffer buf) {
-                    request.sendBuffer(buf, resultHandler);
+                    request.sendBuffer(buf).onComplete(resultHandler);
                     return false;
                 }
 
@@ -117,9 +117,9 @@ public class VertxHttpProducer extends DefaultAsyncProducer 
{
                             type = "application/octet-stream"; // default 
binary
                         }
                         MultipartForm form = 
MultipartForm.create().binaryFileUpload(multipartName, fileName, buf, type);
-                        request.sendMultipartForm(form, resultHandler);
+                        
request.sendMultipartForm(form).onComplete(resultHandler);
                     } else {
-                        request.sendBuffer(buf, resultHandler);
+                        request.sendBuffer(buf).onComplete(resultHandler);
                     }
                 } else if (body instanceof String str) {
                     // Try to extract URL encoded form data from the message 
body
@@ -127,11 +127,11 @@ public class VertxHttpProducer extends 
DefaultAsyncProducer {
                         MultiMap map = MultiMap.caseInsensitiveMultiMap();
                         Map<String, Object> formParams = 
URISupport.parseQuery(str);
                         formParams.forEach((key, o) -> map.add(key, 
String.valueOf(o)));
-                        request.sendForm(map, resultHandler);
+                        request.sendForm(map).onComplete(resultHandler);
                     } else {
                         // Fallback to send as Buffer
                         Buffer buffer = VertxBufferConverter.toBuffer(str, 
exchange);
-                        request.sendBuffer(buffer, resultHandler);
+                        request.sendBuffer(buffer).onComplete(resultHandler);
                     }
                 } else {
                     // Handle x-java-serialized-object Content-Type
@@ -144,11 +144,11 @@ public class VertxHttpProducer extends 
DefaultAsyncProducer {
                         try (ByteArrayOutputStream baos = new 
ByteArrayOutputStream()) {
                             Serializable serializable = 
message.getMandatoryBody(Serializable.class);
                             VertxHttpHelper.writeObjectToStream(baos, 
serializable);
-                            
request.sendBuffer(Buffer.buffer(baos.toByteArray()), resultHandler);
+                            
request.sendBuffer(Buffer.buffer(baos.toByteArray())).onComplete(resultHandler);
                         }
                     } else {
                         Buffer buffer = message.getMandatoryBody(Buffer.class);
-                        request.sendBuffer(buffer, resultHandler);
+                        request.sendBuffer(buffer).onComplete(resultHandler);
                     }
                 }
             }
diff --git 
a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelper.java
 
b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelper.java
index 4c8d6183e2ee..883a4effc525 100644
--- 
a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelper.java
+++ 
b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelper.java
@@ -19,7 +19,6 @@ package org.apache.camel.component.vertx.websocket;
 import java.net.URI;
 import java.util.Map;
 
-import io.vertx.core.http.impl.HttpUtils;
 import org.apache.camel.util.CollectionHelper;
 import org.apache.camel.util.ObjectHelper;
 
@@ -62,8 +61,8 @@ public final class VertxWebsocketHelper {
             hostPath = hostPath.substring(0, hostPath.lastIndexOf('*'));
         }
 
-        String normalizedHostPath = HttpUtils.normalizePath(hostPath + "/");
-        String normalizedTargetPath = HttpUtils.normalizePath(targetPath + 
"/");
+        String normalizedHostPath = normalizePath(hostPath + "/");
+        String normalizedTargetPath = normalizePath(targetPath + "/");
         String[] hostPathElements = normalizedHostPath.split("/");
         String[] targetPathElements = normalizedTargetPath.split("/");
 
@@ -77,4 +76,101 @@ public final class VertxWebsocketHelper {
             return normalizedTargetPath.startsWith(normalizedHostPath);
         }
     }
+
+    /**
+     * Normalizes a path in the same way that Vert.x normalizes the path of an 
HTTP request. A leading slash is
+     * guaranteed, percent-encoded unreserved characters are decoded, dot 
segments are removed as described in RFC 3986
+     * section 5.2.4 and consecutive slashes are collapsed into one.
+     */
+    private static String normalizePath(String path) {
+        if (path.isEmpty()) {
+            return "/";
+        }
+
+        if (path.indexOf('%') == -1 && path.indexOf('.') == -1 && 
!path.contains("//")) {
+            // Nothing to decode or remove
+            return path.charAt(0) == '/' ? path : "/" + path;
+        }
+
+        StringBuilder buffer = new StringBuilder(path.length() + 1);
+        if (path.charAt(0) != '/') {
+            buffer.append('/');
+        }
+        buffer.append(path);
+        decodeUnreservedCharacters(buffer);
+        return removeDotSegments(buffer);
+    }
+
+    /**
+     * Decodes the percent-encoded characters that RFC 3986 section 2.3 
defines as unreserved. Any other percent-encoded
+     * character is left as it is.
+     */
+    private static void decodeUnreservedCharacters(StringBuilder path) {
+        for (int i = 0; i < path.length(); i++) {
+            if (path.charAt(i) != '%') {
+                continue;
+            }
+
+            if (i + 3 > path.length()) {
+                throw new IllegalArgumentException("Invalid position for 
escape character: " + i);
+            }
+
+            String escapeSequence = path.substring(i + 1, i + 3);
+            int unescaped;
+            try {
+                unescaped = Integer.parseInt(escapeSequence, 16);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Invalid escape sequence: 
%" + escapeSequence);
+            }
+            if (unescaped < 0) {
+                throw new IllegalArgumentException("Invalid escape sequence: 
%" + escapeSequence);
+            }
+
+            if (isUnreservedCharacter(unescaped)) {
+                path.setCharAt(i, (char) unescaped);
+                path.delete(i + 1, i + 3);
+            }
+        }
+    }
+
+    private static boolean isUnreservedCharacter(int c) {
+        return c >= 'A' && c <= 'Z'
+                || c >= 'a' && c <= 'z'
+                || c >= '0' && c <= '9'
+                || c == '-' || c == '.' || c == '_' || c == '~';
+    }
+
+    /**
+     * Removes the dot segments of a path that starts with a slash, and 
collapses consecutive slashes into one.
+     */
+    private static String removeDotSegments(StringBuilder path) {
+        StringBuilder result = new StringBuilder(path.length());
+
+        // Each iteration handles one segment, where start is the position of 
the slash that precedes it
+        int start = 0;
+        while (start != -1) {
+            int end = path.indexOf("/", start + 1);
+            String segment = path.substring(start + 1, end == -1 ? 
path.length() : end);
+            boolean dotSegment = segment.equals(".") || segment.equals("..");
+
+            if (segment.equals("..")) {
+                // Step back over the previous segment
+                result.setLength(Math.max(result.lastIndexOf("/"), 0));
+            }
+
+            // A dot segment is dropped, but when it ends the path its slash 
is preserved
+            if (!dotSegment || end == -1) {
+                if (result.length() == 0 || result.charAt(result.length() - 1) 
!= '/') {
+                    result.append('/');
+                }
+                if (!dotSegment) {
+                    result.append(segment);
+                }
+            }
+
+            start = end;
+        }
+
+        return result.toString();
+    }
 }
diff --git 
a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHost.java
 
b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHost.java
index 630d85f1ad20..8118b7a7054f 100644
--- 
a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHost.java
+++ 
b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHost.java
@@ -100,7 +100,7 @@ public class VertxWebsocketHost {
                     request.pause();
                 }
                 // upgrade
-                request.toWebSocket(toWebSocket -> {
+                request.toWebSocket().onComplete(toWebSocket -> {
                     if (toWebSocket.succeeded()) {
                         // resume the parsing
                         if (!parseEnded) {
@@ -200,7 +200,7 @@ public class VertxWebsocketHost {
             }
 
             CompletableFuture<Void> future = new CompletableFuture<>();
-            server.requestHandler(router).listen(hostKey.getPort(), 
hostKey.getHost(), result -> {
+            server.requestHandler(router).listen(hostKey.getPort(), 
hostKey.getHost()).onComplete(result -> {
                 if (!result.failed()) {
                     port = result.result().actualPort();
                     future.complete(null);
@@ -221,7 +221,7 @@ public class VertxWebsocketHost {
             LOG.info("Stopping server");
             try {
                 CompletableFuture<Void> future = new CompletableFuture<>();
-                server.close(result -> {
+                server.close().onComplete(result -> {
                     if (result.failed()) {
                         future.completeExceptionally(result.cause());
                         return;
diff --git 
a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketProducer.java
 
b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketProducer.java
index 28ab393b84a3..a1475f84e46a 100644
--- 
a/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketProducer.java
+++ 
b/components/camel-vertx/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketProducer.java
@@ -89,12 +89,12 @@ public class VertxWebsocketProducer extends 
DefaultAsyncProducer {
                         vertxWebsocketResultHandler.onResult(connectionKey);
                     } else {
                         if (message instanceof String) {
-                            webSocket.writeTextMessage((String) message, 
handler);
+                            webSocket.writeTextMessage((String) 
message).onComplete(handler);
                         } else if (message instanceof byte[]) {
-                            
webSocket.writeBinaryMessage(Buffer.buffer((byte[]) message), handler);
+                            
webSocket.writeBinaryMessage(Buffer.buffer((byte[]) 
message)).onComplete(handler);
                         } else {
                             // Try to fallback on String conversion
-                            
webSocket.writeTextMessage(in.getBody(String.class), handler);
+                            
webSocket.writeTextMessage(in.getBody(String.class)).onComplete(handler);
                         }
                     }
                 } else {
diff --git 
a/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelperTest.java
 
b/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelperTest.java
index 2d2f1d3d3124..0300e2b35f77 100644
--- 
a/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelperTest.java
+++ 
b/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelperTest.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.vertx.websocket;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class VertxWebsocketHelperTest {
@@ -106,4 +107,74 @@ public class VertxWebsocketHelperTest {
         String targetPath = null;
         assertFalse(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
     }
+
+    @Test
+    void webSocketHostPathWithDotSegmentsMatches() {
+        String hostPath = "/foo/bar/cheese/wine";
+        String targetPath = "/foo/./bar/beer/../cheese/wine";
+        assertTrue(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithTrailingDotSegmentMatches() {
+        String hostPath = "/foo/bar/cheese/wine";
+        String targetPath = "/foo/bar/cheese/wine/beer/..";
+        assertTrue(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithDotSegmentsNotMatches() {
+        String hostPath = "/foo/bar/cheese/wine";
+        String targetPath = "/foo/bar/cheese/wine/../beer";
+        assertFalse(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostWildcardPathWithDotSegmentsNotMatches() {
+        String hostPath = "/foo/bar*";
+        String targetPath = "/foo/bar/../../cheese/wine";
+        assertFalse(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithEncodedDotSegmentsNotMatches() {
+        String hostPath = "/foo/bar*";
+        String targetPath = "/foo/bar/%2E%2E/%2e%2e/cheese/wine";
+        assertFalse(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithEncodedUnreservedCharactersMatches() {
+        String hostPath = "/foo/bar/cheese/wine";
+        String targetPath = "/foo/%62%61%72/cheese/wine";
+        assertTrue(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithEncodedReservedCharactersNotMatches() {
+        String hostPath = "/foo/bar/cheese/wine";
+        String targetPath = "/foo/bar%2Fcheese/wine";
+        assertFalse(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithoutLeadingSlashMatches() {
+        String hostPath = "/foo/bar/cheese/wine";
+        String targetPath = "foo/bar/cheese/wine";
+        assertTrue(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithMultipleSlashesMatches() {
+        String hostPath = "/foo/bar/cheese/wine";
+        String targetPath = "//foo///bar/cheese//wine";
+        assertTrue(VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
targetPath));
+    }
+
+    @Test
+    void webSocketHostPathWithInvalidEscapeSequenceThrows() {
+        String hostPath = "/foo/bar";
+        assertThrows(IllegalArgumentException.class,
+                () -> VertxWebsocketHelper.webSocketHostPathMatches(hostPath, 
"/foo/%zz"));
+    }
 }
diff --git 
a/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketSSLTest.java
 
b/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketSSLTest.java
index 75fd3b1111ea..51af01de398e 100644
--- 
a/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketSSLTest.java
+++ 
b/components/camel-vertx/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketSSLTest.java
@@ -16,10 +16,19 @@
  */
 package org.apache.camel.component.vertx.websocket;
 
+import java.util.concurrent.TimeUnit;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpClientOptions;
+import io.vertx.core.http.HttpClientRequest;
+import io.vertx.core.http.HttpClientResponse;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerOptions;
 import org.apache.camel.CamelContext;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.vertx.common.VertxHelper;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.support.jsse.KeyManagersParameters;
 import org.apache.camel.support.jsse.KeyStoreParameters;
@@ -29,6 +38,8 @@ import org.apache.camel.support.jsse.TrustManagersParameters;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 public class VertxWebsocketSSLTest extends VertxWebSocketTestSupport {
 
     private SSLContextParameters serverSSLParameters;
@@ -209,6 +220,45 @@ public class VertxWebsocketSSLTest extends 
VertxWebSocketTestSupport {
         }
     }
 
+    @Test
+    void testServerNameIndication() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() {
+                
fromF("vertx-websocket:localhost:%d/echo?sslContextParameters=#serverSSLParameters&serverOptions=#serverOptions",
+                        port.getPort())
+                        .to("mock:result");
+            }
+        });
+
+        context.getRegistry().bind("serverSSLParameters", serverSSLParameters);
+        context.getRegistry().bind("serverOptions", new 
HttpServerOptions().setSni(true));
+
+        context.start();
+        Vertx vertx = Vertx.vertx();
+        try {
+            // The JDK does not indicate a server name for localhost, so make 
the client do it
+            HttpClientOptions clientOptions = new 
HttpClientOptions().setForceSni(true);
+            VertxHelper.setupSSLOptions(context, clientSSLParameters, 
clientOptions);
+
+            // A request that is not a WebSocket upgrade is rejected, which 
can only happen once the TLS handshake
+            // has succeeded with the key material of the SSLContextParameters 
on both sides
+            int statusCode = vertx.createHttpClient(clientOptions)
+                    .request(HttpMethod.GET, port.getPort(), "localhost", 
"/echo")
+                    .compose(HttpClientRequest::send)
+                    .map(HttpClientResponse::statusCode)
+                    .toCompletionStage()
+                    .toCompletableFuture()
+                    .get(10, TimeUnit.SECONDS);
+
+            assertEquals(400, statusCode);
+        } finally {
+            vertx.close();
+            context.stop();
+        }
+    }
+
     @Override
     protected void startCamelContext() {
     }
diff --git 
a/components/camel-vertx/camel-vertx/src/generated/java/org/apache/camel/component/vertx/VertxComponentConfigurer.java
 
b/components/camel-vertx/camel-vertx/src/generated/java/org/apache/camel/component/vertx/VertxComponentConfigurer.java
index a0e651a7e586..465afe5dd349 100644
--- 
a/components/camel-vertx/camel-vertx/src/generated/java/org/apache/camel/component/vertx/VertxComponentConfigurer.java
+++ 
b/components/camel-vertx/camel-vertx/src/generated/java/org/apache/camel/component/vertx/VertxComponentConfigurer.java
@@ -34,7 +34,7 @@ public class VertxComponentConfigurer extends 
PropertyConfigurerSupport implemen
         case "timeout": target.setTimeout(property(camelContext, int.class, 
value)); return true;
         case "vertx": target.setVertx(property(camelContext, 
io.vertx.core.Vertx.class, value)); return true;
         case "vertxfactory":
-        case "vertxFactory": target.setVertxFactory(property(camelContext, 
io.vertx.core.impl.VertxBuilder.class, value)); return true;
+        case "vertxFactory": target.setVertxFactory(property(camelContext, 
io.vertx.core.VertxBuilder.class, value)); return true;
         case "vertxoptions":
         case "vertxOptions": target.setVertxOptions(property(camelContext, 
io.vertx.core.VertxOptions.class, value)); return true;
         default: return false;
@@ -60,7 +60,7 @@ public class VertxComponentConfigurer extends 
PropertyConfigurerSupport implemen
         case "timeout": return int.class;
         case "vertx": return io.vertx.core.Vertx.class;
         case "vertxfactory":
-        case "vertxFactory": return io.vertx.core.impl.VertxBuilder.class;
+        case "vertxFactory": return io.vertx.core.VertxBuilder.class;
         case "vertxoptions":
         case "vertxOptions": return io.vertx.core.VertxOptions.class;
         default: return null;
diff --git 
a/components/camel-vertx/camel-vertx/src/generated/resources/META-INF/org/apache/camel/component/vertx/vertx.json
 
b/components/camel-vertx/camel-vertx/src/generated/resources/META-INF/org/apache/camel/component/vertx/vertx.json
index b7795dc51c07..acea0b0eab45 100644
--- 
a/components/camel-vertx/camel-vertx/src/generated/resources/META-INF/org/apache/camel/component/vertx/vertx.json
+++ 
b/components/camel-vertx/camel-vertx/src/generated/resources/META-INF/org/apache/camel/component/vertx/vertx.json
@@ -32,7 +32,7 @@
     "bridgeErrorHandler": { "index": 5, "kind": "property", "displayName": 
"Bridge Error Handler", "group": "consumer", "label": "consumer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Allows for bridging the consumer to the Camel routing Error Handler, which 
mean any exceptions (if possible) occurred while the Camel consumer is trying 
to pickup incoming messages, or the like [...]
     "lazyStartProducer": { "index": 6, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
     "autowiredEnabled": { "index": 7, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
-    "vertxFactory": { "index": 8, "kind": "property", "displayName": "Vertx 
Factory", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "io.vertx.core.impl.VertxBuilder", "deprecated": false, 
"autowired": false, "secret": false, "description": "To use a custom 
VertxFactory implementation" }
+    "vertxFactory": { "index": 8, "kind": "property", "displayName": "Vertx 
Factory", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "io.vertx.core.VertxBuilder", "deprecated": false, 
"autowired": false, "secret": false, "description": "To use a custom 
VertxFactory implementation" }
   },
   "properties": {
     "address": { "index": 0, "kind": "path", "displayName": "Address", 
"group": "common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Sets the event bus address used to 
communicate" },
diff --git 
a/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxComponent.java
 
b/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxComponent.java
index 259e08e6fdb4..9a9ab509514f 100644
--- 
a/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxComponent.java
+++ 
b/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxComponent.java
@@ -20,10 +20,9 @@ import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import io.vertx.core.AsyncResult;
 import io.vertx.core.Vertx;
+import io.vertx.core.VertxBuilder;
 import io.vertx.core.VertxOptions;
-import io.vertx.core.impl.VertxBuilder;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.spi.Metadata;
@@ -156,7 +155,7 @@ public class VertxComponent extends DefaultComponent {
             }
 
             if (vertxFactory == null) {
-                vertxFactory = new VertxBuilder(vertxOptions);
+                vertxFactory = Vertx.builder().with(vertxOptions);
             }
 
             // we are creating vertx so we should handle its lifecycle
@@ -169,7 +168,7 @@ public class VertxComponent extends DefaultComponent {
                 LOG.info("Creating Clustered Vertx {}:{}", 
vertxOptions.getEventBusOptions().getHost(),
                         vertxOptions.getEventBusOptions().getPort());
                 // use the async api as we want to wait for the eventbus to be 
ready before we are in started state
-                vertxFactory.clusteredVertx((AsyncResult<Vertx> event) -> {
+                vertxFactory.buildClustered().onComplete(event -> {
                     if (event.cause() != null) {
                         LOG.warn("Error creating Clustered Vertx {}:{} due 
{}", host, port,
                                 event.cause().getMessage(), event.cause());
@@ -182,7 +181,7 @@ public class VertxComponent extends DefaultComponent {
                 });
             } else {
                 LOG.info("Creating Non-Clustered Vertx");
-                vertx = vertxFactory.init().vertx();
+                vertx = vertxFactory.build();
                 LOG.info("EventBus is ready: {}", vertx);
                 latch.countDown();
             }
diff --git 
a/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxProducer.java
 
b/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxProducer.java
index ea4eb70124b8..a1b292626c81 100644
--- 
a/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxProducer.java
+++ 
b/components/camel-vertx/camel-vertx/src/main/java/org/apache/camel/component/vertx/VertxProducer.java
@@ -60,7 +60,7 @@ public class VertxProducer extends DefaultAsyncProducer {
         if (body != null) {
             if (reply) {
                 LOG.debug("Sending to: {} with body: {}", address, body);
-                eventBus.request(address, body, new 
CamelReplyHandler(exchange, callback));
+                eventBus.<Object> request(address, body).onComplete(new 
CamelReplyHandler(exchange, callback));
                 return false;
             } else {
                 if (pubSub) {
diff --git 
a/components/camel-vertx/camel-vertx/src/test/java/org/apache/camel/component/vertx/VertxFactoryTest.java
 
b/components/camel-vertx/camel-vertx/src/test/java/org/apache/camel/component/vertx/VertxFactoryTest.java
new file mode 100644
index 000000000000..551820e3a1c9
--- /dev/null
+++ 
b/components/camel-vertx/camel-vertx/src/test/java/org/apache/camel/component/vertx/VertxFactoryTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.component.vertx;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
+import io.vertx.core.spi.VertxMetricsFactory;
+import io.vertx.core.spi.metrics.VertxMetrics;
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class VertxFactoryTest extends VertxBaseTestSupport {
+
+    private final AtomicBoolean metricsCreated = new AtomicBoolean();
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+
+        // The metrics factory is only consulted when Vert.x is built by this 
builder
+        VertxMetricsFactory metricsFactory = options -> {
+            metricsCreated.set(true);
+            return new VertxMetrics() {
+            };
+        };
+
+        VertxComponent component = new VertxComponent();
+        component.setVertxFactory(Vertx.builder().with(new 
VertxOptions()).withMetrics(metricsFactory));
+        context.addComponent("vertx", component);
+        return context;
+    }
+
+    @Test
+    public void testVertxFactory() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello World");
+
+        template.sendBody("vertx:foo", "Hello World");
+
+        mock.assertIsSatisfied();
+        assertTrue(metricsCreated.get(), "Vert.x was not created by the 
configured vertxFactory");
+        assertTrue(context.getComponent("vertx", 
VertxComponent.class).getVertx().isMetricsEnabled());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("vertx:foo").to("mock:result");
+            }
+        };
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 85f7d6333c9f..2170298d9585 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -3394,6 +3394,25 @@ custom `headerFilterStrategy` is used as-is and is 
unaffected.
 Routes that relied on one of those headers reaching the wire must set it 
through the endpoint
 configuration or supply a `headerFilterStrategy` that permits it.
 
+=== camel-vertx - the vertxFactory option takes the public VertxBuilder
+
+The type of the `vertxFactory` option of the `vertx` component changed from 
the Vert.x internal class
+`io.vertx.core.impl.VertxBuilder` to the public interface 
`io.vertx.core.VertxBuilder`. The internal
+class does not implement the interface, and it no longer exists in Vert.x 5.
+
+An application that sets this option must create the builder with 
`Vertx.builder()`:
+
+[source,java]
+----
+// before
+component.setVertxFactory(new io.vertx.core.impl.VertxBuilder(options));
+
+// after
+component.setVertxFactory(Vertx.builder().with(options));
+----
+
+An application that does not set `vertxFactory` is not affected.
+
 === camel-disruptor - an interrupted request/reply producer fails the exchange
 
 A Disruptor producer whose thread is interrupted while it waits for the reply 
without a timeout (`waitForTaskToComplete`
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/VertxComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/VertxComponentBuilderFactory.java
index 9e9140b88ef1..e9f11c1cf141 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/VertxComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/VertxComponentBuilderFactory.java
@@ -208,15 +208,15 @@ public interface VertxComponentBuilderFactory {
         /**
          * To use a custom VertxFactory implementation.
          * 
-         * The option is a:
-         * &lt;code&gt;io.vertx.core.impl.VertxBuilder&lt;/code&gt; type.
+         * The option is a: &lt;code&gt;io.vertx.core.VertxBuilder&lt;/code&gt;
+         * type.
          * 
          * Group: advanced
          * 
          * @param vertxFactory the value to set
          * @return the dsl builder
          */
-        default VertxComponentBuilder 
vertxFactory(io.vertx.core.impl.VertxBuilder vertxFactory) {
+        default VertxComponentBuilder vertxFactory(io.vertx.core.VertxBuilder 
vertxFactory) {
             doSetProperty("vertxFactory", vertxFactory);
             return this;
         }
@@ -243,7 +243,7 @@ public interface VertxComponentBuilderFactory {
             case "bridgeErrorHandler": ((VertxComponent) 
component).setBridgeErrorHandler((boolean) value); return true;
             case "lazyStartProducer": ((VertxComponent) 
component).setLazyStartProducer((boolean) value); return true;
             case "autowiredEnabled": ((VertxComponent) 
component).setAutowiredEnabled((boolean) value); return true;
-            case "vertxFactory": ((VertxComponent) 
component).setVertxFactory((io.vertx.core.impl.VertxBuilder) value); return 
true;
+            case "vertxFactory": ((VertxComponent) 
component).setVertxFactory((io.vertx.core.VertxBuilder) value); return true;
             default: return false;
             }
         }

Reply via email to