You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2023/03/22 11:32:18 UTC

[camel] branch camel-3.x created (now fdc1de89df2)

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

acosentino pushed a change to branch camel-3.x
in repository https://gitbox.apache.org/repos/asf/camel.git


      at fdc1de89df2 Upgrade to Jetty 9.4.51

This branch includes the following new commits:

     new ea9e0a451ad Not setting events for log methods on routes (#9583)
     new 497350c4dc3 [CAMEL-19014] - Fixing issue about concurrence on the SimpleLanguage  (#9531)
     new a56b1976741 Rethrow exceptions in Azure Service Bus consumer (#9593)
     new aeb95f016e0 CAMEL-19014 - Fixing issue about concurrence on the SimpleLanguage
     new fdc1de89df2 Upgrade to Jetty 9.4.51

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[camel] 04/05: CAMEL-19014 - Fixing issue about concurrence on the SimpleLanguage

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit aeb95f016e0ce46981d8e5783d5c9aa49b7f220b
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Mar 22 12:03:40 2023 +0100

    CAMEL-19014 - Fixing issue about concurrence on the SimpleLanguage
---
 .../camel/support/builder/ExpressionBuilder.java   | 36 +++++++++++++---------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
index 1ec39556bf1..4fcad2a08c5 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
@@ -20,7 +20,6 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
@@ -1594,14 +1593,12 @@ public class ExpressionBuilder {
      * @return an expression which when evaluated will return the concatenated values
      */
     public static Expression concatExpression(final Collection<Expression> expressions, final String description) {
-
         for (Expression expression : expressions) {
-            if(expression instanceof ConstantExpressionAdapter){
+            if (expression instanceof ConstantExpressionAdapter) {
                 return concatExpressionOptimized(expressions, description);
             }
         }
-
-        return concatExpressionUnoptimized(expressions,description);
+        return concatExpressionUnoptimized(expressions, description);
     }
 
     /**
@@ -1654,14 +1651,15 @@ public class ExpressionBuilder {
      * @return an expression which when evaluated will return the concatenated values
      */
     private static Expression concatExpressionOptimized(final Collection<Expression> expressions, final String description) {
-
-
         return new ExpressionAdapter() {
-
             private Collection<Object> optimized;
+            private String optimizedValue;
 
             @Override
             public Object evaluate(Exchange exchange) {
+                if (optimizedValue != null) {
+                    return optimizedValue;
+                }
                 StringBuilder buffer = new StringBuilder();
                 Collection<?> col = optimized != null ? optimized : expressions;
                 for (Object obj : col) {
@@ -1671,8 +1669,8 @@ public class ExpressionBuilder {
                         if (text != null) {
                             buffer.append(text);
                         }
-                    } else {
-                        buffer.append((String) obj);
+                    } else if (obj != null) {
+                        buffer.append(obj);
                     }
                 }
                 return buffer.toString();
@@ -1680,8 +1678,9 @@ public class ExpressionBuilder {
 
             @Override
             public void init(CamelContext context) {
-                if(optimized == null) {
+                if (optimized == null) {
                     Collection<Object> preprocessedExpression = new ArrayList<>(expressions.size());
+                    boolean constantsOnly = true;
                     for (Expression expression : expressions) {
                         expression.init(context);
                         if (expression instanceof ConstantExpressionAdapter) {
@@ -1689,16 +1688,23 @@ public class ExpressionBuilder {
                             preprocessedExpression.add(value.toString());
                         } else {
                             preprocessedExpression.add(expression);
+                            constantsOnly = false;
                         }
                     }
-                    optimized = Collections.unmodifiableCollection(preprocessedExpression);
-                }
-                else{
+                    if (constantsOnly) {
+                        StringBuilder sb = new StringBuilder();
+                        for (Object o : preprocessedExpression) {
+                            sb.append(o);
+                        }
+                        optimizedValue = sb.toString();
+                    } else {
+                        optimized = preprocessedExpression;
+                    }
+                } else {
                     for (Expression expression : expressions) {
                         expression.init(context);
                     }
                 }
-
             }
 
             @Override


[camel] 03/05: Rethrow exceptions in Azure Service Bus consumer (#9593)

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit a56b19767413dc8f07861cfdf96748943321fb12
Author: Dylan Piergies <dy...@gmail.com>
AuthorDate: Wed Mar 22 11:07:27 2023 +0000

    Rethrow exceptions in Azure Service Bus consumer (#9593)
    
    * CAMEL-19155 Re-throw exceptions in `ServiceBusConsumer`
    
    If an exception occurred during Exchange processing, the exception must
    be rethrown in the message receive and error handlers to trigger the
    `ServiceBusReceiverAsyncClient` to abandon the message so that the
    message is requeued.
    
    * Revert "CAMEL-19155 Re-throw exceptions in `ServiceBusConsumer`"
    
    This reverts commit a2efbed012935b760d56dc935c4736c2bb303e81.
    
    * CAMEL-19155 - Explicitly complete/abandon Azure Service Bus messages
    
    Taking control of message complete/abandon when auto-complete is
    enabled, since allowing the Service Bus client to do this automatically
    causes messages to be completed even if the Exchange failed because
    errors do not propagate back to the reactive message Publisher.
    
    * CAMEL-19155 - Add explanatory comment
    
    * CAMEL-19155 - Correct explanatory comment
    
    ---------
    
    Co-authored-by: Dylan Piergies <Dy...@tesco.com>
---
 .../azure/servicebus/ServiceBusConsumer.java       | 22 ++++++++++++++++++----
 .../servicebus/client/ServiceBusClientFactory.java |  7 ++++---
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java
index fcf1f5c6385..167f303b9c6 100644
--- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java
+++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/ServiceBusConsumer.java
@@ -30,14 +30,13 @@ import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.azure.servicebus.client.ServiceBusClientFactory;
 import org.apache.camel.component.azure.servicebus.client.ServiceBusReceiverAsyncClientWrapper;
 import org.apache.camel.component.azure.servicebus.operations.ServiceBusReceiverOperations;
-import org.apache.camel.spi.Synchronization;
 import org.apache.camel.support.DefaultConsumer;
 import org.apache.camel.support.SynchronizationAdapter;
 import org.apache.camel.util.ObjectHelper;
+import reactor.core.scheduler.Schedulers;
 
 public class ServiceBusConsumer extends DefaultConsumer {
 
-    private Synchronization onCompletion;
     private ServiceBusReceiverAsyncClientWrapper clientWrapper;
     private ServiceBusReceiverOperations operations;
 
@@ -55,7 +54,6 @@ public class ServiceBusConsumer extends DefaultConsumer {
     @Override
     protected void doInit() throws Exception {
         super.doInit();
-        onCompletion = new ConsumerOnCompletion();
     }
 
     @Override
@@ -139,7 +137,7 @@ public class ServiceBusConsumer extends DefaultConsumer {
 
     private void onEventListener(final ServiceBusReceivedMessage message) {
         final Exchange exchange = createServiceBusExchange(message);
-
+        final ConsumerOnCompletion onCompletion = new ConsumerOnCompletion(message);
         // add exchange callback
         exchange.adapt(ExtendedExchange.class).addOnCompletion(onCompletion);
         // use default consumer callback
@@ -202,6 +200,19 @@ public class ServiceBusConsumer extends DefaultConsumer {
     }
 
     private class ConsumerOnCompletion extends SynchronizationAdapter {
+        private final ServiceBusReceivedMessage message;
+
+        public ConsumerOnCompletion(ServiceBusReceivedMessage message) {
+            this.message = message;
+        }
+
+        @Override
+        public void onComplete(Exchange exchange) {
+            super.onComplete(exchange);
+            if (!getConfiguration().isDisableAutoComplete()) {
+                clientWrapper.complete(message).subscribeOn(Schedulers.boundedElastic()).subscribe();
+            }
+        }
 
         @Override
         public void onFailure(Exchange exchange) {
@@ -209,6 +220,9 @@ public class ServiceBusConsumer extends DefaultConsumer {
             if (cause != null) {
                 getExceptionHandler().handleException("Error during processing exchange.", exchange, cause);
             }
+            if (!getConfiguration().isDisableAutoComplete()) {
+                clientWrapper.abandon(message).subscribeOn(Schedulers.boundedElastic()).subscribe();
+            }
         }
     }
 }
diff --git a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java
index 7292bc3dce4..0e2e1161b26 100644
--- a/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java
+++ b/components/camel-azure/camel-azure-servicebus/src/main/java/org/apache/camel/component/azure/servicebus/client/ServiceBusClientFactory.java
@@ -79,9 +79,10 @@ public final class ServiceBusClientFactory {
             final ServiceBusClientBuilder busClientBuilder, final ServiceBusConfiguration configuration) {
         final ServiceBusClientBuilder.ServiceBusReceiverClientBuilder receiverClientBuilder = busClientBuilder.receiver();
 
-        if (configuration.isDisableAutoComplete()) {
-            receiverClientBuilder.disableAutoComplete();
-        }
+        // We handle auto-complete in the consumer, since we have no way to propagate errors back to the reactive
+        // pipeline messages are published on so the message would be completed even if an error occurs during Exchange
+        // processing.
+        receiverClientBuilder.disableAutoComplete();
 
         if (configuration.getServiceBusType() == ServiceBusType.queue) {
             return receiverClientBuilder.queueName(configuration.getTopicOrQueueName());


[camel] 05/05: Upgrade to Jetty 9.4.51

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit fdc1de89df22ff49fd0428f1907cc357a2be03bc
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Mar 22 12:19:54 2023 +0100

    Upgrade to Jetty 9.4.51
---
 camel-dependencies/pom.xml | 2 +-
 parent/pom.xml             | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/camel-dependencies/pom.xml b/camel-dependencies/pom.xml
index 6507ca289ce..292aa3b3808 100644
--- a/camel-dependencies/pom.xml
+++ b/camel-dependencies/pom.xml
@@ -308,7 +308,7 @@
         <jetcd-grpc-version>1.47.0</jetcd-grpc-version>
         <jetcd-guava-version>31.1-jre</jetcd-guava-version>
         <jetcd-version>0.7.3</jetcd-version>
-        <jetty9-version>9.4.50.v20221201</jetty9-version>
+        <jetty9-version>9.4.51.v20230217</jetty9-version>
         <jetty-version>${jetty9-version}</jetty-version>
         <jetty-plugin-version>${jetty-version}</jetty-plugin-version>
         <jetty-runner-groupId>org.eclipse.jetty</jetty-runner-groupId>
diff --git a/parent/pom.xml b/parent/pom.xml
index 31458b3f834..d7649b8ed0b 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -303,7 +303,7 @@
         <jetcd-grpc-version>1.47.0</jetcd-grpc-version>
         <jetcd-guava-version>31.1-jre</jetcd-guava-version>
         <jetcd-version>0.7.3</jetcd-version>
-        <jetty9-version>9.4.50.v20221201</jetty9-version>
+        <jetty9-version>9.4.51.v20230217</jetty9-version>
         <jetty-version>${jetty9-version}</jetty-version>
         <jetty-plugin-version>${jetty-version}</jetty-plugin-version>
         <jetty-runner-groupId>org.eclipse.jetty</jetty-runner-groupId>


[camel] 01/05: Not setting events for log methods on routes (#9583)

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ea9e0a451adc71677a8c92aedaa7e762c2c040c6
Author: Marcin Grzejszczak <ma...@grzejszczak.pl>
AuthorDate: Wed Mar 22 11:55:59 2023 +0100

    Not setting events for log methods on routes (#9583)
    
    without this change we are always creating an event when a log happens within a route. That corresponds to a log on a span and a counter on a metrics. The log statement is arbitrary and logs on spans should be meaningful and short in name. Same thing for metric names that should of super low cardinality. Since we can't ensure that the log statement follows these requirements (nor should we) we think that we should not set those entries on spans and create such counters.
---
 .../camel/observation/MicrometerObservationSpanAdapter.java | 13 ++-----------
 .../java/org/apache/camel/observation/ABCRouteTest.java     |  6 +++---
 .../camel/observation/CustomComponentNameRouteTest.java     |  6 +++---
 .../camel/observation/MulticastParallelRouteTest.java       |  6 +++---
 .../org/apache/camel/observation/SpanProcessorsTest.java    |  6 +++---
 5 files changed, 14 insertions(+), 23 deletions(-)

diff --git a/components/camel-observation/src/main/java/org/apache/camel/observation/MicrometerObservationSpanAdapter.java b/components/camel-observation/src/main/java/org/apache/camel/observation/MicrometerObservationSpanAdapter.java
index 1eb6c4237d2..f644f5e1674 100644
--- a/components/camel-observation/src/main/java/org/apache/camel/observation/MicrometerObservationSpanAdapter.java
+++ b/components/camel-observation/src/main/java/org/apache/camel/observation/MicrometerObservationSpanAdapter.java
@@ -111,9 +111,9 @@ public class MicrometerObservationSpanAdapter implements SpanAdapter {
             } else {
                 setError(true);
             }
-        } else {
-            observation.event(() -> getMessageNameFromFields(fields));
         }
+        // Making a log in spans / creating counters doesn't make a lot of sense
+        // This is a difference between Observation and OTel versions
     }
 
     @Override
@@ -137,15 +137,6 @@ public class MicrometerObservationSpanAdapter implements SpanAdapter {
         return observation.openScope();
     }
 
-    String getMessageNameFromFields(Map<String, ?> fields) {
-        Object eventValue = fields == null ? null : fields.get("message");
-        if (eventValue != null) {
-            return eventValue.toString();
-        }
-
-        return DEFAULT_EVENT_NAME;
-    }
-
     public void setCorrelationContextItem(String key, String value) {
         Baggage baggage = tracer.createBaggage(key);
         Span span = getTracingContext().getSpan();
diff --git a/components/camel-observation/src/test/java/org/apache/camel/observation/ABCRouteTest.java b/components/camel-observation/src/test/java/org/apache/camel/observation/ABCRouteTest.java
index 2ff64eea1a2..62a7bfa6136 100644
--- a/components/camel-observation/src/test/java/org/apache/camel/observation/ABCRouteTest.java
+++ b/components/camel-observation/src/test/java/org/apache/camel/observation/ABCRouteTest.java
@@ -24,11 +24,11 @@ import org.junit.jupiter.api.Test;
 class ABCRouteTest extends CamelMicrometerObservationTestSupport {
     private static SpanTestData[] testdata = {
             new SpanTestData().setLabel("seda:b server").setUri("seda://b").setOperation("b")
-                    .setParentId(2).addLogMessage("routing at b"),
+                    .setParentId(2),
             new SpanTestData().setLabel("seda:c server").setUri("seda://c").setOperation("c")
-                    .setParentId(2).addLogMessage("Exchange[ExchangePattern: InOut, BodyType: String, Body: Hello]"),
+                    .setParentId(2),
             new SpanTestData().setLabel("seda:a server").setUri("seda://a").setOperation("a")
-                    .setParentId(3).addLogMessage("routing at a").addLogMessage("End of routing"),
+                    .setParentId(3),
             new SpanTestData().setLabel("direct:start server").setUri("direct://start").setOperation("start")
                     .setKind(SpanKind.SERVER)
     };
diff --git a/components/camel-observation/src/test/java/org/apache/camel/observation/CustomComponentNameRouteTest.java b/components/camel-observation/src/test/java/org/apache/camel/observation/CustomComponentNameRouteTest.java
index 1144883a448..3ad1b7e4512 100644
--- a/components/camel-observation/src/test/java/org/apache/camel/observation/CustomComponentNameRouteTest.java
+++ b/components/camel-observation/src/test/java/org/apache/camel/observation/CustomComponentNameRouteTest.java
@@ -25,11 +25,11 @@ class CustomComponentNameRouteTest extends CamelMicrometerObservationTestSupport
 
     private static SpanTestData[] testdata = {
             new SpanTestData().setLabel("myseda:b server").setUri("myseda://b").setOperation("b")
-                    .setParentId(2).addLogMessage("routing at b"),
+                    .setParentId(2),
             new SpanTestData().setLabel("myseda:c server").setUri("myseda://c").setOperation("c")
-                    .setParentId(2).addLogMessage("Exchange[ExchangePattern: InOut, BodyType: String, Body: Hello]"),
+                    .setParentId(2),
             new SpanTestData().setLabel("myseda:a server").setUri("myseda://a").setOperation("a")
-                    .setParentId(3).addLogMessage("routing at a").addLogMessage("End of routing"),
+                    .setParentId(3),
             new SpanTestData().setLabel("direct:start server").setUri("direct://start").setOperation("start")
                     .setKind(SpanKind.SERVER)
     };
diff --git a/components/camel-observation/src/test/java/org/apache/camel/observation/MulticastParallelRouteTest.java b/components/camel-observation/src/test/java/org/apache/camel/observation/MulticastParallelRouteTest.java
index b55bef9166f..da08d83ad8f 100644
--- a/components/camel-observation/src/test/java/org/apache/camel/observation/MulticastParallelRouteTest.java
+++ b/components/camel-observation/src/test/java/org/apache/camel/observation/MulticastParallelRouteTest.java
@@ -25,11 +25,11 @@ class MulticastParallelRouteTest extends CamelMicrometerObservationTestSupport {
 
     private static SpanTestData[] testdata = {
             new SpanTestData().setLabel("seda:b server").setUri("seda://b").setOperation("b")
-                    .setParentId(2).addLogMessage("routing at b"),
+                    .setParentId(2),
             new SpanTestData().setLabel("seda:c server").setUri("seda://c").setOperation("c")
-                    .setParentId(2).addLogMessage("routing at c"),
+                    .setParentId(2),
             new SpanTestData().setLabel("seda:a server").setUri("seda://a").setOperation("a")
-                    .setParentId(3).addLogMessage("routing at a").addLogMessage("End of routing"),
+                    .setParentId(3),
             new SpanTestData().setLabel("direct:start server").setUri("direct://start").setOperation("start")
                     .setKind(SpanKind.SERVER)
     };
diff --git a/components/camel-observation/src/test/java/org/apache/camel/observation/SpanProcessorsTest.java b/components/camel-observation/src/test/java/org/apache/camel/observation/SpanProcessorsTest.java
index 4dee0090b3e..2eaf25f5eed 100644
--- a/components/camel-observation/src/test/java/org/apache/camel/observation/SpanProcessorsTest.java
+++ b/components/camel-observation/src/test/java/org/apache/camel/observation/SpanProcessorsTest.java
@@ -29,12 +29,12 @@ class SpanProcessorsTest extends CamelMicrometerObservationTestSupport {
 
     private static final SpanTestData[] TEST_DATA = {
             new SpanTestData().setLabel("seda:b server").setUri("seda://b").setOperation("b")
-                    .setParentId(2).addLogMessage("routing at b")
+                    .setParentId(2)
                     .addTag("b-tag", "request-header-value"),
             new SpanTestData().setLabel("seda:c server").setUri("seda://c").setOperation("c")
-                    .setParentId(2).addLogMessage("Exchange[ExchangePattern: InOut, BodyType: String, Body: Hello]"),
+                    .setParentId(2),
             new SpanTestData().setLabel("seda:a server").setUri("seda://a").setOperation("a")
-                    .setParentId(3).addLogMessage("routing at a").addLogMessage("End of routing"),
+                    .setParentId(3),
             new SpanTestData().setLabel("direct:start server").setUri("direct://start").setOperation("start")
                     .setKind(SpanKind.SERVER)
     };


[camel] 02/05: [CAMEL-19014] - Fixing issue about concurrence on the SimpleLanguage (#9531)

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 497350c4dc3385dab8c484d4cf83d949e06a7536
Author: Rhuan Rocha <rh...@gmail.com>
AuthorDate: Wed Mar 22 08:02:16 2023 -0300

    [CAMEL-19014] - Fixing issue about concurrence on the SimpleLanguage  (#9531)
    
    * CAMEL-19014 - Fixing issue about concurrence on the SimpleLanguage
    
    Signed-off-by: Rhuan Rocha <rh...@gmail.com>
    
    * CAMEL-19014 - Fixing issue about concurrence on the SimpleLanguage
    
    Signed-off-by: Rhuan Rocha <rh...@gmail.com>
    
    ---------
    
    Signed-off-by: Rhuan Rocha <rh...@gmail.com>
---
 .../builder/ExpressionBuilderConcurrencyTest.java  |  97 ++++++++++++++++++
 .../camel/support/builder/ExpressionBuilder.java   | 109 +++++++++++++++------
 2 files changed, 178 insertions(+), 28 deletions(-)

diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/ExpressionBuilderConcurrencyTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/ExpressionBuilderConcurrencyTest.java
new file mode 100644
index 00000000000..273d18245fe
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/ExpressionBuilderConcurrencyTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.builder;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.language.SimpleExpression;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ExpressionBuilderConcurrencyTest extends ContextTestSupport {
+
+    @Test
+    public void testConcatExpressionConcurrency() throws Exception {
+        MockEndpoint mockWithFailure = getMockEndpoint("mock:result");
+        mockWithFailure.expectedMinimumMessageCount(100);
+        mockWithFailure.assertIsSatisfied();
+        List<Exchange> exchanges = mockWithFailure.getExchanges();
+        exchanges.stream()
+                .forEach(exchange -> Assertions
+                        .assertEquals(
+                                "This is a test a with startLabel: `Document` endLabel: `Document` and label: `ALabel`",
+                                exchange.getMessage().getHeader("#CustomHeader", String.class)));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+
+        return new RouteBuilder() {
+            Map body = Map.of("label", "ALabel", "startLabel", "Document", "endLabel", "Document");
+            String simpleTemplate
+                    = "This is a test a with startLabel: `${body.get('startLabel')}` endLabel: `${body.get('endLabel')}` and label: `${body.get('label')}`";
+
+            @Override
+            public void configure() throws Exception {
+
+                from("timer://test-timer3?fixedRate=true&period=10&delay=1")
+                        .process(new Processor() {
+                            @Override
+                            public void process(Exchange exchange) throws Exception {
+                                exchange.getMessage().setBody(body);
+                                exchange.getMessage().setHeader("#CustomHeader", resolveTemplate(simpleTemplate, exchange));
+                            }
+                        })
+                        .to("mock:result");
+
+                from("timer://test-timer4?fixedRate=true&period=10&delay=1")
+
+                        .process(new Processor() {
+                            @Override
+                            public void process(Exchange exchange) throws Exception {
+                                exchange.getMessage().setBody(body);
+                                exchange.getMessage().setHeader("#CustomHeader", resolveTemplate(simpleTemplate, exchange));
+                            }
+                        })
+                        .to("mock:result");
+
+                from("timer://test-timer5?fixedRate=true&period=10&delay=1")
+                        .process(new Processor() {
+                            @Override
+                            public void process(Exchange exchange) throws Exception {
+                                exchange.getMessage().setBody(body);
+                                exchange.getMessage().setHeader("#CustomHeader", resolveTemplate(simpleTemplate, exchange));
+                            }
+                        })
+                        .to("mock:result");
+            }
+
+        };
+    }
+
+    public String resolveTemplate(String template, Exchange exchange) {
+        var simpleExpression = new SimpleExpression();
+        simpleExpression.setExpression(template);
+        return simpleExpression.evaluate(exchange, String.class);
+    }
+
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
index 2d8a08ec715..1ec39556bf1 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
@@ -20,6 +20,7 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
@@ -1593,32 +1594,85 @@ public class ExpressionBuilder {
      * @return an expression which when evaluated will return the concatenated values
      */
     public static Expression concatExpression(final Collection<Expression> expressions, final String description) {
-        return new ExpressionAdapter() {
 
-            private Collection<Object> col;
+        for (Expression expression : expressions) {
+            if(expression instanceof ConstantExpressionAdapter){
+                return concatExpressionOptimized(expressions, description);
+            }
+        }
+
+        return concatExpressionUnoptimized(expressions,description);
+    }
+
+    /**
+     * Returns an expression which returns the string concatenation value of the various
+     * expressions
+     *
+     * @param expressions the expression to be concatenated dynamically
+     * @param description the text description of the expression
+     * @return an expression which when evaluated will return the concatenated values
+     */
+    private static Expression concatExpressionUnoptimized(final Collection<Expression> expressions, final String description) {
+        return new ExpressionAdapter() {
 
             @Override
             public Object evaluate(Exchange exchange) {
                 StringBuilder buffer = new StringBuilder();
-                if (col != null) {
-                    // optimize for constant expressions so we can do this a bit faster
-                    for (Object obj : col) {
-                        if (obj instanceof Expression) {
-                            Expression expression = (Expression) obj;
-                            String text = expression.evaluate(exchange, String.class);
-                            if (text != null) {
-                                buffer.append(text);
-                            }
-                        } else {
-                            buffer.append((String) obj);
-                        }
+                for (Expression expression : expressions) {
+                    String text = expression.evaluate(exchange, String.class);
+                    if (text != null) {
+                        buffer.append(text);
                     }
+                }
+                return buffer.toString();
+            }
+
+            @Override
+            public void init(CamelContext context) {
+                for (Expression expression : expressions) {
+                    expression.init(context);
+                }
+            }
+
+            @Override
+            public String toString() {
+                if (description != null) {
+                    return description;
                 } else {
-                    for (Expression expression : expressions) {
+                    return "concat(" + expressions + ")";
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns an optimized expression which returns the string concatenation value of the various.
+     * expressions
+     *
+     * @param expressions the expression to be concatenated dynamically
+     * @param description the text description of the expression
+     * @return an expression which when evaluated will return the concatenated values
+     */
+    private static Expression concatExpressionOptimized(final Collection<Expression> expressions, final String description) {
+
+
+        return new ExpressionAdapter() {
+
+            private Collection<Object> optimized;
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                StringBuilder buffer = new StringBuilder();
+                Collection<?> col = optimized != null ? optimized : expressions;
+                for (Object obj : col) {
+                    if (obj instanceof Expression) {
+                        Expression expression = (Expression) obj;
                         String text = expression.evaluate(exchange, String.class);
                         if (text != null) {
                             buffer.append(text);
                         }
+                    } else {
+                        buffer.append((String) obj);
                     }
                 }
                 return buffer.toString();
@@ -1626,26 +1680,25 @@ public class ExpressionBuilder {
 
             @Override
             public void init(CamelContext context) {
-                boolean constant = false;
-                for (Expression expression : expressions) {
-                    expression.init(context);
-                    constant |= expression instanceof ConstantExpressionAdapter;
-                }
-                if (constant) {
-                    // okay some of the expressions are constant so we can optimize and avoid
-                    // evaluate them but use their constant value as-is directly
-                    // this can be common with the simple language where you use it for templating
-                    // by mixing string text and simple functions together (or via the log EIP)
-                    col = new ArrayList<>(expressions.size());
+                if(optimized == null) {
+                    Collection<Object> preprocessedExpression = new ArrayList<>(expressions.size());
                     for (Expression expression : expressions) {
+                        expression.init(context);
                         if (expression instanceof ConstantExpressionAdapter) {
                             Object value = ((ConstantExpressionAdapter) expression).getValue();
-                            col.add(value.toString());
+                            preprocessedExpression.add(value.toString());
                         } else {
-                            col.add(expression);
+                            preprocessedExpression.add(expression);
                         }
                     }
+                    optimized = Collections.unmodifiableCollection(preprocessedExpression);
                 }
+                else{
+                    for (Expression expression : expressions) {
+                        expression.init(context);
+                    }
+                }
+
             }
 
             @Override