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);
+ }
}