You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/12/18 19:08:11 UTC

[camel] branch master updated: CAMEL-13903: camel-telegram - use a stock HTTP client instead of the JAX-RS client (#3414)

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

davsclaus 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 a9b52e9  CAMEL-13903: camel-telegram - use a stock HTTP client instead of the JAX-RS client (#3414)
a9b52e9 is described below

commit a9b52e9ac54737c2cb57d12f40cdb5fde7f301d8
Author: Peter Palaga <pp...@redhat.com>
AuthorDate: Wed Dec 18 20:07:58 2019 +0100

    CAMEL-13903: camel-telegram - use a stock HTTP client instead of the JAX-RS client (#3414)
---
 components/camel-telegram/pom.xml                  |  20 +-
 .../src/main/docs/telegram-component.adoc          |  15 +-
 .../component/telegram/TelegramComponent.java      |  49 ++-
 .../component/telegram/TelegramConfiguration.java  |  14 +
 .../camel/component/telegram/TelegramConsumer.java |   4 +-
 .../camel/component/telegram/TelegramEndpoint.java | 105 ++++-
 .../camel/component/telegram/TelegramProducer.java |  18 +-
 .../camel/component/telegram/TelegramService.java  |  12 +-
 .../telegram/TelegramServiceProvider.java          |  91 ----
 .../model/EditMessageLiveLocationMessage.java      |   5 +
 .../component/telegram/model/IncomingMessage.java  |   2 +
 .../telegram/model/InlineKeyboardButton.java       |  15 +-
 .../telegram/model/OutgoingAudioMessage.java       |   4 +
 .../telegram/model/OutgoingDocumentMessage.java    |   2 +
 .../component/telegram/model/OutgoingMessage.java  |   2 +
 .../telegram/model/OutgoingPhotoMessage.java       |   5 +
 .../telegram/model/OutgoingTextMessage.java        |  34 +-
 .../telegram/model/OutgoingVideoMessage.java       |   2 +
 .../telegram/model/ReplyKeyboardMarkup.java        |  38 +-
 .../telegram/model/SendLocationMessage.java        |   5 +
 .../component/telegram/model/SendVenueMessage.java |   5 +
 .../model/StopMessageLiveLocationMessage.java      |   2 +
 .../UnixTimestampSerializer.java}                  |  27 +-
 .../component/telegram/service/RestBotAPI.java     | 119 ------
 .../service/TelegramServiceRestBotAPIAdapter.java  | 461 +++++++++++++++------
 .../component/telegram/TelegramChatBotTest.java    |  97 +++--
 .../telegram/TelegramConsumerChannelPostTest.java  |  61 +--
 .../TelegramConsumerEmptyResponseTest.java         |  50 ++-
 .../TelegramConsumerFallbackConversionTest.java    |  54 ++-
 .../telegram/TelegramConsumerMappingTest.java      |  46 +-
 .../TelegramConsumerMediaDocumentTest.java         |  51 ++-
 .../telegram/TelegramConsumerMediaPhotoTest.java   |  50 ++-
 .../telegram/TelegramConsumerMediaVideoTest.java   |  50 ++-
 .../telegram/TelegramConsumerMultipleTest.java     |  61 +--
 .../telegram/TelegramConsumerServiceErrorTest.java |  68 +--
 .../telegram/TelegramConsumerSingleTest.java       |  62 +--
 .../TelegramProducerChatIdResolutionTest.java      |  64 +--
 .../telegram/TelegramProducerLocationTest.java     | 113 ++---
 .../telegram/TelegramProducerMediaTest.java        | 242 ++++++-----
 .../telegram/TelegramWebhookRegistrationTest.java  | 131 ++++--
 .../telegram/integration/TelegramServiceTest.java  | 120 ++----
 .../component/telegram/util/TelegramApiConfig.java |  61 +++
 .../telegram/util/TelegramMockRoutes.java          | 125 ++++++
 .../telegram/util/TelegramTestSupport.java         |  99 ++---
 .../component/telegram/util/TelegramTestUtil.java  |  42 +-
 .../messages/edit-message-live-location.json       |  24 ++
 .../src/test/resources/messages/send-audio.json    |  25 ++
 .../src/test/resources/messages/send-document.json |  24 ++
 .../src/test/resources/messages/send-location.json |  23 +
 .../src/test/resources/messages/send-message.json  |  20 +
 .../src/test/resources/messages/send-photo.json    |  27 ++
 .../src/test/resources/messages/send-venue.json    |  31 ++
 .../src/test/resources/messages/send-video.json    |  33 ++
 .../messages/stop-message-live-location.json       |  24 ++
 .../dsl/TelegramEndpointBuilderFactory.java        | 194 +++++++++
 .../modules/ROOT/pages/telegram-component.adoc     |  15 +-
 .../example/telegram/usage/GetUpdatesUsage.java    |   9 +-
 .../karaf/features/src/main/resources/features.xml |  21 +-
 pom.xml                                            |   2 +
 59 files changed, 2060 insertions(+), 1115 deletions(-)

diff --git a/components/camel-telegram/pom.xml b/components/camel-telegram/pom.xml
index f897b26..73a03b9 100644
--- a/components/camel-telegram/pom.xml
+++ b/components/camel-telegram/pom.xml
@@ -49,11 +49,11 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-rs-client</artifactId>
+            <groupId>org.asynchttpclient</groupId>
+            <artifactId>async-http-client</artifactId>
+            <version>${ahc-version}</version>
         </dependency>
 
-
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
@@ -64,10 +64,9 @@
             <artifactId>jackson-annotations</artifactId>
             <version>${jackson2-version}</version>
         </dependency>
-
         <dependency>
-            <groupId>com.fasterxml.jackson.jaxrs</groupId>
-            <artifactId>jackson-jaxrs-json-provider</artifactId>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
             <version>${jackson2-version}</version>
         </dependency>
 
@@ -83,13 +82,8 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-junit-jupiter</artifactId>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/components/camel-telegram/src/main/docs/telegram-component.adoc b/components/camel-telegram/src/main/docs/telegram-component.adoc
index 13bc7dc..b855e31 100644
--- a/components/camel-telegram/src/main/docs/telegram-component.adoc
+++ b/components/camel-telegram/src/main/docs/telegram-component.adoc
@@ -48,7 +48,7 @@ You can append query options to the URI in the following format,
 == Options
 
 // component options: START
-The Telegram component supports 4 options, which are listed below.
+The Telegram component supports 7 options, which are listed below.
 
 
 
@@ -56,6 +56,9 @@ The Telegram component supports 4 options, which are listed below.
 |===
 | Name | Description | Default | Type
 | *authorizationToken* (security) | The default Telegram authorization token to be used when the information is not provided in the endpoints. |  | String
+| *client* (advanced) | To use a custom AsyncHttpClient |  | AsyncHttpClient
+| *clientConfig* (advanced) | To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance. |  | AsyncHttpClientConfig
+| *baseUri* (common) | Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API. |  | String
 | *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | 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 [...]
 | *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
@@ -83,7 +86,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (28 parameters):
+=== Query Parameters (31 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -98,7 +101,10 @@ with the following path and query parameters:
 | *pollStrategy* (consumer) | A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel. |  | PollingConsumerPollStrategy
 | *chatId* (producer) | The identifier of the chat that will receive the produced messages. Chat ids can be first obtained from incoming messages (eg. when a telegram user starts a conversation with a bot, its client sends automatically a '/start' message containing the chat id). It is an optional parameter, as the chat id can be set dynamically for each outgoing message (using body or headers). |  | String
 | *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 [...]
+| *baseUri* (advanced) | Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API. |  | String
 | *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *bufferSize* (advanced) | The initial in-memory buffer size used when transferring data between Camel and AHC Client. | 4096 | int
+| *clientConfig* (advanced) | To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance. |  | AsyncHttpClientConfig
 | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
 | *backoffErrorThreshold* (scheduler) | The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffIdleThreshold* (scheduler) | The number of subsequent idle polls that should happen before the backoffMultipler should kick-in. |  | int
@@ -135,7 +141,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 
 
-The component supports 5 options, which are listed below.
+The component supports 8 options, which are listed below.
 
 
 
@@ -143,8 +149,11 @@ The component supports 5 options, which are listed below.
 |===
 | Name | Description | Default | Type
 | *camel.component.telegram.authorization-token* | The default Telegram authorization token to be used when the information is not provided in the endpoints. |  | String
+| *camel.component.telegram.base-uri* | Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API. |  | String
 | *camel.component.telegram.basic-property-binding* | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | Boolean
 | *camel.component.telegram.bridge-error-handler* | 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
+| *camel.component.telegram.client* | To use a custom AsyncHttpClient. The option is a org.asynchttpclient.AsyncHttpClient type. |  | String
+| *camel.component.telegram.client-config* | To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance. The option is a org.asynchttpclient.AsyncHttpClientConfig type. |  | String
 | *camel.component.telegram.enabled* | Whether to enable auto configuration of the telegram component. This is enabled by default. |  | Boolean
 | *camel.component.telegram.lazy-start-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 t [...]
 |===
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramComponent.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramComponent.java
index 97b72eb8..2980cd7 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramComponent.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramComponent.java
@@ -22,13 +22,24 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.annotations.Component;
 import org.apache.camel.support.DefaultComponent;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.AsyncHttpClientConfig;
 
 @Component("telegram")
 public class TelegramComponent extends DefaultComponent {
+    public static final String BOT_API_DEFAULT_URL = "https://api.telegram.org";
 
     @Metadata(label = "security", secret = true)
     private String authorizationToken;
 
+    @Metadata(label = "advanced")
+    private AsyncHttpClient client;
+    @Metadata(label = "advanced")
+    private AsyncHttpClientConfig clientConfig;
+
+    @Metadata(label = "advanced", defaultValue = BOT_API_DEFAULT_URL, description = "Can be used to set an alternative base URI, e.g. when you want to test the component against a mock Telegram API")
+    private String baseUri = BOT_API_DEFAULT_URL;
+
     public TelegramComponent() {
     }
 
@@ -45,8 +56,11 @@ public class TelegramComponent extends DefaultComponent {
         if (!remaining.equals(TelegramConfiguration.ENDPOINT_TYPE_BOTS)) {
             throw new IllegalArgumentException("Unsupported endpoint type for uri " + uri + ", remaining " + remaining);
         }
+        if (configuration.getBaseUri() == null) {
+            configuration.setBaseUri(baseUri);
+        }
 
-        TelegramEndpoint endpoint = new TelegramEndpoint(uri, this, configuration);
+        TelegramEndpoint endpoint = new TelegramEndpoint(uri, this, configuration, client, clientConfig);
         configuration.setAuthorizationToken(authorizationToken);
         setProperties(endpoint, parameters);
 
@@ -68,4 +82,37 @@ public class TelegramComponent extends DefaultComponent {
         this.authorizationToken = authorizationToken;
     }
 
+    public AsyncHttpClient getClient() {
+        return client;
+    }
+
+    /**
+     * To use a custom {@link AsyncHttpClient}
+     */
+    public void setClient(AsyncHttpClient client) {
+        this.client = client;
+    }
+
+    public AsyncHttpClientConfig getClientConfig() {
+        return clientConfig;
+    }
+
+    /**
+     * To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance.
+     */
+    public void setClientConfig(AsyncHttpClientConfig clientConfig) {
+        this.clientConfig = clientConfig;
+    }
+
+    public String getBaseUri() {
+        return baseUri;
+    }
+
+    /**
+     * Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API.
+     */
+    public void setBaseUri(String telegramBaseUri) {
+        this.baseUri = telegramBaseUri;
+    }
+
 }
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConfiguration.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConfiguration.java
index 4e07e64..1cc6695 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConfiguration.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConfiguration.java
@@ -56,6 +56,9 @@ public class TelegramConfiguration {
             optionalPrefix = "consumer.", defaultValue = "100", label = "consumer")
     private Integer limit = 100;
 
+    @UriParam(label = "advanced", description = "Can be used to set an alternative base URI, e.g. when you want to test the component against a mock Telegram API")
+    private String baseUri;
+
     public TelegramConfiguration() {
     }
 
@@ -115,6 +118,17 @@ public class TelegramConfiguration {
         this.limit = limit;
     }
 
+    public String getBaseUri() {
+        return baseUri;
+    }
+
+    /**
+     * Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API.
+     */
+    public void setBaseUri(String telegramBaseUri) {
+        this.baseUri = telegramBaseUri;
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("TelegramConfiguration{");
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConsumer.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConsumer.java
index e29d4fa..50b53b7 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConsumer.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramConsumer.java
@@ -48,11 +48,11 @@ public class TelegramConsumer extends ScheduledPollConsumer {
 
         TelegramConfiguration config = endpoint.getConfiguration();
 
-        TelegramService service = TelegramServiceProvider.get().getService();
+        TelegramService service = endpoint.getTelegramService();
 
         log.debug("Polling Telegram service to get updates");
 
-        UpdateResult updateResult = service.getUpdates(config.getAuthorizationToken(), offset, config.getLimit(), config.getTimeout());
+        UpdateResult updateResult = service.getUpdates(offset, config.getLimit(), config.getTimeout());
         if (updateResult.getUpdates() == null) {
             // to simplify processing
             updateResult.setUpdates(Collections.emptyList());
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java
index 45d7815..59bfe5d 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramEndpoint.java
@@ -26,12 +26,18 @@ import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.telegram.model.Update;
+import org.apache.camel.component.telegram.service.TelegramServiceRestBotAPIAdapter;
 import org.apache.camel.component.webhook.WebhookCapableEndpoint;
 import org.apache.camel.component.webhook.WebhookConfiguration;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.ScheduledPollEndpoint;
 import org.apache.camel.util.ObjectHelper;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.AsyncHttpClientConfig;
+import org.asynchttpclient.DefaultAsyncHttpClient;
+import org.asynchttpclient.DefaultAsyncHttpClientConfig;
+import org.asynchttpclient.proxy.ProxyServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,17 +52,63 @@ public class TelegramEndpoint extends ScheduledPollEndpoint implements WebhookCa
 
     @UriParam
     private TelegramConfiguration configuration;
+    @UriParam(label = "advanced")
+    private AsyncHttpClientConfig clientConfig;
+    @UriParam(label = "advanced", defaultValue = "" + (4 * 1024))
+    private int bufferSize = 4 * 1024;
 
     private WebhookConfiguration webhookConfiguration;
 
-    public TelegramEndpoint(String endpointUri, Component component, TelegramConfiguration configuration) {
+    private AsyncHttpClient client;
+    private TelegramService telegramService;
+
+    public TelegramEndpoint(
+            String endpointUri,
+            Component component,
+            TelegramConfiguration configuration,
+            AsyncHttpClient client,
+            AsyncHttpClientConfig clientConfig) {
         super(endpointUri, component);
         this.configuration = configuration;
-        // setup the proxy setting here
-        if (ObjectHelper.isNotEmpty(configuration.getProxyHost()) && ObjectHelper.isNotEmpty(configuration.getProxyPort())) {
-            LOG.debug("Setup http proxy host:{} port:{} for TelegramService", configuration.getProxyHost(), configuration.getProxyPort());
-            TelegramServiceProvider.get().getService().setHttpProxy(configuration.getProxyHost(), configuration.getProxyPort());
+        this.client = client;
+        this.clientConfig = clientConfig;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        if (client == null) {
+            DefaultAsyncHttpClientConfig.Builder builder = clientConfig != null
+                    ? new DefaultAsyncHttpClientConfig.Builder(clientConfig)
+                    : new DefaultAsyncHttpClientConfig.Builder();
+
+            if (configuration != null && ObjectHelper.isNotEmpty(configuration.getProxyHost())
+                    && ObjectHelper.isNotEmpty(configuration.getProxyPort())) {
+                LOG.debug("Setup http proxy host:{} port:{} for TelegramService", configuration.getProxyHost(),
+                        configuration.getProxyPort());
+                builder.setProxyServer(
+                        new ProxyServer.Builder(configuration.getProxyHost(), configuration.getProxyPort()).build());
+            }
+            final AsyncHttpClientConfig config = builder.build();
+            client = new DefaultAsyncHttpClient(config);
+        }
+        if (telegramService == null) {
+            telegramService = new TelegramServiceRestBotAPIAdapter(
+                    client,
+                    bufferSize,
+                    configuration.getBaseUri(),
+                    configuration.getAuthorizationToken());
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+        // ensure client is closed when stopping
+        if (client != null && !client.isClosed()) {
+            client.close();
         }
+        client = null;
     }
 
     @Override
@@ -84,16 +136,14 @@ public class TelegramEndpoint extends ScheduledPollEndpoint implements WebhookCa
 
     @Override
     public void registerWebhook() throws Exception {
-        TelegramService service = TelegramServiceProvider.get().getService();
-        if (!service.setWebhook(configuration.getAuthorizationToken(), webhookConfiguration.computeFullExternalUrl())) {
+        if (!telegramService.setWebhook(webhookConfiguration.computeFullExternalUrl())) {
             throw new RuntimeCamelException("The Telegram API refused to register a webhook");
         }
     }
 
     @Override
     public void unregisterWebhook() throws Exception {
-        TelegramService service = TelegramServiceProvider.get().getService();
-        if (!service.removeWebhook(configuration.getAuthorizationToken())) {
+        if (!telegramService.removeWebhook()) {
             throw new RuntimeCamelException("The Telegram API refused to unregister the webhook");
         }
     }
@@ -120,4 +170,41 @@ public class TelegramEndpoint extends ScheduledPollEndpoint implements WebhookCa
         this.configuration = configuration;
     }
 
+    public TelegramService getTelegramService() {
+        return telegramService;
+    }
+
+    public AsyncHttpClient getClient() {
+        return client;
+    }
+
+    /**
+     * To use a custom {@link AsyncHttpClient}
+     */
+    public void setClient(AsyncHttpClient client) {
+        this.client = client;
+    }
+
+    public AsyncHttpClientConfig getClientConfig() {
+        return clientConfig;
+    }
+
+    /**
+     * To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance.
+     */
+    public void setClientConfig(AsyncHttpClientConfig clientConfig) {
+        this.clientConfig = clientConfig;
+    }
+
+    public int getBufferSize() {
+        return bufferSize;
+    }
+
+    /**
+     * The initial in-memory buffer size used when transferring data between Camel and AHC Client.
+     */
+    public void setBufferSize(int bufferSize) {
+        this.bufferSize = bufferSize;
+    }
+
 }
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramProducer.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramProducer.java
index 2b75524..58a4fb5 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramProducer.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramProducer.java
@@ -16,14 +16,15 @@
  */
 package org.apache.camel.component.telegram;
 
+import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.component.telegram.model.OutgoingMessage;
-import org.apache.camel.support.DefaultProducer;
+import org.apache.camel.support.DefaultAsyncProducer;
 
 /**
  * A producer that sends messages to Telegram through the bot API.
  */
-public class TelegramProducer extends DefaultProducer {
+public class TelegramProducer extends DefaultAsyncProducer {
 
     private TelegramEndpoint endpoint;
 
@@ -33,12 +34,13 @@ public class TelegramProducer extends DefaultProducer {
     }
 
     @Override
-    public void process(Exchange exchange) throws Exception {
+    public boolean process(Exchange exchange, AsyncCallback callback) {
 
         if (exchange.getIn().getBody() == null) {
             // fail fast
             log.debug("Received exchange with empty body, skipping");
-            return;
+            callback.done(true);
+            return true;
         }
 
         TelegramConfiguration config = endpoint.getConfiguration();
@@ -57,15 +59,13 @@ public class TelegramProducer extends DefaultProducer {
             message.setChatId(chatId);
         }
 
-        TelegramService service = TelegramServiceProvider.get().getService();
+        final TelegramService service = endpoint.getTelegramService();
 
         log.debug("Message being sent is: {}", message);
         log.debug("Headers of message being sent are: {}", exchange.getIn().getHeaders());
 
-        Object receivedMessage = service.sendMessage(config.getAuthorizationToken(), message);
-        log.debug("Message being received is: {}", receivedMessage);
-
-        exchange.getOut().setBody(receivedMessage);
+        service.sendMessage(exchange, callback, message);
+        return false;
     }
 
     private String resolveChatId(TelegramConfiguration config, OutgoingMessage message, Exchange exchange) {
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramService.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramService.java
index d90a811..0a6d59a 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramService.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramService.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.telegram;
 
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
 import org.apache.camel.component.telegram.model.OutgoingMessage;
 import org.apache.camel.component.telegram.model.UpdateResult;
 
@@ -24,14 +26,12 @@ import org.apache.camel.component.telegram.model.UpdateResult;
  */
 public interface TelegramService {
 
-    void setHttpProxy(String host, Integer port);
+    UpdateResult getUpdates(Long offset, Integer limit, Integer timeoutSeconds);
 
-    UpdateResult getUpdates(String authorizationToken, Long offset, Integer limit, Integer timeoutSeconds);
+    void sendMessage(Exchange exchange, AsyncCallback callback, OutgoingMessage message);
 
-    Object sendMessage(String authorizationToken, OutgoingMessage message);
+    boolean setWebhook(String url);
 
-    boolean setWebhook(String authorizationToken, String url);
-
-    boolean removeWebhook(String authorizationToken);
+    boolean removeWebhook();
 
 }
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramServiceProvider.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramServiceProvider.java
deleted file mode 100644
index b437da6..0000000
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramServiceProvider.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.telegram;
-
-import org.apache.camel.component.telegram.service.TelegramServiceRestBotAPIAdapter;
-
-/**
- * Provides access to an instance of the Telegram service. It allows changing the default implementation of the service for testing purposes.
- * Currently the Telegram API does not allow a Bot sending messages to other BOTs (https://core.telegram.org/bots/faq#why-doesn-39t-my-bot-see-messages-from-other-bots),
- * so the service needs to be mocked for end-to-end testing.
- *
- * The Rest client used as default implementation is thread safe, considering the current usage of the APIs. It is treated as a singleton.
- */
-public final class TelegramServiceProvider {
-
-    private static final TelegramServiceProvider INSTANCE = new TelegramServiceProvider();
-
-    /**
-     * The default service.
-     */
-    private final TelegramService service;
-
-    /**
-     * An alternative service used for testing purposes.
-     */
-    private TelegramService telegramService;
-
-    private TelegramServiceProvider() {
-        // Using the Rest Bot API by default
-        this.service = new TelegramServiceRestBotAPIAdapter();
-    }
-
-    /**
-     * Returns the singleton provider.
-     */
-    public static TelegramServiceProvider get() {
-        return INSTANCE;
-    }
-
-    /**
-     * Provides the current service. It can be the default one or an alternative one.
-     * @return the active {@code TelegramService}
-     */
-    public TelegramService getService() {
-        if (telegramService != null) {
-            // no need for synchronization, it's only for testing purposes
-            return telegramService;
-        }
-        return service;
-    }
-
-    /**
-     * Get the current alternative service, if any.
-     *
-     * @return the current alternative service
-     */
-    public TelegramService getAlternativeService() {
-        return telegramService;
-    }
-
-    /**
-     * Allows setting an alternative service.
-     *
-     * @param service the alternative service
-     */
-    public void setAlternativeService(TelegramService service) {
-        this.telegramService = service;
-    }
-
-    /**
-     * Restores the provider to its original state.
-     */
-    public void restoreDefaultService() {
-        this.telegramService = null;
-    }
-
-}
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/EditMessageLiveLocationMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/EditMessageLiveLocationMessage.java
index 9aa9183..8e55c8c 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/EditMessageLiveLocationMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/EditMessageLiveLocationMessage.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class EditMessageLiveLocationMessage extends OutgoingMessage {
 
     @JsonProperty("latitude")
@@ -35,6 +37,9 @@ public class EditMessageLiveLocationMessage extends OutgoingMessage {
     @JsonProperty("reply_markup")
     private ReplyKeyboardMarkup replyKeyboardMarkup;
 
+    public EditMessageLiveLocationMessage() {
+    }
+
     public EditMessageLiveLocationMessage(double latitude, double longitude) {
         this.setLatitude(latitude);
         this.setLongitude(longitude);
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/IncomingMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/IncomingMessage.java
index cf463b2..89a7934 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/IncomingMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/IncomingMessage.java
@@ -23,6 +23,7 @@ import java.util.List;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
 /**
  * A message that is exchanged with the Telegram network.
@@ -36,6 +37,7 @@ public class IncomingMessage implements Serializable {
     private Long messageId;
 
     @JsonDeserialize(using = UnixTimestampDeserializer.class)
+    @JsonSerialize(using = UnixTimestampSerializer.class)
     private Instant date;
 
     private User from;
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/InlineKeyboardButton.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/InlineKeyboardButton.java
index cc1b361..0378d60 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/InlineKeyboardButton.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/InlineKeyboardButton.java
@@ -16,36 +16,39 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class InlineKeyboardButton {
 
     private String text;
 
     public InlineKeyboardButton() {
-        
+
     }
-    
+
     public InlineKeyboardButton(String text) {
 
         this.text = text;
     }
 
     public String getText() {
-        
+
         return text;
     }
 
     public void setText(String text) {
-        
+
         this.text = text;
     }
-    
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("InlineKeyboardButton{");
         sb.append("text='").append(text);
         sb.append('}');
         return sb.toString();
-    }        
+    }
 
     public static Builder builder() {
 
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingAudioMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingAudioMessage.java
index 59f8969..9779e90 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingAudioMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingAudioMessage.java
@@ -16,11 +16,15 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import java.util.Arrays;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 /**
  * An outgoing audio message.
  */
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class OutgoingAudioMessage extends OutgoingMessage {
 
     private static final long serialVersionUID = 2716544815581270395L;
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingDocumentMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingDocumentMessage.java
index 5ca1db5..50ba653 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingDocumentMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingDocumentMessage.java
@@ -16,9 +16,11 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 /**
  * An outgoing document message.
  */
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class OutgoingDocumentMessage extends OutgoingMessage {
 
     private byte[] document;
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingMessage.java
index 5005dc0..094218c 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingMessage.java
@@ -18,11 +18,13 @@ package org.apache.camel.component.telegram.model;
 
 import java.io.Serializable;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 /**
  * The superclass of all outgoing messages.
  */
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public abstract class OutgoingMessage implements Serializable {
 
     private static final long serialVersionUID = -5958829164103569292L;
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingPhotoMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingPhotoMessage.java
index 65cd0bb..2d6656d 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingPhotoMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingPhotoMessage.java
@@ -16,9 +16,14 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import java.util.Arrays;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
 /**
  * An outgoing photo message.
  */
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class OutgoingPhotoMessage extends OutgoingMessage {
 
     private static final long serialVersionUID = -6730785675407947090L;
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingTextMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingTextMessage.java
index 7a9abf9..49bc917 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingTextMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingTextMessage.java
@@ -16,11 +16,13 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 /**
  * An outgoing text message.
  */
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class OutgoingTextMessage extends OutgoingMessage {
 
     private static final long serialVersionUID = -8684079202025229263L;
@@ -32,16 +34,17 @@ public class OutgoingTextMessage extends OutgoingMessage {
 
     @JsonProperty("disable_web_page_preview")
     private Boolean disableWebPagePreview;
-    
+
     @JsonProperty("reply_markup")
     private ReplyKeyboardMarkup replyKeyboardMarkup;
 
     public OutgoingTextMessage() {
-        
+
     }
 
-    public OutgoingTextMessage(String text, String parseMode, Boolean disableWebPagePreview, ReplyKeyboardMarkup replyKeyboardMarkup) {
-        
+    public OutgoingTextMessage(String text, String parseMode, Boolean disableWebPagePreview,
+            ReplyKeyboardMarkup replyKeyboardMarkup) {
+
         this.text = text;
         this.parseMode = parseMode;
         this.disableWebPagePreview = disableWebPagePreview;
@@ -97,41 +100,28 @@ public class OutgoingTextMessage extends OutgoingMessage {
             this.text = text;
             return this;
         }
-        
+
         public Builder parseMode(String parseMode) {
 
             this.parseMode = parseMode;
             return this;
         }
-        
+
         public Builder disableWebPagePreview(Boolean disableWebPagePreview) {
 
             this.disableWebPagePreview = disableWebPagePreview;
             return this;
         }
-        
+
         public Builder replyKeyboardMarkup(ReplyKeyboardMarkup replyKeyboardMarkup) {
 
             this.replyKeyboardMarkup = replyKeyboardMarkup;
             return this;
-        }        
+        }
 
         public OutgoingTextMessage build() {
-            
+
             return new OutgoingTextMessage(text, parseMode, disableWebPagePreview, replyKeyboardMarkup);
         }
-    }    
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder("OutgoingTextMessage{");
-        sb.append("text='").append(text).append('\'');
-        sb.append(", parseMode='").append(parseMode).append('\'');
-        sb.append(", disableWebPagePreview=").append(disableWebPagePreview).append('\'');
-        sb.append(", replyKeyboardMarkup=").append(replyKeyboardMarkup);
-        sb.append('}');
-        sb.append(' ');
-        sb.append(super.toString());
-        return sb.toString();
     }
 }
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingVideoMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingVideoMessage.java
index 6e5a86f..341722d 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingVideoMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/OutgoingVideoMessage.java
@@ -16,11 +16,13 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 /**
  * An outgoing video message.
  */
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class OutgoingVideoMessage extends OutgoingMessage {
 
     private static final long serialVersionUID = 1617845992454497132L;
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/ReplyKeyboardMarkup.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/ReplyKeyboardMarkup.java
index 92c680d..5fd1cd0 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/ReplyKeyboardMarkup.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/ReplyKeyboardMarkup.java
@@ -22,30 +22,32 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class ReplyKeyboardMarkup implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
     @JsonProperty("one_time_keyboard")
     private Boolean oneTimeKeyboard;
-    
+
     @JsonProperty("remove_keyboard")
     private Boolean removeKeyboard;
-    
+
     private List<List<InlineKeyboardButton>> keyboard;
-    
+
     public ReplyKeyboardMarkup() {
-        
+
     }
-    
+
     public ReplyKeyboardMarkup(Boolean oneTimeKeyboard, Boolean removeKeyboard, List<List<InlineKeyboardButton>> keyboard) {
         this.oneTimeKeyboard = oneTimeKeyboard;
         this.removeKeyboard = removeKeyboard;
         this.keyboard = keyboard;
     }
-    
+
     public Boolean getOneTimeKeyboard() {
         return oneTimeKeyboard;
     }
@@ -86,7 +88,7 @@ public class ReplyKeyboardMarkup implements Serializable {
 
     public static class Builder {
 
-        private Boolean oneTimeKeyboard;        
+        private Boolean oneTimeKeyboard;
         private Boolean removeKeyboard;
         private List<List<InlineKeyboardButton>> keyboard;
 
@@ -95,30 +97,30 @@ public class ReplyKeyboardMarkup implements Serializable {
             this.oneTimeKeyboard = oneTimeKeyboard;
             return this;
         }
-        
+
         public Builder removeKeyboard(Boolean removeKeyboard) {
-            
+
             this.removeKeyboard = removeKeyboard;
             return this;
         }
 
         public ReplyKeyboardMarkup build() {
-            
+
             return new ReplyKeyboardMarkup(oneTimeKeyboard, removeKeyboard, keyboard);
         }
 
         public KeyboardBuilder keyboard() {
-            
+
             return new KeyboardBuilder(this);
         }
-        
+
         public static class KeyboardBuilder {
-            
+
             private Builder builder;
             private List<List<InlineKeyboardButton>> keyboard;
-            
+
             public KeyboardBuilder(Builder builder) {
-                
+
                 this.builder = builder;
                 this.keyboard = new ArrayList<>();
             }
@@ -128,11 +130,11 @@ public class ReplyKeyboardMarkup implements Serializable {
                 keyboard.add(inlineKeyboardButtons);
                 return this;
             }
-            
+
             public KeyboardBuilder addOneRowByEachButton(List<InlineKeyboardButton> inlineKeyboardButtons) {
-                
+
                 for (Iterator<InlineKeyboardButton> iterator = inlineKeyboardButtons.iterator(); iterator.hasNext();) {
-                    
+
                     keyboard.add(Arrays.asList(iterator.next()));
                 }
 
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendLocationMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendLocationMessage.java
index c438bad..24f740f 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendLocationMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendLocationMessage.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class SendLocationMessage extends OutgoingMessage {
     @JsonProperty("longitude")
     private double longitude;
@@ -31,6 +33,9 @@ public class SendLocationMessage extends OutgoingMessage {
     @JsonProperty("reply_markup")
     private ReplyKeyboardMarkup replyKeyboardMarkup;
 
+    public SendLocationMessage() {
+    }
+
     public SendLocationMessage(double latitude, double longitude) {
         this.setLatitude(latitude);
         this.setLongitude(longitude);
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendVenueMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendVenueMessage.java
index bdc6433..34c85fd 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendVenueMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/SendVenueMessage.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class SendVenueMessage extends OutgoingMessage {
     @JsonProperty("longitude")
     private double longitude;
@@ -40,6 +42,9 @@ public class SendVenueMessage extends OutgoingMessage {
     @JsonProperty("reply_markup")
     private ReplyKeyboardMarkup replyKeyboardMarkup;
 
+    public SendVenueMessage() {
+    }
+
     public SendVenueMessage(double latitude, double longitude, String title, String address) {
         this.setLatitude(latitude);
         this.setLongitude(longitude);
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/StopMessageLiveLocationMessage.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/StopMessageLiveLocationMessage.java
index 2151531..396a74c 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/StopMessageLiveLocationMessage.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/StopMessageLiveLocationMessage.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.telegram.model;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class StopMessageLiveLocationMessage extends OutgoingMessage {
 
     @JsonProperty("message_id")
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramService.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/UnixTimestampSerializer.java
similarity index 56%
copy from components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramService.java
copy to components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/UnixTimestampSerializer.java
index d90a811..a5ea82a 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/TelegramService.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/model/UnixTimestampSerializer.java
@@ -14,24 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.telegram;
+package org.apache.camel.component.telegram.model;
 
-import org.apache.camel.component.telegram.model.OutgoingMessage;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import java.io.IOException;
+import java.time.Instant;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
 
 /**
- * Allows interacting with the Telegram server to exchange messages.
+ * A serializer for {@link Instant} compatible with {@link UnixTimestampDeserializer}.
  */
-public interface TelegramService {
-
-    void setHttpProxy(String host, Integer port);
-
-    UpdateResult getUpdates(String authorizationToken, Long offset, Integer limit, Integer timeoutSeconds);
-
-    Object sendMessage(String authorizationToken, OutgoingMessage message);
-
-    boolean setWebhook(String authorizationToken, String url);
+public class UnixTimestampSerializer extends JsonSerializer<Instant> {
 
-    boolean removeWebhook(String authorizationToken);
+    @Override
+    public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        gen.writeNumber(value.getEpochSecond());
+    }
 
 }
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/RestBotAPI.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/RestBotAPI.java
deleted file mode 100644
index d6b491a..0000000
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/RestBotAPI.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.telegram.service;
-
-import java.util.List;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-
-import org.apache.camel.component.telegram.model.EditMessageLiveLocationMessage;
-import org.apache.camel.component.telegram.model.MessageResult;
-import org.apache.camel.component.telegram.model.OutgoingTextMessage;
-import org.apache.camel.component.telegram.model.SendLocationMessage;
-import org.apache.camel.component.telegram.model.SendVenueMessage;
-import org.apache.camel.component.telegram.model.StopMessageLiveLocationMessage;
-import org.apache.camel.component.telegram.model.UpdateResult;
-import org.apache.camel.component.telegram.model.WebhookInfo;
-import org.apache.camel.component.telegram.model.WebhookResult;
-import org.apache.cxf.jaxrs.ext.multipart.Attachment;
-
-/**
- * Describes the Telegram Bot APIs.
- */
-@Path("/")
-public interface RestBotAPI {
-
-    String BOT_API_DEFAULT_URL = "https://api.telegram.org";
-
-    @GET
-    @Path("/bot{authorizationToken}/getUpdates")
-    @Produces(MediaType.APPLICATION_JSON)
-    UpdateResult getUpdates(
-            @PathParam("authorizationToken") String authorizationToken,
-            @QueryParam("offset") Long offset,
-            @QueryParam("limit") Integer limit,
-            @QueryParam("timeout") Integer timeoutSeconds);
-
-    @POST
-    @Path("/bot{authorizationToken}/setWebhook")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    WebhookResult setWebhook(@PathParam("authorizationToken") String authorizationToken, WebhookInfo webhookInfo);
-
-    @POST
-    @Path("/bot{authorizationToken}/sendMessage")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult sendMessage(
-            @PathParam("authorizationToken") String authorizationToken,
-            OutgoingTextMessage message);
-
-    @POST
-    @Path("/bot{authorizationToken}/sendPhoto")
-    @Consumes(MediaType.MULTIPART_FORM_DATA)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult sendPhoto(@PathParam("authorizationToken") String authorizationToken, List<Attachment> attachments);
-
-    @POST
-    @Path("/bot{authorizationToken}/sendAudio")
-    @Consumes(MediaType.MULTIPART_FORM_DATA)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult sendAudio(@PathParam("authorizationToken") String authorizationToken, List<Attachment> attachments);
-
-    @POST
-    @Path("/bot{authorizationToken}/sendVideo")
-    @Consumes(MediaType.MULTIPART_FORM_DATA)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult sendVideo(@PathParam("authorizationToken") String authorizationToken, List<Attachment> attachments);
-
-    @POST
-    @Path("/bot{authorizationToken}/sendDocument")
-    @Consumes(MediaType.MULTIPART_FORM_DATA)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult sendDocument(@PathParam("authorizationToken") String authorizationToken, List<Attachment> attachments);
-
-    @POST
-    @Path("/bot{authorizationToken}/sendLocation")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult sendLocation(@PathParam("authorizationToken") String authorizationToken, SendLocationMessage location);
-
-    @POST
-    @Path("/bot{authorizationToken}/editMessageLiveLocation")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult editMessageLiveLocation(@PathParam("authorizationToken") String authorizationToken, EditMessageLiveLocationMessage message);
-
-    @POST
-    @Path("/bot{authorizationToken}/stopMessageLiveLocation")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult stopMessageLiveLocation(@PathParam("authorizationToken") String authorizationToken, StopMessageLiveLocationMessage message);
-
-    @POST
-    @Path("/bot{authorizationToken}/sendVenue")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    MessageResult sendVenue(@PathParam("authorizationToken") String authorizationToken, SendVenueMessage location);
-}
diff --git a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramServiceRestBotAPIAdapter.java b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramServiceRestBotAPIAdapter.java
index 333c6d9..560d227 100644
--- a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramServiceRestBotAPIAdapter.java
+++ b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramServiceRestBotAPIAdapter.java
@@ -17,16 +17,22 @@
 package org.apache.camel.component.telegram.service;
 
 import java.io.ByteArrayInputStream;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.ws.rs.core.MultivaluedHashMap;
-import javax.ws.rs.core.MultivaluedMap;
-
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+import io.netty.handler.codec.http.HttpHeaders;
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
 import org.apache.camel.component.telegram.TelegramService;
 import org.apache.camel.component.telegram.model.EditMessageLiveLocationMessage;
 import org.apache.camel.component.telegram.model.MessageResult;
@@ -42,186 +48,377 @@ import org.apache.camel.component.telegram.model.StopMessageLiveLocationMessage;
 import org.apache.camel.component.telegram.model.UpdateResult;
 import org.apache.camel.component.telegram.model.WebhookInfo;
 import org.apache.camel.component.telegram.model.WebhookResult;
-import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
-import org.apache.cxf.jaxrs.client.WebClient;
-import org.apache.cxf.jaxrs.ext.multipart.Attachment;
-import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
-import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.camel.support.GZIPHelper;
+import org.apache.camel.util.IOHelper;
+import org.asynchttpclient.AsyncHandler;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.HttpResponseBodyPart;
+import org.asynchttpclient.HttpResponseStatus;
+import org.asynchttpclient.Request;
+import org.asynchttpclient.RequestBuilder;
+import org.asynchttpclient.Response;
+import org.asynchttpclient.request.body.multipart.ByteArrayPart;
+import org.asynchttpclient.request.body.multipart.StringPart;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.asynchttpclient.util.HttpUtils.extractContentTypeCharsetAttribute;
+import static org.asynchttpclient.util.MiscUtils.withDefault;
 
 /**
  * Adapts the {@code RestBotAPI} to the {@code TelegramService} interface.
  */
 public class TelegramServiceRestBotAPIAdapter implements TelegramService {
-
-    private RestBotAPI api;
-
-    public TelegramServiceRestBotAPIAdapter() {
-        this.api = JAXRSClientFactory.create(RestBotAPI.BOT_API_DEFAULT_URL, RestBotAPI.class, Collections.singletonList(providerByCustomObjectMapper()));
-        HTTPConduit httpConduit = WebClient.getConfig(this.api).getHttpConduit();
-        httpConduit.getClient().setAllowChunking(false);
-    }
-
-    public TelegramServiceRestBotAPIAdapter(RestBotAPI api) {
-        this.api = api;
+    private static final Logger LOG = LoggerFactory.getLogger(TelegramServiceRestBotAPIAdapter.class);
+
+    private final Map<Class<?>, OutgoingMessageHandler<?>> handlers;
+    private final AsyncHttpClient asyncHttpClient;
+    private final ObjectMapper mapper;
+    private final String baseUri;
+
+    public TelegramServiceRestBotAPIAdapter(AsyncHttpClient asyncHttpClient, int bufferSize, String telegramBaseUri,
+            String authorizationToken) {
+        this.asyncHttpClient = asyncHttpClient;
+        this.baseUri = telegramBaseUri + "/bot" + authorizationToken;
+        this.mapper = new ObjectMapper();
+        final Map<Class<?>, OutgoingMessageHandler<?>> m = new HashMap<>();
+        m.put(OutgoingTextMessage.class,
+                new OutgoingPlainMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri + "/sendMessage"));
+        m.put(OutgoingPhotoMessage.class, new OutgoingPhotoMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri));
+        m.put(OutgoingAudioMessage.class, new OutgoingAudioMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri));
+        m.put(OutgoingVideoMessage.class, new OutgoingVideoMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri));
+        m.put(OutgoingDocumentMessage.class, new OutgoingDocumentMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri));
+        m.put(SendLocationMessage.class,
+                new OutgoingPlainMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri + "/sendLocation"));
+        m.put(EditMessageLiveLocationMessage.class,
+                new OutgoingPlainMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri + "/editMessageLiveLocation"));
+        m.put(StopMessageLiveLocationMessage.class,
+                new OutgoingPlainMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri + "/stopMessageLiveLocation"));
+        m.put(SendVenueMessage.class,
+                new OutgoingPlainMessageHandler(asyncHttpClient, bufferSize, mapper, baseUri + "/sendVenue"));
+        this.handlers = m;
     }
 
     @Override
-    public void setHttpProxy(String host, Integer port) {
-        HTTPConduit httpConduit = WebClient.getConfig(this.api).getHttpConduit();
-        httpConduit.getClient().setProxyServer(host);
-        httpConduit.getClient().setProxyServerPort(port);
+    public UpdateResult getUpdates(Long offset, Integer limit, Integer timeoutSeconds) {
+        final String uri = baseUri + "/getUpdates";
+        final RequestBuilder request = new RequestBuilder("GET")
+                .setUrl(uri);
+        if (offset != null) {
+            request.addQueryParam("offset", String.valueOf(offset));
+        }
+        if (limit != null) {
+            request.addQueryParam("limit", String.valueOf(limit));
+        }
+        if (timeoutSeconds != null) {
+            request.addQueryParam("timeout", String.valueOf(timeoutSeconds));
+        }
+        return sendSyncRequest(request.build(), UpdateResult.class);
     }
 
-    @Override
-    public UpdateResult getUpdates(String authorizationToken, Long offset, Integer limit, Integer timeoutSeconds) {
-        return api.getUpdates(authorizationToken, offset, limit, timeoutSeconds);
+    <T> T sendSyncRequest(final Request request, Class<T> resultType) {
+        try {
+            final Response response = asyncHttpClient.executeRequest(request).get();
+            int code = response.getStatusCode();
+            if (code >= 200 && code < 300) {
+                try {
+                    final String responseBody = response.getResponseBody();
+                    if (LOG.isWarnEnabled()) {
+                        LOG.warn("Received body for {} {}: {}", request.getMethod(), request.getUrl(), responseBody);
+                    }
+                    return mapper.readValue(responseBody, resultType);
+                } catch (IOException e) {
+                    throw new RuntimeException(
+                            "Could not parse the response from " + request.getMethod() + " " + request.getUrl(), e);
+                }
+            } else {
+                throw new RuntimeException(
+                        "Could not " + request.getMethod() + " " + request.getUrl() + ": " + response.getStatusCode() + " "
+                                + response.getStatusText());
+            }
+        } catch (ExecutionException e) {
+            throw new RuntimeException("Could not request " + request.getMethod() + " " + request.getUrl(), e);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new RuntimeException(e);
+        }
     }
 
     @Override
-    public boolean setWebhook(String authorizationToken, String url) {
-        WebhookResult res = api.setWebhook(authorizationToken, new WebhookInfo(url));
+    public boolean setWebhook(String url) {
+        final String uri = baseUri + "/setWebhook";
+        final RequestBuilder request = new RequestBuilder("POST")
+                .setUrl(uri);
+        final WebhookInfo message = new WebhookInfo(url);
+        try {
+            final String body = mapper.writeValueAsString(message);
+            request.setBody(body);
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException("Could not serialize " + message);
+        }
+        WebhookResult res = sendSyncRequest(request.build(), WebhookResult.class);
         return res.isOk() && res.isResult();
     }
 
     @Override
-    public boolean removeWebhook(String authorizationToken) {
-        WebhookResult res = api.setWebhook(authorizationToken, new WebhookInfo(""));
-        return res.isOk() && res.isResult();
+    public boolean removeWebhook() {
+        return setWebhook("");
     }
 
     @Override
-    public Object sendMessage(String authorizationToken, OutgoingMessage message) {
-        Object resultMessage;
-
-        if (message instanceof OutgoingTextMessage) {
-            resultMessage = this.sendMessage(authorizationToken, (OutgoingTextMessage) message);
-        } else if (message instanceof OutgoingPhotoMessage) {
-            resultMessage = this.sendMessage(authorizationToken, (OutgoingPhotoMessage) message);
-        } else if (message instanceof OutgoingAudioMessage) {
-            resultMessage = this.sendMessage(authorizationToken, (OutgoingAudioMessage) message);
-        } else if (message instanceof OutgoingVideoMessage) {
-            resultMessage = this.sendMessage(authorizationToken, (OutgoingVideoMessage) message);
-        } else if (message instanceof OutgoingDocumentMessage) {
-            resultMessage = this.sendMessage(authorizationToken, (OutgoingDocumentMessage) message);
-        } else if (message instanceof SendLocationMessage) {
-            resultMessage = api.sendLocation(authorizationToken, (SendLocationMessage) message);
-        } else if (message instanceof EditMessageLiveLocationMessage) {
-            resultMessage = api.editMessageLiveLocation(authorizationToken, (EditMessageLiveLocationMessage) message);
-        } else if (message instanceof StopMessageLiveLocationMessage) {
-            resultMessage = api.stopMessageLiveLocation(authorizationToken, (StopMessageLiveLocationMessage) message);
-        } else if (message instanceof SendVenueMessage) {
-            resultMessage = api.sendVenue(authorizationToken, (SendVenueMessage) message);
-        } else {
-            throw new IllegalArgumentException("Unsupported message type " + (message != null ? message.getClass().getName() : null));
-        }
-
-        return resultMessage;
+    public void sendMessage(Exchange exchange, AsyncCallback callback, OutgoingMessage message) {
+        @SuppressWarnings("unchecked")
+        final OutgoingMessageHandler<OutgoingMessage> handler = (OutgoingMessageHandler<OutgoingMessage>) handlers
+                .get(message.getClass());
+        if (handler == null) {
+            throw new IllegalArgumentException(
+                    "Unsupported message type " + (message != null ? message.getClass().getName() : null));
+        }
+        handler.sendMessage(exchange, callback, message);
     }
 
-    private MessageResult sendMessage(String authorizationToken, OutgoingTextMessage message) {
-        return api.sendMessage(authorizationToken, message);
+    static class OutgoingPlainMessageHandler extends OutgoingMessageHandler<OutgoingMessage> {
+
+        public OutgoingPlainMessageHandler(AsyncHttpClient asyncHttpClient, int bufferSize, ObjectMapper mapper, String uri) {
+            super(asyncHttpClient, bufferSize, mapper, uri, "application/json");
+        }
+
+        @Override
+        protected void addBody(RequestBuilder builder, OutgoingMessage message) {
+            try {
+                final String body = mapper.writeValueAsString(message);
+                LOG.warn("sending " + body);
+                builder.setBody(body);
+            } catch (JsonProcessingException e) {
+                throw new RuntimeException("Could not serialize " + message);
+            }
+        }
+
     }
 
-    private MessageResult sendMessage(String authorizationToken, OutgoingPhotoMessage message) {
-        List<Attachment> parts = new LinkedList<>();
+    static class OutgoingAudioMessageHandler extends OutgoingMessageHandler<OutgoingAudioMessage> {
 
-        fillCommonMediaParts(parts, message);
+        public OutgoingAudioMessageHandler(AsyncHttpClient asyncHttpClient, int bufferSize, ObjectMapper mapper,
+                String baseUri) {
+            super(asyncHttpClient, bufferSize, mapper, baseUri + "/sendAudio", null);
+        }
 
-        parts.add(buildMediaPart("photo", message.getFilenameWithExtension(), message.getPhoto()));
-        if (message.getCaption() != null) {
-            parts.add(buildTextPart("caption", message.getCaption()));
+        @Override
+        protected void addBody(RequestBuilder builder, OutgoingAudioMessage message) {
+            fillCommonMediaParts(builder, message);
+            buildMediaPart(builder, "audio", message.getFilenameWithExtension(), message.getAudio());
+            buildTextPart(builder, "title", message.getTitle());
+            buildTextPart(builder, "duration", message.getDurationSeconds());
+            buildTextPart(builder, "performer", message.getPerformer());
         }
 
-        return api.sendPhoto(authorizationToken, parts);
     }
 
-    private MessageResult sendMessage(String authorizationToken, OutgoingAudioMessage message) {
-        List<Attachment> parts = new LinkedList<>();
+    static class OutgoingVideoMessageHandler extends OutgoingMessageHandler<OutgoingVideoMessage> {
 
-        fillCommonMediaParts(parts, message);
+        public OutgoingVideoMessageHandler(AsyncHttpClient asyncHttpClient, int bufferSize, ObjectMapper mapper,
+                String baseUri) {
+            super(asyncHttpClient, bufferSize, mapper, baseUri + "/sendVideo", null);
+        }
 
-        parts.add(buildMediaPart("audio", message.getFilenameWithExtension(), message.getAudio()));
-        if (message.getTitle() != null) {
-            parts.add(buildTextPart("title", message.getTitle()));
+        @Override
+        protected void addBody(RequestBuilder builder, OutgoingVideoMessage message) {
+            fillCommonMediaParts(builder, message);
+            buildMediaPart(builder, "video", message.getFilenameWithExtension(), message.getVideo());
+            buildTextPart(builder, "caption", message.getCaption());
+            buildTextPart(builder, "duration", message.getDurationSeconds());
+            buildTextPart(builder, "width", message.getWidth());
+            buildTextPart(builder, "height", message.getHeight());
         }
-        if (message.getDurationSeconds() != null) {
-            parts.add(buildTextPart("duration", String.valueOf(message.getDurationSeconds())));
+
+    }
+
+    static class OutgoingDocumentMessageHandler extends OutgoingMessageHandler<OutgoingDocumentMessage> {
+
+        public OutgoingDocumentMessageHandler(AsyncHttpClient asyncHttpClient, int bufferSize, ObjectMapper mapper,
+                String baseUri) {
+            super(asyncHttpClient, bufferSize, mapper, baseUri + "/sendDocument", null);
         }
-        if (message.getPerformer() != null) {
-            parts.add(buildTextPart("performer", message.getPerformer()));
+
+        @Override
+        protected void addBody(RequestBuilder builder, OutgoingDocumentMessage message) {
+            fillCommonMediaParts(builder, message);
+            buildMediaPart(builder, "document", message.getFilenameWithExtension(), message.getDocument());
+            buildTextPart(builder, "caption", message.getCaption());
         }
 
-        return api.sendAudio(authorizationToken, parts);
     }
 
-    private MessageResult sendMessage(String authorizationToken, OutgoingVideoMessage message) {
-        List<Attachment> parts = new LinkedList<>();
-
-        fillCommonMediaParts(parts, message);
+    static class OutgoingPhotoMessageHandler extends OutgoingMessageHandler<OutgoingPhotoMessage> {
 
-        parts.add(buildMediaPart("video", message.getFilenameWithExtension(), message.getVideo()));
-        if (message.getCaption() != null) {
-            parts.add(buildTextPart("caption", message.getCaption()));
+        public OutgoingPhotoMessageHandler(AsyncHttpClient asyncHttpClient, int bufferSize, ObjectMapper mapper,
+                String baseUri) {
+            super(asyncHttpClient, bufferSize, mapper, baseUri + "/sendPhoto", null);
         }
-        if (message.getDurationSeconds() != null) {
-            parts.add(buildTextPart("duration", String.valueOf(message.getDurationSeconds())));
+
+        @Override
+        protected void addBody(RequestBuilder builder, OutgoingPhotoMessage message) {
+            fillCommonMediaParts(builder, message);
+            buildMediaPart(builder, "photo", message.getFilenameWithExtension(), message.getPhoto());
+            buildTextPart(builder, "caption", message.getCaption());
         }
-        if (message.getWidth() != null) {
-            parts.add(buildTextPart("width", String.valueOf(message.getWidth())));
+
+    }
+
+    abstract static class OutgoingMessageHandler<T extends OutgoingMessage> {
+        protected final ObjectMapper mapper;
+        private final AsyncHttpClient asyncHttpClient;
+        private final int bufferSize;
+        private final String contentType;
+        private final String uri;
+
+        public OutgoingMessageHandler(AsyncHttpClient asyncHttpClient, int bufferSize, ObjectMapper mapper, String uri,
+                String contentType) {
+            this.asyncHttpClient = asyncHttpClient;
+            this.bufferSize = bufferSize;
+            this.mapper = mapper;
+            this.uri = uri;
+            this.contentType = contentType;
         }
-        if (message.getHeight() != null) {
-            parts.add(buildTextPart("height", String.valueOf(message.getHeight())));
+
+        public void sendMessage(Exchange exchange, AsyncCallback callback, T message) {
+            final RequestBuilder builder = new RequestBuilder("POST")
+                    .setUrl(uri);
+            if (contentType != null) {
+                builder.setHeader("Content-Type", contentType);
+            }
+            builder.setHeader("Accept", "application/json");
+            addBody(builder, message);
+            asyncHttpClient.executeRequest(builder.build(),
+                    new TelegramAsyncHandler(exchange, callback, uri, bufferSize, mapper));
         }
 
-        return api.sendVideo(authorizationToken, parts);
-    }
+        protected abstract void addBody(RequestBuilder builder, T message);
 
-    private MessageResult sendMessage(String authorizationToken, OutgoingDocumentMessage message) {
-        List<Attachment> parts = new LinkedList<>();
+        protected void fillCommonMediaParts(RequestBuilder builder, OutgoingMessage message) {
+            buildTextPart(builder, "chat_id", message.getChatId());
+            buildTextPart(builder, "reply_to_message_id", message.getReplyToMessageId());
+            buildTextPart(builder, "disable_notification", message.getDisableNotification());
+        }
 
-        fillCommonMediaParts(parts, message);
+        protected void buildTextPart(RequestBuilder builder, String name, Object value) {
+            if (value != null) {
+                builder.addBodyPart(new StringPart(name, String.valueOf(value), "text/plain", StandardCharsets.UTF_8));
+            }
+        }
 
-        parts.add(buildMediaPart("document", message.getFilenameWithExtension(), message.getDocument()));
-        if (message.getCaption() != null) {
-            parts.add(buildTextPart("caption", message.getCaption()));
+        protected void buildMediaPart(RequestBuilder builder, String name, String fileNameWithExtension, byte[] value) {
+            builder.addBodyPart(
+                    new ByteArrayPart(name, value, "application/octet-stream", StandardCharsets.UTF_8, fileNameWithExtension));
         }
 
-        return api.sendDocument(authorizationToken, parts);
     }
 
-    private void fillCommonMediaParts(List<Attachment> parts, OutgoingMessage message) {
-        parts.add(buildTextPart("chat_id", message.getChatId()));
+    private static final class TelegramAsyncHandler implements AsyncHandler<Exchange> {
+
+        private final Exchange exchange;
+        private final AsyncCallback callback;
+        private final String url;
+        private final ByteArrayOutputStream os;
+        private final ObjectMapper mapper;
+        private int statusCode;
+        private String statusText;
+        private String contentType;
+        private String contentEncoding;
+        private Charset charset;
+
+        private TelegramAsyncHandler(Exchange exchange, AsyncCallback callback, String url, int bufferSize,
+                ObjectMapper mapper) {
+            this.exchange = exchange;
+            this.callback = callback;
+            this.url = url;
+            this.os = new ByteArrayOutputStream(bufferSize);
+            this.mapper = mapper;
+        }
 
-        if (message.getReplyToMessageId() != null) {
-            parts.add(buildTextPart("reply_to_message_id", String.valueOf(message.getReplyToMessageId())));
+        @Override
+        public void onThrowable(Throwable t) {
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("{} onThrowable {}", exchange.getExchangeId(), t);
+            }
+            exchange.setException(t);
+            callback.done(false);
         }
-        if (message.getDisableNotification() != null) {
-            parts.add(buildTextPart("disable_notification", String.valueOf(message.getDisableNotification())));
+
+        @Override
+        public Exchange onCompleted() throws Exception {
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("{} onCompleted", exchange.getExchangeId());
+            }
+            try {
+                // copy from output stream to input stream
+                os.flush();
+                os.close();
+                final boolean success = statusCode >= 200 && statusCode < 300;
+                try (InputStream maybeGzStream = new ByteArrayInputStream(os.toByteArray());
+                        InputStream is = GZIPHelper.uncompressGzip(contentEncoding, maybeGzStream);
+                        Reader r = new InputStreamReader(is, charset)) {
+
+                    if (success) {
+                        final Object result;
+                        if (LOG.isTraceEnabled()) {
+                            final String body = IOHelper.toString(r);
+                            LOG.trace("Received body for {}: {}", url, body);
+                            result = mapper.readValue(body, MessageResult.class);
+                        } else {
+                            result = mapper.readValue(r, MessageResult.class);
+                        }
+
+                        exchange.getMessage().setBody(result);
+                    } else {
+                        throw new RuntimeException(
+                                url + " responded: " + statusCode + " " + statusText + " " + IOHelper.toString(r));
+                    }
+                } catch (IOException e) {
+                    throw new RuntimeException("Could not parse the response from " + url, e);
+                }
+            } catch (Exception e) {
+                exchange.setException(e);
+            } finally {
+                // signal we are done
+                callback.done(false);
+            }
+            return exchange;
         }
-    }
 
-    private Attachment buildTextPart(String name, String value) {
-        MultivaluedMap m = new MultivaluedHashMap<>();
-        m.putSingle("Content-Type", "text/plain");
-        m.putSingle("Content-Disposition", "form-data; name=\"" + escapeMimeName(name) + "\"");
+        @Override
+        public String toString() {
+            return "AhcAsyncHandler for exchangeId: " + exchange.getExchangeId() + " -> " + url;
+        }
 
-        Attachment a = new Attachment(m, value);
-        return a;
-    }
+        @Override
+        public State onBodyPartReceived(HttpResponseBodyPart bodyPart)
+                throws Exception {
+            // write body parts to stream, which we will bind to the Camel Exchange in onComplete
+            os.write(bodyPart.getBodyPartBytes());
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("{} onBodyPartReceived {} bytes", exchange.getExchangeId(), bodyPart.length());
+            }
+            return State.CONTINUE;
+        }
 
-    private Attachment buildMediaPart(String name, String fileNameWithExtension, byte[] value) {
-        Attachment a = new Attachment(name, new ByteArrayInputStream(value),
-                new ContentDisposition("form-data; name=\"" + escapeMimeName(name) + "\"; filename=\"" + escapeMimeName(fileNameWithExtension) + "\""));
-        return a;
-    }
+        @Override
+        public State onStatusReceived(HttpResponseStatus responseStatus)
+                throws Exception {
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("{} onStatusReceived {}", exchange.getExchangeId(), responseStatus);
+            }
+            statusCode = responseStatus.getStatusCode();
+            statusText = responseStatus.getStatusText();
+            return State.CONTINUE;
+        }
 
-    private String escapeMimeName(String name) {
-        return name.replace("\"", "");
+        @Override
+        public State onHeadersReceived(HttpHeaders headers) throws Exception {
+            contentEncoding = headers.get("Content-Encoding");
+            contentType = headers.get("Content-Type");
+            charset = withDefault(extractContentTypeCharsetAttribute(contentType), StandardCharsets.UTF_8);
+            return State.CONTINUE;
+        }
     }
-    
-    private JacksonJsonProvider providerByCustomObjectMapper() {
-        ObjectMapper mapper = new ObjectMapper();
-        mapper.setSerializationInclusion(Include.NON_NULL);
-        return new JacksonJsonProvider(mapper);
-    }    
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramChatBotTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramChatBotTest.java
index c371ec6..d8685ca 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramChatBotTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramChatBotTest.java
@@ -17,61 +17,37 @@
 package org.apache.camel.component.telegram;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.telegram.model.OutgoingTextMessage;
 import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
+import org.awaitility.Awaitility;
 import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.verification.Timeout;
 
 import static org.apache.camel.test.junit5.TestSupport.assertCollectionSize;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+
 
 /**
  * Tests a chain made of a consumer and a producer to create a direct chat-bot.
  */
 public class TelegramChatBotTest extends TelegramTestSupport {
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService service = mockTelegramService();
-
-        UpdateResult request = getJSONResource("messages/updates-single.json", UpdateResult.class);
-        request.getUpdates().get(0).getMessage().setText("Hello World!");
-        request.getUpdates().get(0).getMessage().getChat().setId("my-chat-id");
-
-        UpdateResult request2 = getJSONResource("messages/updates-single.json", UpdateResult.class);
-        request2.getUpdates().get(0).getMessage().setText("intercept");
-        request2.getUpdates().get(0).getMessage().getChat().setId("my-chat-id");
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(service.getUpdates(any(), any(), any(), any()))
-                .thenReturn(request)
-                .thenReturn(request2)
-                .thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testChatBotResult() throws Exception {
 
-        TelegramService service = currentMockService();
-
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
-
-        verify(service, new Timeout(5000, times(2))).sendMessage(eq("mock-token"), captor.capture());
-
-        List<OutgoingTextMessage> msgs = captor.getAllValues();
+        List<OutgoingTextMessage> msgs = Awaitility.await().atMost(5, TimeUnit.SECONDS)
+                .until(() -> getMockRoutes().getMock("sendMessage").getRecordedMessages(), rawMessages -> rawMessages.size() >= 2)
+                .stream()
+                .map(message -> (OutgoingTextMessage) message)
+                .collect(Collectors.toList());
 
         assertCollectionSize(msgs, 2);
         assertTrue(msgs.stream().anyMatch(m -> "echo from the bot: Hello World!".equals(m.getText())));
@@ -101,17 +77,46 @@ public class TelegramChatBotTest extends TelegramTestSupport {
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-
-                from("telegram:bots?authorizationToken=mock-token")
-                        .bean(TelegramChatBotTest.this, "chatBotProcess1")
-                        .bean(TelegramChatBotTest.this, "chatBotProcess2")
-                        .to("telegram:bots?authorizationToken=mock-token");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .bean(TelegramChatBotTest.this, "chatBotProcess1")
+                            .bean(TelegramChatBotTest.this, "chatBotProcess2")
+                            .to("telegram:bots?authorizationToken=mock-token");
+                }
+            }};
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        UpdateResult request = getJSONResource("messages/updates-single.json", UpdateResult.class);
+        request.getUpdates().get(0).getMessage().setText("Hello World!");
+        request.getUpdates().get(0).getMessage().getChat().setId("my-chat-id");
+
+        UpdateResult request2 = getJSONResource("messages/updates-single.json", UpdateResult.class);
+        request2.getUpdates().get(0).getMessage().setText("intercept");
+        request2.getUpdates().get(0).getMessage().getChat().setId("my-chat-id");
+
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.serialize(request),
+                        TelegramTestUtil.serialize(request2),
+                        TelegramTestUtil.stringResource("messages/updates-empty.json"))
+                .addEndpoint(
+                        "sendMessage",
+                        "POST",
+                        OutgoingTextMessage.class,
+                        TelegramTestUtil.stringResource("messages/send-message.json"),
+                        TelegramTestUtil.stringResource("messages/send-message.json"),
+                        TelegramTestUtil.stringResource("messages/send-message.json"));
     }
 
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerChannelPostTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerChannelPostTest.java
index 7c34000..78078b7 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerChannelPostTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerChannelPostTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.telegram;
 
 import java.time.Instant;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.EndpointInject;
 import org.apache.camel.Exchange;
@@ -25,18 +26,17 @@ import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.Chat;
 import org.apache.camel.component.telegram.model.IncomingMessage;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 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.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
+
 
 /**
- * 
+ *
  * Test channel data updates are converted by camel application.
  *
  */
@@ -45,33 +45,22 @@ public class TelegramConsumerChannelPostTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult res1 = getJSONResource("messages/updates-channelMessage.json", UpdateResult.class);
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(api.getUpdates(any(), any(), any(), any())).thenReturn(res1).thenAnswer(i -> defaultRes);
-    }
-    
     @Test
     public void testReceptionOfMessageWithAMessage() throws Exception {
         endpoint.expectedMinimumMessageCount(1);
-        endpoint.assertIsSatisfied();
+        endpoint.assertIsSatisfied(5000);
 
         Exchange mediaExchange = endpoint.getExchanges().get(0);
         IncomingMessage msg = mediaExchange.getIn().getBody(IncomingMessage.class);
-        
+
         assertEquals("-1001245756934", mediaExchange.getIn().getHeader(TelegramConstants.TELEGRAM_CHAT_ID));
-        
+
         //checking body
         assertNotNull(msg);
         assertEquals("test", msg.getText());
         assertEquals(Long.valueOf(67L), msg.getMessageId());
         assertEquals(Instant.ofEpochSecond(1546505413L), msg.getDate());
-        
+
         // checking chat
         Chat chat = msg.getChat();
         assertNotNull(chat);
@@ -80,15 +69,29 @@ public class TelegramConsumerChannelPostTest extends TelegramTestSupport {
         assertEquals("channel", chat.getType());
 
     }
-    
+
+    @Override
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .to("mock:telegram");
+                }
+            }};
+    }
+
+
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token")
-                        .to("mock:telegram");
-            }
-        };
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.stringResource("messages/updates-channelMessage.json"),
+                        TelegramTestUtil.stringResource("messages/updates-empty.json"));
     }
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerEmptyResponseTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerEmptyResponseTest.java
index bdaa461..164eb4a 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerEmptyResponseTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerEmptyResponseTest.java
@@ -16,18 +16,19 @@
  */
 package org.apache.camel.component.telegram;
 
+import java.util.concurrent.TimeUnit;
+
 import org.apache.camel.EndpointInject;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
+import org.awaitility.Awaitility;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
 
 /**
  * Test the empty responses.
@@ -37,33 +38,40 @@ public class TelegramConsumerEmptyResponseTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(api.getUpdates(any(), any(), any(), any())).thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testBehaviourWithEmptyUpdates() {
+        /* First make sure the message containing zero updates was sent by the API */
+        Awaitility.await().atMost(5, TimeUnit.SECONDS)
+                .until(() -> getMockRoutes().getMock("getUpdates").getRecordedMessages().size() >= 1);
+
+        /* Then make sure that the consumer has sent zero exchanges to the route */
         assertThrows(AssertionError.class, () -> {
             endpoint.setResultWaitTime(500L);
             endpoint.expectedMinimumMessageCount(1);
-
             endpoint.assertIsSatisfied();
         });
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token").to("mock:telegram");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token").to("mock:telegram");
+                }
+            }};
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.stringResource("messages/updates-empty.json"));
     }
 
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerFallbackConversionTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerFallbackConversionTest.java
index 186235e..bb81e4c 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerFallbackConversionTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerFallbackConversionTest.java
@@ -17,21 +17,22 @@
 package org.apache.camel.component.telegram;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import org.apache.camel.EndpointInject;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.telegram.model.OutgoingTextMessage;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
+import org.awaitility.Awaitility;
 import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentCaptor;
 
 import static org.apache.camel.test.junit5.TestSupport.assertCollectionSize;
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
 
 /**
  * Checks if conversions of generic objects are happening correctly.
@@ -41,21 +42,16 @@ public class TelegramConsumerFallbackConversionTest extends TelegramTestSupport
     @EndpointInject("direct:message")
     protected ProducerTemplate template;
 
-    @BeforeEach
-    public void mockAPIs() {
-        mockTelegramService();
-    }
-
     @Test
     public void testEverythingOk() throws Exception {
-        TelegramService service = currentMockService();
 
         template.sendBody(new BrandNewType("wrapped message"));
 
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
-        verify(service).sendMessage(eq("mock-token"), captor.capture());
-
-        List<OutgoingTextMessage> msgs = captor.getAllValues();
+        List<OutgoingTextMessage> msgs = Awaitility.await().atMost(5, TimeUnit.SECONDS)
+                .until(() -> getMockRoutes().getMock("sendMessage").getRecordedMessages(), rawMessages -> rawMessages.size() == 1)
+                .stream()
+                .map(message -> (OutgoingTextMessage) message)
+                .collect(Collectors.toList());
 
         assertCollectionSize(msgs, 1);
         String text = msgs.get(0).getText();
@@ -63,14 +59,28 @@ public class TelegramConsumerFallbackConversionTest extends TelegramTestSupport
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("direct:message")
-                        .to("telegram:bots?authorizationToken=mock-token&chatId=1234");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("direct:message")
+                            .to("telegram:bots?authorizationToken=mock-token&chatId=1234");
+                }
+            }};
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "sendMessage",
+                        "POST",
+                        OutgoingTextMessage.class,
+                        TelegramTestUtil.stringResource("messages/send-message.json"),
+                        TelegramTestUtil.stringResource("messages/send-message.json"),
+                        TelegramTestUtil.stringResource("messages/send-message.json"));
     }
 
     private static class BrandNewType {
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMappingTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMappingTest.java
index a1ce073..ef2b86d 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMappingTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMappingTest.java
@@ -27,17 +27,15 @@ import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.Chat;
 import org.apache.camel.component.telegram.model.IncomingMessage;
 import org.apache.camel.component.telegram.model.MessageResult;
-import org.apache.camel.component.telegram.model.UpdateResult;
 import org.apache.camel.component.telegram.model.User;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 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.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
 
 /**
  * Tests the JSON mapping of the API updates.
@@ -47,22 +45,11 @@ public class TelegramConsumerMappingTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult res1 = getJSONResource("messages/updates-single.json", UpdateResult.class);
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(api.getUpdates(any(), any(), any(), any())).thenReturn(res1).thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testMessageMapping() throws Exception {
         endpoint.expectedMinimumMessageCount(1);
         endpoint.expectedMessageCount(1);
-        endpoint.assertIsSatisfied();
+        endpoint.assertIsSatisfied(5000);
 
         Exchange ex = endpoint.getExchanges().get(0);
         Message m = ex.getIn();
@@ -120,13 +107,26 @@ public class TelegramConsumerMappingTest extends TelegramTestSupport {
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token").to("mock:telegram");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token").to("mock:telegram");
+                }
+            }};
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.stringResource("messages/updates-single.json"),
+                        TelegramTestUtil.stringResource("messages/updates-empty.json"));
     }
 
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaDocumentTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaDocumentTest.java
index c366593..40ff6d0 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaDocumentTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaDocumentTest.java
@@ -23,15 +23,13 @@ import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.IncomingDocument;
 import org.apache.camel.component.telegram.model.IncomingMessage;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 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.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
 
 /**
  * Tests the reception of messages without text having media content.
@@ -41,23 +39,10 @@ public class TelegramConsumerMediaDocumentTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult res = getJSONResource("messages/updates-media-document.json", UpdateResult.class);
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(api.getUpdates(any(), any(), any(), any()))
-                .thenReturn(res)
-                .thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testReceptionOfMessageWithADocument() throws Exception {
         endpoint.expectedMinimumMessageCount(1);
-        endpoint.assertIsSatisfied();
+        endpoint.assertIsSatisfied(5000);
 
         Exchange mediaExchange = endpoint.getExchanges().get(0);
         IncomingMessage msg = mediaExchange.getIn().getBody(IncomingMessage.class);
@@ -77,13 +62,27 @@ public class TelegramConsumerMediaDocumentTest extends TelegramTestSupport {
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token")
-                        .to("mock:telegram");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .to("mock:telegram");
+                }
+            }};
     }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.stringResource("messages/updates-media-document.json"),
+                        TelegramTestUtil.stringResource("messages/updates-empty.json"));
+    }
+
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaPhotoTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaPhotoTest.java
index 75d8f75..24ff235 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaPhotoTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaPhotoTest.java
@@ -22,16 +22,14 @@ import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.IncomingMessage;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 import org.junit.jupiter.api.Test;
 
 import static org.apache.camel.test.junit5.TestSupport.assertCollectionSize;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
 
 /**
  * Tests the reception of messages without text having media content.
@@ -41,23 +39,10 @@ public class TelegramConsumerMediaPhotoTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult res = getJSONResource("messages/updates-media.json", UpdateResult.class);
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(api.getUpdates(any(), any(), any(), any()))
-                .thenReturn(res)
-                .thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testReceptionOfTwoMessagesOneWithMedia() throws Exception {
         endpoint.expectedMinimumMessageCount(2);
-        endpoint.assertIsSatisfied();
+        endpoint.assertIsSatisfied(5000);
 
         Exchange mediaExchange = endpoint.getExchanges().get(1);
         IncomingMessage msg = mediaExchange.getIn().getBody(IncomingMessage.class);
@@ -68,14 +53,27 @@ public class TelegramConsumerMediaPhotoTest extends TelegramTestSupport {
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token")
-                        .to("mock:telegram");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .to("mock:telegram");
+                }
+            }};
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.stringResource("messages/updates-media.json"),
+                        TelegramTestUtil.stringResource("messages/updates-empty.json"));
     }
 
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaVideoTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaVideoTest.java
index 9e96111..ec7d2c6 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaVideoTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMediaVideoTest.java
@@ -24,15 +24,13 @@ import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.IncomingMessage;
 import org.apache.camel.component.telegram.model.IncomingPhotoSize;
 import org.apache.camel.component.telegram.model.IncomingVideo;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 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.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
 
 /**
  * Tests the reception of messages without text having media content.
@@ -42,23 +40,10 @@ public class TelegramConsumerMediaVideoTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult res = getJSONResource("messages/updates-media-video.json", UpdateResult.class);
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(api.getUpdates(any(), any(), any(), any()))
-                .thenReturn(res)
-                .thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testReceptionOfAMessageWithAVideo() throws Exception {
         endpoint.expectedMinimumMessageCount(1);
-        endpoint.assertIsSatisfied();
+        endpoint.assertIsSatisfied(5000);
 
         Exchange mediaExchange = endpoint.getExchanges().get(0);
         IncomingMessage msg = mediaExchange.getIn().getBody(IncomingMessage.class);
@@ -78,14 +63,27 @@ public class TelegramConsumerMediaVideoTest extends TelegramTestSupport {
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token")
-                        .to("mock:telegram");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .to("mock:telegram");
+                }
+            }};
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.stringResource("messages/updates-media-video.json"),
+                        TelegramTestUtil.stringResource("messages/updates-empty.json"));
     }
 
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMultipleTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMultipleTest.java
index 15f0594..a9158b6 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMultipleTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerMultipleTest.java
@@ -21,13 +21,11 @@ import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 import org.junit.jupiter.api.Test;
 
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
-
 /**
  * Tests a conversation having multiple updates.
  */
@@ -36,10 +34,30 @@ public class TelegramConsumerMultipleTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
+    @Test
+    public void testReceptionOfThreeMessagesFromTwoUpdates() throws Exception {
+        endpoint.expectedMinimumMessageCount(3);
+        endpoint.expectedBodiesReceived("message1", "message2", "message3");
 
+        endpoint.assertIsSatisfied(5000);
+    }
+
+    @Override
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .convertBodyTo(String.class)
+                            .to("mock:telegram");
+                }
+            } };
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
         UpdateResult res1 = getJSONResource("messages/updates-single.json", UpdateResult.class);
         res1.getUpdates().get(0).getMessage().setText("message1");
 
@@ -49,27 +67,14 @@ public class TelegramConsumerMultipleTest extends TelegramTestSupport {
 
         UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
 
-        when(api.getUpdates(any(), any(), any(), any())).thenReturn(res1).thenReturn(res2).thenAnswer(i -> defaultRes);
-    }
-
-    @Test
-    public void testReceptionOfThreeMessagesFromTwoUpdates() throws Exception {
-        endpoint.expectedMinimumMessageCount(3);
-        endpoint.expectedBodiesReceived("message1", "message2", "message3");
-
-        endpoint.assertIsSatisfied();
-    }
-
-    @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token")
-                        .convertBodyTo(String.class)
-                        .to("mock:telegram");
-            }
-        };
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.serialize(res1),
+                        TelegramTestUtil.serialize(res2),
+                        TelegramTestUtil.serialize(defaultRes));
     }
 
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerServiceErrorTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerServiceErrorTest.java
index 29d3c7e..4321c4a 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerServiceErrorTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerServiceErrorTest.java
@@ -21,13 +21,11 @@ import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 import org.junit.jupiter.api.Test;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
-
 /**
  * Test the recovery after service unavailability.
  */
@@ -36,43 +34,47 @@ public class TelegramConsumerServiceErrorTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult res1 = getJSONResource("messages/updates-single.json", UpdateResult.class);
-        res1.getUpdates().get(0).getMessage().setText("message1");
-
-        UpdateResult logicalErrorRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-        logicalErrorRes.setOk(false);
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-
-        when(api.getUpdates(any(), any(), any(), any()))
-                .thenThrow(new RuntimeException("Service exception"))
-                .thenReturn(logicalErrorRes)
-                .thenReturn(res1)
-                .thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testConsumerRecovery() throws Exception {
         endpoint.expectedMinimumMessageCount(1);
         endpoint.expectedBodiesReceived("message1");
 
-        endpoint.assertIsSatisfied();
+        endpoint.assertIsSatisfied(5000);
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token")
-                        .convertBodyTo(String.class)
-                        .to("mock:telegram");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .convertBodyTo(String.class)
+                            .to("mock:telegram");
+                }
+            }};
     }
 
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+
+
+        UpdateResult res1 = getJSONResource("messages/updates-single.json", UpdateResult.class);
+        res1.getUpdates().get(0).getMessage().setText("message1");
+
+        UpdateResult logicalErrorRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
+        logicalErrorRes.setOk(false);
+
+        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
+
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.serialize(res1),
+                        TelegramTestUtil.serialize(logicalErrorRes),
+                        TelegramTestUtil.serialize(defaultRes));
+    }
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerSingleTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerSingleTest.java
index 842d8d9..7816b8b 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerSingleTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramConsumerSingleTest.java
@@ -21,13 +21,11 @@ import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 import org.junit.jupiter.api.Test;
 
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
-
 /**
  * Tests a simple conversation.
  */
@@ -36,38 +34,46 @@ public class TelegramConsumerSingleTest extends TelegramTestSupport {
     @EndpointInject("mock:telegram")
     private MockEndpoint endpoint;
 
-    @BeforeEach
-    public void mockAPIs() {
-        TelegramService api = mockTelegramService();
-
-        UpdateResult res1 = getJSONResource("messages/updates-single.json", UpdateResult.class);
-        res1.getUpdates().get(0).getMessage().setText("message1");
-
-        UpdateResult res2 = getJSONResource("messages/updates-single.json", UpdateResult.class);
-        res2.getUpdates().get(0).getMessage().setText("message2");
-
-        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
-        when(api.getUpdates(any(), any(), any(), any())).thenReturn(res1).thenReturn(res2).thenAnswer(i -> defaultRes);
-    }
-
     @Test
     public void testReceptionOfTwoMessages() throws Exception {
         endpoint.expectedMinimumMessageCount(2);
         endpoint.expectedBodiesReceived("message1", "message2");
 
-        endpoint.assertIsSatisfied();
+        endpoint.assertIsSatisfied(5000);
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("telegram:bots?authorizationToken=mock-token")
-                        .convertBodyTo(String.class)
-                        .to("mock:telegram");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("telegram:bots?authorizationToken=mock-token")
+                            .convertBodyTo(String.class)
+                            .to("mock:telegram");
+                }
+            }};
     }
 
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+
+        UpdateResult res1 = getJSONResource("messages/updates-single.json", UpdateResult.class);
+        res1.getUpdates().get(0).getMessage().setText("message1");
+
+        UpdateResult res2 = getJSONResource("messages/updates-single.json", UpdateResult.class);
+        res2.getUpdates().get(0).getMessage().setText("message2");
+
+        UpdateResult defaultRes = getJSONResource("messages/updates-empty.json", UpdateResult.class);
+
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getUpdates",
+                        "GET",
+                        String.class,
+                        TelegramTestUtil.serialize(res1),
+                        TelegramTestUtil.serialize(res2),
+                        TelegramTestUtil.serialize(defaultRes));
+    }
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerChatIdResolutionTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerChatIdResolutionTest.java
index 096d417..4106817 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerChatIdResolutionTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerChatIdResolutionTest.java
@@ -22,14 +22,14 @@ import org.apache.camel.Exchange;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.telegram.model.OutgoingTextMessage;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes.MockProcessor;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.mockito.ArgumentMatchers.eq;
 
 /**
  * Tests a producer route with a fixed destination.
@@ -41,47 +41,55 @@ public class TelegramProducerChatIdResolutionTest extends TelegramTestSupport {
 
     @Test
     public void testRouteWithFixedChatId() throws Exception {
+        final MockProcessor<OutgoingTextMessage> mockProcessor = getMockRoutes().getMock("sendMessage");
+        mockProcessor.clearRecordedMessages();
 
-        TelegramService api = mockTelegramService();
+        template.sendBody(endpoint, "Hello");
 
-        context().createProducerTemplate().sendBody(endpoint, "Hello");
-
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
-
-        Mockito.verify(api).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals("Hello", captor.getValue().getText());
-        assertNull(captor.getValue().getParseMode());
+        final OutgoingTextMessage message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertEquals("my-id", message.getChatId());
+        assertEquals("Hello", message.getText());
+        assertNull(message.getParseMode());
     }
 
     @Test
     public void testRouteWithOverridenChatId() throws Exception {
-
-        TelegramService api = mockTelegramService();
+        final MockProcessor<OutgoingTextMessage> mockProcessor = getMockRoutes().getMock("sendMessage");
+        mockProcessor.clearRecordedMessages();
 
         Exchange exchange = endpoint.createExchange();
         exchange.getIn().setBody("Hello 2");
         exchange.getIn().setHeader(TelegramConstants.TELEGRAM_CHAT_ID, "my-second-id");
 
-        context().createProducerTemplate().send(endpoint, exchange);
+        template.send(endpoint, exchange);
 
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
-
-        Mockito.verify(api).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-second-id", captor.getValue().getChatId());
-        assertEquals("Hello 2", captor.getValue().getText());
-        assertNull(captor.getValue().getParseMode());
+        final OutgoingTextMessage message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertEquals("my-second-id", message.getChatId());
+        assertEquals("Hello 2", message.getText());
+        assertNull(message.getParseMode());
 
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("direct:telegram").to("telegram:bots?authorizationToken=mock-token&chatId=my-id");
-            }
-        };
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("direct:telegram")
+                            .to("telegram:bots?authorizationToken=mock-token&chatId=my-id");
+                }
+            }};
     }
 
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "sendMessage",
+                        "POST",
+                        OutgoingTextMessage.class,
+                        TelegramTestUtil.stringResource("messages/send-message.json"));
+    }
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerLocationTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerLocationTest.java
index 8140c17..fcb38d2 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerLocationTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerLocationTest.java
@@ -23,96 +23,101 @@ import org.apache.camel.component.telegram.model.MessageResult;
 import org.apache.camel.component.telegram.model.SendLocationMessage;
 import org.apache.camel.component.telegram.model.SendVenueMessage;
 import org.apache.camel.component.telegram.model.StopMessageLiveLocationMessage;
-import org.apache.camel.component.telegram.service.RestBotAPI;
-import org.apache.camel.component.telegram.service.TelegramServiceRestBotAPIAdapter;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes.MockProcessor;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
+import static org.assertj.core.api.Assertions.assertThat;
 
 /**
  * Tests a producer that sends location information.
  */
-@ExtendWith(MockitoExtension.class)
 public class TelegramProducerLocationTest extends TelegramTestSupport {
 
     private final double latitude = 59.9386292;
     private final double longitude = 30.3141308;
 
-    private TelegramService service;
-
-    @Mock
-    private RestBotAPI restBotAPI;
-
-    @Override
-    @BeforeEach
-    public void setUp() {
-        service = new TelegramServiceRestBotAPIAdapter(restBotAPI);
-        TelegramServiceProvider.get().setAlternativeService(service);
-    }
-
     @Test
     public void testSendLocation() {
-        MessageResult expected = new MessageResult();
-        expected.setOk(true);
-        when(restBotAPI.sendLocation(anyString(), any(SendLocationMessage.class))).thenReturn(expected);
-
         SendLocationMessage msg = new SendLocationMessage(latitude, longitude);
-        MessageResult actual = (MessageResult) service.sendMessage("mock-token", msg);
+        template.requestBody("direct:telegram", msg, MessageResult.class);
 
-        assertEquals(expected, actual);
+        final MockProcessor<SendLocationMessage> mockProcessor = getMockRoutes().getMock("sendLocation");
+        assertThat(mockProcessor.awaitRecordedMessages(1, 5000).get(0))
+                .usingRecursiveComparison()
+                .isEqualTo(msg);
     }
 
     @Test
     public void testSendVenue() {
-        MessageResult expected = new MessageResult();
-        expected.setOk(true);
-        when(restBotAPI.sendVenue(anyString(), any(SendVenueMessage.class))).thenReturn(expected);
-
         SendVenueMessage msg = new SendVenueMessage(latitude, longitude, "title", "address");
-        MessageResult actual = (MessageResult) service.sendMessage("mock-token", msg);
+        template.requestBody("direct:telegram", msg, MessageResult.class);
 
-        assertEquals(expected, actual);
+        final MockProcessor<SendLocationMessage> mockProcessor = getMockRoutes().getMock("sendVenue");
+        assertThat(mockProcessor.awaitRecordedMessages(1, 5000).get(0))
+                .usingRecursiveComparison()
+                .isEqualTo(msg);
     }
 
     @Test
     public void testEditMessageLiveLocation() {
-        MessageResult expected = new MessageResult();
-        expected.setOk(true);
-        when(restBotAPI.editMessageLiveLocation(anyString(), any(EditMessageLiveLocationMessage.class))).thenReturn(expected);
-
         EditMessageLiveLocationMessage msg = new EditMessageLiveLocationMessage(latitude, longitude);
-        MessageResult actual = (MessageResult) service.sendMessage("mock-token", msg);
+        template.requestBody("direct:telegram", msg, MessageResult.class);
 
-        assertEquals(expected, actual);
+        final MockProcessor<SendLocationMessage> mockProcessor = getMockRoutes().getMock("editMessageLiveLocation");
+        assertThat(mockProcessor.awaitRecordedMessages(1, 5000).get(0))
+                .usingRecursiveComparison()
+                .isEqualTo(msg);
     }
 
     @Test
     public void testStopMessageLiveLocation() {
-        MessageResult expected = new MessageResult();
-        expected.setOk(true);
-        when(restBotAPI.stopMessageLiveLocation(anyString(), any(StopMessageLiveLocationMessage.class))).thenReturn(expected);
-
         StopMessageLiveLocationMessage msg = new StopMessageLiveLocationMessage();
-        MessageResult actual = (MessageResult) service.sendMessage("mock-token", msg);
+        template.requestBody("direct:telegram", msg, MessageResult.class);
+
+        final MockProcessor<SendLocationMessage> mockProcessor = getMockRoutes().getMock("stopMessageLiveLocation");
+        assertThat(mockProcessor.awaitRecordedMessages(1, 5000).get(0))
+                .usingRecursiveComparison()
+                .isEqualTo(msg);
+    }
 
-        assertEquals(expected, actual);
+    @Override
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("direct:telegram").to("telegram:bots?authorizationToken=mock-token&chatId=" + chatId);
+                }
+            }};
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                from("direct:telegram").to("telegram:bots?authorizationToken=mock-token&chatId=my-id");
-            }
-        };
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "sendLocation",
+                        "POST",
+                        SendLocationMessage.class,
+                        TelegramTestUtil.stringResource("messages/send-location.json"))
+                .addEndpoint(
+                        "sendVenue",
+                        "POST",
+                        SendVenueMessage.class,
+                        TelegramTestUtil.stringResource("messages/send-venue.json"))
+                .addEndpoint(
+                        "editMessageLiveLocation",
+                        "POST",
+                        EditMessageLiveLocationMessage.class,
+                        TelegramTestUtil.stringResource("messages/edit-message-live-location.json"))
+                .addEndpoint(
+                        "stopMessageLiveLocation",
+                        "POST",
+                        StopMessageLiveLocationMessage.class,
+                        TelegramTestUtil.stringResource("messages/stop-message-live-location.json"));
     }
+
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerMediaTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerMediaTest.java
index 3d9ec56..e6e15d7 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerMediaTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerMediaTest.java
@@ -16,25 +16,23 @@
  */
 package org.apache.camel.component.telegram;
 
+import java.nio.charset.StandardCharsets;
+
 import org.apache.camel.Endpoint;
 import org.apache.camel.EndpointInject;
 import org.apache.camel.Exchange;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.telegram.model.OutgoingAudioMessage;
-import org.apache.camel.component.telegram.model.OutgoingDocumentMessage;
-import org.apache.camel.component.telegram.model.OutgoingPhotoMessage;
 import org.apache.camel.component.telegram.model.OutgoingTextMessage;
-import org.apache.camel.component.telegram.model.OutgoingVideoMessage;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes.MockProcessor;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
 import org.apache.camel.component.telegram.util.TelegramTestUtil;
 import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Tests a producer that sends media information.
@@ -47,7 +45,8 @@ public class TelegramProducerMediaTest extends TelegramTestSupport {
     @Test
     public void testRouteWithPngImage() throws Exception {
 
-        TelegramService service = mockTelegramService();
+        final MockProcessor<byte[]> mockProcessor = getMockRoutes().getMock("sendPhoto");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TITLE_CAPTION, "Photo");
@@ -55,43 +54,42 @@ public class TelegramProducerMediaTest extends TelegramTestSupport {
         byte[] image = TelegramTestUtil.createSampleImage("PNG");
         ex.getIn().setBody(image);
 
-        context().createProducerTemplate().send(endpoint, ex);
-
-        ArgumentCaptor<OutgoingPhotoMessage> captor = ArgumentCaptor.forClass(OutgoingPhotoMessage.class);
+        template.send(endpoint, ex);
 
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals(image, captor.getValue().getPhoto());
-        assertEquals("photo.png", captor.getValue().getFilenameWithExtension());
-        assertEquals("Photo", captor.getValue().getCaption());
+        /* message contains a multipart body */
+        final byte[] message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertMultipartText(message, "chat_id", "my-id");
+        assertTrue(contains(message, image));
+        assertMultipartFilename(message, "photo", "photo.png");
+        assertMultipartText(message, "caption", "Photo");
     }
 
     @Test
     public void testRouteWithJpgImage() throws Exception {
 
-        TelegramService service = mockTelegramService();
+        final MockProcessor<byte[]> mockProcessor = getMockRoutes().getMock("sendPhoto");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TITLE_CAPTION, "Photo");
-        ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TYPE, TelegramMediaType.PHOTO_JPG); // without using .name()
+        ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TYPE, TelegramMediaType.PHOTO_JPG); // without using
+                                                                                                  // .name()
         byte[] image = TelegramTestUtil.createSampleImage("JPG");
         ex.getIn().setBody(image);
 
-        context().createProducerTemplate().send(endpoint, ex);
+        template.send(endpoint, ex);
 
-        ArgumentCaptor<OutgoingPhotoMessage> captor = ArgumentCaptor.forClass(OutgoingPhotoMessage.class);
-
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals(image, captor.getValue().getPhoto());
-        assertEquals("photo.jpg", captor.getValue().getFilenameWithExtension());
-        assertEquals("Photo", captor.getValue().getCaption());
+        final byte[] message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertMultipartText(message, "chat_id", "my-id");
+        assertTrue(contains(message, image));
+        assertMultipartFilename(message, "photo", "photo.jpg");
+        assertMultipartText(message, "caption", "Photo");
     }
 
     @Test
     public void testRouteWithAudio() throws Exception {
-
-        TelegramService service = mockTelegramService();
+        final MockProcessor<byte[]> mockProcessor = getMockRoutes().getMock("sendAudio");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TITLE_CAPTION, "Audio");
@@ -99,21 +97,20 @@ public class TelegramProducerMediaTest extends TelegramTestSupport {
         byte[] audio = TelegramTestUtil.createSampleAudio();
         ex.getIn().setBody(audio);
 
-        context().createProducerTemplate().send(endpoint, ex);
+        template.send(endpoint, ex);
 
-        ArgumentCaptor<OutgoingAudioMessage> captor = ArgumentCaptor.forClass(OutgoingAudioMessage.class);
+        final byte[] message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
 
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals(audio, captor.getValue().getAudio());
-        assertEquals("audio.mp3", captor.getValue().getFilenameWithExtension());
-        assertEquals("Audio", captor.getValue().getTitle());
+        assertMultipartText(message, "chat_id", "my-id");
+        assertTrue(contains(message, audio));
+        assertMultipartFilename(message, "audio", "audio.mp3");
+        assertMultipartText(message, "title", "Audio");
     }
 
     @Test
     public void testRouteWithVideo() throws Exception {
-
-        TelegramService service = mockTelegramService();
+        final MockProcessor<byte[]> mockProcessor = getMockRoutes().getMock("sendVideo");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TITLE_CAPTION, "Video");
@@ -121,21 +118,19 @@ public class TelegramProducerMediaTest extends TelegramTestSupport {
         byte[] video = TelegramTestUtil.createSampleVideo();
         ex.getIn().setBody(video);
 
-        context().createProducerTemplate().send(endpoint, ex);
-
-        ArgumentCaptor<OutgoingVideoMessage> captor = ArgumentCaptor.forClass(OutgoingVideoMessage.class);
+        template.send(endpoint, ex);
 
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals(video, captor.getValue().getVideo());
-        assertEquals("video.mp4", captor.getValue().getFilenameWithExtension());
-        assertEquals("Video", captor.getValue().getCaption());
+        final byte[] message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertMultipartText(message, "chat_id", "my-id");
+        assertTrue(contains(message, video));
+        assertMultipartFilename(message, "video", "video.mp4");
+        assertMultipartText(message, "caption", "Video");
     }
 
     @Test
     public void testRouteWithDocument() throws Exception {
-
-        TelegramService service = mockTelegramService();
+        final MockProcessor<byte[]> mockProcessor = getMockRoutes().getMock("sendDocument");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TITLE_CAPTION, "Document");
@@ -143,108 +138,151 @@ public class TelegramProducerMediaTest extends TelegramTestSupport {
         byte[] document = TelegramTestUtil.createSampleDocument();
         ex.getIn().setBody(document);
 
-        context().createProducerTemplate().send(endpoint, ex);
+        template.send(endpoint, ex);
 
-        ArgumentCaptor<OutgoingDocumentMessage> captor = ArgumentCaptor.forClass(OutgoingDocumentMessage.class);
-
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals(document, captor.getValue().getDocument());
-        assertEquals("file", captor.getValue().getFilenameWithExtension());
-        assertEquals("Document", captor.getValue().getCaption());
+        final byte[] message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertMultipartText(message, "chat_id", "my-id");
+        assertTrue(contains(message, document));
+        assertMultipartFilename(message, "document", "file");
+        assertMultipartText(message, "caption", "Document");
     }
 
     @Test
     public void testRouteWithText() throws Exception {
-
-        TelegramService service = mockTelegramService();
+        final MockProcessor<OutgoingTextMessage> mockProcessor = getMockRoutes().getMock("sendMessage");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TYPE, TelegramMediaType.TEXT.name());
         ex.getIn().setBody("Hello");
 
-        context().createProducerTemplate().send(endpoint, ex);
-
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
+        template.send(endpoint, ex);
 
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals("Hello", captor.getValue().getText());
-        assertNull(captor.getValue().getParseMode());
+        final OutgoingTextMessage message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertEquals("my-id", message.getChatId());
+        assertEquals("Hello", message.getText());
+        assertNull(message.getParseMode());
     }
-    
+
     @Test
     public void testRouteWithTextAndCustomKeyBoard() throws Exception {
-
-        TelegramService service = mockTelegramService();
+        final MockProcessor<OutgoingTextMessage> mockProcessor = getMockRoutes().getMock("sendMessage");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
 
         OutgoingTextMessage msg = new OutgoingTextMessage.Builder().text("Hello").build();
         withInlineKeyboardContainingTwoRows(msg);
-        
-        ex.getIn().setBody(msg);
 
-        context().createProducerTemplate().send(endpoint, ex);
+        ex.getIn().setBody(msg);
 
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
+        template.send(endpoint, ex);
 
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals("Hello", captor.getValue().getText());
-        assertEquals(2, captor.getValue().getReplyKeyboardMarkup().getKeyboard().size());
-        assertEquals(true, captor.getValue().getReplyKeyboardMarkup().getOneTimeKeyboard());
-        assertNull(captor.getValue().getParseMode());
-    }    
+        final OutgoingTextMessage message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertEquals("my-id", message.getChatId());
+        assertEquals("Hello", message.getText());
+        assertEquals(2, message.getReplyKeyboardMarkup().getKeyboard().size());
+        assertEquals(true, message.getReplyKeyboardMarkup().getOneTimeKeyboard());
+        assertNull(message.getParseMode());
+    }
 
     @Test
     public void testRouteWithTextHtml() throws Exception {
-
-        TelegramService service = mockTelegramService();
+        final MockProcessor<OutgoingTextMessage> mockProcessor = getMockRoutes().getMock("sendMessage");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TYPE, TelegramMediaType.TEXT.name());
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_PARSE_MODE, TelegramParseMode.HTML.name());
         ex.getIn().setBody("Hello");
 
-        context().createProducerTemplate().send(endpoint, ex);
+        template.send(endpoint, ex);
 
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
-
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals("Hello", captor.getValue().getText());
-        assertEquals("HTML", captor.getValue().getParseMode());
+        final OutgoingTextMessage message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertEquals("my-id", message.getChatId());
+        assertEquals("Hello", message.getText());
+        assertEquals("HTML", message.getParseMode());
     }
 
     @Test
     public void testRouteWithTextMarkdown() throws Exception {
-
-        TelegramService service = mockTelegramService();
+        final MockProcessor<OutgoingTextMessage> mockProcessor = getMockRoutes().getMock("sendMessage");
+        mockProcessor.clearRecordedMessages();
 
         Exchange ex = endpoint.createExchange();
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_MEDIA_TYPE, TelegramMediaType.TEXT.name());
         ex.getIn().setHeader(TelegramConstants.TELEGRAM_PARSE_MODE, TelegramParseMode.MARKDOWN);
         ex.getIn().setBody("Hello");
 
-        context().createProducerTemplate().send(endpoint, ex);
+        template.send(endpoint, ex);
 
-        ArgumentCaptor<OutgoingTextMessage> captor = ArgumentCaptor.forClass(OutgoingTextMessage.class);
+        final OutgoingTextMessage message = mockProcessor.awaitRecordedMessages(1, 5000).get(0);
+        assertEquals("my-id", message.getChatId());
+        assertEquals("Hello", message.getText());
+        assertEquals("Markdown", message.getParseMode());
+    }
 
-        Mockito.verify(service).sendMessage(eq("mock-token"), captor.capture());
-        assertEquals("my-id", captor.getValue().getChatId());
-        assertEquals("Hello", captor.getValue().getText());
-        assertEquals("Markdown", captor.getValue().getParseMode());
+    @Override
+    protected RoutesBuilder[] createRouteBuilders() throws Exception {
+        return new RoutesBuilder[] {
+            getMockRoutes(),
+            new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("direct:telegram").to("telegram:bots?authorizationToken=mock-token&chatId=my-id");
+                }
+            }};
     }
 
     @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("direct:telegram").to("telegram:bots?authorizationToken=mock-token&chatId=my-id");
-            }
-        };
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "sendPhoto",
+                        "POST",
+                        byte[].class,
+                        TelegramTestUtil.stringResource("messages/send-photo.json"))
+                .addEndpoint(
+                        "sendAudio",
+                        "POST",
+                        byte[].class,
+                        TelegramTestUtil.stringResource("messages/send-audio.json"))
+                .addEndpoint(
+                        "sendVideo",
+                        "POST",
+                        byte[].class,
+                        TelegramTestUtil.stringResource("messages/send-video.json"))
+                .addEndpoint(
+                        "sendDocument",
+                        "POST",
+                        byte[].class,
+                        TelegramTestUtil.stringResource("messages/send-document.json"))
+                .addEndpoint(
+                        "sendMessage",
+                        "POST",
+                        OutgoingTextMessage.class,
+                        TelegramTestUtil.stringResource("messages/send-message.json"));
     }
 
+    static void assertMultipartFilename(byte[] message, String name, String filename) {
+        assertTrue(contains(message, ("name=\"" + name + "\"; filename=\"" + filename + "\"").getBytes(StandardCharsets.UTF_8)));
+    }
+    static void assertMultipartText(byte[] message, String key, String value) {
+        assertTrue(contains(message, ("name=\"" + key + "\"\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n" + value)
+                .getBytes(StandardCharsets.UTF_8)));
+    }
+    static boolean contains(byte[] array, byte[] target) {
+        if (target.length == 0) {
+            return true;
+        }
+        OUTER_FOR: for (int i = 0; i < array.length - target.length + 1; i++) {
+            for (int j = 0; j < target.length; j++) {
+                if (array[i + j] != target[j]) {
+                    continue OUTER_FOR;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramWebhookRegistrationTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramWebhookRegistrationTest.java
index 6c945c2..9d6d98e 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramWebhookRegistrationTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramWebhookRegistrationTest.java
@@ -16,19 +16,26 @@
  */
 package org.apache.camel.component.telegram;
 
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.ServiceStatus;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.telegram.model.WebhookInfo;
+import org.apache.camel.component.telegram.model.WebhookResult;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes;
+import org.apache.camel.component.telegram.util.TelegramMockRoutes.MockProcessor;
 import org.apache.camel.component.telegram.util.TelegramTestSupport;
+import org.apache.camel.component.telegram.util.TelegramTestUtil;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.asynchttpclient.Dsl;
+import org.asynchttpclient.Response;
+import org.awaitility.Awaitility;
 import org.junit.jupiter.api.Test;
 
 import static org.awaitility.Awaitility.waitAtMost;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 
 /**
  * Tests a producer that sends media information.
@@ -37,39 +44,103 @@ public class TelegramWebhookRegistrationTest extends TelegramTestSupport {
 
     @Test
     public void testAutomaticRegistration() throws Exception {
-        context.addRoutes(new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("webhook:telegram:bots?authorizationToken=mock-token").to("mock:endpoint");
+        final MockProcessor<WebhookInfo> mockProcessor = getMockRoutes().getMock("setWebhook");
+        mockProcessor.clearRecordedMessages();
+        try (final DefaultCamelContext mockContext = new DefaultCamelContext()) {
+            mockContext.addRoutes(getMockRoutes());
+            mockContext.start();
+
+            /* Make sure the Telegram mock API is up and running */
+            Awaitility.await()
+                    .atMost(5, TimeUnit.SECONDS)
+                    .until(() -> {
+                        final Response testResponse = Dsl.asyncHttpClient()
+                                .prepareGet("http://localhost:" + port + "/botmock-token/getTest")
+                                .execute().get();
+                        return testResponse.getStatusCode() == 200;
+                    });
+
+            context().addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("direct:telegram").to("telegram:bots?authorizationToken=mock-token");
+                    from("webhook:telegram:bots?authorizationToken=mock-token").to("mock:endpoint");
+                }
+            });
+            context().start();
+            {
+                final List<WebhookInfo> recordedMessages = mockProcessor.awaitRecordedMessages(1, 5000);
+                assertEquals(1, recordedMessages.size());
+                assertNotEquals("", recordedMessages.get(0).getUrl());
+            }
+
+            mockProcessor.clearRecordedMessages();
+            context().stop();
+            {
+                final List<WebhookInfo> recordedMessages = mockProcessor.awaitRecordedMessages(1, 5000);
+                assertEquals(1, recordedMessages.size());
+                assertEquals("", recordedMessages.get(0).getUrl());
             }
-        });
-        context().start();
-        verify(this.currentMockService()).setWebhook(eq("mock-token"), anyString());
-        context().stop();
-        waitAtMost(5, TimeUnit.SECONDS).until(() -> context().getStatus() == ServiceStatus.Stopped);
-        verify(this.currentMockService()).removeWebhook("mock-token");
+        }
     }
 
     @Test
     public void testNoRegistration() throws Exception {
-        context.addRoutes(new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("webhook:telegram:bots?authorizationToken=mock-token&webhookAutoRegister=false").to("mock:endpoint");
-            }
-        });
-        context().start();
-        verify(this.currentMockService(), never()).setWebhook(eq("mock-token"), anyString());
-        context().stop();
-        waitAtMost(5, TimeUnit.SECONDS).until(() -> context().getStatus() == ServiceStatus.Stopped);
-        verify(this.currentMockService(),  never()).removeWebhook("mock-token");
+        final MockProcessor<WebhookInfo> mockProcessor = getMockRoutes().getMock("setWebhook");
+        mockProcessor.clearRecordedMessages();
+        try (final DefaultCamelContext mockContext = new DefaultCamelContext()) {
+            mockContext.addRoutes(getMockRoutes());
+            mockContext.start();
+
+            /* Make sure the Telegram mock API is up and running */
+            Awaitility.await()
+                    .atMost(5, TimeUnit.SECONDS)
+                    .until(() -> {
+                        final Response testResponse = Dsl.asyncHttpClient()
+                                .prepareGet("http://localhost:" + port + "/botmock-token/getTest")
+                                .execute().get();
+                        return testResponse.getStatusCode() == 200;
+                    });
+
+            context().addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    from("webhook:telegram:bots?authorizationToken=mock-token&webhookAutoRegister=false").to("mock:endpoint");
+                }
+            });
+            context().start();
+
+            Awaitility.await()
+                    .pollDelay(500, TimeUnit.MILLISECONDS)
+                    .until(() -> mockProcessor.getRecordedMessages().size() == 0);
+
+            context().stop();
+
+            waitAtMost(5, TimeUnit.SECONDS).until(() -> context().getStatus() == ServiceStatus.Stopped);
+
+            Awaitility.await()
+                    .pollDelay(500, TimeUnit.MILLISECONDS)
+                    .until(() -> mockProcessor.getRecordedMessages().size() == 0);
+
+        }
     }
 
     @Override
-    protected void doPreSetup() throws Exception {
-        TelegramService api = mockTelegramService();
-        when(api.setWebhook(anyString(), anyString())).thenReturn(true);
-        when(api.removeWebhook(anyString())).thenReturn(true);
+    protected TelegramMockRoutes createMockRoutes() {
+        final WebhookResult result = new WebhookResult();
+        result.setOk(true);
+        result.setResult(true);
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "getTest",
+                        "GET",
+                        String.class,
+                        "running")
+                .addEndpoint(
+                        "setWebhook",
+                        "POST",
+                        WebhookInfo.class,
+                        TelegramTestUtil.serialize(result));
     }
 
     @Override
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/integration/TelegramServiceTest.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/integration/TelegramServiceTest.java
index 16f585c..0d2e517 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/integration/TelegramServiceTest.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/integration/TelegramServiceTest.java
@@ -20,8 +20,7 @@ import java.io.IOException;
 import java.util.Arrays;
 
 import org.apache.camel.component.telegram.TelegramParseMode;
-import org.apache.camel.component.telegram.TelegramService;
-import org.apache.camel.component.telegram.TelegramServiceProvider;
+import org.apache.camel.component.telegram.model.IncomingMessage;
 import org.apache.camel.component.telegram.model.InlineKeyboardButton;
 import org.apache.camel.component.telegram.model.OutgoingAudioMessage;
 import org.apache.camel.component.telegram.model.OutgoingDocumentMessage;
@@ -29,97 +28,78 @@ import org.apache.camel.component.telegram.model.OutgoingPhotoMessage;
 import org.apache.camel.component.telegram.model.OutgoingTextMessage;
 import org.apache.camel.component.telegram.model.OutgoingVideoMessage;
 import org.apache.camel.component.telegram.model.ReplyKeyboardMarkup;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.component.telegram.util.TelegramApiConfig;
+import org.apache.camel.component.telegram.util.TelegramTestSupport;
 import org.apache.camel.component.telegram.util.TelegramTestUtil;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
-/**
- * Tests if the BotAPI are working correctly.
- */
-public class TelegramServiceTest {
-
-    private static String authorizationToken;
-
-    private static String chatId;
+public class TelegramServiceTest extends TelegramTestSupport {
 
-    @BeforeAll
-    public static void init() {
-        authorizationToken = System.getenv("TELEGRAM_AUTHORIZATION_TOKEN");
-        chatId = System.getenv("TELEGRAM_CHAT_ID");
+    protected TelegramApiConfig getTelegramApiConfig() {
+        return TelegramApiConfig.fromEnv();
     }
 
     @Test
     public void testGetUpdates() {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
-        UpdateResult res = service.getUpdates(authorizationToken, null, null, null);
-
+        /* Telegram bots by design see neither their own messages nor other bots' messages.
+         * So, for this test to succeed a human should have sent some messages to the bot manually
+         * before running the test */
+        IncomingMessage res = consumer.receiveBody("telegram://bots", 5000, IncomingMessage.class);
         assertNotNull(res);
-        assertTrue(res.isOk());
     }
 
     @Test
     public void testSendMessage() {
-        TelegramService service = TelegramServiceProvider.get().getService();
 
         OutgoingTextMessage msg = new OutgoingTextMessage();
         msg.setChatId(chatId);
         msg.setText("This is an auto-generated message from the Bot");
-
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendMessageHtml() {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         OutgoingTextMessage msg = new OutgoingTextMessage();
         msg.setChatId(chatId);
         msg.setText("This is a <b>HTML</b> <i>auto-generated</i> message from the Bot");
         msg.setParseMode(TelegramParseMode.HTML.getCode());
 
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendMessageMarkdown() {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         OutgoingTextMessage msg = new OutgoingTextMessage();
         msg.setChatId(chatId);
         msg.setText("This is a *Markdown* _auto-generated_ message from the Bot");
         msg.setParseMode(TelegramParseMode.MARKDOWN.getCode());
 
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
-    
+
     @Test
     public void testSendMessageWithKeyboard() {
-        TelegramService service = TelegramServiceProvider.get().getService();
-        
         OutgoingTextMessage msg = new OutgoingTextMessage();
         msg.setChatId(chatId);
         msg.setText("Choose one option!");
-        
+
         InlineKeyboardButton buttonOptionOneI = InlineKeyboardButton.builder()
                 .text("Option One - I").build();
-        
+
         InlineKeyboardButton buttonOptionOneII = InlineKeyboardButton.builder()
                 .text("Option One - II").build();
-        
+
         InlineKeyboardButton buttonOptionTwoI = InlineKeyboardButton.builder()
                 .text("Option Two - I").build();
-        
+
         InlineKeyboardButton buttonOptionThreeI = InlineKeyboardButton.builder()
                 .text("Option Three - I").build();
-        
+
         InlineKeyboardButton buttonOptionThreeII = InlineKeyboardButton.builder()
                 .text("Option Three - II").build();
-        
+
         ReplyKeyboardMarkup replyMarkup = ReplyKeyboardMarkup.builder()
                 .keyboard()
                     .addRow(Arrays.asList(buttonOptionOneI, buttonOptionOneII))
@@ -128,33 +108,29 @@ public class TelegramServiceTest {
                     .close()
                 .oneTimeKeyboard(true)
                 .build();
-        
+
         msg.setReplyKeyboardMarkup(replyMarkup);
-        
-        service.sendMessage(authorizationToken, msg);        
+
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
-    
+
     @Test
     public void testSendMessageDisablingCustomKeyboard() {
-        TelegramService service = TelegramServiceProvider.get().getService();
-        
         OutgoingTextMessage msg = new OutgoingTextMessage();
         msg.setChatId(chatId);
         msg.setText("Your answer was accepted!");
-        
+
         ReplyKeyboardMarkup replyMarkup = ReplyKeyboardMarkup.builder()
                 .removeKeyboard(true)
                 .build();
-        
+
         msg.setReplyKeyboardMarkup(replyMarkup);
-        
-        service.sendMessage(authorizationToken, msg);        
-    }    
+
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
+    }
 
     @Test
     public void testSendFull() {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         OutgoingTextMessage msg = new OutgoingTextMessage();
         msg.setChatId(chatId);
         msg.setText("This is an *auto-generated* message from the Bot");
@@ -162,13 +138,11 @@ public class TelegramServiceTest {
         msg.setParseMode("Markdown");
         msg.setDisableNotification(false);
 
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendPhoto() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] image = TelegramTestUtil.createSampleImage("PNG");
 
         OutgoingPhotoMessage msg = new OutgoingPhotoMessage();
@@ -176,14 +150,11 @@ public class TelegramServiceTest {
         msg.setChatId(chatId);
         msg.setFilenameWithExtension("file.png");
 
-
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendPhotoFull() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] image = TelegramTestUtil.createSampleImage("PNG");
 
         OutgoingPhotoMessage msg = new OutgoingPhotoMessage();
@@ -193,14 +164,11 @@ public class TelegramServiceTest {
         msg.setCaption("Photo");
         msg.setDisableNotification(false);
 
-
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendAudio() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] audio = TelegramTestUtil.createSampleAudio();
 
         OutgoingAudioMessage msg = new OutgoingAudioMessage();
@@ -208,14 +176,11 @@ public class TelegramServiceTest {
         msg.setChatId(chatId);
         msg.setFilenameWithExtension("audio.mp3");
 
-
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendAudioFull() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] audio = TelegramTestUtil.createSampleAudio();
 
         OutgoingAudioMessage msg = new OutgoingAudioMessage();
@@ -226,13 +191,11 @@ public class TelegramServiceTest {
         msg.setDurationSeconds(5);
         msg.setPerformer("Myself");
 
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendVideo() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] video = TelegramTestUtil.createSampleVideo();
 
         OutgoingVideoMessage msg = new OutgoingVideoMessage();
@@ -240,14 +203,11 @@ public class TelegramServiceTest {
         msg.setChatId(chatId);
         msg.setFilenameWithExtension("video.mp4");
 
-
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendVideoFull() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] video = TelegramTestUtil.createSampleVideo();
 
         OutgoingVideoMessage msg = new OutgoingVideoMessage();
@@ -259,13 +219,11 @@ public class TelegramServiceTest {
         msg.setWidth(90);
         msg.setHeight(50);
 
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendDocument() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] document = TelegramTestUtil.createSampleDocument();
 
         OutgoingDocumentMessage msg = new OutgoingDocumentMessage();
@@ -273,13 +231,11 @@ public class TelegramServiceTest {
         msg.setChatId(chatId);
         msg.setFilenameWithExtension("file.txt");
 
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
     @Test
     public void testSendDocumentFull() throws IOException {
-        TelegramService service = TelegramServiceProvider.get().getService();
-
         byte[] document = TelegramTestUtil.createSampleDocument();
 
         OutgoingDocumentMessage msg = new OutgoingDocumentMessage();
@@ -288,7 +244,7 @@ public class TelegramServiceTest {
         msg.setFilenameWithExtension("file.png");
         msg.setCaption("A document");
 
-        service.sendMessage(authorizationToken, msg);
+        template.requestBody(String.format("telegram://bots?chatId=%s", chatId), msg);
     }
 
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramApiConfig.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramApiConfig.java
new file mode 100644
index 0000000..55923ac
--- /dev/null
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramApiConfig.java
@@ -0,0 +1,61 @@
+/*
+ * 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.telegram.util;
+
+import org.apache.camel.component.telegram.TelegramComponent;
+
+public class TelegramApiConfig {
+
+    private final String authorizationToken;
+    private final int port;
+    private final String baseUri;
+    private final String chatId;
+
+    public TelegramApiConfig(String baseUri, int port, String authorizationToken, String chatId) {
+        super();
+        this.baseUri = baseUri;
+        this.port = port;
+        this.authorizationToken = authorizationToken;
+        this.chatId = chatId;
+    }
+
+    public static TelegramApiConfig fromEnv() {
+        final String authorizationToken = System.getenv("TELEGRAM_AUTHORIZATION_TOKEN");
+        final String chatId = System.getenv("TELEGRAM_CHAT_ID");
+        return new TelegramApiConfig(TelegramComponent.BOT_API_DEFAULT_URL, 443, authorizationToken, chatId);
+    }
+
+    public static TelegramApiConfig mock(int port) {
+        return new TelegramApiConfig("http://localhost:" + port, port, "mock-token", "-1");
+    }
+
+    public String getAuthorizationToken() {
+        return authorizationToken;
+    }
+
+    public String getBaseUri() {
+        return baseUri;
+    }
+
+    public String getChatId() {
+        return chatId;
+    }
+
+    public int getPort() {
+        return port;
+    }
+}
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramMockRoutes.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramMockRoutes.java
new file mode 100644
index 0000000..52015a4
--- /dev/null
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramMockRoutes.java
@@ -0,0 +1,125 @@
+/*
+ * 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.telegram.util;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.awaitility.Awaitility;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TelegramMockRoutes extends RouteBuilder {
+    private static final Logger LOG = LoggerFactory.getLogger(TelegramMockRoutes.class);
+
+    private final int port;
+    private final Map<String, MockProcessor<?>> mocks = new LinkedHashMap<>();
+
+    public TelegramMockRoutes(int port) {
+        super();
+        this.port = port;
+    }
+
+    public TelegramMockRoutes addEndpoint(String path, String method, Class<?> returnType, String... responseBodies) {
+        this.mocks.put(path, new MockProcessor<>(method, path, returnType, responseBodies));
+        return this;
+    }
+
+    @Override
+    public void configure() throws Exception {
+
+        mocks.entrySet().stream().forEach(en -> {
+            from("netty-http:http://localhost:" + port + "/botmock-token/" + en.getKey() + "?httpMethodRestrict=" + en.getValue().method)
+                .process(en.getValue());
+        });
+
+    }
+
+    public static class MockProcessor<T> implements Processor {
+        private final String method;
+        private final String path;
+        private final List<T> recordedMessages = new ArrayList<>();
+        private final String[] responseBodies;
+        private final Object lock = new Object();
+        private final Class<?> returnType;
+
+        public MockProcessor(String method, String path, Class<T> returnType, String... responseBodies) {
+            this.method = method;
+            this.path = path;
+            this.returnType = returnType;
+            this.responseBodies = responseBodies;
+        }
+
+        @Override
+        public void process(Exchange exchange) throws Exception {
+            synchronized (lock) {
+                final Message m = exchange.getMessage();
+                final int responseIndex = Math.min(recordedMessages.size(), responseBodies.length - 1);
+                if (returnType == byte[].class) {
+                    recordedMessages.add((T) m.getBody(byte[].class));
+                } else {
+                    final String rawBody = m.getBody(String.class);
+                    LOG.debug("Recording {} {} body {}", method, path, rawBody);
+                    @SuppressWarnings("unchecked")
+                    final T body = returnType != String.class ? (T) new ObjectMapper().readValue(rawBody, returnType) : (T) rawBody;
+                    recordedMessages.add(body);
+                    final byte[] bytes = responseBodies[responseIndex].getBytes(StandardCharsets.UTF_8);
+                    m.setBody(bytes);
+                    m.setHeader("Content-Length", bytes.length);
+                    m.setHeader("Content-Type", "application/json; charset=UTF-8");
+                }
+            }
+        }
+
+        public void clearRecordedMessages() {
+            synchronized (lock) {
+                recordedMessages.clear();
+            }
+        }
+        public List<T> getRecordedMessages() {
+            synchronized (lock) {
+                return new ArrayList<T>(recordedMessages);
+            }
+        }
+
+        public List<T> awaitRecordedMessages(int count, long timeoutMillis) {
+            return Awaitility.await()
+                    .atMost(timeoutMillis, TimeUnit.MILLISECONDS)
+                    .until(() -> getRecordedMessages(), msgs -> msgs.size() >= count);
+        }
+
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> MockProcessor<T> getMock(String path) {
+        return (MockProcessor<T>) mocks.get(path);
+    }
+
+}
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestSupport.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestSupport.java
index 0de4aff..298a346 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestSupport.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestSupport.java
@@ -21,84 +21,57 @@ import java.io.InputStream;
 import java.util.Arrays;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.camel.component.telegram.TelegramService;
-import org.apache.camel.component.telegram.TelegramServiceProvider;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.telegram.TelegramComponent;
 import org.apache.camel.component.telegram.model.InlineKeyboardButton;
 import org.apache.camel.component.telegram.model.OutgoingTextMessage;
 import org.apache.camel.component.telegram.model.ReplyKeyboardMarkup;
+import org.apache.camel.test.AvailablePortFinder;
 import org.apache.camel.test.junit5.CamelTestSupport;
-import org.mockito.Mockito;
+import org.junit.jupiter.api.BeforeAll;
 
 /**
  * A support test class for Telegram tests.
  */
 public class TelegramTestSupport extends CamelTestSupport {
 
-    /**
-     * Indicates whether the {@code TelegramService} has been mocked during last test.
-     */
-    private boolean telegramServiceMocked;
+    protected static volatile int port;
 
-    /**
-     * Restores the status of {@code TelegramServiceProvider} if it has been mocked.
-     */
-    @Override
-    public void doPostTearDown() throws Exception {
-        if (telegramServiceMocked) {
-            TelegramServiceProvider.get().restoreDefaultService();
-            this.telegramServiceMocked = false;
-        }
-    }
-
-    /**
-     * Setup an alternative mock {@code TelegramService} in the {@code TelegramServiceProvider} and return it.
-     *
-     * @return the mock service
-     */
-    public TelegramService mockTelegramService() {
-        TelegramService mockService = Mockito.mock(TelegramService.class);
-        TelegramServiceProvider.get().setAlternativeService(mockService);
-        this.telegramServiceMocked = true;
+    protected String chatId;
+    private TelegramMockRoutes mockRoutes;
 
-        return mockService;
+    @BeforeAll
+    public static void initPort() throws Exception {
+        port = AvailablePortFinder.getNextAvailable();
     }
-    
+
     /**
      * Construct an inline keyboard sample to be used with an OutgoingTextMessage.
-     * 
+     *
      * @param message OutgoingTextMessage previously created
      * @return OutgoingTextMessage set with an inline keyboard
      */
     public OutgoingTextMessage withInlineKeyboardContainingTwoRows(OutgoingTextMessage message) {
-        
+
         InlineKeyboardButton buttonOptionOneI = InlineKeyboardButton.builder()
                 .text("Option One - I").build();
-        
+
         InlineKeyboardButton buttonOptionOneII = InlineKeyboardButton.builder()
                 .text("Option One - II").build();
-        
+
         InlineKeyboardButton buttonOptionTwoI = InlineKeyboardButton.builder()
                 .text("Option Two - I").build();
-        
+
         ReplyKeyboardMarkup replyMarkup = ReplyKeyboardMarkup.builder()
                 .keyboard()
                     .addRow(Arrays.asList(buttonOptionOneI, buttonOptionOneII))
                     .addRow(Arrays.asList(buttonOptionTwoI))
                     .close()
                 .oneTimeKeyboard(true)
-                .build();        
-        message.setReplyKeyboardMarkup(replyMarkup);        
-        
-        return message;
-    }
+                .build();
+        message.setReplyKeyboardMarkup(replyMarkup);
 
-    /**
-     * Retrieves the currently mocked {@code TelegramService}.
-     *
-     * @return the current mock of the telegram service
-     */
-    public TelegramService currentMockService() {
-        return TelegramServiceProvider.get().getAlternativeService();
+        return message;
     }
 
     /**
@@ -109,9 +82,9 @@ public class TelegramTestSupport extends CamelTestSupport {
      * @param <T> the type of the returned object
      * @return the object representation of the JSON file
      */
-    public <T> T getJSONResource(String fileName, Class<T> clazz) {
+    public static <T> T getJSONResource(String fileName, Class<T> clazz) {
         ObjectMapper mapper = new ObjectMapper();
-        try (InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName)) {
+        try (InputStream stream = TelegramTestSupport.class.getClassLoader().getResourceAsStream(fileName)) {
             T value = mapper.readValue(stream, clazz);
             return value;
         } catch (IOException e) {
@@ -119,4 +92,34 @@ public class TelegramTestSupport extends CamelTestSupport {
         }
     }
 
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        final CamelContext context = super.createCamelContext();
+        final TelegramComponent component = new TelegramComponent();
+
+        TelegramApiConfig apiConfig = getTelegramApiConfig();
+        component.setBaseUri(apiConfig.getBaseUri());
+        component.setAuthorizationToken(apiConfig.getAuthorizationToken());
+        this.chatId = apiConfig.getChatId();
+
+        context.addComponent("telegram", component);
+        return context;
+    }
+
+    protected TelegramApiConfig getTelegramApiConfig() {
+        return TelegramApiConfig.mock(port);
+    }
+
+    protected TelegramMockRoutes getMockRoutes() {
+        if (mockRoutes == null) {
+            mockRoutes = createMockRoutes();
+        }
+        return mockRoutes;
+    }
+
+    protected TelegramMockRoutes createMockRoutes() {
+        throw new UnsupportedOperationException();
+    }
+
+
 }
diff --git a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestUtil.java b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestUtil.java
index 9f4a393..b5630da 100644
--- a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestUtil.java
+++ b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/util/TelegramTestUtil.java
@@ -16,9 +16,17 @@
  */
 package org.apache.camel.component.telegram.util;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
 
-import org.apache.cxf.helpers.IOUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.util.IOHelper;
 
 /**
  * Utility functions for telegram tests.
@@ -38,9 +46,9 @@ public final class TelegramTestUtil {
     public static byte[] createSampleImage(String imageIOType) throws IOException {
         byte[] img;
         if (imageIOType.equalsIgnoreCase("png")) {
-            img = IOUtils.readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.png"));
+            img = readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.png"));
         } else if (imageIOType.equalsIgnoreCase("jpg")) {
-            img = IOUtils.readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.jpg"));
+            img = readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.jpg"));
         } else {
             throw new IllegalArgumentException("Unknown format " + imageIOType);
         }
@@ -48,18 +56,40 @@ public final class TelegramTestUtil {
     }
 
 
+    private static byte[] readBytesFromStream(InputStream in) throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream(IOHelper.DEFAULT_BUFFER_SIZE);
+        IOHelper.copy(in, out, IOHelper.DEFAULT_BUFFER_SIZE);
+        return out.toByteArray();
+    }
+
     public static byte[] createSampleAudio() throws IOException {
-        byte[] audio = IOUtils.readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.mp3"));
+        byte[] audio = readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.mp3"));
         return audio;
     }
 
     public static byte[] createSampleVideo() throws IOException {
-        byte[] video = IOUtils.readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.mp4"));
+        byte[] video = readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.mp4"));
         return video;
     }
 
     public static byte[] createSampleDocument() throws IOException {
-        byte[] document = IOUtils.readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.txt"));
+        byte[] document = readBytesFromStream(TelegramTestUtil.class.getResourceAsStream("/attachments/sample.txt"));
         return document;
     }
+
+    public static String stringResource(String path) {
+        try (Reader r = new InputStreamReader(TelegramTestUtil.class.getClassLoader().getResourceAsStream(path), StandardCharsets.UTF_8)) {
+            return IOHelper.toString(r);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String serialize(Object result) {
+        try {
+            return new ObjectMapper().writeValueAsString(result);
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/components/camel-telegram/src/test/resources/messages/edit-message-live-location.json b/components/camel-telegram/src/test/resources/messages/edit-message-live-location.json
new file mode 100644
index 0000000..a6a060d3
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/edit-message-live-location.json
@@ -0,0 +1,24 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 938,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "edit_date": 1576249601,
+        "location": {
+            "latitude": 29.974934,
+            "longitude": 31.131109
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/send-audio.json b/components/camel-telegram/src/test/resources/messages/send-audio.json
new file mode 100644
index 0000000..ed4ac2d
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/send-audio.json
@@ -0,0 +1,25 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 932,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249599,
+        "audio": {
+            "duration": 1,
+            "mime_type": "audio/mpeg",
+            "file_id": "CQADBAAD5QUAAmcaoVMYrfWhEfLFTBYE",
+            "file_size": 9657
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/send-document.json b/components/camel-telegram/src/test/resources/messages/send-document.json
new file mode 100644
index 0000000..f352d13
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/send-document.json
@@ -0,0 +1,24 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 934,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "document": {
+            "file_name": "file",
+            "file_id": "BQADBAAD5wUAAmcaoVNbRjnV8IcCmhYE",
+            "file_size": 7638
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/send-location.json b/components/camel-telegram/src/test/resources/messages/send-location.json
new file mode 100644
index 0000000..5b645a1
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/send-location.json
@@ -0,0 +1,23 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 938,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "location": {
+            "latitude": 29.974830,
+            "longitude": 31.138579
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/send-message.json b/components/camel-telegram/src/test/resources/messages/send-message.json
new file mode 100644
index 0000000..8f37da2
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/send-message.json
@@ -0,0 +1,20 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 937,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "text": "A message from camel-quarkus-telegram ffdcc8ef72a34053a3e75daec74676a9"
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/send-photo.json b/components/camel-telegram/src/test/resources/messages/send-photo.json
new file mode 100644
index 0000000..8523d11
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/send-photo.json
@@ -0,0 +1,27 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 935,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "photo": [
+            {
+                "file_id": "AgADBAADYbExG2caoVPPY5I2XKLPM3lKqBsABAEAAwIAA20AA80nBQABFgQ",
+                "file_size": 1005,
+                "width": 108,
+                "height": 10
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/send-venue.json b/components/camel-telegram/src/test/resources/messages/send-venue.json
new file mode 100644
index 0000000..f098ac2
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/send-venue.json
@@ -0,0 +1,31 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 936,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "location": {
+            "latitude": 29.977826,
+            "longitude": 31.136330
+        },
+        "venue": {
+            "location": {
+                "latitude": 29.977826,
+                "longitude": 31.136330
+            },
+            "title": "Pyramid of Queen Henutsen",
+            "address": "El-Hussein Ibn Ali Ln, Nazlet El-Semman, Al Haram, Giza Governorate, Egypt"
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/send-video.json b/components/camel-telegram/src/test/resources/messages/send-video.json
new file mode 100644
index 0000000..4f8d0ef
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/send-video.json
@@ -0,0 +1,33 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 933,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "video": {
+            "duration": 4,
+            "width": 108,
+            "height": 10,
+            "mime_type": "video/mp4",
+            "thumb": {
+                "file_id": "AAQEAAPmBQACZxqhU8LAVawXPI5dMWO3GwAEAQAHbQADcxQAAhYE",
+                "file_size": 991,
+                "width": 108,
+                "height": 10
+            },
+            "file_id": "BAADBAAD5gUAAmcaoVPCwFWsFzyOXRYE",
+            "file_size": 27845
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-telegram/src/test/resources/messages/stop-message-live-location.json b/components/camel-telegram/src/test/resources/messages/stop-message-live-location.json
new file mode 100644
index 0000000..a6a060d3
--- /dev/null
+++ b/components/camel-telegram/src/test/resources/messages/stop-message-live-location.json
@@ -0,0 +1,24 @@
+{
+    "ok": true,
+    "result": {
+        "message_id": 938,
+        "from": {
+            "id": 770882310,
+            "is_bot": true,
+            "first_name": "camelDemoBot",
+            "username": "camelDemoBot"
+        },
+        "chat": {
+            "id": 434822960,
+            "first_name": "Peter",
+            "last_name": "Palaga",
+            "type": "private"
+        },
+        "date": 1576249600,
+        "edit_date": 1576249601,
+        "location": {
+            "latitude": 29.974934,
+            "longitude": 31.131109
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/TelegramEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/TelegramEndpointBuilderFactory.java
index d00e12b..c8012c4 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/TelegramEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/TelegramEndpointBuilderFactory.java
@@ -667,6 +667,18 @@ public interface TelegramEndpointBuilderFactory {
             return this;
         }
         /**
+         * Set an alternative base URI, e.g. when you want to test the component
+         * against a mock Telegram API.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointConsumerBuilder baseUri(String baseUri) {
+            doSetProperty("baseUri", baseUri);
+            return this;
+        }
+        /**
          * Whether the endpoint should use basic property binding (Camel 2.x) or
          * the newer property binding with additional capabilities.
          * 
@@ -693,6 +705,60 @@ public interface TelegramEndpointBuilderFactory {
             return this;
         }
         /**
+         * The initial in-memory buffer size used when transferring data between
+         * Camel and AHC Client.
+         * 
+         * The option is a: <code>int</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointConsumerBuilder bufferSize(
+                int bufferSize) {
+            doSetProperty("bufferSize", bufferSize);
+            return this;
+        }
+        /**
+         * The initial in-memory buffer size used when transferring data between
+         * Camel and AHC Client.
+         * 
+         * The option will be converted to a <code>int</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointConsumerBuilder bufferSize(
+                String bufferSize) {
+            doSetProperty("bufferSize", bufferSize);
+            return this;
+        }
+        /**
+         * To configure the AsyncHttpClient to use a custom
+         * com.ning.http.client.AsyncHttpClientConfig instance.
+         * 
+         * The option is a:
+         * <code>org.asynchttpclient.AsyncHttpClientConfig</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointConsumerBuilder clientConfig(
+                Object clientConfig) {
+            doSetProperty("clientConfig", clientConfig);
+            return this;
+        }
+        /**
+         * To configure the AsyncHttpClient to use a custom
+         * com.ning.http.client.AsyncHttpClientConfig instance.
+         * 
+         * The option will be converted to a
+         * <code>org.asynchttpclient.AsyncHttpClientConfig</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointConsumerBuilder clientConfig(
+                String clientConfig) {
+            doSetProperty("clientConfig", clientConfig);
+            return this;
+        }
+        /**
          * Sets whether synchronous processing should be strictly used, or Camel
          * is allowed to use asynchronous processing (if supported).
          * 
@@ -844,6 +910,18 @@ public interface TelegramEndpointBuilderFactory {
             return (TelegramEndpointProducerBuilder) this;
         }
         /**
+         * Set an alternative base URI, e.g. when you want to test the component
+         * against a mock Telegram API.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointProducerBuilder baseUri(String baseUri) {
+            doSetProperty("baseUri", baseUri);
+            return this;
+        }
+        /**
          * Whether the endpoint should use basic property binding (Camel 2.x) or
          * the newer property binding with additional capabilities.
          * 
@@ -870,6 +948,60 @@ public interface TelegramEndpointBuilderFactory {
             return this;
         }
         /**
+         * The initial in-memory buffer size used when transferring data between
+         * Camel and AHC Client.
+         * 
+         * The option is a: <code>int</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointProducerBuilder bufferSize(
+                int bufferSize) {
+            doSetProperty("bufferSize", bufferSize);
+            return this;
+        }
+        /**
+         * The initial in-memory buffer size used when transferring data between
+         * Camel and AHC Client.
+         * 
+         * The option will be converted to a <code>int</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointProducerBuilder bufferSize(
+                String bufferSize) {
+            doSetProperty("bufferSize", bufferSize);
+            return this;
+        }
+        /**
+         * To configure the AsyncHttpClient to use a custom
+         * com.ning.http.client.AsyncHttpClientConfig instance.
+         * 
+         * The option is a:
+         * <code>org.asynchttpclient.AsyncHttpClientConfig</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointProducerBuilder clientConfig(
+                Object clientConfig) {
+            doSetProperty("clientConfig", clientConfig);
+            return this;
+        }
+        /**
+         * To configure the AsyncHttpClient to use a custom
+         * com.ning.http.client.AsyncHttpClientConfig instance.
+         * 
+         * The option will be converted to a
+         * <code>org.asynchttpclient.AsyncHttpClientConfig</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointProducerBuilder clientConfig(
+                String clientConfig) {
+            doSetProperty("clientConfig", clientConfig);
+            return this;
+        }
+        /**
          * Sets whether synchronous processing should be strictly used, or Camel
          * is allowed to use asynchronous processing (if supported).
          * 
@@ -965,6 +1097,18 @@ public interface TelegramEndpointBuilderFactory {
             return (TelegramEndpointBuilder) this;
         }
         /**
+         * Set an alternative base URI, e.g. when you want to test the component
+         * against a mock Telegram API.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointBuilder baseUri(String baseUri) {
+            doSetProperty("baseUri", baseUri);
+            return this;
+        }
+        /**
          * Whether the endpoint should use basic property binding (Camel 2.x) or
          * the newer property binding with additional capabilities.
          * 
@@ -991,6 +1135,56 @@ public interface TelegramEndpointBuilderFactory {
             return this;
         }
         /**
+         * The initial in-memory buffer size used when transferring data between
+         * Camel and AHC Client.
+         * 
+         * The option is a: <code>int</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointBuilder bufferSize(int bufferSize) {
+            doSetProperty("bufferSize", bufferSize);
+            return this;
+        }
+        /**
+         * The initial in-memory buffer size used when transferring data between
+         * Camel and AHC Client.
+         * 
+         * The option will be converted to a <code>int</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointBuilder bufferSize(String bufferSize) {
+            doSetProperty("bufferSize", bufferSize);
+            return this;
+        }
+        /**
+         * To configure the AsyncHttpClient to use a custom
+         * com.ning.http.client.AsyncHttpClientConfig instance.
+         * 
+         * The option is a:
+         * <code>org.asynchttpclient.AsyncHttpClientConfig</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointBuilder clientConfig(Object clientConfig) {
+            doSetProperty("clientConfig", clientConfig);
+            return this;
+        }
+        /**
+         * To configure the AsyncHttpClient to use a custom
+         * com.ning.http.client.AsyncHttpClientConfig instance.
+         * 
+         * The option will be converted to a
+         * <code>org.asynchttpclient.AsyncHttpClientConfig</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedTelegramEndpointBuilder clientConfig(String clientConfig) {
+            doSetProperty("clientConfig", clientConfig);
+            return this;
+        }
+        /**
          * Sets whether synchronous processing should be strictly used, or Camel
          * is allowed to use asynchronous processing (if supported).
          * 
diff --git a/docs/components/modules/ROOT/pages/telegram-component.adoc b/docs/components/modules/ROOT/pages/telegram-component.adoc
index 9124bf2..26fd3de 100644
--- a/docs/components/modules/ROOT/pages/telegram-component.adoc
+++ b/docs/components/modules/ROOT/pages/telegram-component.adoc
@@ -49,7 +49,7 @@ You can append query options to the URI in the following format,
 == Options
 
 // component options: START
-The Telegram component supports 4 options, which are listed below.
+The Telegram component supports 7 options, which are listed below.
 
 
 
@@ -57,6 +57,9 @@ The Telegram component supports 4 options, which are listed below.
 |===
 | Name | Description | Default | Type
 | *authorizationToken* (security) | The default Telegram authorization token to be used when the information is not provided in the endpoints. |  | String
+| *client* (advanced) | To use a custom AsyncHttpClient |  | AsyncHttpClient
+| *clientConfig* (advanced) | To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance. |  | AsyncHttpClientConfig
+| *baseUri* (common) | Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API. |  | String
 | *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | 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 [...]
 | *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
@@ -84,7 +87,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (28 parameters):
+=== Query Parameters (31 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -99,7 +102,10 @@ with the following path and query parameters:
 | *pollStrategy* (consumer) | A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel. |  | PollingConsumerPollStrategy
 | *chatId* (producer) | The identifier of the chat that will receive the produced messages. Chat ids can be first obtained from incoming messages (eg. when a telegram user starts a conversation with a bot, its client sends automatically a '/start' message containing the chat id). It is an optional parameter, as the chat id can be set dynamically for each outgoing message (using body or headers). |  | String
 | *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 [...]
+| *baseUri* (advanced) | Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API. |  | String
 | *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *bufferSize* (advanced) | The initial in-memory buffer size used when transferring data between Camel and AHC Client. | 4096 | int
+| *clientConfig* (advanced) | To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance. |  | AsyncHttpClientConfig
 | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
 | *backoffErrorThreshold* (scheduler) | The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in. |  | int
 | *backoffIdleThreshold* (scheduler) | The number of subsequent idle polls that should happen before the backoffMultipler should kick-in. |  | int
@@ -136,7 +142,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 
 
-The component supports 5 options, which are listed below.
+The component supports 8 options, which are listed below.
 
 
 
@@ -144,8 +150,11 @@ The component supports 5 options, which are listed below.
 |===
 | Name | Description | Default | Type
 | *camel.component.telegram.authorization-token* | The default Telegram authorization token to be used when the information is not provided in the endpoints. |  | String
+| *camel.component.telegram.base-uri* | Set an alternative base URI, e.g. when you want to test the component against a mock Telegram API. |  | String
 | *camel.component.telegram.basic-property-binding* | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | Boolean
 | *camel.component.telegram.bridge-error-handler* | 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
+| *camel.component.telegram.client* | To use a custom AsyncHttpClient. The option is a org.asynchttpclient.AsyncHttpClient type. |  | String
+| *camel.component.telegram.client-config* | To configure the AsyncHttpClient to use a custom com.ning.http.client.AsyncHttpClientConfig instance. The option is a org.asynchttpclient.AsyncHttpClientConfig type. |  | String
 | *camel.component.telegram.enabled* | Whether to enable auto configuration of the telegram component. This is enabled by default. |  | Boolean
 | *camel.component.telegram.lazy-start-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 t [...]
 |===
diff --git a/examples/camel-example-telegram/src/main/java/org/apache/camel/example/telegram/usage/GetUpdatesUsage.java b/examples/camel-example-telegram/src/main/java/org/apache/camel/example/telegram/usage/GetUpdatesUsage.java
index 8fec138..2aa321c 100644
--- a/examples/camel-example-telegram/src/main/java/org/apache/camel/example/telegram/usage/GetUpdatesUsage.java
+++ b/examples/camel-example-telegram/src/main/java/org/apache/camel/example/telegram/usage/GetUpdatesUsage.java
@@ -17,17 +17,16 @@
 package org.apache.camel.example.telegram.usage;
 
 import org.apache.camel.CamelContext;
-import org.apache.camel.component.telegram.TelegramService;
-import org.apache.camel.component.telegram.TelegramServiceProvider;
-import org.apache.camel.component.telegram.model.UpdateResult;
+import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.component.telegram.model.Update;
 import org.apache.camel.example.telegram.Application;
 
 public class GetUpdatesUsage implements TelegramMethodUsage {
 
     @Override
     public void run(CamelContext context) {
-        TelegramService service = TelegramServiceProvider.get().getService();
-        UpdateResult message = service.getUpdates(Application.AUTHORIZATION_TOKEN, (long) 10, 10, 10);
+        ConsumerTemplate template = context.createConsumerTemplate();
+        Update message = template.receiveBodyNoWait(String.format("telegram:bots/?authorizationToken=%s&chatId=%s", Application.AUTHORIZATION_TOKEN, Application.CHAT_ID), Update.class);
         System.out.println(message);
     }
 }
diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml
index 90e1e3d..1260f53 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -2493,13 +2493,26 @@
   <feature name='camel-telegram' version='${project.version}' start-level='50'>
     <feature version='${project.version}'>camel-core</feature>
     <feature version='${project.version}'>camel-webhook</feature>
-    <feature version='${cxf-version-range}'>cxf-core</feature>
-    <feature version='${cxf-version-range}'>cxf-jaxrs</feature>
     <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-core/${jackson2-version}</bundle>
     <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-databind/${jackson2-version}</bundle>
     <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson2-version}</bundle>
-    <bundle dependency='true'>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson2-version}</bundle>
-    <bundle dependency='true'>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson2-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:org.asynchttpclient/async-http-client/${ahc-version}$Export-Package=org.asynchttpclient.*;version=${ahc-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:org.asynchttpclient/async-http-client-netty-utils/${ahc-version}$Export-Package=org.asynchttpclient.netty.util.*;version=${ahc-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-buffer/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-codec/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-codec-dns/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-codec-http/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-codec-socks/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-common/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-handler/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-handler-proxy/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-resolver/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-transport/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-transport-native-epoll/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-transport-native-kqueue/${netty-version}</bundle>
+    <bundle dependency='true'>mvn:io.netty/netty-transport-native-unix-common/${netty-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:com.typesafe.netty/netty-reactive-streams/${netty-reactive-streams-version}</bundle>
+    <bundle dependency='true'>mvn:org.reactivestreams/reactive-streams/${reactive-streams-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-telegram/${project.version}</bundle>
   </feature>
   <feature name='camel-test' version='${project.version}' start-level='50'>
diff --git a/pom.xml b/pom.xml
index 92f83a7..935db06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -752,6 +752,8 @@
                                 <exclude>**/cacerts</exclude>
                                 <exclude>**/*.p12</exclude>
                                 <exclude>**/*.txt</exclude>
+                                <exclude>**/*.mp3</exclude>
+                                <exclude>**/*.mp4</exclude>
                                 <exclude>.mvn/**</exclude>
                                 <exclude>mvnw*</exclude>
                                 <exclude>**/META-INF/persistence*.xsd</exclude>