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 ead30881a4da [backport camel-4.22.x] CAMEL-25620: camel-console - 
allow dev consoles to be registered while the registry starts (#27808)
ead30881a4da is described below

commit ead30881a4dad0ec9e9ed55b39ced3f841c4f9cb
Author: Guillaume Nodet <[email protected]>
AuthorDate: Wed Oct 14 13:45:45 2026 +0200

    [backport camel-4.22.x] CAMEL-25620: camel-console - allow dev consoles to 
be registered while the registry starts (#27808)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../impl/console/DefaultDevConsoleRegistry.java    | 21 ++++-----
 .../console/DefaultDevConsoleRegistryTest.java     | 55 ++++++++++++++++++++++
 2 files changed, 65 insertions(+), 11 deletions(-)

diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java
index 8b6c2b882c32..3146b8bae1c9 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java
@@ -19,7 +19,7 @@ package org.apache.camel.impl.console;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Set;
-import java.util.TreeSet;
+import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.stream.Stream;
 
 import org.apache.camel.CamelContext;
@@ -56,8 +56,9 @@ public class DefaultDevConsoleRegistry extends ServiceSupport 
implements DevCons
     }
 
     public DefaultDevConsoleRegistry(CamelContext camelContext) {
-        // sort by id
-        this.consoles = new TreeSet<>(Comparator.comparing(DevConsole::getId));
+        // sort by id, and allow consoles to be registered while the registry 
is iterating its consoles
+        // (such as camel-cli-connector resolving consoles while camel is 
starting)
+        this.consoles = new 
ConcurrentSkipListSet<>(Comparator.comparing(DevConsole::getId));
         setCamelContext(camelContext);
     }
 
@@ -120,8 +121,10 @@ public class DefaultDevConsoleRegistry extends 
ServiceSupport implements DevCons
         if (answer == null) {
             DevConsoleResolver resolver = 
PluginHelper.getDevConsoleResolver(camelContext);
             answer = resolver.resolveDevConsole(id);
-            if (answer != null) {
-                register(answer);
+            if (answer != null && !register(answer)) {
+                // another thread registered the console in the meantime, so 
use that one
+                DevConsole resolved = answer;
+                answer = consoles.stream().filter(h -> 
h.getId().equals(id)).findFirst().orElse(resolved);
             }
         }
 
@@ -130,12 +133,8 @@ public class DefaultDevConsoleRegistry extends 
ServiceSupport implements DevCons
 
     @Override
     public boolean register(DevConsole console) {
-        boolean result;
-        // do we have this already
-        if (getConsole(console.getId()).isPresent()) {
-            return false;
-        }
-        result = consoles.add(console);
+        // the consoles are sorted by id, so adding a console with an id that 
is already registered is rejected
+        boolean result = consoles.add(console);
         if (result) {
             CamelContextAware.trySetCamelContext(console, camelContext);
             // ensure console is started as it may be registered later
diff --git 
a/core/camel-console/src/test/java/org/apache/camel/impl/console/DefaultDevConsoleRegistryTest.java
 
b/core/camel-console/src/test/java/org/apache/camel/impl/console/DefaultDevConsoleRegistryTest.java
index 4e5af79bd7d0..79538b1581c8 100644
--- 
a/core/camel-console/src/test/java/org/apache/camel/impl/console/DefaultDevConsoleRegistryTest.java
+++ 
b/core/camel-console/src/test/java/org/apache/camel/impl/console/DefaultDevConsoleRegistryTest.java
@@ -16,10 +16,13 @@
  */
 package org.apache.camel.impl.console;
 
+import java.util.Map;
+
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.console.DevConsole;
 import org.apache.camel.console.DevConsoleRegistry;
 import org.apache.camel.support.PluginHelper;
+import org.apache.camel.support.console.AbstractDevConsole;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -74,4 +77,56 @@ public class DefaultDevConsoleRegistryTest extends 
ContextTestSupport {
         Assertions.assertTrue(unregistered);
         Assertions.assertFalse(registry.getConsole("custom-test").isPresent());
     }
+
+    @Test
+    public void testRegisterWhileStarting() throws Exception {
+        DefaultDevConsoleRegistry registry = new 
DefaultDevConsoleRegistry(context);
+        registry.start();
+
+        // a console that registers another console when started, such as 
camel-cli-connector
+        // resolving consoles from its own thread while the registry is 
starting its consoles
+        DevConsole first = new TestConsole("a-first") {
+            @Override
+            protected void doStart() throws Exception {
+                registry.register(new TestConsole("z-late-" + 
registry.stream().count()));
+            }
+        };
+        registry.register(first);
+        registry.register(new TestConsole("b-second"));
+        registry.stop();
+
+        // starting again registers a console while the registry iterates its 
consoles
+        registry.start();
+
+        Assertions.assertTrue(registry.getConsole("a-first").isPresent());
+        Assertions.assertTrue(registry.getConsole("b-second").isPresent());
+        Assertions.assertEquals(4, registry.stream().count());
+    }
+
+    @Test
+    public void testRegisterSameIdTwice() {
+        DefaultDevConsoleRegistry registry = new 
DefaultDevConsoleRegistry(context);
+
+        DevConsole console = new TestConsole("same");
+        Assertions.assertTrue(registry.register(console));
+        Assertions.assertFalse(registry.register(new TestConsole("same")));
+        Assertions.assertSame(console, 
registry.getConsole("same").orElse(null));
+    }
+
+    private static class TestConsole extends AbstractDevConsole {
+
+        TestConsole(String id) {
+            super("test", id, id, id);
+        }
+
+        @Override
+        protected Map<String, Object> doCallJson(Map<String, Object> options) {
+            return Map.of();
+        }
+
+        @Override
+        protected String doCallText(Map<String, Object> options) {
+            return "";
+        }
+    }
 }

Reply via email to