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

mattsicker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 9bc2f462567bc3343705c8480f84a209590dc2e7
Author: Matt Sicker <[email protected]>
AuthorDate: Sun Oct 30 19:51:03 2022 -0500

    Make ServiceRegistry resilient to recursive service loading
    
    Also fixes a casting mixup.
    
    Signed-off-by: Matt Sicker <[email protected]>
---
 .../logging/log4j/util3/ServiceRegistry.java       | 30 +++++++++++++---------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util3/ServiceRegistry.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util3/ServiceRegistry.java
index 75e49e9280..f493c6110e 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/util3/ServiceRegistry.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/util3/ServiceRegistry.java
@@ -21,8 +21,10 @@ import org.apache.logging.log4j.util.Lazy;
 
 import java.lang.invoke.MethodHandles.Lookup;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Predicate;
@@ -37,11 +39,6 @@ import java.util.stream.Stream;
  */
 public class ServiceRegistry {
     private static final Lazy<ServiceRegistry> INSTANCE = 
Lazy.relaxed(ServiceRegistry::new);
-    @SuppressWarnings("unchecked")
-    private static <T> T cast(final Object o) {
-        return (T) o;
-    }
-
 
     /**
      * Returns the singleton ServiceRegistry instance.
@@ -77,16 +74,25 @@ public class ServiceRegistry {
      * Set 'verbose' to false if the `StatusLogger` is not available yet.
      */
     <S> List<S> getServices(final Class<S> serviceType, final Lookup lookup, 
final Predicate<S> validator, boolean verbose) {
-        final List<S> services = cast(mainServices.computeIfAbsent(serviceType,
-                ignored -> ServiceLoaderUtil.loadServices(serviceType, lookup, 
false, verbose)
-                        .filter(validator != null ? validator : unused -> true)
-                        .collect(Collectors.toList())));
+        final List<S> services = getMainServices(serviceType, lookup, 
validator, verbose);
         return Stream.concat(services.stream(), 
bundleServices.values().stream().flatMap(map -> {
             final Stream<S> stream = map.getOrDefault(serviceType, 
List.of()).stream().map(serviceType::cast);
             return validator != null ? stream.filter(validator) : stream;
         })).distinct().collect(Collectors.toCollection(ArrayList::new));
     }
 
+    <S> List<S> getMainServices(final Class<S> serviceType, final Lookup 
lookup, final Predicate<S> validator, boolean verbose) {
+        final List<?> existing = mainServices.get(serviceType);
+        if (existing != null) {
+            return Cast.cast(existing);
+        }
+        final List<S> services = ServiceLoaderUtil.loadServices(serviceType, 
lookup, false, verbose)
+                .filter(validator != null ? validator : unused -> true)
+                .collect(Collectors.toList());
+        final List<S> oldValue = 
Cast.cast(mainServices.putIfAbsent(serviceType, services));
+        return oldValue != null ? oldValue : services;
+    }
+
     /**
      * Loads and registers services from an OSGi context.
      *
@@ -113,9 +119,9 @@ public class ServiceRegistry {
      * @param <S>         type of service
      */
     public <S> void registerBundleServices(final Class<S> serviceType, final 
long bundleId, final List<S> services) {
-        bundleServices.computeIfAbsent(bundleId, ignored -> new 
ConcurrentHashMap<>())
-                .computeIfAbsent(serviceType, ignored -> new ArrayList<>())
-                .addAll(cast(services));
+        final List<S> currentServices = 
Cast.cast(bundleServices.computeIfAbsent(bundleId, ignored -> new 
ConcurrentHashMap<>())
+                .computeIfAbsent(serviceType, ignored -> new ArrayList<S>()));
+        currentServices.addAll(services);
     }
 
     /**

Reply via email to