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); } /**
