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

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


The following commit(s) were added to refs/heads/camel-4.22.x by this push:
     new a6660150c283 [backport camel-4.22.x] CAMEL-25734: camel-core - the 
bean introspection can be used by another thread while Camel starts (#28022)
a6660150c283 is described below

commit a6660150c2834f81ff20cec2c365160dddfcdf4b
Author: Guillaume Nodet <[email protected]>
AuthorDate: Sat Oct 17 20:41:25 2026 +0200

    [backport camel-4.22.x] CAMEL-25734: camel-core - the bean introspection 
can be used by another thread while Camel starts (#28022)
---
 .../impl/engine/DefaultBeanIntrospection.java      | 25 +++++---
 .../impl/engine/DefaultBeanIntrospectionTest.java  | 71 ++++++++++++++++++++++
 2 files changed, 88 insertions(+), 8 deletions(-)

diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultBeanIntrospection.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultBeanIntrospection.java
index 93377a086ca3..bf7851fc5a8b 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultBeanIntrospection.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultBeanIntrospection.java
@@ -108,12 +108,17 @@ public class DefaultBeanIntrospection extends 
ServiceSupport implements BeanIntr
                    + obj + "]";
         }
 
-        if (preStartDone) {
-            logger.log(line);
-        } else {
-            // remember log lines before we are starting
-            preStartLogs.add(line);
+        if (!preStartDone) {
+            // other threads (such as the cli-connector, which is started 
early) can use this while camel is starting
+            synchronized (preStartLogs) {
+                if (!preStartDone) {
+                    // remember log lines before we are starting
+                    preStartLogs.add(line);
+                    return;
+                }
+            }
         }
+        logger.log(line);
     }
 
     @Override
@@ -233,9 +238,13 @@ public class DefaultBeanIntrospection extends 
ServiceSupport implements BeanIntr
     @Override
     public void afterPropertiesConfigured(CamelContext camelContext) {
         // log any pre starting logs so we can see them all
-        preStartLogs.forEach(logger::log);
-        preStartLogs.clear();
-        preStartDone = true;
+        List<String> lines;
+        synchronized (preStartLogs) {
+            lines = new ArrayList<>(preStartLogs);
+            preStartLogs.clear();
+            preStartDone = true;
+        }
+        lines.forEach(logger::log);
     }
 
     @Override
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultBeanIntrospectionTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultBeanIntrospectionTest.java
new file mode 100644
index 000000000000..941e8ac14ffb
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultBeanIntrospectionTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.impl.engine;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Another thread (such as the cli-connector, which is started early) can use 
the bean introspection while Camel is
+ * starting, when the log lines from before the start are logged.
+ */
+public class DefaultBeanIntrospectionTest {
+
+    @Test
+    public void testUsedByAnotherThreadWhileStarting() throws Exception {
+        for (int i = 0; i < 20; i++) {
+            DefaultBeanIntrospection introspection = new 
DefaultBeanIntrospection();
+            // many log lines from before the start, so logging them takes a 
while
+            for (int j = 0; j < 10000; j++) {
+                introspection.cacheClass(String.class);
+            }
+
+            AtomicBoolean done = new AtomicBoolean();
+            AtomicReference<Throwable> failure = new AtomicReference<>();
+            CountDownLatch using = new CountDownLatch(1);
+            Thread other = new Thread(() -> {
+                try {
+                    while (!done.get()) {
+                        introspection.cacheClass(Integer.class);
+                        using.countDown();
+                    }
+                } catch (Throwable e) {
+                    failure.set(e);
+                }
+            }, "other");
+            other.start();
+            try {
+                assertTrue(using.await(5, TimeUnit.SECONDS));
+                assertDoesNotThrow(() -> 
introspection.afterPropertiesConfigured(null));
+            } finally {
+                done.set(true);
+                other.join(5000);
+            }
+            assertFalse(other.isAlive(), "the other thread should have 
stopped");
+            assertNull(failure.get());
+        }
+    }
+}

Reply via email to