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

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


The following commit(s) were added to refs/heads/camel-4.18.x by this push:
     new 97a92844f0cb [backport camel-4.18.x] CAMEL-26027: camel-telegram - 
concurrent sends through one endpoint each build their own request (#28335)
97a92844f0cb is described below

commit 97a92844f0cb717410dcfa969a88a6af9a17769d
Author: Guillaume Nodet <[email protected]>
AuthorDate: Mon Nov 2 09:56:40 2026 +0100

    [backport camel-4.18.x] CAMEL-26027: camel-telegram - concurrent sends 
through one endpoint each build their own request (#28335)
    
    …s through one endpoint each build their own request
    
    …18.x
---
 .../telegram/service/OutgoingMessageHandler.java   |   8 +-
 .../telegram/service/TelegramHandlerRegistry.java  |   2 +-
 .../telegram/service/TelegramMessageHandler.java   |  17 +---
 .../service/TelegramServiceRestBotAPIAdapter.java  |  58 ++++++------
 .../telegram/TelegramProducerConcurrentTest.java   | 100 +++++++++++++++++++++
 5 files changed, 138 insertions(+), 47 deletions(-)

diff --git 
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/OutgoingMessageHandler.java
 
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/OutgoingMessageHandler.java
index 2daa1d77fbe1..18e22962f29e 100644
--- 
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/OutgoingMessageHandler.java
+++ 
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/OutgoingMessageHandler.java
@@ -27,10 +27,10 @@ abstract class OutgoingMessageHandler<T extends 
OutgoingMessage> extends Telegra
         super(apiClient, uri, contentType, resultClass);
     }
 
-    protected void fillCommonMediaParts(OutgoingMessage message) {
+    protected void fillCommonMediaParts(TelegramBodyPublisher bodyPublisher, 
OutgoingMessage message) {
 
-        buildTextPart("chat_id", message.getChatId());
-        buildTextPart("reply_to_message_id", message.getReplyToMessageId());
-        buildTextPart("disable_notification", 
message.getDisableNotification());
+        buildTextPart(bodyPublisher, "chat_id", message.getChatId());
+        buildTextPart(bodyPublisher, "reply_to_message_id", 
message.getReplyToMessageId());
+        buildTextPart(bodyPublisher, "disable_notification", 
message.getDisableNotification());
     }
 }
diff --git 
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramHandlerRegistry.java
 
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramHandlerRegistry.java
index 314835d17169..628c4886cf42 100644
--- 
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramHandlerRegistry.java
+++ 
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramHandlerRegistry.java
@@ -82,7 +82,7 @@ final class TelegramHandlerRegistry {
         }
 
         @Override
-        protected void addBody(TelegramMessage message) {
+        protected void addBody(TelegramBodyPublisher bodyPublisher, 
TelegramMessage message) {
             try {
                 final String body = mapper.writeValueAsString(message);
                 bodyPublisher.addBodyPart(new 
TelegramBodyPublisher.SingleBodyPart(body));
diff --git 
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramMessageHandler.java
 
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramMessageHandler.java
index fea04895e7ff..e019f705059c 100644
--- 
a/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramMessageHandler.java
+++ 
b/components/camel-telegram/src/main/java/org/apache/camel/component/telegram/service/TelegramMessageHandler.java
@@ -29,7 +29,6 @@ import 
org.apache.camel.component.telegram.model.MessageResult;
 
 abstract class TelegramMessageHandler<T extends TelegramMessage> {
     protected final ObjectMapper mapper;
-    protected final TelegramBodyPublisher bodyPublisher;
 
     private final TelegramApiClient apiClient;
     private final String contentType;
@@ -43,14 +42,14 @@ abstract class TelegramMessageHandler<T extends 
TelegramMessage> {
         this.uri = uri;
         this.contentType = contentType;
         this.resultClass = resultClass;
-
-        bodyPublisher = new TelegramBodyPublisher(apiClient.bufferSize());
     }
 
     public void sendMessage(Exchange exchange, AsyncCallback callback, T 
message) {
         HttpRequest.Builder builder = 
HttpRequest.newBuilder().uri(URI.create(uri));
 
-        addBody(message);
+        // the body of this request only: the producer may send from several 
threads at once
+        TelegramBodyPublisher bodyPublisher = new 
TelegramBodyPublisher(apiClient.bufferSize());
+        addBody(bodyPublisher, message);
 
         if (bodyPublisher.getBodyParts().size() > 1) {
             builder.setHeader("Content-type", "multipart/form-data; 
boundary=\"" + bodyPublisher.getBoundary() + "\"");
@@ -77,11 +76,7 @@ abstract class TelegramMessageHandler<T extends 
TelegramMessage> {
         }
     }
 
-    protected abstract void addBody(T message);
-
-    protected <T> void buildTextPart(String name, T value) {
-        buildTextPart(bodyPublisher, name, value);
-    }
+    protected abstract void addBody(TelegramBodyPublisher bodyPublisher, T 
message);
 
     static <T> void buildTextPart(TelegramBodyPublisher bodyPublisher, String 
name, T value) {
         if (value != null) {
@@ -92,10 +87,6 @@ abstract class TelegramMessageHandler<T extends 
TelegramMessage> {
         }
     }
 
-    protected void buildMediaPart(String name, String fileNameWithExtension, 
byte[] value) {
-        buildMediaPart(bodyPublisher, name, fileNameWithExtension, value);
-    }
-
     void buildMediaPart(TelegramBodyPublisher bodyPublisher, String name, 
String fileNameWithExtension, byte[] value) {
         TelegramBodyPublisher.MultilineBodyPart<byte[]> bodyPart
                 = new TelegramBodyPublisher.MultilineBodyPart<>(name, value, 
"application/octet-stream", null);
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 a509dfbb7eb1..087e4656e393 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
@@ -236,13 +236,13 @@ public class TelegramServiceRestBotAPIAdapter implements 
TelegramService {
         }
 
         @Override
-        protected void addBody(OutgoingAudioMessage message) {
-            fillCommonMediaParts(message);
-            buildMediaPart("audio", message.getFilenameWithExtension(), 
message.getAudio());
-            buildTextPart("title", message.getTitle());
-            buildTextPart("duration", message.getDurationSeconds());
-            buildTextPart("performer", message.getPerformer());
-            buildTextPart("reply_markup", message.replyMarkupJson());
+        protected void addBody(TelegramBodyPublisher bodyPublisher, 
OutgoingAudioMessage message) {
+            fillCommonMediaParts(bodyPublisher, message);
+            buildMediaPart(bodyPublisher, "audio", 
message.getFilenameWithExtension(), message.getAudio());
+            buildTextPart(bodyPublisher, "title", message.getTitle());
+            buildTextPart(bodyPublisher, "duration", 
message.getDurationSeconds());
+            buildTextPart(bodyPublisher, "performer", message.getPerformer());
+            buildTextPart(bodyPublisher, "reply_markup", 
message.replyMarkupJson());
         }
 
     }
@@ -254,14 +254,14 @@ public class TelegramServiceRestBotAPIAdapter implements 
TelegramService {
         }
 
         @Override
-        protected void addBody(OutgoingVideoMessage message) {
-            fillCommonMediaParts(message);
-            buildMediaPart("video", message.getFilenameWithExtension(), 
message.getVideo());
-            buildTextPart("caption", message.getCaption());
-            buildTextPart("duration", message.getDurationSeconds());
-            buildTextPart("width", message.getWidth());
-            buildTextPart("height", message.getHeight());
-            buildTextPart("reply_markup", message.replyMarkupJson());
+        protected void addBody(TelegramBodyPublisher bodyPublisher, 
OutgoingVideoMessage message) {
+            fillCommonMediaParts(bodyPublisher, message);
+            buildMediaPart(bodyPublisher, "video", 
message.getFilenameWithExtension(), message.getVideo());
+            buildTextPart(bodyPublisher, "caption", message.getCaption());
+            buildTextPart(bodyPublisher, "duration", 
message.getDurationSeconds());
+            buildTextPart(bodyPublisher, "width", message.getWidth());
+            buildTextPart(bodyPublisher, "height", message.getHeight());
+            buildTextPart(bodyPublisher, "reply_markup", 
message.replyMarkupJson());
         }
     }
 
@@ -272,11 +272,11 @@ public class TelegramServiceRestBotAPIAdapter implements 
TelegramService {
         }
 
         @Override
-        protected void addBody(OutgoingDocumentMessage message) {
-            fillCommonMediaParts(message);
-            buildMediaPart("document", message.getFilenameWithExtension(), 
message.getDocument());
-            buildTextPart("caption", message.getCaption());
-            buildTextPart("reply_markup", message.replyMarkupJson());
+        protected void addBody(TelegramBodyPublisher bodyPublisher, 
OutgoingDocumentMessage message) {
+            fillCommonMediaParts(bodyPublisher, message);
+            buildMediaPart(bodyPublisher, "document", 
message.getFilenameWithExtension(), message.getDocument());
+            buildTextPart(bodyPublisher, "caption", message.getCaption());
+            buildTextPart(bodyPublisher, "reply_markup", 
message.replyMarkupJson());
         }
 
     }
@@ -288,11 +288,11 @@ public class TelegramServiceRestBotAPIAdapter implements 
TelegramService {
         }
 
         @Override
-        protected void addBody(OutgoingPhotoMessage message) {
-            fillCommonMediaParts(message);
-            buildMediaPart("photo", message.getFilenameWithExtension(), 
message.getPhoto());
-            buildTextPart("caption", message.getCaption());
-            buildTextPart("reply_markup", message.replyMarkupJson());
+        protected void addBody(TelegramBodyPublisher bodyPublisher, 
OutgoingPhotoMessage message) {
+            fillCommonMediaParts(bodyPublisher, message);
+            buildMediaPart(bodyPublisher, "photo", 
message.getFilenameWithExtension(), message.getPhoto());
+            buildTextPart(bodyPublisher, "caption", message.getCaption());
+            buildTextPart(bodyPublisher, "reply_markup", 
message.replyMarkupJson());
         }
 
     }
@@ -303,12 +303,12 @@ public class TelegramServiceRestBotAPIAdapter implements 
TelegramService {
         }
 
         @Override
-        protected void addBody(OutgoingStickerMessage message) {
-            fillCommonMediaParts(message);
+        protected void addBody(TelegramBodyPublisher bodyPublisher, 
OutgoingStickerMessage message) {
+            fillCommonMediaParts(bodyPublisher, message);
             if (message.getSticker() != null) {
-                buildTextPart("sticker", message.getSticker());
+                buildTextPart(bodyPublisher, "sticker", message.getSticker());
             } else {
-                buildMediaPart("sticker", message.getFilenameWithExtension(), 
message.getStickerImage());
+                buildMediaPart(bodyPublisher, "sticker", 
message.getFilenameWithExtension(), message.getStickerImage());
             }
         }
     }
diff --git 
a/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerConcurrentTest.java
 
b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerConcurrentTest.java
new file mode 100644
index 000000000000..eb9d9676e2d2
--- /dev/null
+++ 
b/components/camel-telegram/src/test/java/org/apache/camel/component/telegram/TelegramProducerConcurrentTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.telegram;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+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 static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Sends from several threads at once through one endpoint: each request 
carries the message of its own send only.
+ */
+public class TelegramProducerConcurrentTest extends TelegramTestSupport {
+
+    private static final int MESSAGES = 100;
+
+    @Test
+    public void testConcurrentSends() throws Exception {
+        final MockProcessor<String> mockProcessor = 
getMockRoutes().getMock("sendMessage");
+        mockProcessor.clearRecordedMessages();
+
+        ExecutorService executor = Executors.newFixedThreadPool(10);
+        try {
+            List<Future<?>> sends = new ArrayList<>();
+            for (int i = 0; i < MESSAGES; i++) {
+                final int n = i;
+                sends.add(executor.submit(() -> 
template.sendBodyAndHeader("direct:telegram", "msg-" + n,
+                        TelegramConstants.TELEGRAM_CHAT_ID, "chat-" + n)));
+            }
+            for (Future<?> send : sends) {
+                send.get(30, TimeUnit.SECONDS);
+            }
+        } finally {
+            executor.shutdownNow();
+        }
+
+        // each request is the JSON of one message, sent to the chat of that 
message
+        ObjectMapper mapper = new ObjectMapper();
+        Set<String> texts = new HashSet<>();
+        for (String request : mockProcessor.awaitRecordedMessages(MESSAGES, 
10000)) {
+            OutgoingTextMessage message = mapper.readValue(request, 
OutgoingTextMessage.class);
+            assertEquals(message.getText().replace("msg-", "chat-"), 
message.getChatId(), request);
+            texts.add(message.getText());
+        }
+        assertEquals(MESSAGES, texts.size());
+    }
+
+    @Override
+    protected RoutesBuilder[] createRouteBuilders() {
+        return new RoutesBuilder[] {
+                getMockRoutes(),
+                new RouteBuilder() {
+                    @Override
+                    public void configure() {
+                        from("direct:telegram")
+                                
.to("telegram:bots?authorizationToken=mock-token");
+                    }
+                } };
+    }
+
+    @Override
+    protected TelegramMockRoutes createMockRoutes() {
+        return new TelegramMockRoutes(port)
+                .addEndpoint(
+                        "sendMessage",
+                        "POST",
+                        String.class,
+                        
TelegramTestUtil.stringResource("messages/send-message.json"));
+    }
+}

Reply via email to