You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2020/07/02 12:23:06 UTC

[camel] branch master updated: CAMEL-14956: Add Vert.x WebSocket component (#3966)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 93cc47b  CAMEL-14956: Add Vert.x WebSocket component (#3966)
93cc47b is described below

commit 93cc47bf46516f088bcb69cf31658e4996348879
Author: James Netherton <ja...@users.noreply.github.com>
AuthorDate: Thu Jul 2 13:17:07 2020 +0100

    CAMEL-14956: Add Vert.x WebSocket component (#3966)
---
 apache-camel/src/main/descriptors/common-bin.xml   |   1 +
 bom/camel-bom/pom.xml                              |   5 +
 .../org/apache/camel/catalog/components.properties |   1 +
 .../camel/catalog/components/vertx-websocket.json  |  48 ++
 .../org/apache/camel/catalog/docs.properties       |   1 +
 .../catalog/docs/vertx-websocket-component.adoc    | 131 ++++
 components/camel-vertx-websocket/pom.xml           |  60 ++
 .../VertxWebsocketComponentConfigurer.java         |  68 ++
 .../VertxWebsocketEndpointConfigurer.java          |  96 +++
 .../services/org/apache/camel/component.properties |   7 +
 .../org/apache/camel/component/vertx-websocket     |   2 +
 .../camel/configurer/vertx-websocket-component     |   2 +
 .../camel/configurer/vertx-websocket-endpoint      |   2 +
 .../component/vertx/websocket/vertx-websocket.json |  48 ++
 .../src/main/docs/vertx-websocket-component.adoc   | 131 ++++
 .../vertx/websocket/VertxWebsocketComponent.java   | 172 ++++++
 .../websocket/VertxWebsocketConfiguration.java     | 150 +++++
 .../vertx/websocket/VertxWebsocketConsumer.java    |  84 +++
 .../vertx/websocket/VertxWebsocketContants.java    |  32 +
 .../vertx/websocket/VertxWebsocketEndpoint.java    | 161 +++++
 .../vertx/websocket/VertxWebsocketHelper.java      | 185 ++++++
 .../vertx/websocket/VertxWebsocketHost.java        | 199 ++++++
 .../websocket/VertxWebsocketHostConfiguration.java |  52 ++
 .../vertx/websocket/VertxWebsocketHostKey.java     |  62 ++
 .../vertx/websocket/VertxWebsocketProducer.java    | 137 +++++
 .../websocket/VertxWebsocketResultHandler.java     |  75 +++
 .../vertx/websocket/VertxWebSocketTestSupport.java |  99 +++
 .../VertxWebsocketComponentConfigurationTest.java  |  86 +++
 .../VertxWebsocketEndpointConfigurationTest.java   |  76 +++
 .../VertxWebsocketExternalServerTest.java          | 100 +++
 .../vertx/websocket/VertxWebsocketHelperTest.java  |  54 ++
 .../websocket/VertxWebsocketMultiConsumerTest.java |  59 ++
 .../vertx/websocket/VertxWebsocketOriginTest.java  |  82 +++
 .../vertx/websocket/VertxWebsocketRouterTest.java  | 146 +++++
 .../vertx/websocket/VertxWebsocketSSLTest.java     | 143 +++++
 .../vertx/websocket/VertxWebsocketTest.java        | 262 ++++++++
 .../src/test/resources/client.jks                  | Bin 0 -> 582 bytes
 .../src/test/resources/log4j2.properties           |  30 +
 .../src/test/resources/server.jks                  | Bin 0 -> 1969 bytes
 components/pom.xml                                 |   1 +
 core/camel-allcomponents/pom.xml                   |   4 +
 .../component/ComponentsBuilderFactory.java        |  11 +
 .../dsl/VertxWebsocketComponentBuilderFactory.java | 168 +++++
 .../src/generated/resources/metadata.json          |  21 +
 .../builder/endpoint/EndpointBuilderFactory.java   |   1 +
 .../camel/builder/endpoint/EndpointBuilders.java   |   1 +
 .../builder/endpoint/StaticEndpointBuilders.java   | 124 ++++
 .../dsl/VertxWebsocketEndpointBuilderFactory.java  | 684 +++++++++++++++++++++
 docs/components/modules/ROOT/nav.adoc              |   1 +
 .../ROOT/pages/vertx-websocket-component.adoc      | 133 ++++
 parent/pom.xml                                     |   5 +
 51 files changed, 4203 insertions(+)

diff --git a/apache-camel/src/main/descriptors/common-bin.xml b/apache-camel/src/main/descriptors/common-bin.xml
index b54a518..a9a3708 100644
--- a/apache-camel/src/main/descriptors/common-bin.xml
+++ b/apache-camel/src/main/descriptors/common-bin.xml
@@ -376,6 +376,7 @@
         <include>org.apache.camel:camel-validator</include>
         <include>org.apache.camel:camel-velocity</include>
         <include>org.apache.camel:camel-vertx</include>
+        <include>org.apache.camel:camel-vertx-websocket</include>
         <include>org.apache.camel:camel-vm</include>
         <include>org.apache.camel:camel-weather</include>
         <include>org.apache.camel:camel-web3j</include>
diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index b81eb55..e1bab41 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -1855,6 +1855,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-vertx-websocket</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-vm</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties
index a3672e5..e3b8acf 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties
@@ -327,6 +327,7 @@ undertow
 validator
 velocity
 vertx
+vertx-websocket
 vm
 weather
 web3j
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-websocket.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-websocket.json
new file mode 100644
index 0000000..2e98799
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-websocket.json
@@ -0,0 +1,48 @@
+{
+  "component": {
+    "kind": "component",
+    "name": "vertx-websocket",
+    "title": "Vert.x WebSocket",
+    "description": "Camel WebSocket support with Vert.x",
+    "deprecated": false,
+    "firstVersion": "3.5.0",
+    "label": "websocket",
+    "javaType": "org.apache.camel.component.vertx.websocket.VertxWebsocketComponent",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-vertx-websocket",
+    "version": "3.5.0-SNAPSHOT",
+    "scheme": "vertx-websocket",
+    "extendsScheme": "",
+    "syntax": "vertx-websocket:host:port\/resourceUri",
+    "async": false,
+    "consumerOnly": false,
+    "producerOnly": false,
+    "lenientProperties": false
+  },
+  "componentProperties": {
+    "bridgeErrorHandler": { "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by [...]
+    "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": 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 during starting and cause the r [...]
+    "basicPropertyBinding": { "kind": "property", "displayName": "Basic Property Binding", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities" },
+    "vertx": { "kind": "property", "displayName": "Vertx", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.vertx.core.Vertx", "deprecated": false, "secret": false, "description": "To use an existing vertx instead of creating a new instance" },
+    "vertxOptions": { "kind": "property", "displayName": "Vertx Options", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.vertx.core.VertxOptions", "deprecated": false, "secret": false, "description": "To provide a custom set of vertx options for configuring vertx" },
+    "useGlobalSslContextParameters": { "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": "false", "description": "Enable usage of global SSL context parameters." }
+  },
+  "properties": {
+    "host": { "kind": "path", "displayName": "Host", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "defaultValue": "0.0.0.0", "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "The host that the consumer should bind to or the host of the remote websocket destination that the producer should connect to" },
+    "port": { "kind": "path", "displayName": "Port", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "secret": false, "defaultValue": "0", "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "The port that the consumer should bind to or port of the remote websocket destination that the producer should connect to" },
+    "path": { "kind": "path", "displayName": "Path", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "secret": false, "defaultValue": "\/", "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "The path that the consumer should bind to or path of the remote websocket destination that the producer s [...]
+    "allowedOriginPattern": { "kind": "parameter", "displayName": "Allowed Origin Pattern", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "Regex pattern to match the origin header sent by WebSocket clients" },
+    "bridgeErrorHandler": { "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled b [...]
+    "router": { "kind": "parameter", "displayName": "Router", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.Router", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "To use an existing vertx router for the HTTP server" },
+    "serverOptions": { "kind": "parameter", "displayName": "Server Options", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "io.vertx.core.http.HttpServerOptions", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the HTTP server hosting the WebSocket for the consumer" },
+    "exceptionHandler": { "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with [...]
+    "exchangePattern": { "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut", "InOptionalOut" ], "deprecated": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." },
+    "clientOptions": { "kind": "parameter", "displayName": "Client Options", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.core.http.HttpClientOptions", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the WebSocket client used in the producer" },
+    "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": 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 during starting and cause the  [...]
+    "sendToAll": { "kind": "parameter", "displayName": "Send To All", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "To send to all websocket subscribers. Can be used to configure on endpoint level, instead of having to use  [...]
+    "basicPropertyBinding": { "kind": "parameter", "displayName": "Basic Property Binding", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities" },
+    "synchronous": { "kind": "parameter", "displayName": "Synchronous", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": "false", "description": "Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported)." },
+    "sslContextParameters": { "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" }
+  }
+}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties
index d876d4e..747b52c 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties
@@ -519,6 +519,7 @@ validate-eip
 validator-component
 velocity-component
 vertx-component
+vertx-websocket-component
 vm-component
 weather-component
 web3j-component
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/vertx-websocket-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/vertx-websocket-component.adoc
new file mode 100644
index 0000000..0b3329f
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/vertx-websocket-component.adoc
@@ -0,0 +1,131 @@
+[[vertx-websocket-component]]
+= Vert.x WebSocket Component
+:docTitle: Vert.x WebSocket
+:artifactId: camel-vertx-websocket
+:description: Camel WebSocket support with Vert.x
+:since: 3.5
+:supportLevel: Preview
+:component-header: Both producer and consumer are supported
+
+*Since Camel {since}*
+
+*{component-header}*
+
+The Vert.x WebSocket component provides WebSocket capabilities as a WebSocket server, or as a client to connect to existing an WebSocket.
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-vertx-websocket</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+== URI format
+
+[source,java]
+---------------------------
+vertx-websocket://hostname[:port][/resourceUri][?options]
+---------------------------
+
+== Options
+
+
+
+// component options: START
+The Vert.x WebSocket component supports 6 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *lazyStartProducer* (producer) | 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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *vertx* (advanced) | To use an existing vertx instead of creating a new instance |  | Vertx
+| *vertxOptions* (advanced) | To provide a custom set of vertx options for configuring vertx |  | VertxOptions
+| *useGlobalSslContextParameters* (security) | Enable usage of global SSL context parameters. | false | boolean
+|===
+// component options: END
+
+
+
+
+// endpoint options: START
+The Vert.x WebSocket endpoint is configured using URI syntax:
+
+----
+vertx-websocket:host:port/resourceUri
+----
+
+with the following path and query parameters:
+
+=== Path Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *host* | The host that the consumer should bind to or the host of the remote websocket destination that the producer should connect to | 0.0.0.0 | String
+| *port* | The port that the consumer should bind to or port of the remote websocket destination that the producer should connect to | 0 | int
+| *path* | *Required* The path that the consumer should bind to or path of the remote websocket destination that the producer should connect to | / | String
+|===
+
+
+=== Query Parameters (12 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *allowedOriginPattern* (consumer) | Regex pattern to match the origin header sent by WebSocket clients |  | String
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *router* (consumer) | To use an existing vertx router for the HTTP server |  | Router
+| *serverOptions* (consumer) | Sets customized options for configuring the HTTP server hosting the WebSocket for the consumer |  | HttpServerOptions
+| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. The value can be one of: InOnly, InOut, InOptionalOut |  | ExchangePattern
+| *clientOptions* (producer) | Sets customized options for configuring the WebSocket client used in the producer |  | HttpClientOptions
+| *lazyStartProducer* (producer) | 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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *sendToAll* (producer) | To send to all websocket subscribers. Can be used to configure on endpoint level, instead of having to use the VertxWebsocketConstants.SEND_TO_ALL header on the message. | false | boolean
+| *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+| *sslContextParameters* (security) | To configure security using SSLContextParameters |  | SSLContextParameters
+|===
+// endpoint options: END
+
+
+=== Message Headers
+
+The WebSocket component uses 2 headers to indicate to either send
+messages back to a single/current client, or to all clients.
+
+[width="100%",cols="10%,90%",options="header",]
+|=======================================================================
+
+|`VertxWebsocketConstants.SEND_TO_ALL` |Sends the message to all clients which are currently connected. You can
+use the `sendToAll` option on the endpoint instead of using this header.
+
+|`VertxWebsocketConstants.CONNECTION_KEY` |Sends the message to the client with the given connection key. You can
+use a comma separated list of keys to send a message to multiple clients
+|=======================================================================
+
+=== Usage
+The following example shows how to expose a WebSocket on http://localhost:8080/echo and returns an 'echo' response back to the same channel:
+
+[source,java]
+----
+from("vertx-websocket:localhost:8080/echo")
+    .transform().simple("Echo: ${body}")
+    .to("vertx-websocket:localhost:8080/echo");
+----
+
+==== SSL
+
+By default the `ws://` protocol is used, but secure connections with `wss://` are supported by configuring the consumer or producer
+via the `sslContextParameters` URI parameter and the xref:manual::camel-configuration-utilities.adoc[Camel JSSE Configuration Utility]
diff --git a/components/camel-vertx-websocket/pom.xml b/components/camel-vertx-websocket/pom.xml
new file mode 100644
index 0000000..ce7cbb2
--- /dev/null
+++ b/components/camel-vertx-websocket/pom.xml
@@ -0,0 +1,60 @@
+<?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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>3.5.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-vertx-websocket</artifactId>
+    <packaging>jar</packaging>
+    <name>Camel :: Vert.x :: WebSocket</name>
+    <description>Camel WebSocket support with Vert.x</description>
+
+    <properties>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-support</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.vertx</groupId>
+            <artifactId>vertx-web</artifactId>
+            <version>${vertx-version}</version>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-junit5</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/components/camel-vertx-websocket/src/generated/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponentConfigurer.java b/components/camel-vertx-websocket/src/generated/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponentConfigurer.java
new file mode 100644
index 0000000..fb2975d
--- /dev/null
+++ b/components/camel-vertx-websocket/src/generated/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponentConfigurer.java
@@ -0,0 +1,68 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.vertx.websocket;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class VertxWebsocketComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        VertxWebsocketComponent target = (VertxWebsocketComponent) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "basicpropertybinding":
+        case "basicPropertyBinding": target.setBasicPropertyBinding(property(camelContext, boolean.class, value)); return true;
+        case "bridgeerrorhandler":
+        case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true;
+        case "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        case "useglobalsslcontextparameters":
+        case "useGlobalSslContextParameters": target.setUseGlobalSslContextParameters(property(camelContext, boolean.class, value)); return true;
+        case "vertx": target.setVertx(property(camelContext, io.vertx.core.Vertx.class, value)); return true;
+        case "vertxoptions":
+        case "vertxOptions": target.setVertxOptions(property(camelContext, io.vertx.core.VertxOptions.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getAllOptions(Object target) {
+        Map<String, Object> answer = new CaseInsensitiveMap();
+        answer.put("basicPropertyBinding", boolean.class);
+        answer.put("bridgeErrorHandler", boolean.class);
+        answer.put("lazyStartProducer", boolean.class);
+        answer.put("useGlobalSslContextParameters", boolean.class);
+        answer.put("vertx", io.vertx.core.Vertx.class);
+        answer.put("vertxOptions", io.vertx.core.VertxOptions.class);
+        return answer;
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        VertxWebsocketComponent target = (VertxWebsocketComponent) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "basicpropertybinding":
+        case "basicPropertyBinding": return target.isBasicPropertyBinding();
+        case "bridgeerrorhandler":
+        case "bridgeErrorHandler": return target.isBridgeErrorHandler();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        case "useglobalsslcontextparameters":
+        case "useGlobalSslContextParameters": return target.isUseGlobalSslContextParameters();
+        case "vertx": return target.getVertx();
+        case "vertxoptions":
+        case "vertxOptions": return target.getVertxOptions();
+        default: return null;
+        }
+    }
+}
+
diff --git a/components/camel-vertx-websocket/src/generated/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpointConfigurer.java b/components/camel-vertx-websocket/src/generated/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpointConfigurer.java
new file mode 100644
index 0000000..16e92c2
--- /dev/null
+++ b/components/camel-vertx-websocket/src/generated/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpointConfigurer.java
@@ -0,0 +1,96 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.vertx.websocket;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class VertxWebsocketEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        VertxWebsocketEndpoint target = (VertxWebsocketEndpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowedoriginpattern":
+        case "allowedOriginPattern": target.getConfiguration().setAllowedOriginPattern(property(camelContext, java.lang.String.class, value)); return true;
+        case "basicpropertybinding":
+        case "basicPropertyBinding": target.setBasicPropertyBinding(property(camelContext, boolean.class, value)); return true;
+        case "bridgeerrorhandler":
+        case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true;
+        case "clientoptions":
+        case "clientOptions": target.getConfiguration().setClientOptions(property(camelContext, io.vertx.core.http.HttpClientOptions.class, value)); return true;
+        case "exceptionhandler":
+        case "exceptionHandler": target.setExceptionHandler(property(camelContext, org.apache.camel.spi.ExceptionHandler.class, value)); return true;
+        case "exchangepattern":
+        case "exchangePattern": target.setExchangePattern(property(camelContext, org.apache.camel.ExchangePattern.class, value)); return true;
+        case "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        case "router": target.getConfiguration().setRouter(property(camelContext, io.vertx.ext.web.Router.class, value)); return true;
+        case "sendtoall":
+        case "sendToAll": target.getConfiguration().setSendToAll(property(camelContext, boolean.class, value)); return true;
+        case "serveroptions":
+        case "serverOptions": target.getConfiguration().setServerOptions(property(camelContext, io.vertx.core.http.HttpServerOptions.class, value)); return true;
+        case "sslcontextparameters":
+        case "sslContextParameters": target.getConfiguration().setSslContextParameters(property(camelContext, org.apache.camel.support.jsse.SSLContextParameters.class, value)); return true;
+        case "synchronous": target.setSynchronous(property(camelContext, boolean.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getAllOptions(Object target) {
+        Map<String, Object> answer = new CaseInsensitiveMap();
+        answer.put("allowedOriginPattern", java.lang.String.class);
+        answer.put("basicPropertyBinding", boolean.class);
+        answer.put("bridgeErrorHandler", boolean.class);
+        answer.put("clientOptions", io.vertx.core.http.HttpClientOptions.class);
+        answer.put("exceptionHandler", org.apache.camel.spi.ExceptionHandler.class);
+        answer.put("exchangePattern", org.apache.camel.ExchangePattern.class);
+        answer.put("lazyStartProducer", boolean.class);
+        answer.put("router", io.vertx.ext.web.Router.class);
+        answer.put("sendToAll", boolean.class);
+        answer.put("serverOptions", io.vertx.core.http.HttpServerOptions.class);
+        answer.put("sslContextParameters", org.apache.camel.support.jsse.SSLContextParameters.class);
+        answer.put("synchronous", boolean.class);
+        return answer;
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        VertxWebsocketEndpoint target = (VertxWebsocketEndpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowedoriginpattern":
+        case "allowedOriginPattern": return target.getConfiguration().getAllowedOriginPattern();
+        case "basicpropertybinding":
+        case "basicPropertyBinding": return target.isBasicPropertyBinding();
+        case "bridgeerrorhandler":
+        case "bridgeErrorHandler": return target.isBridgeErrorHandler();
+        case "clientoptions":
+        case "clientOptions": return target.getConfiguration().getClientOptions();
+        case "exceptionhandler":
+        case "exceptionHandler": return target.getExceptionHandler();
+        case "exchangepattern":
+        case "exchangePattern": return target.getExchangePattern();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        case "router": return target.getConfiguration().getRouter();
+        case "sendtoall":
+        case "sendToAll": return target.getConfiguration().isSendToAll();
+        case "serveroptions":
+        case "serverOptions": return target.getConfiguration().getServerOptions();
+        case "sslcontextparameters":
+        case "sslContextParameters": return target.getConfiguration().getSslContextParameters();
+        case "synchronous": return target.isSynchronous();
+        default: return null;
+        }
+    }
+}
+
diff --git a/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/component.properties
new file mode 100644
index 0000000..deaafd6
--- /dev/null
+++ b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/component.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+components=vertx-websocket
+groupId=org.apache.camel
+artifactId=camel-vertx-websocket
+version=3.5.0-SNAPSHOT
+projectName=Camel :: Vert.x :: WebSocket
+projectDescription=Camel WebSocket support with Vert.x
diff --git a/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/component/vertx-websocket b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/component/vertx-websocket
new file mode 100644
index 0000000..54834a8
--- /dev/null
+++ b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/component/vertx-websocket
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.vertx.websocket.VertxWebsocketComponent
diff --git a/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/configurer/vertx-websocket-component b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/configurer/vertx-websocket-component
new file mode 100644
index 0000000..cd81adf
--- /dev/null
+++ b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/configurer/vertx-websocket-component
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.vertx.websocket.VertxWebsocketComponentConfigurer
diff --git a/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/configurer/vertx-websocket-endpoint b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/configurer/vertx-websocket-endpoint
new file mode 100644
index 0000000..ab3189f
--- /dev/null
+++ b/components/camel-vertx-websocket/src/generated/resources/META-INF/services/org/apache/camel/configurer/vertx-websocket-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.vertx.websocket.VertxWebsocketEndpointConfigurer
diff --git a/components/camel-vertx-websocket/src/generated/resources/org/apache/camel/component/vertx/websocket/vertx-websocket.json b/components/camel-vertx-websocket/src/generated/resources/org/apache/camel/component/vertx/websocket/vertx-websocket.json
new file mode 100644
index 0000000..2e98799
--- /dev/null
+++ b/components/camel-vertx-websocket/src/generated/resources/org/apache/camel/component/vertx/websocket/vertx-websocket.json
@@ -0,0 +1,48 @@
+{
+  "component": {
+    "kind": "component",
+    "name": "vertx-websocket",
+    "title": "Vert.x WebSocket",
+    "description": "Camel WebSocket support with Vert.x",
+    "deprecated": false,
+    "firstVersion": "3.5.0",
+    "label": "websocket",
+    "javaType": "org.apache.camel.component.vertx.websocket.VertxWebsocketComponent",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-vertx-websocket",
+    "version": "3.5.0-SNAPSHOT",
+    "scheme": "vertx-websocket",
+    "extendsScheme": "",
+    "syntax": "vertx-websocket:host:port\/resourceUri",
+    "async": false,
+    "consumerOnly": false,
+    "producerOnly": false,
+    "lenientProperties": false
+  },
+  "componentProperties": {
+    "bridgeErrorHandler": { "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by [...]
+    "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": 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 during starting and cause the r [...]
+    "basicPropertyBinding": { "kind": "property", "displayName": "Basic Property Binding", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities" },
+    "vertx": { "kind": "property", "displayName": "Vertx", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.vertx.core.Vertx", "deprecated": false, "secret": false, "description": "To use an existing vertx instead of creating a new instance" },
+    "vertxOptions": { "kind": "property", "displayName": "Vertx Options", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.vertx.core.VertxOptions", "deprecated": false, "secret": false, "description": "To provide a custom set of vertx options for configuring vertx" },
+    "useGlobalSslContextParameters": { "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": "false", "description": "Enable usage of global SSL context parameters." }
+  },
+  "properties": {
+    "host": { "kind": "path", "displayName": "Host", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "defaultValue": "0.0.0.0", "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "The host that the consumer should bind to or the host of the remote websocket destination that the producer should connect to" },
+    "port": { "kind": "path", "displayName": "Port", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "secret": false, "defaultValue": "0", "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "The port that the consumer should bind to or port of the remote websocket destination that the producer should connect to" },
+    "path": { "kind": "path", "displayName": "Path", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "secret": false, "defaultValue": "\/", "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "The path that the consumer should bind to or path of the remote websocket destination that the producer s [...]
+    "allowedOriginPattern": { "kind": "parameter", "displayName": "Allowed Origin Pattern", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "Regex pattern to match the origin header sent by WebSocket clients" },
+    "bridgeErrorHandler": { "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled b [...]
+    "router": { "kind": "parameter", "displayName": "Router", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "io.vertx.ext.web.Router", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "To use an existing vertx router for the HTTP server" },
+    "serverOptions": { "kind": "parameter", "displayName": "Server Options", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "io.vertx.core.http.HttpServerOptions", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the HTTP server hosting the WebSocket for the consumer" },
+    "exceptionHandler": { "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with [...]
+    "exchangePattern": { "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut", "InOptionalOut" ], "deprecated": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." },
+    "clientOptions": { "kind": "parameter", "displayName": "Client Options", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "io.vertx.core.http.HttpClientOptions", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "Sets customized options for configuring the WebSocket client used in the producer" },
+    "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": 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 during starting and cause the  [...]
+    "sendToAll": { "kind": "parameter", "displayName": "Send To All", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "To send to all websocket subscribers. Can be used to configure on endpoint level, instead of having to use  [...]
+    "basicPropertyBinding": { "kind": "parameter", "displayName": "Basic Property Binding", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities" },
+    "synchronous": { "kind": "parameter", "displayName": "Synchronous", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": "false", "description": "Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported)." },
+    "sslContextParameters": { "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "secret": false, "configurationClass": "org.apache.camel.component.vertx.websocket.VertxWebsocketConfiguration", "configurationField": "configuration", "description": "To configure security using SSLContextParameters" }
+  }
+}
diff --git a/components/camel-vertx-websocket/src/main/docs/vertx-websocket-component.adoc b/components/camel-vertx-websocket/src/main/docs/vertx-websocket-component.adoc
new file mode 100644
index 0000000..0b3329f
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/docs/vertx-websocket-component.adoc
@@ -0,0 +1,131 @@
+[[vertx-websocket-component]]
+= Vert.x WebSocket Component
+:docTitle: Vert.x WebSocket
+:artifactId: camel-vertx-websocket
+:description: Camel WebSocket support with Vert.x
+:since: 3.5
+:supportLevel: Preview
+:component-header: Both producer and consumer are supported
+
+*Since Camel {since}*
+
+*{component-header}*
+
+The Vert.x WebSocket component provides WebSocket capabilities as a WebSocket server, or as a client to connect to existing an WebSocket.
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-vertx-websocket</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+== URI format
+
+[source,java]
+---------------------------
+vertx-websocket://hostname[:port][/resourceUri][?options]
+---------------------------
+
+== Options
+
+
+
+// component options: START
+The Vert.x WebSocket component supports 6 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *lazyStartProducer* (producer) | 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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *vertx* (advanced) | To use an existing vertx instead of creating a new instance |  | Vertx
+| *vertxOptions* (advanced) | To provide a custom set of vertx options for configuring vertx |  | VertxOptions
+| *useGlobalSslContextParameters* (security) | Enable usage of global SSL context parameters. | false | boolean
+|===
+// component options: END
+
+
+
+
+// endpoint options: START
+The Vert.x WebSocket endpoint is configured using URI syntax:
+
+----
+vertx-websocket:host:port/resourceUri
+----
+
+with the following path and query parameters:
+
+=== Path Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *host* | The host that the consumer should bind to or the host of the remote websocket destination that the producer should connect to | 0.0.0.0 | String
+| *port* | The port that the consumer should bind to or port of the remote websocket destination that the producer should connect to | 0 | int
+| *path* | *Required* The path that the consumer should bind to or path of the remote websocket destination that the producer should connect to | / | String
+|===
+
+
+=== Query Parameters (12 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *allowedOriginPattern* (consumer) | Regex pattern to match the origin header sent by WebSocket clients |  | String
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *router* (consumer) | To use an existing vertx router for the HTTP server |  | Router
+| *serverOptions* (consumer) | Sets customized options for configuring the HTTP server hosting the WebSocket for the consumer |  | HttpServerOptions
+| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. The value can be one of: InOnly, InOut, InOptionalOut |  | ExchangePattern
+| *clientOptions* (producer) | Sets customized options for configuring the WebSocket client used in the producer |  | HttpClientOptions
+| *lazyStartProducer* (producer) | 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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *sendToAll* (producer) | To send to all websocket subscribers. Can be used to configure on endpoint level, instead of having to use the VertxWebsocketConstants.SEND_TO_ALL header on the message. | false | boolean
+| *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+| *sslContextParameters* (security) | To configure security using SSLContextParameters |  | SSLContextParameters
+|===
+// endpoint options: END
+
+
+=== Message Headers
+
+The WebSocket component uses 2 headers to indicate to either send
+messages back to a single/current client, or to all clients.
+
+[width="100%",cols="10%,90%",options="header",]
+|=======================================================================
+
+|`VertxWebsocketConstants.SEND_TO_ALL` |Sends the message to all clients which are currently connected. You can
+use the `sendToAll` option on the endpoint instead of using this header.
+
+|`VertxWebsocketConstants.CONNECTION_KEY` |Sends the message to the client with the given connection key. You can
+use a comma separated list of keys to send a message to multiple clients
+|=======================================================================
+
+=== Usage
+The following example shows how to expose a WebSocket on http://localhost:8080/echo and returns an 'echo' response back to the same channel:
+
+[source,java]
+----
+from("vertx-websocket:localhost:8080/echo")
+    .transform().simple("Echo: ${body}")
+    .to("vertx-websocket:localhost:8080/echo");
+----
+
+==== SSL
+
+By default the `ws://` protocol is used, but secure connections with `wss://` are supported by configuring the consumer or producer
+via the `sslContextParameters` URI parameter and the xref:manual::camel-configuration-utilities.adoc[Camel JSSE Configuration Utility]
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponent.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponent.java
new file mode 100644
index 0000000..3130542
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponent.java
@@ -0,0 +1,172 @@
+/*
+ * 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.websocket;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
+import io.vertx.ext.web.Router;
+import org.apache.camel.Endpoint;
+import org.apache.camel.SSLContextParametersAware;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.support.DefaultComponent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.component.vertx.websocket.VertxWebsocketHelper.createHostKey;
+import static org.apache.camel.component.vertx.websocket.VertxWebsocketHelper.extractHostName;
+import static org.apache.camel.component.vertx.websocket.VertxWebsocketHelper.extractPath;
+import static org.apache.camel.component.vertx.websocket.VertxWebsocketHelper.extractPortNumber;
+
+@Component("vertx-websocket")
+public class VertxWebsocketComponent extends DefaultComponent implements SSLContextParametersAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VertxWebsocketComponent.class);
+
+    private final Map<VertxWebsocketHostKey, VertxWebsocketHost> vertxHostRegistry = new ConcurrentHashMap<>();
+
+    @Metadata(label = "advanced")
+    private Vertx vertx;
+    @Metadata(label = "advanced")
+    private VertxOptions vertxOptions;
+    @Metadata(label = "security", defaultValue = "false")
+    private boolean useGlobalSslContextParameters;
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        VertxWebsocketConfiguration configuration = new VertxWebsocketConfiguration();
+        configuration.setHost(extractHostName(remaining));
+        configuration.setPort(extractPortNumber(remaining));
+        configuration.setPath(extractPath(remaining));
+
+        VertxWebsocketEndpoint endpoint = new VertxWebsocketEndpoint(uri, this, configuration);
+        setProperties(endpoint, parameters);
+
+        if (configuration.getSslContextParameters() == null) {
+            configuration.setSslContextParameters(retrieveGlobalSslContextParameters());
+        }
+
+        return endpoint;
+    }
+
+    public void connectConsumer(VertxWebsocketConsumer consumer) {
+        VertxWebsocketEndpoint endpoint = consumer.getEndpoint();
+        VertxWebsocketConfiguration configuration = endpoint.getConfiguration();
+        VertxWebsocketHostKey hostKey = createHostKey(configuration);
+        VertxWebsocketHost host = vertxHostRegistry.computeIfAbsent(hostKey, key -> {
+            Router router = configuration.getRouter();
+            if (router == null) {
+                Set<Router> routers = getCamelContext().getRegistry().findByType(Router.class);
+                if (routers.size() == 1) {
+                    router = routers.iterator().next();
+                }
+
+                if (router == null) {
+                    router = Router.router(getVertx());
+                }
+            }
+
+            VertxWebsocketHostConfiguration hostConfiguration = new VertxWebsocketHostConfiguration(
+                    getVertx(),
+                    router,
+                    configuration.getServerOptions(),
+                    configuration.getSslContextParameters());
+
+            return createVertxWebsocketHost(hostConfiguration, hostKey);
+        });
+
+        host.connect(consumer);
+        try {
+            host.start();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void disconnectConsumer(VertxWebsocketConsumer consumer) {
+        VertxWebsocketEndpoint endpoint = consumer.getEndpoint();
+        VertxWebsocketConfiguration configuration = endpoint.getConfiguration();
+        VertxWebsocketHostKey hostKey = createHostKey(configuration);
+        VertxWebsocketHost vertxWebsocketHost = vertxHostRegistry.remove(hostKey);
+
+        if (vertxWebsocketHost != null) {
+            vertxWebsocketHost.disconnect(configuration.getPath());
+        }
+    }
+
+    public Vertx getVertx() {
+        if (vertx == null) {
+            Set<Vertx> vertxes = getCamelContext().getRegistry().findByType(Vertx.class);
+            if (vertxes.size() == 1) {
+                vertx  = vertxes.iterator().next();
+            }
+        }
+
+        if (vertx == null) {
+            if (vertxOptions != null) {
+                vertx = Vertx.vertx(vertxOptions);
+            } else {
+                vertx = Vertx.vertx();
+            }
+        }
+
+        return vertx;
+    }
+
+    /**
+     * To use an existing vertx instead of creating a new instance
+     */
+    public void setVertx(Vertx vertx) {
+        this.vertx = vertx;
+    }
+
+    public VertxOptions getVertxOptions() {
+        return vertxOptions;
+    }
+
+    /**
+     * To provide a custom set of vertx options for configuring vertx
+     */
+    public void setVertxOptions(VertxOptions vertxOptions) {
+        this.vertxOptions = vertxOptions;
+    }
+
+    @Override
+    public boolean isUseGlobalSslContextParameters() {
+        return this.useGlobalSslContextParameters;
+    }
+
+    /**
+     * Enable usage of global SSL context parameters.
+     */
+    @Override
+    public void setUseGlobalSslContextParameters(boolean useGlobalSslContextParameters) {
+        this.useGlobalSslContextParameters = useGlobalSslContextParameters;
+    }
+
+    protected Map<VertxWebsocketHostKey, VertxWebsocketHost> getVerxHostRegistry() {
+        return this.vertxHostRegistry;
+    }
+
+    protected VertxWebsocketHost createVertxWebsocketHost(VertxWebsocketHostConfiguration hostConfiguration, VertxWebsocketHostKey hostKey) {
+        return new VertxWebsocketHost(hostConfiguration, hostKey);
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketConfiguration.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketConfiguration.java
new file mode 100644
index 0000000..8cd4913
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketConfiguration.java
@@ -0,0 +1,150 @@
+/*
+ * 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.websocket;
+
+import io.vertx.core.http.HttpClientOptions;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.ext.web.Router;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.support.jsse.SSLContextParameters;
+
+@UriParams
+public class VertxWebsocketConfiguration {
+
+    @UriPath(name = "host", defaultValue = VertxWebsocketContants.DEFAULT_VERTX_SERVER_HOST)
+    private String host;
+    @UriPath(name = "port", defaultValue = "0")
+    private int port;
+    @UriPath(name = "path", defaultValue = VertxWebsocketContants.DEFAULT_VERTX_SERVER_PATH)
+    @Metadata(required = true)
+    private String path;
+    @UriParam(label = "consumer")
+    private String allowedOriginPattern;
+    @UriParam(label = "consumer")
+    private Router router;
+    @UriParam(label = "consumer")
+    private HttpServerOptions serverOptions;
+    @UriParam(label = "producer")
+    private HttpClientOptions clientOptions;
+    @UriParam(label = "producer")
+    private boolean sendToAll;
+    @UriParam(label = "security")
+    private SSLContextParameters sslContextParameters;
+
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * The host that the consumer should bind to or the host of the remote websocket destination that the producer should connect to
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * The port that the consumer should bind to or port of the remote websocket destination that the producer should connect to
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Sets customized options for configuring the WebSocket client used in the producer
+     */
+    public void setClientOptions(HttpClientOptions clientOptions) {
+        this.clientOptions = clientOptions;
+    }
+
+    public HttpServerOptions getServerOptions() {
+        return serverOptions;
+    }
+
+    /**
+     * Sets customized options for configuring the HTTP server hosting the WebSocket for the consumer
+     */
+    public void setServerOptions(HttpServerOptions serverOptions) {
+        this.serverOptions = serverOptions;
+    }
+
+    /**
+     * The path that the consumer should bind to or path of the remote websocket destination that the producer should connect to
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public HttpClientOptions getClientOptions() {
+        return clientOptions;
+    }
+
+    /**
+     * To send to all websocket subscribers. Can be used to configure on endpoint level, instead of having to use the
+     * {@code VertxWebsocketConstants.SEND_TO_ALL} header on the message.
+     */
+    public void setSendToAll(boolean sendToAll) {
+        this.sendToAll = sendToAll;
+    }
+
+    public boolean isSendToAll() {
+        return sendToAll;
+    }
+
+    /**
+     * To configure security using SSLContextParameters
+     */
+    public SSLContextParameters getSslContextParameters() {
+        return sslContextParameters;
+    }
+
+    public void setSslContextParameters(SSLContextParameters sslContextParameters) {
+        this.sslContextParameters = sslContextParameters;
+    }
+
+    public String getAllowedOriginPattern() {
+        return allowedOriginPattern;
+    }
+
+    /**
+     * Regex pattern to match the origin header sent by WebSocket clients
+     */
+    public void setAllowedOriginPattern(String allowedOriginPattern) {
+        this.allowedOriginPattern = allowedOriginPattern;
+    }
+
+    public Router getRouter() {
+        return router;
+    }
+
+    /**
+     * To use an existing vertx router for the HTTP server
+     */
+    public void setRouter(Router router) {
+        this.router = router;
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketConsumer.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketConsumer.java
new file mode 100644
index 0000000..2813ce3
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketConsumer.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.component.vertx.websocket;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import io.vertx.core.http.ServerWebSocket;
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.support.DefaultConsumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implements a Vert.x Handler to handle WebSocket upgrade
+ */
+public class VertxWebsocketConsumer extends DefaultConsumer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VertxWebsocketConsumer.class);
+
+    private final VertxWebsocketEndpoint endpoint;
+    private final ConcurrentHashMap<String, ServerWebSocket> connectedPeers = new ConcurrentHashMap();
+
+    public VertxWebsocketConsumer(VertxWebsocketEndpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+        this.endpoint = endpoint;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        getComponent().connectConsumer(this);
+        super.doStart();
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        getComponent().disconnectConsumer(this);
+        super.doStop();
+    }
+
+    @Override
+    public VertxWebsocketEndpoint getEndpoint() {
+        return endpoint;
+    }
+
+    public VertxWebsocketComponent getComponent() {
+        return endpoint.getComponent();
+    }
+
+    public void onMessage(String connectionKey, Object message) {
+        Exchange exchange = endpoint.createExchange();
+        exchange.getMessage().setHeader(VertxWebsocketContants.CONNECTION_KEY, connectionKey);
+        exchange.getMessage().setBody(message);
+
+        getAsyncProcessor().process(exchange, new AsyncCallback() {
+            public void done(boolean doneSync) {
+                if (exchange.getException() != null) {
+                    getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
+                }
+            }
+        });
+    }
+
+    public void onException(String connectionKey, Throwable cause) {
+        Exchange exchange = endpoint.createExchange();
+        exchange.getMessage().setHeader(VertxWebsocketContants.CONNECTION_KEY, connectionKey);
+        getExceptionHandler().handleException("Error processing exchange", exchange, cause);
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketContants.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketContants.java
new file mode 100644
index 0000000..32fba84
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketContants.java
@@ -0,0 +1,32 @@
+/*
+ * 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.websocket;
+
+import io.vertx.core.net.NetServerOptions;
+
+public final class VertxWebsocketContants {
+
+    public static final String DEFAULT_VERTX_SERVER_HOST = NetServerOptions.DEFAULT_HOST;
+    public static final int DEFAULT_VERTX_SERVER_PORT = NetServerOptions.DEFAULT_PORT;
+    public static final String DEFAULT_VERTX_SERVER_PATH = "/";
+
+    public static final String CONNECTION_KEY = "CamelVertxWebsocket.connectionKey";
+    public static final String SEND_TO_ALL = "CamelVertxWebsocket.sendToAll";
+
+    private VertxWebsocketContants() {
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpoint.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpoint.java
new file mode 100644
index 0000000..b994dab
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpoint.java
@@ -0,0 +1,161 @@
+/*
+ * 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.websocket;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpClient;
+import io.vertx.core.http.HttpClientOptions;
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.core.http.WebSocket;
+import org.apache.camel.Category;
+import org.apache.camel.Consumer;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.support.DefaultEndpoint;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@UriEndpoint(firstVersion = "3.5.0", scheme = "vertx-websocket", title = "Vert.x WebSocket", syntax = "vertx-websocket:host:port/resourceUri", category = {Category.WEBSOCKET})
+public class VertxWebsocketEndpoint extends DefaultEndpoint {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VertxWebsocketEndpoint.class);
+
+    @UriParam
+    private VertxWebsocketConfiguration configuration;
+
+    private WebSocket webSocket;
+
+    public VertxWebsocketEndpoint(String uri, VertxWebsocketComponent component, VertxWebsocketConfiguration configuration) {
+        super(uri, component);
+        this.configuration = configuration;
+    }
+
+    @Override
+    public VertxWebsocketComponent getComponent() {
+        return (VertxWebsocketComponent) super.getComponent();
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        return new VertxWebsocketProducer(this);
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+        VertxWebsocketConsumer consumer = new VertxWebsocketConsumer(this, processor);
+        configureConsumer(consumer);
+        return consumer;
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (webSocket != null && !webSocket.isClosed()) {
+            webSocket.close();
+            webSocket = null;
+        }
+        super.doStop();
+    }
+
+    public VertxWebsocketConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    protected Vertx getVertx() {
+        return getComponent().getVertx();
+    }
+
+    protected WebSocket getWebSocket(Exchange exchange) throws InterruptedException, ExecutionException, TimeoutException {
+        if (webSocket == null || webSocket.isClosed()) {
+            HttpClientOptions options = configuration.getClientOptions();
+            HttpClient client;
+
+            if (options == null) {
+                options = new HttpClientOptions();
+            }
+
+            SSLContextParameters sslContextParameters = configuration.getSslContextParameters();
+            if (sslContextParameters != null) {
+                VertxWebsocketHelper.setupSSLOptions(sslContextParameters, options);
+            }
+
+            client = getVertx().createHttpClient(options);
+
+            CompletableFuture<WebSocket> future = new CompletableFuture<>();
+            client.webSocket(configuration.getPort(), configuration.getHost(), configuration.getPath(), result -> {
+                if (!result.failed()) {
+                    LOG.info("Connected to WebSocket on {}:{}", configuration.getHost(), configuration.getPort());
+                    future.complete(result.result());
+                } else {
+                    webSocket = null;
+                    future.completeExceptionally(result.cause());
+                }
+            });
+            webSocket = future.get(options.getConnectTimeout(), TimeUnit.MILLISECONDS);
+            webSocket.exceptionHandler(event -> exchange.setException(event.getCause()));
+        }
+        return webSocket;
+    }
+
+    protected Map<VertxWebsocketHostKey, VertxWebsocketHost> getVertxHostRegistry() {
+        return getComponent().getVerxHostRegistry();
+    }
+
+    /**
+     * Finds a WebSocket associated with host for the given connection key
+     */
+    protected ServerWebSocket findPeerForConnectionKey(String connectionKey) {
+        Map<VertxWebsocketHostKey, VertxWebsocketHost> registry = getVertxHostRegistry();
+        for (VertxWebsocketHost host : registry.values()) {
+            Map<String, ServerWebSocket> hostPeers = host.getConnectedPeers();
+            if (hostPeers.containsKey(connectionKey) && host.getPort() == getConfiguration().getPort()) {
+                return hostPeers.get(connectionKey);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds all WebSockets associated with a host matching this endpoint configured port
+     */
+    protected Map<String, ServerWebSocket> findPeersForHostPort() {
+        Map<VertxWebsocketHostKey, VertxWebsocketHost> registry = getVertxHostRegistry();
+        for (VertxWebsocketHost host : registry.values()) {
+            if (host.getPort() == getConfiguration().getPort()) {
+                return host.getConnectedPeers();
+            }
+        }
+        return null;
+    }
+
+    protected boolean isManagedPort() {
+        return getVertxHostRegistry().values()
+                .stream()
+                .filter(host -> host.getPort() == getConfiguration().getPort())
+                .findFirst()
+                .isPresent();
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelper.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelper.java
new file mode 100644
index 0000000..0978292
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelper.java
@@ -0,0 +1,185 @@
+/*
+ * 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.websocket;
+
+import java.security.KeyStore;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.net.KeyCertOptions;
+import io.vertx.core.net.TCPSSLOptions;
+import io.vertx.core.net.TrustOptions;
+import org.apache.camel.support.jsse.KeyManagersParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+
+public final class VertxWebsocketHelper {
+
+    private VertxWebsocketHelper() {
+        // Utility class
+    }
+
+    /**
+     * Configures key store and trust store options for the Vert.x client and server
+     */
+    public static void setupSSLOptions(SSLContextParameters sslContextParameters, TCPSSLOptions options) {
+        options.setSsl(true);
+        options.setKeyCertOptions(new KeyCertOptions() {
+            @Override
+            public KeyManagerFactory getKeyManagerFactory(Vertx vertx) throws Exception {
+                return createKeyManagerFactory(sslContextParameters);
+            }
+
+            @Override
+            @SuppressWarnings("deprecation")
+            public KeyCertOptions clone() {
+                return this;
+            }
+        });
+        options.setTrustOptions(new TrustOptions() {
+            @Override
+            public TrustManagerFactory getTrustManagerFactory(Vertx vertx) throws Exception {
+                return createTrustManagerFactory(sslContextParameters);
+            }
+
+            @Override
+            @SuppressWarnings("deprecation")
+            public TrustOptions clone() {
+                return this;
+            }
+        });
+    }
+
+    /**
+     * Extracts the port number from the endpoint URI path or returns the Vert.x default HTTP server
+     * port (0) if one was not provided
+     */
+    public static int extractPortNumber(String remaining) {
+        int index1 = remaining.indexOf(':');
+        int index2 = remaining.indexOf('/');
+        if ((index1 != -1) && (index2 != -1)) {
+            String result = remaining.substring(index1 + 1, index2);
+            if (result.isEmpty()) {
+                throw new IllegalArgumentException("Unable to resolve port from URI: " + remaining);
+            }
+
+            try {
+                return Integer.parseInt(result);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Unable to parse port: " + result);
+            }
+        } else {
+            return VertxWebsocketContants.DEFAULT_VERTX_SERVER_PORT;
+        }
+    }
+
+    /**
+     * Extracts the host name from the endpoint URI path or returns the Vert.x default HTTP server
+     * host (0.0.0.0) if one was not provided
+     */
+    public static String extractHostName(String remaining) {
+        int index = remaining.indexOf(':');
+        if (index != -1) {
+            return remaining.substring(0, index);
+        } else {
+            return VertxWebsocketContants.DEFAULT_VERTX_SERVER_HOST;
+        }
+    }
+
+    /**
+     * Extracts the WebSocket path from the endpoint URI path or returns the Vert.x default HTTP server
+     * path (/) if one was not provided
+     */
+    public static String extractPath(String remaining) {
+        int index = remaining.indexOf('/');
+        if (index != -1) {
+            return remaining.substring(index);
+        } else {
+            return VertxWebsocketContants.DEFAULT_VERTX_SERVER_PATH + remaining;
+        }
+    }
+
+    /**
+     * Creates a VertxWebsocketHostKey from a given VertxWebsocketConfiguration
+     */
+    public static VertxWebsocketHostKey createHostKey(VertxWebsocketConfiguration configuration) {
+        return new VertxWebsocketHostKey(configuration.getHost(), configuration.getPort());
+    }
+
+    /**
+     * Creates a KeyManagerFactory from a given SSLContextParameters
+     */
+    private static KeyManagerFactory createKeyManagerFactory(SSLContextParameters sslContextParameters) throws Exception {
+        final KeyManagersParameters keyManagers = sslContextParameters.getKeyManagers();
+        if (keyManagers == null) {
+            return null;
+        }
+
+        String kmfAlgorithm = keyManagers.getAlgorithm();
+        if (kmfAlgorithm == null) {
+            kmfAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+        }
+
+        KeyManagerFactory kmf;
+        if (keyManagers.getProvider() == null) {
+            kmf = KeyManagerFactory.getInstance(kmfAlgorithm);
+        } else {
+            kmf = KeyManagerFactory.getInstance(kmfAlgorithm, keyManagers.getProvider());
+        }
+
+        char[] kmfPassword = null;
+        if (keyManagers.getKeyPassword() != null) {
+            kmfPassword = keyManagers.getKeyPassword().toCharArray();
+        }
+
+        KeyStore ks = keyManagers.getKeyStore() == null ? null : keyManagers.getKeyStore().createKeyStore();
+
+        kmf.init(ks, kmfPassword);
+        return kmf;
+    }
+
+    /**
+     * Creates a TrustManagerFactory from a given SSLContextParameters
+     */
+    private static TrustManagerFactory createTrustManagerFactory(SSLContextParameters sslContextParameters) throws Exception {
+        final TrustManagersParameters trustManagers = sslContextParameters.getTrustManagers();
+        if (trustManagers == null) {
+            return null;
+        }
+
+        TrustManagerFactory tmf = null;
+
+        if (trustManagers.getKeyStore() != null) {
+            String tmfAlgorithm = trustManagers.getAlgorithm();
+            if (tmfAlgorithm == null) {
+                tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+            }
+
+            if (trustManagers.getProvider() == null) {
+                tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
+            } else {
+                tmf = TrustManagerFactory.getInstance(tmfAlgorithm, trustManagers.getProvider());
+            }
+
+            KeyStore ks = trustManagers.getKeyStore() == null ? null : trustManagers.getKeyStore().createKeyStore();
+            tmf.init(ks);
+        }
+        return tmf;
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHost.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHost.java
new file mode 100644
index 0000000..ca57ca8
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHost.java
@@ -0,0 +1,199 @@
+/*
+ * 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.websocket;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpServer;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.core.net.SocketAddress;
+import io.vertx.ext.web.Route;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.handler.CorsHandler;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Vert.x backed WebSocket host bound to a specified host & port
+ */
+public class VertxWebsocketHost {
+    private static final Logger LOG = LoggerFactory.getLogger(VertxWebsocketHost.class);
+
+    private final VertxWebsocketHostConfiguration hostConfiguration;
+    private final VertxWebsocketHostKey hostKey;
+    private final Map<String, Route> routeRegistry = new HashMap<>();
+    private final Map<String, ServerWebSocket> connectedPeers = new ConcurrentHashMap<>();
+    private HttpServer server;
+    private int port = VertxWebsocketContants.DEFAULT_VERTX_SERVER_PORT;
+
+    public VertxWebsocketHost(VertxWebsocketHostConfiguration websocketHostConfiguration, VertxWebsocketHostKey key) {
+        this.hostConfiguration = websocketHostConfiguration;
+        this.hostKey = key;
+    }
+
+    /**
+     * Sets up a Vert.x route and handler for the WebSocket path specified by the consumer configuration
+     */
+    public void connect(VertxWebsocketConsumer consumer) {
+        VertxWebsocketEndpoint endpoint = consumer.getEndpoint();
+        VertxWebsocketConfiguration configuration = endpoint.getConfiguration();
+
+        LOG.info("Connected consumer for path {}", configuration.getPath());
+        Router router = hostConfiguration.getRouter();
+        Route route = router.route(configuration.getPath());
+
+        if (!ObjectHelper.isEmpty(configuration.getAllowedOriginPattern())) {
+            CorsHandler corsHandler = CorsHandler.create(configuration.getAllowedOriginPattern());
+            route.handler(corsHandler);
+        }
+
+        route.handler(routingContext -> {
+            HttpServerRequest request = routingContext.request();
+            ServerWebSocket webSocket = request.upgrade();
+            SocketAddress socketAddress = webSocket.localAddress();
+
+            String connectionKey = UUID.randomUUID().toString();
+            connectedPeers.put(connectionKey, webSocket);
+
+            if (LOG.isDebugEnabled()) {
+                if (socketAddress != null) {
+                    LOG.debug("WebSocket peer {} connected from {}", connectionKey, socketAddress.host());
+                }
+            }
+
+            webSocket.textMessageHandler(message -> consumer.onMessage(connectionKey, message));
+            webSocket.binaryMessageHandler(message -> consumer.onMessage(connectionKey, message.getBytes()));
+            webSocket.exceptionHandler(exception -> consumer.onException(connectionKey, exception));
+            webSocket.closeHandler(closeEvent -> {
+                if (LOG.isDebugEnabled()) {
+                    if (socketAddress != null) {
+                        LOG.debug("WebSocket peer {} disconnected from {}", connectionKey, socketAddress.host());
+                    }
+                }
+                connectedPeers.remove(connectionKey);
+            });
+        });
+
+        routeRegistry.put(configuration.getPath(), route);
+    }
+
+    /**
+     * Removes the Vert.x route and handler for the WebSocket path specified by the consumer configuration
+     */
+    public void disconnect(String path) {
+        LOG.info("Disconnected consumer for path {}", path);
+        Route route = routeRegistry.remove(path);
+        route.remove();
+        if (routeRegistry.isEmpty()) {
+            try {
+                stop();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Starts a Vert.x HTTP server to host the WebSocket router
+     */
+    public void start() throws InterruptedException, ExecutionException {
+        if (server == null) {
+            Vertx vertx = hostConfiguration.getVertx();
+            Router router = hostConfiguration.getRouter();
+            HttpServerOptions options = hostConfiguration.getServerOptions();
+
+            SSLContextParameters sslContextParameters = hostConfiguration.getSslContextParameters();
+            if (sslContextParameters != null) {
+                if (options == null) {
+                    options = new HttpServerOptions();
+                }
+
+                VertxWebsocketHelper.setupSSLOptions(sslContextParameters, options);
+            }
+
+            if (options != null) {
+                server = vertx.createHttpServer(options);
+            } else {
+                server = vertx.createHttpServer();
+            }
+
+            CompletableFuture<Void> future = new CompletableFuture<>();
+            server.requestHandler(router).listen(hostKey.getPort(), hostKey.getHost(), result -> {
+                if (!result.failed()) {
+                    port = result.result().actualPort();
+                    future.complete(null);
+                    LOG.info("Vert.x HTTP server started on {}:{}", hostKey.getHost(), port);
+                } else {
+                    future.completeExceptionally(result.cause());
+                }
+            });
+            future.get();
+        }
+    }
+
+    /**
+     * Starts a previously started Vert.x HTTP server
+     */
+    public void stop() throws ExecutionException, InterruptedException {
+        if (server != null) {
+            LOG.info("Stopping server");
+            try {
+                CompletableFuture<Void> future = new CompletableFuture<>();
+                server.close(result -> {
+                    if (result.failed()) {
+                        future.completeExceptionally(result.cause());
+                        return;
+                    }
+                    LOG.info("Vert.x HTTP server stopped");
+                    future.complete(null);
+                });
+                future.get();
+            } finally {
+                this.server = null;
+            }
+        }
+        connectedPeers.clear();
+        routeRegistry.clear();
+        port = VertxWebsocketContants.DEFAULT_VERTX_SERVER_PORT;
+    }
+
+    /**
+     * Gets all WebSocket peers connected to the Vert.x HTTP sever together
+     * with their associated connection key
+     */
+    public Map<String, ServerWebSocket> getConnectedPeers() {
+        return connectedPeers;
+    }
+
+    /**
+     * Gets the port that the server is bound to. This could be a random value if 0 was specified
+     * as the initial port number
+     */
+    public int getPort() {
+        return port;
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHostConfiguration.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHostConfiguration.java
new file mode 100644
index 0000000..448e337
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHostConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.websocket;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.ext.web.Router;
+import org.apache.camel.support.jsse.SSLContextParameters;
+
+public class VertxWebsocketHostConfiguration {
+    private final Vertx vertx;
+    private final Router router;
+    private final HttpServerOptions serverOptions;
+    private final SSLContextParameters sslContextParameters;
+
+    public VertxWebsocketHostConfiguration(Vertx vertx, Router router, HttpServerOptions serverOptions, SSLContextParameters sslContextParameters) {
+        this.vertx = vertx;
+        this.router = router;
+        this.serverOptions = serverOptions;
+        this.sslContextParameters = sslContextParameters;
+    }
+
+    public Vertx getVertx() {
+        return vertx;
+    }
+
+    public Router getRouter() {
+        return router;
+    }
+
+    public HttpServerOptions getServerOptions() {
+        return serverOptions;
+    }
+
+    public SSLContextParameters getSslContextParameters() {
+        return sslContextParameters;
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHostKey.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHostKey.java
new file mode 100644
index 0000000..9e82ca9
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHostKey.java
@@ -0,0 +1,62 @@
+/*
+ * 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.websocket;
+
+import java.util.Objects;
+
+/**
+ * A key to identify Vert.x WebSocket hosts
+ */
+public final class VertxWebsocketHostKey {
+    private final String host;
+    private final int port;
+
+    public VertxWebsocketHostKey(String host, int port) {
+        this.host = host;
+        this.port = port;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        VertxWebsocketHostKey that = (VertxWebsocketHostKey) o;
+        return port == that.port && Objects.equals(host, that.host);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(host, port);
+    }
+
+    @Override
+    public String toString() {
+        return host + ":" + port;
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketProducer.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketProducer.java
new file mode 100644
index 0000000..5d4366b
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketProducer.java
@@ -0,0 +1,137 @@
+/*
+ * 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.websocket;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import io.vertx.core.AsyncResult;
+import io.vertx.core.Handler;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.core.http.WebSocketBase;
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.support.DefaultAsyncProducer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VertxWebsocketProducer extends DefaultAsyncProducer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VertxWebsocketProducer.class);
+
+    public VertxWebsocketProducer(VertxWebsocketEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    public VertxWebsocketEndpoint getEndpoint() {
+        return (VertxWebsocketEndpoint) super.getEndpoint();
+    }
+
+    @Override
+    public boolean process(Exchange exchange, AsyncCallback callback) {
+        try {
+            Message in = exchange.getIn();
+            Object message = in.getBody();
+
+            if (message == null) {
+                // Nothing to do for a null body
+                callback.done(true);
+                return true;
+            }
+
+            Map<String, WebSocketBase> connectedPeers = getConnectedPeers(exchange);
+            VertxWebsocketResultHandler vertxWebsocketResultHandler = new VertxWebsocketResultHandler(exchange, callback, connectedPeers.keySet());
+
+            if (connectedPeers.isEmpty()) {
+                callback.done(true);
+            }
+
+            // Send message to each peer then record and process the results asynchronously
+            connectedPeers.forEach((connectionKey, webSocket) -> {
+                Handler<AsyncResult<Void>> handler = result -> {
+                    if (!result.succeeded()) {
+                        vertxWebsocketResultHandler.onError(connectionKey, result.cause());
+                    }
+                    vertxWebsocketResultHandler.onResult(connectionKey);
+                };
+
+                if (webSocket != null) {
+                    if (webSocket.isClosed()) {
+                        LOG.warn("WebSocket peer connection with key {} is already closed", connectionKey);
+                        vertxWebsocketResultHandler.onResult(connectionKey);
+                    } else {
+                        if (message instanceof String) {
+                            webSocket.writeTextMessage((String) message, handler);
+                        } else if (message instanceof byte[]) {
+                            webSocket.writeBinaryMessage(Buffer.buffer((byte[]) message), handler);
+                        } else {
+                            // Try to fallback on String conversion
+                            webSocket.writeTextMessage(in.getBody(String.class), handler);
+                        }
+                    }
+                } else {
+                    LOG.warn("No WebSocket peer connection found for connection key {}", connectionKey);
+                    vertxWebsocketResultHandler.onResult(connectionKey);
+                }
+            });
+
+            return false;
+        } catch (Exception e) {
+            exchange.setException(e);
+            callback.done(true);
+            return true;
+        }
+    }
+
+    private Map<String, WebSocketBase> getConnectedPeers(Exchange exchange) throws Exception {
+        Map<String, WebSocketBase> connectedPeers = new HashMap<>();
+        VertxWebsocketEndpoint endpoint = getEndpoint();
+
+        String connectionKey = exchange.getMessage().getHeader(VertxWebsocketContants.CONNECTION_KEY, String.class);
+        if (connectionKey != null) {
+            if (endpoint.isManagedPort()) {
+                Stream.of(connectionKey.split(","))
+                        .forEach(key -> connectedPeers.put(key, endpoint.findPeerForConnectionKey(key)));
+            } else {
+                // The producer is invoking an external server not managed by camel
+                connectedPeers.put(UUID.randomUUID().toString(), endpoint.getWebSocket(exchange));
+            }
+        } else {
+            connectedPeers.put(UUID.randomUUID().toString(), endpoint.getWebSocket(exchange));
+        }
+
+        if (isSendToAll(exchange.getMessage())) {
+            // Try to find all peers connected to an existing vertx-websocket consumer
+            Map<String, ServerWebSocket> peers = endpoint.findPeersForHostPort();
+            if (peers != null) {
+                peers.forEach(connectedPeers::put);
+            }
+        }
+
+        return connectedPeers;
+    }
+
+    private boolean isSendToAll(Message message) {
+        Boolean value = message.getHeader(VertxWebsocketContants.SEND_TO_ALL, getEndpoint().getConfiguration().isSendToAll(), Boolean.class);
+        return value == null ? false : value;
+    }
+}
diff --git a/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketResultHandler.java b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketResultHandler.java
new file mode 100644
index 0000000..52c73ff
--- /dev/null
+++ b/components/camel-vertx-websocket/src/main/java/org/apache/camel/component/vertx/websocket/VertxWebsocketResultHandler.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.component.vertx.websocket;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+
+/**
+ * Handles the result of one or more asynchronous WebSocket write operations
+ */
+class VertxWebsocketResultHandler {
+    private final Exchange exchange;
+    private final AsyncCallback callback;
+    private final Set<String> connectionKeys;
+    private final Map<String, Throwable> errors = new HashMap<>();
+    private final Object lock = new Object();
+
+    VertxWebsocketResultHandler(Exchange exchange, AsyncCallback callback, Set<String> connectionKeys) {
+        this.exchange = exchange;
+        this.callback = callback;
+        this.connectionKeys = new HashSet<>(connectionKeys);
+    }
+
+    void onResult(String connectionKey) {
+        synchronized (lock) {
+            connectionKeys.remove(connectionKey);
+            if (connectionKeys.isEmpty()) {
+                onComplete();
+            }
+        }
+    }
+
+    void onError(String connectionKey, Throwable cause) {
+        synchronized (lock) {
+            errors.put(connectionKey, cause);
+        }
+    }
+
+    private void onComplete() {
+        if (!errors.isEmpty()) {
+            if (errors.size() == 1) {
+                final Map.Entry<String, Throwable> entry = errors.entrySet().iterator().next();
+                final String msg = "Sending message to WebSocket peer for connection key " + entry.getKey() + " failed";
+                exchange.setException(new CamelExecutionException(msg, exchange, entry.getValue()));
+            } else {
+                final StringBuilder msg = new StringBuilder("Sending message to multiple WebSocket peers failed:");
+                for (Map.Entry<String, Throwable> entry : errors.entrySet()) {
+                    msg.append("\n  connection key: ").append(entry.getKey()).append(", cause: " + entry.getValue().getMessage());
+                }
+                exchange.setException(new CamelExecutionException(msg.toString(), exchange));
+            }
+        }
+        callback.done(false);
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebSocketTestSupport.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebSocketTestSupport.java
new file mode 100644
index 0000000..158e763
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebSocketTestSupport.java
@@ -0,0 +1,99 @@
+/*
+ * 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.websocket;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import io.vertx.core.Handler;
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpClient;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.core.http.WebSocket;
+import io.vertx.ext.web.Route;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit5.CamelTestSupport;
+
+public class VertxWebSocketTestSupport extends CamelTestSupport {
+
+    protected final int port = AvailablePortFinder.getNextAvailable();
+
+    /**
+     * Returns the randomized port used for the Vert.x server if no port
+     * was provided to the consumer.
+     */
+    public int getVertxServerRandomPort() {
+        VertxWebsocketComponent component = context.getComponent("vertx-websocket", VertxWebsocketComponent.class);
+        Map<VertxWebsocketHostKey, VertxWebsocketHost> registry = component.getVerxHostRegistry();
+        return registry.values()
+                .stream()
+                .filter(wsHost -> wsHost.getPort() != port)
+                .findFirst()
+                .get()
+                .getPort();
+    }
+
+    public WebSocket openWebSocketConnection(String host, int port, String path, Consumer<String> handler) throws Exception {
+        HttpClient client = Vertx.vertx().createHttpClient();
+        CompletableFuture<WebSocket> future = new CompletableFuture<>();
+        client.webSocket(port, host, path, result -> {
+            if (!result.failed()) {
+                future.complete(result.result());
+            } else {
+                future.completeExceptionally(result.cause());
+            }
+        });
+        WebSocket webSocket = future.get(5, TimeUnit.SECONDS);
+        webSocket.textMessageHandler(message -> handler.accept(message));
+        return webSocket;
+    }
+
+    public Router createRouter(String path, CountDownLatch latch) {
+        return createRouter(path, null, latch);
+    }
+
+    public Router createRouter(String path, Handler<RoutingContext> handler, CountDownLatch latch) {
+        Router router = Router.router(Vertx.vertx());
+        Route route = router.route(path);
+
+        if (handler == null) {
+            handler = new Handler<RoutingContext>() {
+                @Override
+                public void handle(RoutingContext context) {
+                    HttpServerRequest request = context.request();
+                    ServerWebSocket webSocket = request.upgrade();
+                    webSocket.textMessageHandler(new Handler<String>() {
+                        @Override
+                        public void handle(String message) {
+                            webSocket.writeTextMessage("Hello world");
+                            latch.countDown();
+                        }
+                    });
+                }
+            };
+        }
+
+        route.handler(handler);
+        return router;
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponentConfigurationTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponentConfigurationTest.java
new file mode 100644
index 0000000..79b05be
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketComponentConfigurationTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.websocket;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
+import io.vertx.core.metrics.MetricsOptions;
+import io.vertx.core.metrics.impl.DummyVertxMetrics;
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class VertxWebsocketComponentConfigurationTest {
+
+    @Test
+    public void testCustomVertx() {
+        Vertx vertx = Vertx.vertx();
+
+        CamelContext context = new DefaultCamelContext();
+        VertxWebsocketComponent component = new VertxWebsocketComponent();
+        component.setVertx(vertx);
+
+        context.start();
+        try {
+            assertSame(vertx, component.getVertx());
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testCustomVertxFromRegistry() {
+        Vertx vertx = Vertx.vertx();
+
+        CamelContext context = new DefaultCamelContext();
+        context.getRegistry().bind("vertx", vertx);
+        context.start();
+        try {
+            VertxWebsocketComponent component = context.getComponent("vertx-websocket", VertxWebsocketComponent.class);
+            assertSame(vertx, component.getVertx());
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testCustomVertxOptions() {
+        MetricsOptions metrics = new MetricsOptions();
+        metrics.setEnabled(true);
+        metrics.setFactory(options -> DummyVertxMetrics.INSTANCE);
+
+        VertxOptions options = new VertxOptions();
+        options.setMetricsOptions(metrics);
+
+        CamelContext context = new DefaultCamelContext();
+        VertxWebsocketComponent component = new VertxWebsocketComponent();
+        component.setVertxOptions(options);
+
+        context.addComponent("vertx-websocket", component);
+        context.start();
+        try {
+            Vertx vertx = component.getVertx();
+            assertTrue(vertx.isMetricsEnabled());
+        } finally {
+            context.stop();
+        }
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpointConfigurationTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpointConfigurationTest.java
new file mode 100644
index 0000000..bde4816
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketEndpointConfigurationTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.websocket;
+
+import io.vertx.core.http.HttpClientOptions;
+import io.vertx.core.http.HttpServerOptions;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+public class VertxWebsocketEndpointConfigurationTest extends VertxWebSocketTestSupport {
+
+    private static final int PORT = AvailablePortFinder.getNextAvailable();
+
+    @BindToRegistry("clientOptions")
+    HttpClientOptions clientOptions = new HttpClientOptions();
+
+    @BindToRegistry("serverOptions")
+    HttpServerOptions serverOptions = new HttpServerOptions();
+
+    @Test
+    public void testHttpClientOptions() {
+        VertxWebsocketEndpoint endpoint = context
+                .getEndpoint("vertx-websocket:localhost:" + PORT + "/options/client?clientOptions=#clientOptions", VertxWebsocketEndpoint.class);
+
+        assertSame(clientOptions, endpoint.getConfiguration().getClientOptions());
+    }
+
+    @Test
+    public void testHttpServerOptions() {
+        VertxWebsocketEndpoint endpoint = context
+                .getEndpoint("vertx-websocket:localhost:" + PORT + "/options/server?serverOptions=#serverOptions", VertxWebsocketEndpoint.class);
+
+        assertSame(serverOptions, endpoint.getConfiguration().getServerOptions());
+    }
+
+    @Test
+    public void testDefaultHostConfiguration() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:defaultConfiguration");
+        mockEndpoint.expectedMessageCount(1);
+
+        template.sendBody("vertx-websocket:localhost:" + getVertxServerRandomPort() + "/default/configuration", "Hello world");
+
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("vertx-websocket:///default/configuration")
+                        .to("mock:defaultConfiguration");
+            }
+        };
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketExternalServerTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketExternalServerTest.java
new file mode 100644
index 0000000..98da3bd
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketExternalServerTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.websocket;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import io.vertx.core.Handler;
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.ext.web.Route;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
+import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class VertxWebsocketExternalServerTest extends VertxWebSocketTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VertxWebsocketExternalServerTest.class);
+
+    @Test
+    public void testProduceToExternalServer() throws Exception {
+        CountDownLatch latch = new CountDownLatch(2);
+        Vertx vertx = Vertx.vertx();
+        Router router = Router.router(vertx);
+        Route route = router.route("/ws");
+        route.handler(new Handler<RoutingContext>() {
+            @Override
+            public void handle(RoutingContext context) {
+                HttpServerRequest request = context.request();
+                ServerWebSocket webSocket = request.upgrade();
+                webSocket.textMessageHandler(new Handler<String>() {
+                    @Override
+                    public void handle(String message) {
+                        latch.countDown();
+                    }
+                });
+            }
+        });
+
+        VertxWebsocketHostConfiguration configuration = new VertxWebsocketHostConfiguration(vertx, router, null, null);
+        VertxWebsocketHostKey key = new VertxWebsocketHostKey("localhost", 0);
+        VertxWebsocketHost host =  new VertxWebsocketHost(configuration, key);
+        host.start();
+
+        CamelContext context = new DefaultCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .toD("vertx-websocket:localhost:${header.port}/ws");
+
+                from("vertx-websocket:localhost:" + port + "/test")
+                        .toF("vertx-websocket:localhost:%d/ws", host.getPort());
+            }
+        });
+
+        context.start();
+        try {
+            ProducerTemplate template = context.createProducerTemplate();
+            template.sendBodyAndHeader("direct:start", "Hello world", "port", host.getPort());
+            template.sendBody("vertx-websocket:localhost:" + port + "/test", "Hello world");
+
+            assertTrue(latch.await(10, TimeUnit.SECONDS));
+        } finally {
+            try {
+                host.stop();
+            } catch (Exception e) {
+                LOG.warn("Failed to stop Vert.x server {}", e);
+            }
+            context.stop();
+        }
+    }
+
+    @Override
+    protected void startCamelContext() throws Exception {
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelperTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelperTest.java
new file mode 100644
index 0000000..bb217e3
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketHelperTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.websocket;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class VertxWebsocketHelperTest {
+
+    @Test
+    public void extractHostNameTest() {
+        assertEquals("test.host.com", VertxWebsocketHelper.extractHostName("test.host.com:8080/path"));
+        assertEquals("0.0.0.0", VertxWebsocketHelper.extractHostName("/path"));
+    }
+
+    @Test
+    public void extractPortTest() {
+        assertEquals(8888, VertxWebsocketHelper.extractPortNumber("test.host.com:8888/path"));
+        assertEquals(0, VertxWebsocketHelper.extractPortNumber("0.0.0.0/path"));
+    }
+
+    @Test
+    public void extractPortInvalidTest() {
+        assertThrows(IllegalArgumentException.class, () -> {
+            VertxWebsocketHelper.extractPortNumber("test.host.com:/path");
+        });
+
+        assertThrows(IllegalArgumentException.class, () -> {
+            VertxWebsocketHelper.extractPortNumber("test.host.com:port/path");
+        });
+    }
+
+    @Test
+    public void extractPathTest() {
+        assertEquals("/web/socket/path", VertxWebsocketHelper.extractPath("test.host.com:8080/web/socket/path"));
+        assertEquals("/", VertxWebsocketHelper.extractPath(""));
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketMultiConsumerTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketMultiConsumerTest.java
new file mode 100644
index 0000000..be4f14e
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketMultiConsumerTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.websocket;
+
+import java.util.stream.Stream;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+public class VertxWebsocketMultiConsumerTest extends VertxWebSocketTestSupport {
+
+    @Test
+    public void testMultipleConsumersForSameHostAndPort() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedBodiesReceivedInAnyOrder("Hello A", "Hello B", "Hello C");
+
+        Stream.of("A", "B", "C").forEach(body -> {
+            template.sendBody("vertx-websocket:localhost:" + port + "/test/a", body);
+        });
+
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("vertx-websocket:localhost:%d/test/a", port)
+                        .setBody(simple("Hello ${body}"))
+                        .to("mock:result");
+
+                fromF("vertx-websocket:localhost:%d/test/b", port)
+                        .setBody(simple("Hello ${body}"))
+                        .to("mock:result");
+
+                fromF("vertx-websocket:localhost:%d/test/c", port)
+                        .setBody(simple("Hello ${body}"))
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketOriginTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketOriginTest.java
new file mode 100644
index 0000000..f20e6b4
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketOriginTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.websocket;
+
+import java.util.concurrent.ExecutionException;
+
+import io.vertx.core.http.UpgradeRejectedException;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class VertxWebsocketOriginTest  extends VertxWebSocketTestSupport {
+
+    private static final int PORT2 = AvailablePortFinder.getNextAvailable();
+
+    @Test
+    public void testValidOrigin() throws InterruptedException {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedBodiesReceived("Hello world");
+        template.sendBody("vertx-websocket:localhost:" + port + "/test", "world");
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void testInvalidOrigin() {
+        CamelExecutionException e = assertThrows(CamelExecutionException.class, () -> {
+            template.sendBody("vertx-websocket:localhost:" + PORT2 + "/test", "world");
+        });
+
+        UpgradeRejectedException upgradeRejectedException = unwrapException(e);
+        assertNotNull(upgradeRejectedException);
+        assertEquals(403, upgradeRejectedException.getStatus());
+    }
+
+    private UpgradeRejectedException unwrapException(CamelExecutionException e) {
+        Throwable cause = e.getCause();
+        if (cause instanceof ExecutionException) {
+            Throwable originalCause = cause.getCause();
+            if (originalCause != null && originalCause instanceof UpgradeRejectedException) {
+                return (UpgradeRejectedException) originalCause;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("vertx-websocket:localhost:%d/test?allowedOriginPattern=.*localhost.*", port)
+                        .setBody(simple("Hello ${body}"))
+                        .to("mock:result");
+
+                fromF("vertx-websocket:localhost:%d/test?allowedOriginPattern=.*foohost.*", PORT2)
+                        .setBody(simple("Hello ${body}"))
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketRouterTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketRouterTest.java
new file mode 100644
index 0000000..d4dd1ad
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketRouterTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.websocket;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import io.vertx.core.Handler;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class VertxWebsocketRouterTest extends VertxWebSocketTestSupport {
+
+    @Test
+    public void testCustomRouter() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("vertx-websocket:localhost:%d/test?router=#customRouter", port)
+                        .to("mock:result");
+            }
+        });
+
+        CountDownLatch latch = new CountDownLatch(1);
+        Router router = createRouter("/custom", latch);
+
+        context.getRegistry().bind("customRouter", router);
+        context.start();
+        try {
+            MockEndpoint mockEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
+            mockEndpoint.expectedBodiesReceived("Hello world");
+
+            // Verify the WebSocket consumer we configured in the camel route
+            ProducerTemplate template = context.createProducerTemplate();
+            template.sendBody("vertx-websocket:localhost:" + port + "/test", "Hello world");
+            mockEndpoint.assertIsSatisfied();
+
+            // Verify the WebSocket route manually added to the vertx router
+            String result = template.requestBody("vertx-websocket:localhost:" + port + "/custom", "Hello world", String.class);
+            assertTrue(latch.await(10, TimeUnit.SECONDS));
+            assertEquals("Hello world", result);
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testCustomRouterFallbackFromRegistry() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("vertx-websocket:localhost:%d/test", port)
+                        .to("mock:result");
+            }
+        });
+
+        CountDownLatch latch = new CountDownLatch(1);
+        Router router = createRouter("/custom", latch);
+
+        context.getRegistry().bind("vertx-router", router);
+        context.start();
+        try {
+            MockEndpoint mockEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
+            mockEndpoint.expectedBodiesReceived("Hello world");
+
+            // Verify the WebSocket consumer we configured in the camel route
+            ProducerTemplate template = context.createProducerTemplate();
+            template.sendBody("vertx-websocket:localhost:" + port + "/test", "Hello world");
+            mockEndpoint.assertIsSatisfied();
+
+            // Verify the WebSocket route manually added to the vertx router
+            String result = template.requestBody("vertx-websocket:localhost:" + port + "/custom", "Hello world", String.class);
+            assertTrue(latch.await(10, TimeUnit.SECONDS));
+            assertEquals("Hello world", result);
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testCustomVertxRouterWebSocketAlreadyClosedException() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("vertx-websocket:localhost:%d/test", port)
+                        .to("mock:result");
+            }
+        });
+
+        Router router = createRouter("/custom", new Handler<RoutingContext>() {
+            @Override
+            public void handle(RoutingContext context) {
+                HttpServerRequest request = context.request();
+                ServerWebSocket webSocket = request.upgrade();
+
+                // Immediately close the socket to simulate an error scenario
+                webSocket.close();
+            }
+        }, null);
+
+        context.getRegistry().bind("vertx-router", router);
+        context.start();
+        try {
+            assertThrows(CamelExecutionException.class, () -> {
+                ProducerTemplate template = context.createProducerTemplate();
+                template.requestBody("vertx-websocket:localhost:" + port + "/custom", "Hello world", String.class);
+            });
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Override
+    protected void startCamelContext() throws Exception {
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketSSLTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketSSLTest.java
new file mode 100644
index 0000000..9aa919c
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketSSLTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.websocket;
+
+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.impl.DefaultCamelContext;
+import org.apache.camel.support.jsse.KeyManagersParameters;
+import org.apache.camel.support.jsse.KeyStoreParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.SSLContextServerParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class VertxWebsocketSSLTest extends VertxWebSocketTestSupport {
+
+    private SSLContextParameters serverSSLParameters;
+    private SSLContextParameters clientSSLParameters;
+
+    @BeforeEach
+    public void setupSecurity() {
+        serverSSLParameters = new SSLContextParameters();
+        clientSSLParameters = new SSLContextParameters();
+
+        KeyStoreParameters keystoreParameters = new KeyStoreParameters();
+        keystoreParameters.setResource("server.jks");
+        keystoreParameters.setPassword("security");
+
+        KeyManagersParameters serviceSSLKeyManagers = new KeyManagersParameters();
+        serviceSSLKeyManagers.setKeyPassword("security");
+        serviceSSLKeyManagers.setKeyStore(keystoreParameters);
+
+        serverSSLParameters.setKeyManagers(serviceSSLKeyManagers);
+
+        KeyStoreParameters truststoreParameters = new KeyStoreParameters();
+        truststoreParameters.setResource("client.jks");
+        truststoreParameters.setPassword("storepass");
+
+        TrustManagersParameters clientAuthServiceSSLTrustManagers = new TrustManagersParameters();
+        clientAuthServiceSSLTrustManagers.setKeyStore(truststoreParameters);
+        serverSSLParameters.setTrustManagers(clientAuthServiceSSLTrustManagers);
+        SSLContextServerParameters clientAuthSSLContextServerParameters = new SSLContextServerParameters();
+        clientAuthSSLContextServerParameters.setClientAuthentication("REQUIRE");
+        serverSSLParameters.setServerParameters(clientAuthSSLContextServerParameters);
+
+        TrustManagersParameters clientSSLTrustManagers = new TrustManagersParameters();
+        clientSSLTrustManagers.setKeyStore(truststoreParameters);
+        clientSSLParameters.setTrustManagers(clientSSLTrustManagers);
+
+        KeyManagersParameters clientAuthClientSSLKeyManagers = new KeyManagersParameters();
+        clientAuthClientSSLKeyManagers.setKeyPassword("security");
+        clientAuthClientSSLKeyManagers.setKeyStore(keystoreParameters);
+        clientSSLParameters.setKeyManagers(clientAuthClientSSLKeyManagers);
+    }
+
+    @Test
+    public void testSSLContextParametersFromRegistry() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .toF("vertx-websocket:localhost:%d/echo?sslContextParameters=#clientSSLParameters", port);
+
+                fromF("vertx-websocket:localhost:%d/echo?sslContextParameters=#serverSSLParameters", port)
+                        .setBody(simple("Hello ${body}"))
+                        .to("mock:result");
+            }
+        });
+
+        context.getRegistry().bind("clientSSLParameters", clientSSLParameters);
+        context.getRegistry().bind("serverSSLParameters", serverSSLParameters);
+
+        context.start();
+        try {
+            MockEndpoint mockEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
+            mockEndpoint.expectedBodiesReceived("Hello world");
+
+            ProducerTemplate template = context.createProducerTemplate();
+            template.sendBody("direct:start", "world");
+
+            mockEndpoint.assertIsSatisfied();
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testGlobalServerSSLContextParameters() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .toF("vertx-websocket:localhost:%d/echo?sslContextParameters=#clientSSLParameters", port);
+
+                fromF("vertx-websocket:localhost:%d/echo", port)
+                        .setBody(simple("Hello ${body}"))
+                        .to("mock:result");
+            }
+        });
+
+        VertxWebsocketComponent component = new VertxWebsocketComponent();
+        component.setUseGlobalSslContextParameters(true);
+        context.setSSLContextParameters(serverSSLParameters);
+        context.addComponent("vertx-websocket", component);
+        context.getRegistry().bind("clientSSLParameters", clientSSLParameters);
+
+        context.start();
+        try {
+            MockEndpoint mockEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
+            mockEndpoint.expectedBodiesReceived("Hello world");
+
+            ProducerTemplate template = context.createProducerTemplate();
+            template.sendBody("direct:start", "world");
+
+            mockEndpoint.assertIsSatisfied();
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Override
+    protected void startCamelContext() throws Exception {
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketTest.java b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketTest.java
new file mode 100644
index 0000000..0f7fcbc
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/java/org/apache/camel/component/vertx/websocket/VertxWebsocketTest.java
@@ -0,0 +1,262 @@
+/*
+ * 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.websocket;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import io.vertx.core.http.ServerWebSocket;
+import io.vertx.core.http.WebSocket;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.RoutesBuilder;
+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.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class VertxWebsocketTest extends VertxWebSocketTestSupport {
+
+    @Test
+    public void testTextMessage() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedBodiesReceived("Hello world");
+
+        template.sendBody("direct:start", "world");
+
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void testBinaryMessage() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedBodiesReceived("Hello world");
+
+        template.sendBody("direct:start", "world".getBytes(StandardCharsets.UTF_8));
+
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void testStreamMessage() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedBodiesReceived("Hello world");
+
+        InputStream stream = new ByteArrayInputStream("world".getBytes(StandardCharsets.UTF_8));
+
+        template.sendBody("direct:start", stream);
+
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void testNullMessage() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedBodiesReceived("Hello world");
+        mockEndpoint.setResultWaitTime(500);
+
+        template.sendBody("direct:start", null);
+
+        // Since the message body is null, the WebSocket producer will not send payload to the WS endpoint
+        mockEndpoint.assertIsNotSatisfied();
+    }
+
+    @Test
+    public void testSendWithConnectionKey() throws Exception {
+        int expectedResultCount = 1;
+        CountDownLatch latch = new CountDownLatch(expectedResultCount);
+        List<String> results = new ArrayList<>();
+
+        for (int i = 0; i < 2; i++) {
+            openWebSocketConnection("localhost", port, "/test", message -> {
+                synchronized (latch) {
+                    results.add(message);
+                    latch.countDown();
+                }
+            });
+        }
+
+        VertxWebsocketEndpoint endpoint = context.getEndpoint("vertx-websocket:localhost:" + port + "/test", VertxWebsocketEndpoint.class);
+        Map<String, ServerWebSocket> connectedPeers = endpoint.findPeersForHostPort();
+        assertEquals(2, connectedPeers.size());
+
+        String connectionKey = connectedPeers.keySet().iterator().next();
+
+        template.sendBodyAndHeader("vertx-websocket:localhost:" + port + "/test", "Hello World", VertxWebsocketContants.CONNECTION_KEY, connectionKey);
+
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+        assertEquals(expectedResultCount, results.size());
+        assertTrue(results.contains("Hello World"));
+    }
+
+    @Test
+    public void testSendWithInvalidConnectionKey() throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedBodiesReceived("Hello world");
+        mockEndpoint.setResultWaitTime(500);
+
+        template.sendBodyAndHeader("direct:start", "Hello World", VertxWebsocketContants.CONNECTION_KEY, "invalid-key");
+
+        // Since the message body is null, the WebSocket producer will not send payload to the WS endpoint
+        mockEndpoint.assertIsNotSatisfied();
+    }
+
+    @Test
+    public void testSendWithMultipleConnectionKeys() throws Exception {
+        int expectedResultCount = 3;
+        CountDownLatch latch = new CountDownLatch(expectedResultCount);
+        List<String> results = new ArrayList<>();
+
+        for (int i = 0; i < 5; i++) {
+            openWebSocketConnection("localhost", port, "/test", message -> {
+                synchronized (latch) {
+                    results.add(message);
+                    latch.countDown();
+                }
+            });
+        }
+
+        VertxWebsocketEndpoint endpoint = context.getEndpoint("vertx-websocket:localhost:" + port + "/test", VertxWebsocketEndpoint.class);
+        Map<String, ServerWebSocket> connectedPeers = endpoint.findPeersForHostPort();
+        assertEquals(5, connectedPeers.size());
+
+        StringJoiner joiner = new StringJoiner(",");
+        Iterator<String> iterator = connectedPeers.keySet().iterator();
+        for (int i = 0; i < 3; i++) {
+            joiner.add(iterator.next());
+        }
+
+        template.sendBodyAndHeader("vertx-websocket:localhost:" + port + "/test", "Hello World", VertxWebsocketContants.CONNECTION_KEY, joiner.toString());
+
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+        assertEquals(expectedResultCount, results.size());
+        results.forEach(result -> assertEquals("Hello World", result));
+    }
+
+    @Test
+    public void testSendToAll() throws Exception {
+        int expectedResultCount = 5;
+        CountDownLatch latch = new CountDownLatch(expectedResultCount);
+        List<String> results = new ArrayList<>();
+
+        for (int i = 0; i < expectedResultCount; i++) {
+            openWebSocketConnection("localhost", port, "/test", message -> {
+                synchronized (latch) {
+                    results.add(message + " " + latch.getCount());
+                    latch.countDown();
+                }
+            });
+        }
+
+        template.sendBody("vertx-websocket:localhost:" + port + "/test?sendToAll=true", "Hello World");
+
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+        assertEquals(expectedResultCount, results.size());
+
+        for (int i = 1; i <= expectedResultCount; i++) {
+            assertTrue(results.contains("Hello World " + i));
+        }
+    }
+
+    @Test
+    public void testSendToAllWithHeader() throws Exception {
+        int expectedResultCount = 5;
+        CountDownLatch latch = new CountDownLatch(expectedResultCount);
+        List<String> results = new ArrayList<>();
+
+        for (int i = 0; i < expectedResultCount; i++) {
+            openWebSocketConnection("localhost", port, "/test", message -> {
+                synchronized (latch) {
+                    results.add(message + " " + latch.getCount());
+                    latch.countDown();
+                }
+            });
+        }
+
+        template.sendBodyAndHeader("vertx-websocket:localhost:" + port + "/test", "Hello World", VertxWebsocketContants.SEND_TO_ALL, true);
+
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+        assertEquals(expectedResultCount, results.size());
+
+        for (int i = 1; i <= expectedResultCount; i++) {
+            assertTrue(results.contains("Hello World " + i));
+        }
+    }
+
+    @Test
+    public void testEchoRoute() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        List<String> results = new ArrayList<>();
+
+        VertxWebsocketComponent component = context.getComponent("vertx-websocket", VertxWebsocketComponent.class);
+        Map<VertxWebsocketHostKey, VertxWebsocketHost> registry = component.getVerxHostRegistry();
+        VertxWebsocketHost host = registry.values()
+                .stream()
+                .filter(wsHost -> wsHost.getPort() != port)
+                .findFirst()
+                .get();
+
+        WebSocket webSocket = openWebSocketConnection("localhost", host.getPort(), "/greeting", message -> {
+            synchronized (latch) {
+                results.add(message);
+                latch.countDown();
+            }
+        });
+
+        webSocket.writeTextMessage("Camel");
+
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+        assertEquals(1, results.size());
+        assertEquals("Hello Camel", results.get(0));
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .toF("vertx-websocket:localhost:%d/test", port);
+
+                fromF("vertx-websocket:localhost:%d/test", port)
+                    .setBody(simple("Hello ${body}"))
+                    .to("mock:result");
+
+                from("vertx-websocket://greeting")
+                    .setBody(simple("Hello ${body}"))
+                    .process(new Processor() {
+                        @Override
+                        public void process(Exchange exchange) throws Exception {
+                            int serverPort = getVertxServerRandomPort();
+                            exchange.getMessage().setHeader("port", serverPort);
+                        }
+                    })
+                    .toD("vertx-websocket:localhost:${header.port}/greeting");
+            }
+        };
+    }
+}
diff --git a/components/camel-vertx-websocket/src/test/resources/client.jks b/components/camel-vertx-websocket/src/test/resources/client.jks
new file mode 100644
index 0000000..44d82a85
Binary files /dev/null and b/components/camel-vertx-websocket/src/test/resources/client.jks differ
diff --git a/components/camel-vertx-websocket/src/test/resources/log4j2.properties b/components/camel-vertx-websocket/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..57543c5
--- /dev/null
+++ b/components/camel-vertx-websocket/src/test/resources/log4j2.properties
@@ -0,0 +1,30 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-vertx-websocket-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n
+logger.vertx.name = org.apache.camel.component.vertx.websocket
+logger.vertx.level = INFO
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/components/camel-vertx-websocket/src/test/resources/server.jks b/components/camel-vertx-websocket/src/test/resources/server.jks
new file mode 100644
index 0000000..52321ad
Binary files /dev/null and b/components/camel-vertx-websocket/src/test/resources/server.jks differ
diff --git a/components/pom.xml b/components/pom.xml
index 26fd88b..90e1496 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -363,6 +363,7 @@
         <module>camel-univocity-parsers</module>
         <module>camel-velocity</module>
         <module>camel-vertx</module>
+        <module>camel-vertx-websocket</module>
         <module>camel-weather</module>
         <module>camel-web3j</module>
         <module>camel-webhook</module>
diff --git a/core/camel-allcomponents/pom.xml b/core/camel-allcomponents/pom.xml
index 5bf4b41..217414b 100644
--- a/core/camel-allcomponents/pom.xml
+++ b/core/camel-allcomponents/pom.xml
@@ -1160,6 +1160,10 @@
 		</dependency>
 		<dependency>
 			<groupId>org.apache.camel</groupId>
+			<artifactId>camel-vertx-websocket</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.camel</groupId>
 			<artifactId>camel-vertx</artifactId>
 		</dependency>
 		<dependency>
diff --git a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
index f32cf9f..5a6c5d4 100644
--- a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
+++ b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
@@ -3731,6 +3731,17 @@ public interface ComponentsBuilderFactory {
         return org.apache.camel.builder.component.dsl.VertxComponentBuilderFactory.vertx();
     }
     /**
+     * Vert.x WebSocket (camel-vertx-websocket)
+     * Camel WebSocket support with Vert.x
+     * 
+     * Category: websocket
+     * Since: 3.5
+     * Maven coordinates: org.apache.camel:camel-vertx-websocket
+     */
+    static org.apache.camel.builder.component.dsl.VertxWebsocketComponentBuilderFactory.VertxWebsocketComponentBuilder vertxWebsocket() {
+        return org.apache.camel.builder.component.dsl.VertxWebsocketComponentBuilderFactory.vertxWebsocket();
+    }
+    /**
      * VM (camel-vm)
      * Call another endpoint in the same CamelContext asynchronously.
      * 
diff --git a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/VertxWebsocketComponentBuilderFactory.java b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/VertxWebsocketComponentBuilderFactory.java
new file mode 100644
index 0000000..98be6e8
--- /dev/null
+++ b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/VertxWebsocketComponentBuilderFactory.java
@@ -0,0 +1,168 @@
+/*
+ * 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.builder.component.dsl;
+
+import javax.annotation.Generated;
+import org.apache.camel.Component;
+import org.apache.camel.builder.component.AbstractComponentBuilder;
+import org.apache.camel.builder.component.ComponentBuilder;
+import org.apache.camel.component.vertx.websocket.VertxWebsocketComponent;
+
+/**
+ * Camel WebSocket support with Vert.x
+ * 
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.ComponentDslMojo")
+public interface VertxWebsocketComponentBuilderFactory {
+
+    /**
+     * Vert.x WebSocket (camel-vertx-websocket)
+     * Camel WebSocket support with Vert.x
+     * 
+     * Category: websocket
+     * Since: 3.5
+     * Maven coordinates: org.apache.camel:camel-vertx-websocket
+     */
+    static VertxWebsocketComponentBuilder vertxWebsocket() {
+        return new VertxWebsocketComponentBuilderImpl();
+    }
+
+    /**
+     * Builder for the Vert.x WebSocket component.
+     */
+    interface VertxWebsocketComponentBuilder
+            extends
+                ComponentBuilder<VertxWebsocketComponent> {
+        /**
+         * Allows for bridging the consumer to the Camel routing Error Handler,
+         * which mean any exceptions occurred while the consumer is trying to
+         * pickup incoming messages, or the likes, will now be processed as a
+         * message and handled by the routing Error Handler. By default the
+         * consumer will use the org.apache.camel.spi.ExceptionHandler to deal
+         * with exceptions, that will be logged at WARN or ERROR level and
+         * ignored.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: consumer
+         */
+        default VertxWebsocketComponentBuilder bridgeErrorHandler(
+                boolean bridgeErrorHandler) {
+            doSetProperty("bridgeErrorHandler", bridgeErrorHandler);
+            return this;
+        }
+        /**
+         * 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 during
+         * starting and cause the route to fail being started. By deferring this
+         * startup to be lazy then the startup failure can be handled during
+         * routing messages via Camel's routing error handlers. Beware that when
+         * the first message is processed then creating and starting the
+         * producer may take a little time and prolong the total processing time
+         * of the processing.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: producer
+         */
+        default VertxWebsocketComponentBuilder lazyStartProducer(
+                boolean lazyStartProducer) {
+            doSetProperty("lazyStartProducer", lazyStartProducer);
+            return this;
+        }
+        /**
+         * Whether the component should use basic property binding (Camel 2.x)
+         * or the newer property binding with additional capabilities.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default VertxWebsocketComponentBuilder basicPropertyBinding(
+                boolean basicPropertyBinding) {
+            doSetProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * To use an existing vertx instead of creating a new instance.
+         * 
+         * The option is a: <code>io.vertx.core.Vertx</code> type.
+         * 
+         * Group: advanced
+         */
+        default VertxWebsocketComponentBuilder vertx(io.vertx.core.Vertx vertx) {
+            doSetProperty("vertx", vertx);
+            return this;
+        }
+        /**
+         * To provide a custom set of vertx options for configuring vertx.
+         * 
+         * The option is a: <code>io.vertx.core.VertxOptions</code> type.
+         * 
+         * Group: advanced
+         */
+        default VertxWebsocketComponentBuilder vertxOptions(
+                io.vertx.core.VertxOptions vertxOptions) {
+            doSetProperty("vertxOptions", vertxOptions);
+            return this;
+        }
+        /**
+         * Enable usage of global SSL context parameters.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         */
+        default VertxWebsocketComponentBuilder useGlobalSslContextParameters(
+                boolean useGlobalSslContextParameters) {
+            doSetProperty("useGlobalSslContextParameters", useGlobalSslContextParameters);
+            return this;
+        }
+    }
+
+    class VertxWebsocketComponentBuilderImpl
+            extends
+                AbstractComponentBuilder<VertxWebsocketComponent>
+            implements
+                VertxWebsocketComponentBuilder {
+        @Override
+        protected VertxWebsocketComponent buildConcreteComponent() {
+            return new VertxWebsocketComponent();
+        }
+        @Override
+        protected boolean setPropertyOnComponent(
+                Component component,
+                String name,
+                Object value) {
+            switch (name) {
+            case "bridgeErrorHandler": ((VertxWebsocketComponent) component).setBridgeErrorHandler((boolean) value); return true;
+            case "lazyStartProducer": ((VertxWebsocketComponent) component).setLazyStartProducer((boolean) value); return true;
+            case "basicPropertyBinding": ((VertxWebsocketComponent) component).setBasicPropertyBinding((boolean) value); return true;
+            case "vertx": ((VertxWebsocketComponent) component).setVertx((io.vertx.core.Vertx) value); return true;
+            case "vertxOptions": ((VertxWebsocketComponent) component).setVertxOptions((io.vertx.core.VertxOptions) value); return true;
+            case "useGlobalSslContextParameters": ((VertxWebsocketComponent) component).setUseGlobalSslContextParameters((boolean) value); return true;
+            default: return false;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/camel-componentdsl/src/generated/resources/metadata.json b/core/camel-componentdsl/src/generated/resources/metadata.json
index 2203490..ae7cf62 100644
--- a/core/camel-componentdsl/src/generated/resources/metadata.json
+++ b/core/camel-componentdsl/src/generated/resources/metadata.json
@@ -6955,6 +6955,27 @@
     "producerOnly": false,
     "lenientProperties": false
   },
+  "VertxWebsocketComponentBuilderFactory": {
+    "kind": "component",
+    "name": "vertx-websocket",
+    "title": "Vert.x WebSocket",
+    "description": "Camel WebSocket support with Vert.x",
+    "deprecated": false,
+    "firstVersion": "3.5.0",
+    "label": "websocket",
+    "javaType": "org.apache.camel.component.vertx.websocket.VertxWebsocketComponent",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-vertx-websocket",
+    "version": "3.5.0-SNAPSHOT",
+    "scheme": "vertx-websocket",
+    "extendsScheme": "",
+    "syntax": "vertx-websocket:host:port\/resourceUri",
+    "async": false,
+    "consumerOnly": false,
+    "producerOnly": false,
+    "lenientProperties": false
+  },
   "VmComponentBuilderFactory": {
     "kind": "component",
     "name": "vm",
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java
index 803ca80..70fd722 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java
@@ -342,6 +342,7 @@ public interface EndpointBuilderFactory
             org.apache.camel.builder.endpoint.dsl.ValidatorEndpointBuilderFactory.ValidatorBuilders,
             org.apache.camel.builder.endpoint.dsl.VelocityEndpointBuilderFactory.VelocityBuilders,
             org.apache.camel.builder.endpoint.dsl.VertxEndpointBuilderFactory.VertxBuilders,
+            org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.VertxWebsocketBuilders,
             org.apache.camel.builder.endpoint.dsl.VmEndpointBuilderFactory.VmBuilders,
             org.apache.camel.builder.endpoint.dsl.WeatherEndpointBuilderFactory.WeatherBuilders,
             org.apache.camel.builder.endpoint.dsl.Web3jEndpointBuilderFactory.Web3jBuilders,
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java
index 06341c2..7676f4c 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java
@@ -339,6 +339,7 @@ public interface EndpointBuilders
             org.apache.camel.builder.endpoint.dsl.ValidatorEndpointBuilderFactory,
             org.apache.camel.builder.endpoint.dsl.VelocityEndpointBuilderFactory,
             org.apache.camel.builder.endpoint.dsl.VertxEndpointBuilderFactory,
+            org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory,
             org.apache.camel.builder.endpoint.dsl.VmEndpointBuilderFactory,
             org.apache.camel.builder.endpoint.dsl.WeatherEndpointBuilderFactory,
             org.apache.camel.builder.endpoint.dsl.Web3jEndpointBuilderFactory,
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index b1890c3..d0fcba0 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -14420,6 +14420,130 @@ public class StaticEndpointBuilders {
         return org.apache.camel.builder.endpoint.dsl.VertxEndpointBuilderFactory.endpointBuilder(componentName, path);
     }
     /**
+     * Vert.x WebSocket (camel-vertx-websocket)
+     * Camel WebSocket support with Vert.x
+     * 
+     * Category: websocket
+     * Since: 3.5
+     * Maven coordinates: org.apache.camel:camel-vertx-websocket
+     * 
+     * Syntax: <code>vertx-websocket:host:port/resourceUri</code>
+     * 
+     * Path parameter: host
+     * The host that the consumer should bind to or the host of the remote
+     * websocket destination that the producer should connect to
+     * Default value: 0.0.0.0
+     * 
+     * Path parameter: port
+     * The port that the consumer should bind to or port of the remote websocket
+     * destination that the producer should connect to
+     * Default value: 0
+     * 
+     * Path parameter: path (required)
+     * The path that the consumer should bind to or path of the remote websocket
+     * destination that the producer should connect to
+     * Default value: /
+     * 
+     * @param path host:port/resourceUri
+     */
+    static org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.VertxWebsocketEndpointBuilder vertxWebsocket(
+            String path) {
+        return org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.endpointBuilder("vertx-websocket", path);
+    }
+    /**
+     * Vert.x WebSocket (camel-vertx-websocket)
+     * Camel WebSocket support with Vert.x
+     * 
+     * Category: websocket
+     * Since: 3.5
+     * Maven coordinates: org.apache.camel:camel-vertx-websocket
+     * 
+     * Syntax: <code>vertx-websocket:host:port/resourceUri</code>
+     * 
+     * Path parameter: host
+     * The host that the consumer should bind to or the host of the remote
+     * websocket destination that the producer should connect to
+     * Default value: 0.0.0.0
+     * 
+     * Path parameter: port
+     * The port that the consumer should bind to or port of the remote websocket
+     * destination that the producer should connect to
+     * Default value: 0
+     * 
+     * Path parameter: path (required)
+     * The path that the consumer should bind to or path of the remote websocket
+     * destination that the producer should connect to
+     * Default value: /
+     * 
+     * @param componentName to use a custom component name for the endpoint
+     * instead of the default name
+     * @param path host:port/resourceUri
+     */
+    static org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.VertxWebsocketEndpointBuilder vertxWebsocket(
+            String componentName,
+            String path) {
+        return org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.endpointBuilder(componentName, path);
+    }
+    /**
+     * Vert.x WebSocket (camel-vertx-websocket)
+     * Camel Vert.x WebSocket support
+     * 
+     * Category: websocket
+     * Since: 3.5
+     * Maven coordinates: org.apache.camel:camel-vertx-websocket
+     * 
+     * Syntax: <code>vertx-ws:address</code>
+     * 
+     * Path parameter: host
+     * The host that the Vert.x WebSocket consumer should bind to
+     * Default value: 0.0.0.0
+     * 
+     * Path parameter: port
+     * The port that the Vert.x WebSocket consumer should bind to
+     * Default value: 0
+     * 
+     * Path parameter: path (required)
+     * The path that the Vert.x WebSocket consumer should handle requests for
+     * Default value: /
+     * 
+     * @param path address
+     */
+    static org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.VertxWebsocketEndpointBuilder vertxWs(
+            String path) {
+        return org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.endpointBuilder("vertx-ws", path);
+    }
+    /**
+     * Vert.x WebSocket (camel-vertx-websocket)
+     * Camel Vert.x WebSocket support
+     * 
+     * Category: websocket
+     * Since: 3.5
+     * Maven coordinates: org.apache.camel:camel-vertx-websocket
+     * 
+     * Syntax: <code>vertx-ws:address</code>
+     * 
+     * Path parameter: host
+     * The host that the Vert.x WebSocket consumer should bind to
+     * Default value: 0.0.0.0
+     * 
+     * Path parameter: port
+     * The port that the Vert.x WebSocket consumer should bind to
+     * Default value: 0
+     * 
+     * Path parameter: path (required)
+     * The path that the Vert.x WebSocket consumer should handle requests for
+     * Default value: /
+     * 
+     * @param componentName to use a custom component name for the endpoint
+     * instead of the default name
+     * @param path address
+     */
+    static org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.VertxWebsocketEndpointBuilder vertxWs(
+            String componentName,
+            String path) {
+        return org.apache.camel.builder.endpoint.dsl.VertxWebsocketEndpointBuilderFactory.endpointBuilder(componentName, path);
+    }
+    /**
      * VM (camel-vm)
      * Call another endpoint in the same CamelContext asynchronously.
      * 
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/VertxWebsocketEndpointBuilderFactory.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/VertxWebsocketEndpointBuilderFactory.java
new file mode 100644
index 0000000..770d55c
--- /dev/null
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/VertxWebsocketEndpointBuilderFactory.java
@@ -0,0 +1,684 @@
+/*
+ * 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.builder.endpoint.dsl;
+
+import javax.annotation.Generated;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.builder.EndpointConsumerBuilder;
+import org.apache.camel.builder.EndpointProducerBuilder;
+import org.apache.camel.builder.endpoint.AbstractEndpointBuilder;
+import org.apache.camel.spi.ExceptionHandler;
+
+/**
+ * Camel WebSocket support with Vert.x
+ * 
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.EndpointDslMojo")
+public interface VertxWebsocketEndpointBuilderFactory {
+
+
+    /**
+     * Builder for endpoint consumers for the Vert.x WebSocket component.
+     */
+    public interface VertxWebsocketEndpointConsumerBuilder
+            extends
+                EndpointConsumerBuilder {
+        default AdvancedVertxWebsocketEndpointConsumerBuilder advanced() {
+            return (AdvancedVertxWebsocketEndpointConsumerBuilder) this;
+        }
+        /**
+         * Regex pattern to match the origin header sent by WebSocket clients.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: consumer
+         */
+        default VertxWebsocketEndpointConsumerBuilder allowedOriginPattern(
+                String allowedOriginPattern) {
+            doSetProperty("allowedOriginPattern", allowedOriginPattern);
+            return this;
+        }
+        /**
+         * Allows for bridging the consumer to the Camel routing Error Handler,
+         * which mean any exceptions occurred while the consumer is trying to
+         * pickup incoming messages, or the likes, will now be processed as a
+         * message and handled by the routing Error Handler. By default the
+         * consumer will use the org.apache.camel.spi.ExceptionHandler to deal
+         * with exceptions, that will be logged at WARN or ERROR level and
+         * ignored.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: consumer
+         */
+        default VertxWebsocketEndpointConsumerBuilder bridgeErrorHandler(
+                boolean bridgeErrorHandler) {
+            doSetProperty("bridgeErrorHandler", bridgeErrorHandler);
+            return this;
+        }
+        /**
+         * Allows for bridging the consumer to the Camel routing Error Handler,
+         * which mean any exceptions occurred while the consumer is trying to
+         * pickup incoming messages, or the likes, will now be processed as a
+         * message and handled by the routing Error Handler. By default the
+         * consumer will use the org.apache.camel.spi.ExceptionHandler to deal
+         * with exceptions, that will be logged at WARN or ERROR level and
+         * ignored.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: consumer
+         */
+        default VertxWebsocketEndpointConsumerBuilder bridgeErrorHandler(
+                String bridgeErrorHandler) {
+            doSetProperty("bridgeErrorHandler", bridgeErrorHandler);
+            return this;
+        }
+        /**
+         * To use an existing vertx router for the HTTP server.
+         * 
+         * The option is a: <code>io.vertx.ext.web.Router</code> type.
+         * 
+         * Group: consumer
+         */
+        default VertxWebsocketEndpointConsumerBuilder router(Object router) {
+            doSetProperty("router", router);
+            return this;
+        }
+        /**
+         * To use an existing vertx router for the HTTP server.
+         * 
+         * The option will be converted to a
+         * <code>io.vertx.ext.web.Router</code> type.
+         * 
+         * Group: consumer
+         */
+        default VertxWebsocketEndpointConsumerBuilder router(String router) {
+            doSetProperty("router", router);
+            return this;
+        }
+        /**
+         * Sets customized options for configuring the HTTP server hosting the
+         * WebSocket for the consumer.
+         * 
+         * The option is a: <code>io.vertx.core.http.HttpServerOptions</code>
+         * type.
+         * 
+         * Group: consumer
+         */
+        default VertxWebsocketEndpointConsumerBuilder serverOptions(
+                Object serverOptions) {
+            doSetProperty("serverOptions", serverOptions);
+            return this;
+        }
+        /**
+         * Sets customized options for configuring the HTTP server hosting the
+         * WebSocket for the consumer.
+         * 
+         * The option will be converted to a
+         * <code>io.vertx.core.http.HttpServerOptions</code> type.
+         * 
+         * Group: consumer
+         */
+        default VertxWebsocketEndpointConsumerBuilder serverOptions(
+                String serverOptions) {
+            doSetProperty("serverOptions", serverOptions);
+            return this;
+        }
+        /**
+         * To configure security using SSLContextParameters.
+         * 
+         * The option is a:
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> type.
+         * 
+         * Group: security
+         */
+        default VertxWebsocketEndpointConsumerBuilder sslContextParameters(
+                Object sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+        /**
+         * To configure security using SSLContextParameters.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> type.
+         * 
+         * Group: security
+         */
+        default VertxWebsocketEndpointConsumerBuilder sslContextParameters(
+                String sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+    }
+
+    /**
+     * Advanced builder for endpoint consumers for the Vert.x WebSocket
+     * component.
+     */
+    public interface AdvancedVertxWebsocketEndpointConsumerBuilder
+            extends
+                EndpointConsumerBuilder {
+        default VertxWebsocketEndpointConsumerBuilder basic() {
+            return (VertxWebsocketEndpointConsumerBuilder) this;
+        }
+        /**
+         * To let the consumer use a custom ExceptionHandler. Notice if the
+         * option bridgeErrorHandler is enabled then this option is not in use.
+         * By default the consumer will deal with exceptions, that will be
+         * logged at WARN or ERROR level and ignored.
+         * 
+         * The option is a: <code>org.apache.camel.spi.ExceptionHandler</code>
+         * type.
+         * 
+         * Group: consumer (advanced)
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder exceptionHandler(
+                ExceptionHandler exceptionHandler) {
+            doSetProperty("exceptionHandler", exceptionHandler);
+            return this;
+        }
+        /**
+         * To let the consumer use a custom ExceptionHandler. Notice if the
+         * option bridgeErrorHandler is enabled then this option is not in use.
+         * By default the consumer will deal with exceptions, that will be
+         * logged at WARN or ERROR level and ignored.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.spi.ExceptionHandler</code> type.
+         * 
+         * Group: consumer (advanced)
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder exceptionHandler(
+                String exceptionHandler) {
+            doSetProperty("exceptionHandler", exceptionHandler);
+            return this;
+        }
+        /**
+         * Sets the exchange pattern when the consumer creates an exchange.
+         * 
+         * The option is a: <code>org.apache.camel.ExchangePattern</code> type.
+         * 
+         * Group: consumer (advanced)
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder exchangePattern(
+                ExchangePattern exchangePattern) {
+            doSetProperty("exchangePattern", exchangePattern);
+            return this;
+        }
+        /**
+         * Sets the exchange pattern when the consumer creates an exchange.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.ExchangePattern</code> type.
+         * 
+         * Group: consumer (advanced)
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder exchangePattern(
+                String exchangePattern) {
+            doSetProperty("exchangePattern", exchangePattern);
+            return this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder basicPropertyBinding(
+                boolean basicPropertyBinding) {
+            doSetProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder basicPropertyBinding(
+                String basicPropertyBinding) {
+            doSetProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder synchronous(
+                boolean synchronous) {
+            doSetProperty("synchronous", synchronous);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointConsumerBuilder synchronous(
+                String synchronous) {
+            doSetProperty("synchronous", synchronous);
+            return this;
+        }
+    }
+
+    /**
+     * Builder for endpoint producers for the Vert.x WebSocket component.
+     */
+    public interface VertxWebsocketEndpointProducerBuilder
+            extends
+                EndpointProducerBuilder {
+        default AdvancedVertxWebsocketEndpointProducerBuilder advanced() {
+            return (AdvancedVertxWebsocketEndpointProducerBuilder) this;
+        }
+        /**
+         * Sets customized options for configuring the WebSocket client used in
+         * the producer.
+         * 
+         * The option is a: <code>io.vertx.core.http.HttpClientOptions</code>
+         * type.
+         * 
+         * Group: producer
+         */
+        default VertxWebsocketEndpointProducerBuilder clientOptions(
+                Object clientOptions) {
+            doSetProperty("clientOptions", clientOptions);
+            return this;
+        }
+        /**
+         * Sets customized options for configuring the WebSocket client used in
+         * the producer.
+         * 
+         * The option will be converted to a
+         * <code>io.vertx.core.http.HttpClientOptions</code> type.
+         * 
+         * Group: producer
+         */
+        default VertxWebsocketEndpointProducerBuilder clientOptions(
+                String clientOptions) {
+            doSetProperty("clientOptions", clientOptions);
+            return this;
+        }
+        /**
+         * 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 during
+         * starting and cause the route to fail being started. By deferring this
+         * startup to be lazy then the startup failure can be handled during
+         * routing messages via Camel's routing error handlers. Beware that when
+         * the first message is processed then creating and starting the
+         * producer may take a little time and prolong the total processing time
+         * of the processing.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: producer
+         */
+        default VertxWebsocketEndpointProducerBuilder lazyStartProducer(
+                boolean lazyStartProducer) {
+            doSetProperty("lazyStartProducer", lazyStartProducer);
+            return this;
+        }
+        /**
+         * 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 during
+         * starting and cause the route to fail being started. By deferring this
+         * startup to be lazy then the startup failure can be handled during
+         * routing messages via Camel's routing error handlers. Beware that when
+         * the first message is processed then creating and starting the
+         * producer may take a little time and prolong the total processing time
+         * of the processing.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: producer
+         */
+        default VertxWebsocketEndpointProducerBuilder lazyStartProducer(
+                String lazyStartProducer) {
+            doSetProperty("lazyStartProducer", lazyStartProducer);
+            return this;
+        }
+        /**
+         * To send to all websocket subscribers. Can be used to configure on
+         * endpoint level, instead of having to use the
+         * VertxWebsocketConstants.SEND_TO_ALL header on the message.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: producer
+         */
+        default VertxWebsocketEndpointProducerBuilder sendToAll(
+                boolean sendToAll) {
+            doSetProperty("sendToAll", sendToAll);
+            return this;
+        }
+        /**
+         * To send to all websocket subscribers. Can be used to configure on
+         * endpoint level, instead of having to use the
+         * VertxWebsocketConstants.SEND_TO_ALL header on the message.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: producer
+         */
+        default VertxWebsocketEndpointProducerBuilder sendToAll(String sendToAll) {
+            doSetProperty("sendToAll", sendToAll);
+            return this;
+        }
+        /**
+         * To configure security using SSLContextParameters.
+         * 
+         * The option is a:
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> type.
+         * 
+         * Group: security
+         */
+        default VertxWebsocketEndpointProducerBuilder sslContextParameters(
+                Object sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+        /**
+         * To configure security using SSLContextParameters.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> type.
+         * 
+         * Group: security
+         */
+        default VertxWebsocketEndpointProducerBuilder sslContextParameters(
+                String sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+    }
+
+    /**
+     * Advanced builder for endpoint producers for the Vert.x WebSocket
+     * component.
+     */
+    public interface AdvancedVertxWebsocketEndpointProducerBuilder
+            extends
+                EndpointProducerBuilder {
+        default VertxWebsocketEndpointProducerBuilder basic() {
+            return (VertxWebsocketEndpointProducerBuilder) this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointProducerBuilder basicPropertyBinding(
+                boolean basicPropertyBinding) {
+            doSetProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointProducerBuilder basicPropertyBinding(
+                String basicPropertyBinding) {
+            doSetProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointProducerBuilder synchronous(
+                boolean synchronous) {
+            doSetProperty("synchronous", synchronous);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointProducerBuilder synchronous(
+                String synchronous) {
+            doSetProperty("synchronous", synchronous);
+            return this;
+        }
+    }
+
+    /**
+     * Builder for endpoint for the Vert.x WebSocket component.
+     */
+    public interface VertxWebsocketEndpointBuilder
+            extends
+                VertxWebsocketEndpointConsumerBuilder,
+                VertxWebsocketEndpointProducerBuilder {
+        default AdvancedVertxWebsocketEndpointBuilder advanced() {
+            return (AdvancedVertxWebsocketEndpointBuilder) this;
+        }
+        /**
+         * To configure security using SSLContextParameters.
+         * 
+         * The option is a:
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> type.
+         * 
+         * Group: security
+         */
+        default VertxWebsocketEndpointBuilder sslContextParameters(
+                Object sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+        /**
+         * To configure security using SSLContextParameters.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> type.
+         * 
+         * Group: security
+         */
+        default VertxWebsocketEndpointBuilder sslContextParameters(
+                String sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+    }
+
+    /**
+     * Advanced builder for endpoint for the Vert.x WebSocket component.
+     */
+    public interface AdvancedVertxWebsocketEndpointBuilder
+            extends
+                AdvancedVertxWebsocketEndpointConsumerBuilder,
+                AdvancedVertxWebsocketEndpointProducerBuilder {
+        default VertxWebsocketEndpointBuilder basic() {
+            return (VertxWebsocketEndpointBuilder) this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointBuilder basicPropertyBinding(
+                boolean basicPropertyBinding) {
+            doSetProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointBuilder basicPropertyBinding(
+                String basicPropertyBinding) {
+            doSetProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointBuilder synchronous(
+                boolean synchronous) {
+            doSetProperty("synchronous", synchronous);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: advanced
+         */
+        default AdvancedVertxWebsocketEndpointBuilder synchronous(
+                String synchronous) {
+            doSetProperty("synchronous", synchronous);
+            return this;
+        }
+    }
+
+    public interface VertxWebsocketBuilders {
+        /**
+         * Vert.x WebSocket (camel-vertx-websocket)
+         * Camel WebSocket support with Vert.x
+         * 
+         * Category: websocket
+         * Since: 3.5
+         * Maven coordinates: org.apache.camel:camel-vertx-websocket
+         * 
+         * Syntax: <code>vertx-websocket:host:port/resourceUri</code>
+         * 
+         * Path parameter: host
+         * The host that the consumer should bind to or the host of the remote
+         * websocket destination that the producer should connect to
+         * Default value: 0.0.0.0
+         * 
+         * Path parameter: port
+         * The port that the consumer should bind to or port of the remote
+         * websocket destination that the producer should connect to
+         * Default value: 0
+         * 
+         * Path parameter: path (required)
+         * The path that the consumer should bind to or path of the remote
+         * websocket destination that the producer should connect to
+         * Default value: /
+         * 
+         * @param path host:port/resourceUri
+         */
+        default VertxWebsocketEndpointBuilder vertxWebsocket(String path) {
+            return VertxWebsocketEndpointBuilderFactory.endpointBuilder("vertx-websocket", path);
+        }
+        /**
+         * Vert.x WebSocket (camel-vertx-websocket)
+         * Camel WebSocket support with Vert.x
+         * 
+         * Category: websocket
+         * Since: 3.5
+         * Maven coordinates: org.apache.camel:camel-vertx-websocket
+         * 
+         * Syntax: <code>vertx-websocket:host:port/resourceUri</code>
+         * 
+         * Path parameter: host
+         * The host that the consumer should bind to or the host of the remote
+         * websocket destination that the producer should connect to
+         * Default value: 0.0.0.0
+         * 
+         * Path parameter: port
+         * The port that the consumer should bind to or port of the remote
+         * websocket destination that the producer should connect to
+         * Default value: 0
+         * 
+         * Path parameter: path (required)
+         * The path that the consumer should bind to or path of the remote
+         * websocket destination that the producer should connect to
+         * Default value: /
+         * 
+         * @param componentName to use a custom component name for the endpoint
+         * instead of the default name
+         * @param path host:port/resourceUri
+         */
+        default VertxWebsocketEndpointBuilder vertxWebsocket(
+                String componentName,
+                String path) {
+            return VertxWebsocketEndpointBuilderFactory.endpointBuilder(componentName, path);
+        }
+    }
+    static VertxWebsocketEndpointBuilder endpointBuilder(
+            String componentName,
+            String path) {
+        class VertxWebsocketEndpointBuilderImpl extends AbstractEndpointBuilder implements VertxWebsocketEndpointBuilder, AdvancedVertxWebsocketEndpointBuilder {
+            public VertxWebsocketEndpointBuilderImpl(String path) {
+                super(componentName, path);
+            }
+        }
+        return new VertxWebsocketEndpointBuilderImpl(path);
+    }
+}
\ No newline at end of file
diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc
index 2a663f5..62db468 100644
--- a/docs/components/modules/ROOT/nav.adoc
+++ b/docs/components/modules/ROOT/nav.adoc
@@ -328,6 +328,7 @@
 ** xref:validator-component.adoc[Validator]
 ** xref:velocity-component.adoc[Velocity]
 ** xref:vertx-component.adoc[Vert.x]
+** xref:vertx-websocket-component.adoc[Vert.x WebSocket]
 ** xref:vm-component.adoc[VM]
 ** xref:weather-component.adoc[Weather]
 ** xref:web3j-component.adoc[Web3j Ethereum Blockchain]
diff --git a/docs/components/modules/ROOT/pages/vertx-websocket-component.adoc b/docs/components/modules/ROOT/pages/vertx-websocket-component.adoc
new file mode 100644
index 0000000..bbbe4b6
--- /dev/null
+++ b/docs/components/modules/ROOT/pages/vertx-websocket-component.adoc
@@ -0,0 +1,133 @@
+[[vertx-websocket-component]]
+= Vert.x WebSocket Component
+//THIS FILE IS COPIED: EDIT THE SOURCE FILE:
+:page-source: components/camel-vertx-websocket/src/main/docs/vertx-websocket-component.adoc
+:docTitle: Vert.x WebSocket
+:artifactId: camel-vertx-websocket
+:description: Camel WebSocket support with Vert.x
+:since: 3.5
+:supportLevel: Preview
+:component-header: Both producer and consumer are supported
+
+*Since Camel {since}*
+
+*{component-header}*
+
+The Vert.x WebSocket component provides WebSocket capabilities as a WebSocket server, or as a client to connect to existing an WebSocket.
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-vertx-websocket</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+== URI format
+
+[source,java]
+---------------------------
+vertx-websocket://hostname[:port][/resourceUri][?options]
+---------------------------
+
+== Options
+
+
+
+// component options: START
+The Vert.x WebSocket component supports 6 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *lazyStartProducer* (producer) | 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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *vertx* (advanced) | To use an existing vertx instead of creating a new instance |  | Vertx
+| *vertxOptions* (advanced) | To provide a custom set of vertx options for configuring vertx |  | VertxOptions
+| *useGlobalSslContextParameters* (security) | Enable usage of global SSL context parameters. | false | boolean
+|===
+// component options: END
+
+
+
+
+// endpoint options: START
+The Vert.x WebSocket endpoint is configured using URI syntax:
+
+----
+vertx-websocket:host:port/resourceUri
+----
+
+with the following path and query parameters:
+
+=== Path Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *host* | The host that the consumer should bind to or the host of the remote websocket destination that the producer should connect to | 0.0.0.0 | String
+| *port* | The port that the consumer should bind to or port of the remote websocket destination that the producer should connect to | 0 | int
+| *path* | *Required* The path that the consumer should bind to or path of the remote websocket destination that the producer should connect to | / | String
+|===
+
+
+=== Query Parameters (12 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *allowedOriginPattern* (consumer) | Regex pattern to match the origin header sent by WebSocket clients |  | String
+| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *router* (consumer) | To use an existing vertx router for the HTTP server |  | Router
+| *serverOptions* (consumer) | Sets customized options for configuring the HTTP server hosting the WebSocket for the consumer |  | HttpServerOptions
+| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. The value can be one of: InOnly, InOut, InOptionalOut |  | ExchangePattern
+| *clientOptions* (producer) | Sets customized options for configuring the WebSocket client used in the producer |  | HttpClientOptions
+| *lazyStartProducer* (producer) | 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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *sendToAll* (producer) | To send to all websocket subscribers. Can be used to configure on endpoint level, instead of having to use the VertxWebsocketConstants.SEND_TO_ALL header on the message. | false | boolean
+| *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+| *sslContextParameters* (security) | To configure security using SSLContextParameters |  | SSLContextParameters
+|===
+// endpoint options: END
+
+
+=== Message Headers
+
+The WebSocket component uses 2 headers to indicate to either send
+messages back to a single/current client, or to all clients.
+
+[width="100%",cols="10%,90%",options="header",]
+|=======================================================================
+
+|`VertxWebsocketConstants.SEND_TO_ALL` |Sends the message to all clients which are currently connected. You can
+use the `sendToAll` option on the endpoint instead of using this header.
+
+|`VertxWebsocketConstants.CONNECTION_KEY` |Sends the message to the client with the given connection key. You can
+use a comma separated list of keys to send a message to multiple clients
+|=======================================================================
+
+=== Usage
+The following example shows how to expose a WebSocket on http://localhost:8080/echo and returns an 'echo' response back to the same channel:
+
+[source,java]
+----
+from("vertx-websocket:localhost:8080/echo")
+    .transform().simple("Echo: ${body}")
+    .to("vertx-websocket:localhost:8080/echo");
+----
+
+==== SSL
+
+By default the `ws://` protocol is used, but secure connections with `wss://` are supported by configuring the consumer or producer
+via the `sslContextParameters` URI parameter and the xref:manual::camel-configuration-utilities.adoc[Camel JSSE Configuration Utility]
diff --git a/parent/pom.xml b/parent/pom.xml
index 9b97421..2332849 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -2424,6 +2424,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-vertx-websocket</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-vm</artifactId>
         <version>${project.version}</version>
       </dependency>