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

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


The following commit(s) were added to refs/heads/main by this push:
     new b70a0b5  CAMEL-16682: Fixed potential ConcurrentModificationException 
in camel-mock when asserting endpoints.
b70a0b5 is described below

commit b70a0b5e5c96766ef714d9319596fe2ddc6820f3
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jun 3 10:42:29 2021 +0200

    CAMEL-16682: Fixed potential ConcurrentModificationException in camel-mock 
when asserting endpoints.
---
 .../main/java/org/apache/camel/CamelContext.java   |  3 ++-
 .../org/apache/camel/spi/EndpointRegistry.java     |  6 +++++
 .../camel/impl/engine/AbstractCamelContext.java    |  2 +-
 .../camel/impl/engine/AbstractDynamicRegistry.java | 27 +++++++++++++++++++++
 .../impl/engine/ProvisionalEndpointRegistry.java   | 28 ++++++++++++++++++++++
 5 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java 
b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 0a10c8d..387c071 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -438,7 +438,8 @@ public interface CamelContext extends 
CamelContextLifecycle, RuntimeConfiguratio
     <T extends Endpoint> T getEndpoint(String name, Class<T> endpointType);
 
     /**
-     * Returns a new {@link Collection} of all of the endpoints from the 
{@link org.apache.camel.spi.EndpointRegistry}
+     * Returns a read-only {@link Collection} of all of the endpoints from the
+     * {@link org.apache.camel.spi.EndpointRegistry}
      *
      * @return all endpoints
      */
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/EndpointRegistry.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/EndpointRegistry.java
index a216750..0b0fd10 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/EndpointRegistry.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/EndpointRegistry.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.spi;
 
+import java.util.Collection;
 import java.util.Map;
 
 import org.apache.camel.Endpoint;
@@ -81,4 +82,9 @@ public interface EndpointRegistry<K> extends Map<K, 
Endpoint>, StaticService {
      */
     void cleanUp();
 
+    /**
+     * Gets a read-only collection of the endpoints currently in the registry.
+     */
+    Collection<Endpoint> getReadOnlyValues();
+
 }
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 2a4f33c..03d98f3 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -734,7 +734,7 @@ public abstract class AbstractCamelContext extends 
BaseService
 
     @Override
     public Collection<Endpoint> getEndpoints() {
-        return new ArrayList<>(endpoints.values());
+        return endpoints.getReadOnlyValues();
     }
 
     @Override
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractDynamicRegistry.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractDynamicRegistry.java
index 888e05c..c08ef1a 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractDynamicRegistry.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractDynamicRegistry.java
@@ -18,7 +18,11 @@ package org.apache.camel.impl.engine;
 
 import java.util.AbstractMap;
 import java.util.AbstractSet;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
@@ -183,6 +187,29 @@ public class AbstractDynamicRegistry<K, V> extends 
AbstractMap<K, V> implements
         return dynamicMap.containsKey(key);
     }
 
+    public Collection<V> getReadOnlyValues() {
+        if (isEmpty()) {
+            return Collections.EMPTY_LIST;
+        }
+
+        // we want to avoid any kind of locking in get/put methods
+        // as getReadOnlyValues is only seldom used, such as when camel-mock
+        // is asserting endpoints at end of testing
+        // so this code will then just retry in case of a concurrency update
+        Collection<V> answer = new ArrayList<>();
+        boolean done = false;
+        while (!done) {
+            try {
+                answer.addAll(values());
+                done = true;
+            } catch (ConcurrentModificationException e) {
+                answer.clear();
+                // try again
+            }
+        }
+        return Collections.unmodifiableCollection(answer);
+    }
+
     @Override
     public void stop() {
         ServiceHelper.stopService(staticMap.values(), dynamicMap.values());
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/ProvisionalEndpointRegistry.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/ProvisionalEndpointRegistry.java
index e71f098..717268d 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/ProvisionalEndpointRegistry.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/ProvisionalEndpointRegistry.java
@@ -16,6 +16,10 @@
  */
 package org.apache.camel.impl.engine;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 
 import org.apache.camel.Endpoint;
@@ -73,4 +77,28 @@ class ProvisionalEndpointRegistry extends 
HashMap<NormalizedUri, Endpoint> imple
     public void cleanUp() {
         // noop
     }
+
+    @Override
+    public Collection<Endpoint> getReadOnlyValues() {
+        if (isEmpty()) {
+            return Collections.EMPTY_LIST;
+        }
+
+        // we want to avoid any kind of locking in get/put methods
+        // as getReadOnlyValues is only seldom used, such as when camel-mock
+        // is asserting endpoints at end of testing
+        // so this code will then just retry in case of a concurrency update
+        Collection<Endpoint> answer = new ArrayList<>();
+        boolean done = false;
+        while (!done) {
+            try {
+                answer.addAll(values());
+                done = true;
+            } catch (ConcurrentModificationException e) {
+                answer.clear();
+                // try again
+            }
+        }
+        return Collections.unmodifiableCollection(answer);
+    }
 }

Reply via email to