From 81424f1f449592f66bf02d64e4c711e5e176c12b Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 21 Feb 2020 17:36:02 +1100 Subject: [PATCH 01/11] Issue #4340 - Continuing after ServiceLoader ServiceConfigurationError Signed-off-by: Lachlan Roberts --- .../client/ALPNClientConnectionFactory.java | 18 +---- .../server/ALPNServerConnectionFactory.java | 19 +----- .../annotations/AnnotationConfiguration.java | 20 +----- .../jetty/http/PreEncodedHttpField.java | 19 ++---- .../jetty/security/SecurityHandler.java | 8 +-- .../eclipse/jetty/util/ServiceLoaderUtil.java | 68 +++++++++++++++++++ .../jetty/util/security/Credential.java | 7 +- .../eclipse/jetty/webapp/Configurations.java | 28 +++----- .../src/main/java/module-info.java | 2 + .../api/extensions/ExtensionConfig.java | 2 +- .../eclipse/jetty/xml/XmlConfiguration.java | 3 +- 11 files changed, 102 insertions(+), 92 deletions(-) create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index 7ddf404f62e..8d7c75b74de 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -19,10 +19,8 @@ package org.eclipse.jetty.alpn.client; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.ServiceLoader; import java.util.concurrent.Executor; import javax.net.ssl.SSLEngine; @@ -32,6 +30,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.NegotiatingClientConnectionFactory; import org.eclipse.jetty.io.ssl.ALPNProcessor.Client; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -54,21 +53,8 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Iterator i = ServiceLoader.load(Client.class).iterator(); i.hasNext(); ) + for (Client processor : ServiceLoaderUtil.load(Client.class)) { - Client processor; - try - { - processor = i.next(); - } - catch (Throwable x) - { - if (LOG.isDebugEnabled()) - LOG.debug(x); - failure.addSuppressed(x); - continue; - } - try { processor.init(); diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 5615f004fe0..12df1b5f9c4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -20,9 +20,7 @@ package org.eclipse.jetty.alpn.server; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; -import java.util.ServiceLoader; import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.AbstractConnection; @@ -30,6 +28,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.ssl.ALPNProcessor.Server; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -51,22 +50,8 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Iterator i = ServiceLoader.load(Server.class).iterator(); i.hasNext(); ) + for (Server processor : ServiceLoaderUtil.load(Server.class)) { - Server processor; - try - { - processor = i.next(); - } - catch (Throwable x) - { - if (LOG.isDebugEnabled()) - LOG.debug(x); - if (x != failure) - failure.addSuppressed(x); - continue; - } - try { processor.init(); diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 199b313fa14..273ecab21ed 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -31,7 +31,6 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; @@ -48,6 +47,7 @@ import org.eclipse.jetty.plus.webapp.PlusConfiguration; import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.ProcessorUtils; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -811,7 +811,7 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - ServiceLoader loader = ServiceLoader.load(ServletContainerInitializer.class); + List scis = ServiceLoaderUtil.load(ServletContainerInitializer.class); if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); @@ -820,22 +820,8 @@ public class AnnotationConfiguration extends AbstractConfiguration //Get initial set of SCIs that aren't from excluded jars or excluded by the containerExclusionPattern, or excluded //because containerInitializerOrdering omits it - Iterator iter = loader.iterator(); - while (iter.hasNext()) + for (ServletContainerInitializer sci : scis) { - ServletContainerInitializer sci; - try - { - sci = iter.next(); - } - catch (Error e) - { - // Probably a SCI discovered on the system classpath that is hidden by the context classloader - LOG.info("Error: " + e.getMessage() + " for " + context); - LOG.debug(e); - continue; - } - if (matchesExclusionPattern(sci)) { if (LOG.isDebugEnabled()) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index e1f39a60689..f61a615334c 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -20,10 +20,10 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.ServiceLoader; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -44,20 +44,13 @@ public class PreEncodedHttpField extends HttpField static { List encoders = new ArrayList<>(); - Iterator iter = ServiceLoader.load(HttpFieldPreEncoder.class).iterator(); - while (iter.hasNext()) + List discoveredEncoders = ServiceLoaderUtil.load(HttpFieldPreEncoder.class); + for (HttpFieldPreEncoder encoder : discoveredEncoders) { - try - { - HttpFieldPreEncoder encoder = iter.next(); - if (index(encoder.getHttpVersion()) >= 0) - encoders.add(encoder); - } - catch (Error | RuntimeException e) - { - LOG.debug(e); - } + if (index(encoder.getHttpVersion()) >= 0) + encoders.add(encoder); } + LOG.debug("HttpField encoders loaded: {}", encoders); int size = encoders.size(); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index e2a907b53ef..f5aa71449ab 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -26,7 +26,6 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.ServiceLoader; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -41,6 +40,7 @@ import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -76,11 +76,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { - for (Authenticator.Factory factory : ServiceLoader.load(Authenticator.Factory.class)) - { - __knownAuthenticatorFactories.add(factory); - } - + __knownAuthenticatorFactories.addAll(ServiceLoaderUtil.load(Authenticator.Factory.class)); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java new file mode 100644 index 00000000000..c2d02091ff7 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java @@ -0,0 +1,68 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class ServiceLoaderUtil +{ + private static final Logger LOG = Log.getLogger(ServiceLoaderUtil.class); + private static final int MAX_ERRORS = 100; + + /** + * Uses the {@link ServiceLoader} to assemble the service providers into a list. + * If loading a service type throws {@link ServiceConfigurationError}, + * it warns and continues iterating through the service loader. + * @param service The interface or abstract class representing the service. + * @param The class of the service type. + * @return a list of the loaded service providers. + * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} + */ + public static List load(Class service) + { + List list = new ArrayList<>(); + Iterator iterator = ServiceLoader.load(service).iterator(); + + int errors = 0; + while (true) + { + try + { + if (!iterator.hasNext()) + break; + list.add(iterator.next()); + } + catch (ServiceConfigurationError e) + { + LOG.warn(e); + if (++errors >= MAX_ERRORS) + throw e; + } + } + + return list; + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 1876016dd9d..72e85def157 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -21,8 +21,9 @@ package org.eclipse.jetty.util.security; import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.util.ServiceLoader; +import java.util.List; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -42,7 +43,7 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = Log.getLogger(Credential.class); - private static final ServiceLoader CREDENTIAL_PROVIDER_LOADER = ServiceLoader.load(CredentialProvider.class); + private static final List CREDENTIAL_PROVIDERS = ServiceLoaderUtil.load(CredentialProvider.class); /** * Check a credential @@ -68,7 +69,7 @@ public abstract class Credential implements Serializable if (credential.startsWith(MD5.__TYPE)) return new MD5(credential); - for (CredentialProvider cp : CREDENTIAL_PROVIDER_LOADER) + for (CredentialProvider cp : CREDENTIAL_PROVIDERS) { if (credential.startsWith(cp.getPrefix())) { diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index e8ef70913f4..839d663bc36 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -30,12 +30,12 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.ServiceLoader; import java.util.Set; import java.util.stream.Collectors; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.TopologicalSort; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.component.Dumpable; @@ -74,26 +74,18 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - ServiceLoader configs = ServiceLoader.load(Configuration.class); - for (Iterator i = configs.iterator(); i.hasNext(); ) + List configs = ServiceLoaderUtil.load(Configuration.class); + for (Configuration configuration : configs) { - try + if (!configuration.isAvailable()) { - Configuration configuration = i.next(); - if (!configuration.isAvailable()) - { - if (LOG.isDebugEnabled()) - LOG.debug("Configuration unavailable: " + configuration); - __unavailable.add(configuration); - continue; - } - __known.add(configuration); - __knownByClassName.add(configuration.getClass().getName()); - } - catch (Throwable e) - { - LOG.warn(e); + if (LOG.isDebugEnabled()) + LOG.debug("Configuration unavailable: " + configuration); + __unavailable.add(configuration); + continue; } + __known.add(configuration); + __knownByClassName.add(configuration.getClass().getName()); } sort(__known); diff --git a/jetty-websocket/websocket-jetty-api/src/main/java/module-info.java b/jetty-websocket/websocket-jetty-api/src/main/java/module-info.java index d37d34904cb..9bd0d472ca8 100644 --- a/jetty-websocket/websocket-jetty-api/src/main/java/module-info.java +++ b/jetty-websocket/websocket-jetty-api/src/main/java/module-info.java @@ -22,4 +22,6 @@ module org.eclipse.jetty.websocket.jetty.api exports org.eclipse.jetty.websocket.api.annotations; exports org.eclipse.jetty.websocket.api.extensions; exports org.eclipse.jetty.websocket.api.util; + + uses org.eclipse.jetty.websocket.api.extensions.ExtensionConfig.Parser; } diff --git a/jetty-websocket/websocket-jetty-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java b/jetty-websocket/websocket-jetty-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java index 90c52d0d710..5902690f280 100644 --- a/jetty-websocket/websocket-jetty-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java +++ b/jetty-websocket/websocket-jetty-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java @@ -34,7 +34,7 @@ public interface ExtensionConfig private static ExtensionConfig.Parser getParser() { - return ServiceLoader.load(ExtensionConfig.Parser.class).findFirst().get(); + return ServiceLoader.load(ExtensionConfig.Parser.class).iterator().next(); } static ExtensionConfig parse(String parameterizedName) diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 347a21d6319..af3a799bd4a 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -55,6 +55,7 @@ import java.util.Set; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.MultiException; +import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.annotation.Name; @@ -95,7 +96,7 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final Iterable PROCESSOR_FACTORIES = ServiceLoader.load(ConfigurationProcessorFactory.class); + private static final List PROCESSOR_FACTORIES = ServiceLoaderUtil.load(ConfigurationProcessorFactory.class); private static final XmlParser PARSER = initParser(); private static final Comparator EXECUTABLE_COMPARATOR = (o1, o2) -> { From a7f4d2606b3d2bd2fabfde573464857a3b4e021d Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 25 Feb 2020 19:48:17 +1100 Subject: [PATCH 02/11] Issue #4340 - always pass in ServiceLoader to ServiceLoaderUtil this prevents errors where jetty-util must declare it uses the provider class in module.info Signed-off-by: Lachlan Roberts --- .../jetty/alpn/client/ALPNClientConnectionFactory.java | 3 ++- .../jetty/alpn/server/ALPNServerConnectionFactory.java | 3 ++- .../eclipse/jetty/annotations/AnnotationConfiguration.java | 3 ++- .../java/org/eclipse/jetty/http/PreEncodedHttpField.java | 2 +- .../java/org/eclipse/jetty/security/SecurityHandler.java | 3 ++- .../main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java | 6 +++--- .../java/org/eclipse/jetty/util/security/Credential.java | 3 ++- .../main/java/org/eclipse/jetty/webapp/Configurations.java | 3 ++- .../main/java/org/eclipse/jetty/xml/XmlConfiguration.java | 2 +- 9 files changed, 17 insertions(+), 11 deletions(-) diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index 8d7c75b74de..132814c1b97 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.alpn.client; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.ServiceLoader; import java.util.concurrent.Executor; import javax.net.ssl.SSLEngine; @@ -53,7 +54,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Client processor : ServiceLoaderUtil.load(Client.class)) + for (Client processor : ServiceLoaderUtil.load(ServiceLoader.load(Client.class))) { try { diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 12df1b5f9c4..63d49d2caeb 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.alpn.server; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.ServiceLoader; import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.AbstractConnection; @@ -50,7 +51,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Server processor : ServiceLoaderUtil.load(Server.class)) + for (Server processor : ServiceLoaderUtil.load(ServiceLoader.load(Server.class))) { try { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 273ecab21ed..407ac690db1 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -31,6 +31,7 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; @@ -811,7 +812,7 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = ServiceLoaderUtil.load(ServletContainerInitializer.class); + List scis = ServiceLoaderUtil.load(ServiceLoader.load(ServletContainerInitializer.class)); if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index f61a615334c..9236d3468dd 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -44,7 +44,7 @@ public class PreEncodedHttpField extends HttpField static { List encoders = new ArrayList<>(); - List discoveredEncoders = ServiceLoaderUtil.load(HttpFieldPreEncoder.class); + List discoveredEncoders = ServiceLoaderUtil.load(ServiceLoader.load(HttpFieldPreEncoder.class)); for (HttpFieldPreEncoder encoder : discoveredEncoders) { if (index(encoder.getHttpVersion()) >= 0) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index f5aa71449ab..dd1992868e8 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -26,6 +26,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.ServiceLoader; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -76,7 +77,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { - __knownAuthenticatorFactories.addAll(ServiceLoaderUtil.load(Authenticator.Factory.class)); + __knownAuthenticatorFactories.addAll(ServiceLoaderUtil.load(ServiceLoader.load(Authenticator.Factory.class))); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java index c2d02091ff7..8edca00b74b 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java @@ -36,15 +36,15 @@ public class ServiceLoaderUtil * Uses the {@link ServiceLoader} to assemble the service providers into a list. * If loading a service type throws {@link ServiceConfigurationError}, * it warns and continues iterating through the service loader. - * @param service The interface or abstract class representing the service. * @param The class of the service type. + * @param serviceLoader The service loader to use. * @return a list of the loaded service providers. * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} */ - public static List load(Class service) + public static List load(ServiceLoader serviceLoader) { List list = new ArrayList<>(); - Iterator iterator = ServiceLoader.load(service).iterator(); + Iterator iterator = serviceLoader.iterator(); int errors = 0; while (true) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 72e85def157..bcf4d202434 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -22,6 +22,7 @@ import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.List; +import java.util.ServiceLoader; import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.TypeUtil; @@ -43,7 +44,7 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = Log.getLogger(Credential.class); - private static final List CREDENTIAL_PROVIDERS = ServiceLoaderUtil.load(CredentialProvider.class); + private static final List CREDENTIAL_PROVIDERS = ServiceLoaderUtil.load(ServiceLoader.load(CredentialProvider.class)); /** * Check a credential diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index 839d663bc36..51c36b8de18 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -30,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.ServiceLoader; import java.util.Set; import java.util.stream.Collectors; @@ -74,7 +75,7 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - List configs = ServiceLoaderUtil.load(Configuration.class); + List configs = ServiceLoaderUtil.load(ServiceLoader.load(Configuration.class)); for (Configuration configuration : configs) { if (!configuration.isAvailable()) diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index af3a799bd4a..80947c0ec69 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -96,7 +96,7 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final List PROCESSOR_FACTORIES = ServiceLoaderUtil.load(ConfigurationProcessorFactory.class); + private static final List PROCESSOR_FACTORIES = ServiceLoaderUtil.load(ServiceLoader.load(ConfigurationProcessorFactory.class)); private static final XmlParser PARSER = initParser(); private static final Comparator EXECUTABLE_COMPARATOR = (o1, o2) -> { From a277c30b8105f27d3fd5497b61c5d9ac85c9d313 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 26 Feb 2020 10:26:29 +1100 Subject: [PATCH 03/11] Issue #4340 - Move ServiceLoaderUtil.load method to TypeUtil.loadAll - increase MAX_ERRORS to 1000 - introduce a loadFirst method Signed-off-by: Lachlan Roberts --- .../client/ALPNClientConnectionFactory.java | 4 +- .../server/ALPNServerConnectionFactory.java | 4 +- .../annotations/AnnotationConfiguration.java | 3 +- .../jetty/http/PreEncodedHttpField.java | 4 +- .../jetty/security/SecurityHandler.java | 4 +- .../eclipse/jetty/util/ServiceLoaderUtil.java | 68 ------------------ .../java/org/eclipse/jetty/util/TypeUtil.java | 70 +++++++++++++++++++ .../jetty/util/security/Credential.java | 3 +- .../eclipse/jetty/webapp/Configurations.java | 4 +- .../eclipse/jetty/xml/XmlConfiguration.java | 3 +- 10 files changed, 83 insertions(+), 84 deletions(-) delete mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index 132814c1b97..7cbfd289093 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -31,7 +31,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.NegotiatingClientConnectionFactory; import org.eclipse.jetty.io.ssl.ALPNProcessor.Client; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; -import org.eclipse.jetty.util.ServiceLoaderUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -54,7 +54,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Client processor : ServiceLoaderUtil.load(ServiceLoader.load(Client.class))) + for (Client processor : TypeUtil.loadAll(ServiceLoader.load(Client.class))) { try { diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 63d49d2caeb..50da92aab50 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -29,7 +29,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.ssl.ALPNProcessor.Server; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; -import org.eclipse.jetty.util.ServiceLoaderUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -51,7 +51,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Server processor : ServiceLoaderUtil.load(ServiceLoader.load(Server.class))) + for (Server processor : TypeUtil.loadAll(ServiceLoader.load(Server.class))) { try { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 407ac690db1..be37715de76 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -48,7 +48,6 @@ import org.eclipse.jetty.plus.webapp.PlusConfiguration; import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.ProcessorUtils; -import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -812,7 +811,7 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = ServiceLoaderUtil.load(ServiceLoader.load(ServletContainerInitializer.class)); + List scis = TypeUtil.loadAll(ServiceLoader.load(ServletContainerInitializer.class)); if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index 9236d3468dd..a25eb674f79 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.ServiceLoader; -import org.eclipse.jetty.util.ServiceLoaderUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -44,7 +44,7 @@ public class PreEncodedHttpField extends HttpField static { List encoders = new ArrayList<>(); - List discoveredEncoders = ServiceLoaderUtil.load(ServiceLoader.load(HttpFieldPreEncoder.class)); + List discoveredEncoders = TypeUtil.loadAll(ServiceLoader.load(HttpFieldPreEncoder.class)); for (HttpFieldPreEncoder encoder : discoveredEncoders) { if (index(encoder.getHttpVersion()) >= 0) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index dd1992868e8..702ae28b9fa 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -41,7 +41,7 @@ import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; import org.eclipse.jetty.server.handler.HandlerWrapper; -import org.eclipse.jetty.util.ServiceLoaderUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -77,7 +77,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { - __knownAuthenticatorFactories.addAll(ServiceLoaderUtil.load(ServiceLoader.load(Authenticator.Factory.class))); + __knownAuthenticatorFactories.addAll(TypeUtil.loadAll(ServiceLoader.load(Authenticator.Factory.class))); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java deleted file mode 100644 index 8edca00b74b..00000000000 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderUtil.java +++ /dev/null @@ -1,68 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. -// -// This program and the accompanying materials are made available under -// the terms of the Eclipse Public License 2.0 which is available at -// https://www.eclipse.org/legal/epl-2.0 -// -// This Source Code may also be made available under the following -// Secondary Licenses when the conditions for such availability set -// forth in the Eclipse Public License, v. 2.0 are satisfied: -// the Apache License v2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// ======================================================================== -// - -package org.eclipse.jetty.util; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -public class ServiceLoaderUtil -{ - private static final Logger LOG = Log.getLogger(ServiceLoaderUtil.class); - private static final int MAX_ERRORS = 100; - - /** - * Uses the {@link ServiceLoader} to assemble the service providers into a list. - * If loading a service type throws {@link ServiceConfigurationError}, - * it warns and continues iterating through the service loader. - * @param The class of the service type. - * @param serviceLoader The service loader to use. - * @return a list of the loaded service providers. - * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} - */ - public static List load(ServiceLoader serviceLoader) - { - List list = new ArrayList<>(); - Iterator iterator = serviceLoader.iterator(); - - int errors = 0; - while (true) - { - try - { - if (!iterator.hasNext()) - break; - list.add(iterator.next()); - } - catch (ServiceConfigurationError e) - { - LOG.warn(e); - if (++errors >= MAX_ERRORS) - throw e; - } - } - - return list; - } -} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index bb3b80ca2ce..0b905643bd0 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -42,6 +42,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Optional; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -63,6 +65,7 @@ public class TypeUtil public static final int LF = '\n'; private static final HashMap> name2Class = new HashMap<>(); + private static final int MAX_ERRORS = 1000; static { @@ -751,4 +754,71 @@ public class TypeUtil } }; } + + /** + * Uses the {@link ServiceLoader} to assemble the service providers into a list. + * If loading a service type throws {@link ServiceConfigurationError}, + * it warns and continues iterating through the service loader. + * @param The class of the service type. + * @param serviceLoader The service loader to use. + * @return a list of the loaded service providers. + * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} + */ + public static List loadAll(ServiceLoader serviceLoader) + { + List list = new ArrayList<>(); + Iterator iterator = serviceLoader.iterator(); + + int errors = 0; + while (true) + { + try + { + if (!iterator.hasNext()) + break; + list.add(iterator.next()); + } + catch (ServiceConfigurationError e) + { + LOG.warn(e); + if (++errors >= MAX_ERRORS) + throw e; + } + } + + return list; + } + + /** + * Uses the {@link ServiceLoader} to get the first availible service provider. + * If loading a service type throws {@link ServiceConfigurationError}, + * it warns and continues iterating through the service loader until one is found. + * @param The class of the service type. + * @param serviceLoader The service loader to use. + * @return an instance of a service provider, or null if none could be found. + * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} + */ + public static T loadFirst(ServiceLoader serviceLoader) + { + Iterator iterator = serviceLoader.iterator(); + + int errors = 0; + while (true) + { + try + { + if (!iterator.hasNext()) + break; + return iterator.next(); + } + catch (ServiceConfigurationError e) + { + LOG.warn(e); + if (++errors >= MAX_ERRORS) + throw e; + } + } + + return null; + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index bcf4d202434..de689e50fad 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -24,7 +24,6 @@ import java.security.MessageDigest; import java.util.List; import java.util.ServiceLoader; -import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -44,7 +43,7 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = Log.getLogger(Credential.class); - private static final List CREDENTIAL_PROVIDERS = ServiceLoaderUtil.load(ServiceLoader.load(CredentialProvider.class)); + private static final List CREDENTIAL_PROVIDERS = TypeUtil.loadAll(ServiceLoader.load(CredentialProvider.class)); /** * Check a credential diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index 51c36b8de18..01d08f3be4f 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -36,8 +36,8 @@ import java.util.stream.Collectors; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.TopologicalSort; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.DumpableCollection; @@ -75,7 +75,7 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - List configs = ServiceLoaderUtil.load(ServiceLoader.load(Configuration.class)); + List configs = TypeUtil.loadAll(ServiceLoader.load(Configuration.class)); for (Configuration configuration : configs) { if (!configuration.isAvailable()) diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 80947c0ec69..b44cea00d74 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -55,7 +55,6 @@ import java.util.Set; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.MultiException; -import org.eclipse.jetty.util.ServiceLoaderUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.annotation.Name; @@ -96,7 +95,7 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final List PROCESSOR_FACTORIES = ServiceLoaderUtil.load(ServiceLoader.load(ConfigurationProcessorFactory.class)); + private static final List PROCESSOR_FACTORIES = TypeUtil.loadAll(ServiceLoader.load(ConfigurationProcessorFactory.class)); private static final XmlParser PARSER = initParser(); private static final Comparator EXECUTABLE_COMPARATOR = (o1, o2) -> { From 67e88abbe912d64210b05092de1ef6937aa6e2c6 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 26 Feb 2020 10:35:31 +1100 Subject: [PATCH 04/11] Issue #4340 - loadFirst can take a predicate to match a service provider Signed-off-by: Lachlan Roberts --- .../java/org/eclipse/jetty/util/TypeUtil.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 0b905643bd0..6e2cebb520c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.Optional; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import java.util.function.Predicate; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -790,7 +791,7 @@ public class TypeUtil } /** - * Uses the {@link ServiceLoader} to get the first availible service provider. + * Uses the {@link ServiceLoader} to get the first available service provider. * If loading a service type throws {@link ServiceConfigurationError}, * it warns and continues iterating through the service loader until one is found. * @param The class of the service type. @@ -799,6 +800,21 @@ public class TypeUtil * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} */ public static T loadFirst(ServiceLoader serviceLoader) + { + return loadFirst(serviceLoader, t -> true); + } + + /** + * Uses the {@link ServiceLoader} to get the first service provider to match the provided predicate. + * If loading a service type throws {@link ServiceConfigurationError}, + * it warns and continues iterating through the service loader until one is found. + * @param The class of the service type. + * @param serviceLoader The service loader to use. + * @param predicate The predicate used to match a service provider. + * @return an instance of a service provider, or null if none could be found. + * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} + */ + public static T loadFirst(ServiceLoader serviceLoader, Predicate predicate) { Iterator iterator = serviceLoader.iterator(); @@ -809,7 +825,10 @@ public class TypeUtil { if (!iterator.hasNext()) break; - return iterator.next(); + + T t = iterator.next(); + if (predicate.test(t)) + return t; } catch (ServiceConfigurationError e) { From 6832912d49b5ae8785e7f4d828944f04cc637960 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 28 Feb 2020 12:15:27 +1100 Subject: [PATCH 05/11] Issue #4340 - Implement TypeUtil.load(ServiceLoader) with Streams Signed-off-by: Lachlan Roberts --- .../client/ALPNClientConnectionFactory.java | 4 +- .../server/ALPNServerConnectionFactory.java | 4 +- .../annotations/AnnotationConfiguration.java | 5 +- .../jetty/http/PreEncodedHttpField.java | 9 +- .../jetty/security/SecurityHandler.java | 2 +- .../java/org/eclipse/jetty/util/TypeUtil.java | 84 +++---------------- .../jetty/util/security/Credential.java | 3 +- .../eclipse/jetty/webapp/Configurations.java | 7 +- .../eclipse/jetty/xml/XmlConfiguration.java | 3 +- 9 files changed, 30 insertions(+), 91 deletions(-) diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index 7cbfd289093..fec53bbdcbb 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -54,7 +54,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Client processor : TypeUtil.loadAll(ServiceLoader.load(Client.class))) + TypeUtil.load(ServiceLoader.load(Client.class)).forEach((processor) -> { try { @@ -67,7 +67,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact LOG.debug("Could not initialize " + processor, x); failure.addSuppressed(x); } - } + }); if (LOG.isDebugEnabled()) { diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 50da92aab50..0389460c329 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -51,7 +51,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Server processor : TypeUtil.loadAll(ServiceLoader.load(Server.class))) + TypeUtil.load(ServiceLoader.load(Server.class)).forEach((processor) -> { try { @@ -65,7 +65,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact if (x != failure) failure.addSuppressed(x); } - } + }); if (LOG.isDebugEnabled()) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index be37715de76..b24fa45e340 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -39,6 +39,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.servlet.ServletContainerInitializer; import javax.servlet.annotation.HandlesTypes; @@ -811,11 +812,11 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = TypeUtil.loadAll(ServiceLoader.load(ServletContainerInitializer.class)); + List scis = TypeUtil.load(ServiceLoader.load(ServletContainerInitializer.class)).collect(Collectors.toList()); if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); - Map sciResourceMap = new HashMap(); + Map sciResourceMap = new HashMap<>(); ServletContainerInitializerOrdering initializerOrdering = getInitializerOrdering(context); //Get initial set of SCIs that aren't from excluded jars or excluded by the containerExclusionPattern, or excluded diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index a25eb674f79..12a08b2be05 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -44,12 +44,9 @@ public class PreEncodedHttpField extends HttpField static { List encoders = new ArrayList<>(); - List discoveredEncoders = TypeUtil.loadAll(ServiceLoader.load(HttpFieldPreEncoder.class)); - for (HttpFieldPreEncoder encoder : discoveredEncoders) - { - if (index(encoder.getHttpVersion()) >= 0) - encoders.add(encoder); - } + TypeUtil.load(ServiceLoader.load(HttpFieldPreEncoder.class)) + .filter(encoder -> index(encoder.getHttpVersion()) >= 0) + .forEach(encoders::add); LOG.debug("HttpField encoders loaded: {}", encoders); int size = encoders.size(); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index 702ae28b9fa..30ad16d14cf 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -77,7 +77,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { - __knownAuthenticatorFactories.addAll(TypeUtil.loadAll(ServiceLoader.load(Authenticator.Factory.class))); + TypeUtil.load(ServiceLoader.load(Authenticator.Factory.class)).forEach(__knownAuthenticatorFactories::add); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 6e2cebb520c..ef384dc2a0d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -41,10 +41,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; -import java.util.function.Predicate; +import java.util.stream.Stream; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -66,7 +67,6 @@ public class TypeUtil public static final int LF = '\n'; private static final HashMap> name2Class = new HashMap<>(); - private static final int MAX_ERRORS = 1000; static { @@ -757,87 +757,27 @@ public class TypeUtil } /** - * Uses the {@link ServiceLoader} to assemble the service providers into a list. + * Uses the {@link ServiceLoader} to return a Stream of the service providers which does not throw. * If loading a service type throws {@link ServiceConfigurationError}, * it warns and continues iterating through the service loader. * @param The class of the service type. * @param serviceLoader The service loader to use. - * @return a list of the loaded service providers. - * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} + * @return a stream of the loaded service providers. */ - public static List loadAll(ServiceLoader serviceLoader) + public static Stream load(ServiceLoader serviceLoader) { - List list = new ArrayList<>(); - Iterator iterator = serviceLoader.iterator(); - - int errors = 0; - while (true) + return serviceLoader.stream().map((provider) -> { try { - if (!iterator.hasNext()) - break; - list.add(iterator.next()); + // Attempt to load service, will either return a service, throw an error, or return null. + return provider.get(); } - catch (ServiceConfigurationError e) + catch (ServiceConfigurationError error) { - LOG.warn(e); - if (++errors >= MAX_ERRORS) - throw e; + LOG.warn("Service Provider failed to load", error); } - } - - return list; - } - - /** - * Uses the {@link ServiceLoader} to get the first available service provider. - * If loading a service type throws {@link ServiceConfigurationError}, - * it warns and continues iterating through the service loader until one is found. - * @param The class of the service type. - * @param serviceLoader The service loader to use. - * @return an instance of a service provider, or null if none could be found. - * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} - */ - public static T loadFirst(ServiceLoader serviceLoader) - { - return loadFirst(serviceLoader, t -> true); - } - - /** - * Uses the {@link ServiceLoader} to get the first service provider to match the provided predicate. - * If loading a service type throws {@link ServiceConfigurationError}, - * it warns and continues iterating through the service loader until one is found. - * @param The class of the service type. - * @param serviceLoader The service loader to use. - * @param predicate The predicate used to match a service provider. - * @return an instance of a service provider, or null if none could be found. - * @throws ServiceConfigurationError If the number of errors exceeds {@link #MAX_ERRORS} - */ - public static T loadFirst(ServiceLoader serviceLoader, Predicate predicate) - { - Iterator iterator = serviceLoader.iterator(); - - int errors = 0; - while (true) - { - try - { - if (!iterator.hasNext()) - break; - - T t = iterator.next(); - if (predicate.test(t)) - return t; - } - catch (ServiceConfigurationError e) - { - LOG.warn(e); - if (++errors >= MAX_ERRORS) - throw e; - } - } - - return null; + return null; + }).filter(Objects::nonNull); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index de689e50fad..2b946f813b6 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.List; import java.util.ServiceLoader; +import java.util.stream.Collectors; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -43,7 +44,7 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = Log.getLogger(Credential.class); - private static final List CREDENTIAL_PROVIDERS = TypeUtil.loadAll(ServiceLoader.load(CredentialProvider.class)); + private static final List CREDENTIAL_PROVIDERS = TypeUtil.load(ServiceLoader.load(CredentialProvider.class)).collect(Collectors.toList()); /** * Check a credential diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index 01d08f3be4f..888841a02c2 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -75,19 +75,18 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - List configs = TypeUtil.loadAll(ServiceLoader.load(Configuration.class)); - for (Configuration configuration : configs) + TypeUtil.load(ServiceLoader.load(Configuration.class)).forEach(configuration -> { if (!configuration.isAvailable()) { if (LOG.isDebugEnabled()) LOG.debug("Configuration unavailable: " + configuration); __unavailable.add(configuration); - continue; + return; } __known.add(configuration); __knownByClassName.add(configuration.getClass().getName()); - } + }); sort(__known); if (LOG.isDebugEnabled()) diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index b44cea00d74..ff0979093ca 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -51,6 +51,7 @@ import java.util.Properties; import java.util.Queue; import java.util.ServiceLoader; import java.util.Set; +import java.util.stream.Collectors; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; @@ -95,7 +96,7 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final List PROCESSOR_FACTORIES = TypeUtil.loadAll(ServiceLoader.load(ConfigurationProcessorFactory.class)); + private static final List PROCESSOR_FACTORIES = TypeUtil.load(ServiceLoader.load(ConfigurationProcessorFactory.class)).collect(Collectors.toList()); private static final XmlParser PARSER = initParser(); private static final Comparator EXECUTABLE_COMPARATOR = (o1, o2) -> { From 97c55e27cc72270a50538dfb7020fb69397e73c3 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Sat, 29 Feb 2020 11:06:32 +1100 Subject: [PATCH 06/11] Issue #4340 - remove TypeUtil.load and use flatMap() on streams instead Signed-off-by: Lachlan Roberts --- .../client/ALPNClientConnectionFactory.java | 2 +- .../server/ALPNServerConnectionFactory.java | 2 +- .../annotations/AnnotationConfiguration.java | 2 +- .../jetty/http/PreEncodedHttpField.java | 3 +- .../jetty/security/SecurityHandler.java | 3 +- .../java/org/eclipse/jetty/util/TypeUtil.java | 32 ++++++++----------- .../jetty/util/security/Credential.java | 2 +- .../eclipse/jetty/webapp/Configurations.java | 2 +- .../eclipse/jetty/xml/XmlConfiguration.java | 3 +- 9 files changed, 25 insertions(+), 26 deletions(-) diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index fec53bbdcbb..f93b118515e 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -54,7 +54,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - TypeUtil.load(ServiceLoader.load(Client.class)).forEach((processor) -> + ServiceLoader.load(Client.class).stream().flatMap(TypeUtil::providerMap).forEach((processor) -> { try { diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 0389460c329..f612ed02d0c 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -51,7 +51,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - TypeUtil.load(ServiceLoader.load(Server.class)).forEach((processor) -> + ServiceLoader.load(Server.class).stream().flatMap(TypeUtil::providerMap).forEach((processor) -> { try { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index b24fa45e340..05dc524260d 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -812,7 +812,7 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = TypeUtil.load(ServiceLoader.load(ServletContainerInitializer.class)).collect(Collectors.toList()); + List scis = ServiceLoader.load(ServletContainerInitializer.class).stream().flatMap(TypeUtil::providerMap).collect(Collectors.toList()); if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index 12a08b2be05..fa10c624587 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -44,7 +44,8 @@ public class PreEncodedHttpField extends HttpField static { List encoders = new ArrayList<>(); - TypeUtil.load(ServiceLoader.load(HttpFieldPreEncoder.class)) + ServiceLoader.load(HttpFieldPreEncoder.class).stream() + .flatMap(TypeUtil::providerMap) .filter(encoder -> index(encoder.getHttpVersion()) >= 0) .forEach(encoders::add); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index 30ad16d14cf..05fca253fbc 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -77,7 +77,8 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { - TypeUtil.load(ServiceLoader.load(Authenticator.Factory.class)).forEach(__knownAuthenticatorFactories::add); + ServiceLoader.load(Authenticator.Factory.class).stream() + .flatMap(TypeUtil::providerMap).forEach(__knownAuthenticatorFactories::add); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index ef384dc2a0d..3cf57c78873 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -41,10 +41,10 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import java.util.function.Function; import java.util.stream.Stream; import org.eclipse.jetty.util.log.Log; @@ -757,27 +757,23 @@ public class TypeUtil } /** - * Uses the {@link ServiceLoader} to return a Stream of the service providers which does not throw. - * If loading a service type throws {@link ServiceConfigurationError}, - * it warns and continues iterating through the service loader. + * Used on a {@link ServiceLoader#stream()} with {@link Stream#flatMap(Function)}, + * so that in the case a {@link ServiceConfigurationError} is thrown it warns and + * continues iterating through the service loader. * @param The class of the service type. - * @param serviceLoader The service loader to use. + * @param provider The service provider to instantiate. * @return a stream of the loaded service providers. */ - public static Stream load(ServiceLoader serviceLoader) + public static Stream providerMap(ServiceLoader.Provider provider) { - return serviceLoader.stream().map((provider) -> + try { - try - { - // Attempt to load service, will either return a service, throw an error, or return null. - return provider.get(); - } - catch (ServiceConfigurationError error) - { - LOG.warn("Service Provider failed to load", error); - } - return null; - }).filter(Objects::nonNull); + return Stream.of(provider.get()); + } + catch (ServiceConfigurationError error) + { + LOG.warn("Service Provider failed to load", error); + return Stream.empty(); + } } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 2b946f813b6..367beb5762a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -44,7 +44,7 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = Log.getLogger(Credential.class); - private static final List CREDENTIAL_PROVIDERS = TypeUtil.load(ServiceLoader.load(CredentialProvider.class)).collect(Collectors.toList()); + private static final List CREDENTIAL_PROVIDERS = ServiceLoader.load(CredentialProvider.class).stream().flatMap(TypeUtil::providerMap).collect(Collectors.toList()); /** * Check a credential diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index 888841a02c2..fd509cb2e6f 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -75,7 +75,7 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - TypeUtil.load(ServiceLoader.load(Configuration.class)).forEach(configuration -> + ServiceLoader.load(Configuration.class).stream().flatMap(TypeUtil::providerMap).forEach(configuration -> { if (!configuration.isAvailable()) { diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index ff0979093ca..30c4e3a2c2f 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -96,7 +96,8 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final List PROCESSOR_FACTORIES = TypeUtil.load(ServiceLoader.load(ConfigurationProcessorFactory.class)).collect(Collectors.toList()); + private static final List PROCESSOR_FACTORIES = ServiceLoader.load(ConfigurationProcessorFactory.class) + .stream().flatMap(TypeUtil::providerMap).collect(Collectors.toList()); private static final XmlParser PARSER = initParser(); private static final Comparator EXECUTABLE_COMPARATOR = (o1, o2) -> { From 355d21317b85de9efc4af267463987c72b9ba360 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Mon, 2 Mar 2020 10:16:38 +1100 Subject: [PATCH 07/11] Issue #4340 - Changes from review Signed-off-by: Lachlan Roberts --- .../eclipse/jetty/annotations/AnnotationConfiguration.java | 4 +++- .../java/org/eclipse/jetty/http/PreEncodedHttpField.java | 7 +++---- .../java/org/eclipse/jetty/security/SecurityHandler.java | 3 ++- .../src/main/java/org/eclipse/jetty/util/TypeUtil.java | 2 ++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 05dc524260d..0210c509840 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -812,7 +812,9 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = ServiceLoader.load(ServletContainerInitializer.class).stream().flatMap(TypeUtil::providerMap).collect(Collectors.toList()); + List scis = ServiceLoader.load(ServletContainerInitializer.class).stream() + .flatMap(TypeUtil::providerMap) + .collect(Collectors.toList()); if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index fa10c624587..36a48a82138 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -19,9 +19,9 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.List; import java.util.ServiceLoader; +import java.util.stream.Collectors; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -43,11 +43,10 @@ public class PreEncodedHttpField extends HttpField static { - List encoders = new ArrayList<>(); - ServiceLoader.load(HttpFieldPreEncoder.class).stream() + List encoders = ServiceLoader.load(HttpFieldPreEncoder.class).stream() .flatMap(TypeUtil::providerMap) .filter(encoder -> index(encoder.getHttpVersion()) >= 0) - .forEach(encoders::add); + .collect(Collectors.toList()); LOG.debug("HttpField encoders loaded: {}", encoders); int size = encoders.size(); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index 05fca253fbc..c1b3a84064f 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -78,7 +78,8 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { ServiceLoader.load(Authenticator.Factory.class).stream() - .flatMap(TypeUtil::providerMap).forEach(__knownAuthenticatorFactories::add); + .flatMap(TypeUtil::providerMap) + .forEach(__knownAuthenticatorFactories::add); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 3cf57c78873..2178b56d5f7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -760,6 +760,8 @@ public class TypeUtil * Used on a {@link ServiceLoader#stream()} with {@link Stream#flatMap(Function)}, * so that in the case a {@link ServiceConfigurationError} is thrown it warns and * continues iterating through the service loader. + *
Usage Example: + *

{@code ServiceLoader.load(Service.class).stream().flatMap(TypeUtil::providerMap).collect(Collectors.toList());}

* @param The class of the service type. * @param provider The service provider to instantiate. * @return a stream of the loaded service providers. From edd671146dace3fc9c4eeefae3f8920353d9fc60 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 13 Mar 2020 16:59:33 +1100 Subject: [PATCH 08/11] Issue #4340 - ServiceLoader stream which doesn't break if hasNext throws Signed-off-by: Lachlan Roberts --- .../client/ALPNClientConnectionFactory.java | 2 +- .../server/ALPNServerConnectionFactory.java | 2 +- .../annotations/AnnotationConfiguration.java | 2 +- .../jetty/http/PreEncodedHttpField.java | 2 +- .../jetty/security/SecurityHandler.java | 2 +- .../jetty/util/ServiceLoaderSpliterator.java | 103 ++++++++++++++++++ .../java/org/eclipse/jetty/util/TypeUtil.java | 14 +++ .../jetty/util/security/Credential.java | 2 +- .../eclipse/jetty/webapp/Configurations.java | 2 +- .../eclipse/jetty/xml/XmlConfiguration.java | 4 +- 10 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index f93b118515e..176ff17ccdc 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -54,7 +54,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - ServiceLoader.load(Client.class).stream().flatMap(TypeUtil::providerMap).forEach((processor) -> + TypeUtil.serviceLoaderStream(ServiceLoader.load(Client.class)).flatMap(TypeUtil::providerMap).forEach((processor) -> { try { diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index f612ed02d0c..fefc8b39b80 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -51,7 +51,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - ServiceLoader.load(Server.class).stream().flatMap(TypeUtil::providerMap).forEach((processor) -> + TypeUtil.serviceLoaderStream(ServiceLoader.load(Server.class)).flatMap(TypeUtil::providerMap).forEach((processor) -> { try { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 0210c509840..76ebb3826f1 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -812,7 +812,7 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = ServiceLoader.load(ServletContainerInitializer.class).stream() + List scis = TypeUtil.serviceLoaderStream(ServiceLoader.load(ServletContainerInitializer.class)) .flatMap(TypeUtil::providerMap) .collect(Collectors.toList()); if (LOG.isDebugEnabled()) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index 36a48a82138..638c1c75a64 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -43,7 +43,7 @@ public class PreEncodedHttpField extends HttpField static { - List encoders = ServiceLoader.load(HttpFieldPreEncoder.class).stream() + List encoders = TypeUtil.serviceLoaderStream(ServiceLoader.load(HttpFieldPreEncoder.class)) .flatMap(TypeUtil::providerMap) .filter(encoder -> index(encoder.getHttpVersion()) >= 0) .collect(Collectors.toList()); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index c1b3a84064f..2c30c28df6d 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -77,7 +77,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { - ServiceLoader.load(Authenticator.Factory.class).stream() + TypeUtil.serviceLoaderStream(ServiceLoader.load(Authenticator.Factory.class)) .flatMap(TypeUtil::providerMap) .forEach(__knownAuthenticatorFactories::add); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java new file mode 100644 index 00000000000..f5508bee1e1 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java @@ -0,0 +1,103 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.util.Iterator; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.Spliterator; +import java.util.function.Consumer; + +class ServiceLoaderSpliterator implements Spliterator> +{ + private final Iterator iterator; + + public ServiceLoaderSpliterator(ServiceLoader serviceLoader) + { + iterator = serviceLoader.iterator(); + } + + @Override + public boolean tryAdvance(Consumer> action) + { + Provider next = new Provider<>(); + try + { + if (!iterator.hasNext()) + return false; + next.setServiceProvider(iterator.next()); + } + catch (Throwable t) + { + next.setError(t); + } + + action.accept(next); + return true; + } + + @Override + public Spliterator> trySplit() + { + return null; + } + + @Override + public long estimateSize() + { + return Long.MAX_VALUE; + } + + @Override + public int characteristics() + { + return Spliterator.ORDERED; + } + + private static class Provider implements ServiceLoader.Provider + { + private T serviceProvider; + private Throwable error; + + public void setServiceProvider(T serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + public void setError(Throwable error) + { + this.error = error; + } + + @Override + @SuppressWarnings("unchecked") + public Class type() + { + return (Class)get().getClass(); + } + + @Override + public T get() + { + if (error != null) + throw new ServiceConfigurationError("", error); + return serviceProvider; + } + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 2178b56d5f7..9ec2dbd9401 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -46,6 +46,7 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.function.Function; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -778,4 +779,17 @@ public class TypeUtil return Stream.empty(); } } + + /** + * Utility to create a stream which provides the same functionality as {@link ServiceLoader#stream()}. + * However this also guards the case in which {@link Iterator#hasNext()} throws. Any exceptions + * from the underlying iterator will be cached until the {@link ServiceLoader.Provider#get()} is called. + * @param serviceLoader the ServiceLoader instance to use. + * @param the type of the service to load. + * @return A stream that lazily loads providers for this loader's service + */ + public static Stream> serviceLoaderStream(ServiceLoader serviceLoader) + { + return StreamSupport.stream(new ServiceLoaderSpliterator(serviceLoader), false); + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 367beb5762a..0b8d076765d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -44,7 +44,7 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = Log.getLogger(Credential.class); - private static final List CREDENTIAL_PROVIDERS = ServiceLoader.load(CredentialProvider.class).stream().flatMap(TypeUtil::providerMap).collect(Collectors.toList()); + private static final List CREDENTIAL_PROVIDERS = TypeUtil.serviceLoaderStream(ServiceLoader.load(CredentialProvider.class)).flatMap(TypeUtil::providerMap).collect(Collectors.toList()); /** * Check a credential diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index fd509cb2e6f..563f768e452 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -75,7 +75,7 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - ServiceLoader.load(Configuration.class).stream().flatMap(TypeUtil::providerMap).forEach(configuration -> + TypeUtil.serviceLoaderStream(ServiceLoader.load(Configuration.class)).flatMap(TypeUtil::providerMap).forEach(configuration -> { if (!configuration.isAvailable()) { diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 30c4e3a2c2f..69f808d86e6 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -96,8 +96,8 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final List PROCESSOR_FACTORIES = ServiceLoader.load(ConfigurationProcessorFactory.class) - .stream().flatMap(TypeUtil::providerMap).collect(Collectors.toList()); + private static final List PROCESSOR_FACTORIES = TypeUtil.serviceLoaderStream(ServiceLoader.load(ConfigurationProcessorFactory.class)) + .flatMap(TypeUtil::providerMap).collect(Collectors.toList()); private static final XmlParser PARSER = initParser(); private static final Comparator EXECUTABLE_COMPARATOR = (o1, o2) -> { From 7af220dade816ff9865708f89119dbe2bc988153 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Mon, 16 Mar 2020 09:42:32 +1100 Subject: [PATCH 09/11] Issue #4340 - shortcut method for the serviceStream Signed-off-by: Lachlan Roberts --- .../alpn/client/ALPNClientConnectionFactory.java | 2 +- .../alpn/server/ALPNServerConnectionFactory.java | 2 +- .../jetty/annotations/AnnotationConfiguration.java | 3 +-- .../eclipse/jetty/http/PreEncodedHttpField.java | 3 +-- .../eclipse/jetty/security/SecurityHandler.java | 3 +-- .../main/java/org/eclipse/jetty/util/TypeUtil.java | 14 +++++++++++++- .../eclipse/jetty/util/security/Credential.java | 2 +- .../org/eclipse/jetty/webapp/Configurations.java | 2 +- .../org/eclipse/jetty/xml/XmlConfiguration.java | 4 ++-- 9 files changed, 22 insertions(+), 13 deletions(-) diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index 176ff17ccdc..d7ef1132b19 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -54,7 +54,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - TypeUtil.serviceLoaderStream(ServiceLoader.load(Client.class)).flatMap(TypeUtil::providerMap).forEach((processor) -> + TypeUtil.serviceStream(ServiceLoader.load(Client.class)).forEach((processor) -> { try { diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index fefc8b39b80..7c96e0dffa2 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -51,7 +51,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - TypeUtil.serviceLoaderStream(ServiceLoader.load(Server.class)).flatMap(TypeUtil::providerMap).forEach((processor) -> + TypeUtil.serviceStream(ServiceLoader.load(Server.class)).forEach((processor) -> { try { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 63c275cbbb9..bd54f07db8f 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -815,8 +815,7 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = TypeUtil.serviceLoaderStream(ServiceLoader.load(ServletContainerInitializer.class)) - .flatMap(TypeUtil::providerMap) + List scis = TypeUtil.serviceStream(ServiceLoader.load(ServletContainerInitializer.class)) .collect(Collectors.toList()); if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index 638c1c75a64..c5209e4356b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -43,8 +43,7 @@ public class PreEncodedHttpField extends HttpField static { - List encoders = TypeUtil.serviceLoaderStream(ServiceLoader.load(HttpFieldPreEncoder.class)) - .flatMap(TypeUtil::providerMap) + List encoders = TypeUtil.serviceStream(ServiceLoader.load(HttpFieldPreEncoder.class)) .filter(encoder -> index(encoder.getHttpVersion()) >= 0) .collect(Collectors.toList()); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index 2c30c28df6d..3bd153fe74b 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -77,8 +77,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti static { - TypeUtil.serviceLoaderStream(ServiceLoader.load(Authenticator.Factory.class)) - .flatMap(TypeUtil::providerMap) + TypeUtil.serviceStream(ServiceLoader.load(Authenticator.Factory.class)) .forEach(__knownAuthenticatorFactories::add); __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 9ec2dbd9401..7cc9b8a81b2 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -780,6 +780,18 @@ public class TypeUtil } } + /** + * Shortcut method combining {@link #serviceProviderStream(ServiceLoader)} with + * with {@link #providerMap(ServiceLoader.Provider)} using {@link Stream#flatMap(Function)}. + * @param serviceLoader the ServiceLoader instance to use. + * @param the type of the service to load. + * @return a stream of the service provider type which will not throw {@link ServiceConfigurationError}. + */ + public static Stream serviceStream(ServiceLoader serviceLoader) + { + return serviceProviderStream(serviceLoader).flatMap(TypeUtil::providerMap); + } + /** * Utility to create a stream which provides the same functionality as {@link ServiceLoader#stream()}. * However this also guards the case in which {@link Iterator#hasNext()} throws. Any exceptions @@ -788,7 +800,7 @@ public class TypeUtil * @param the type of the service to load. * @return A stream that lazily loads providers for this loader's service */ - public static Stream> serviceLoaderStream(ServiceLoader serviceLoader) + public static Stream> serviceProviderStream(ServiceLoader serviceLoader) { return StreamSupport.stream(new ServiceLoaderSpliterator(serviceLoader), false); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 0b8d076765d..272081931b3 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -44,7 +44,7 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = Log.getLogger(Credential.class); - private static final List CREDENTIAL_PROVIDERS = TypeUtil.serviceLoaderStream(ServiceLoader.load(CredentialProvider.class)).flatMap(TypeUtil::providerMap).collect(Collectors.toList()); + private static final List CREDENTIAL_PROVIDERS = TypeUtil.serviceStream(ServiceLoader.load(CredentialProvider.class)).collect(Collectors.toList()); /** * Check a credential diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index 563f768e452..1c40807fcf9 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -75,7 +75,7 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - TypeUtil.serviceLoaderStream(ServiceLoader.load(Configuration.class)).flatMap(TypeUtil::providerMap).forEach(configuration -> + TypeUtil.serviceStream(ServiceLoader.load(Configuration.class)).forEach(configuration -> { if (!configuration.isAvailable()) { diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 9621cbc1147..cc7e6806229 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -97,8 +97,8 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final List PROCESSOR_FACTORIES = TypeUtil.serviceLoaderStream(ServiceLoader.load(ConfigurationProcessorFactory.class)) - .flatMap(TypeUtil::providerMap).collect(Collectors.toList()); + private static final List PROCESSOR_FACTORIES = TypeUtil.serviceStream(ServiceLoader.load(ConfigurationProcessorFactory.class)) + .collect(Collectors.toList()); private static final XmlParser PARSER = initParser(); public static final Comparator EXECUTABLE_COMPARATOR = (e1, e2) -> { From 9363a3c39ae6adac229ee50d39de2a630ac55e7d Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Tue, 17 Mar 2020 15:14:52 +1100 Subject: [PATCH 10/11] Issue #4340 - changes from review Signed-off-by: Lachlan Roberts --- .../jetty/util/ServiceLoaderSpliterator.java | 29 ++++++++++++------- .../java/org/eclipse/jetty/util/TypeUtil.java | 6 ++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java index f5508bee1e1..f2deaf001c2 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ServiceLoaderSpliterator.java @@ -36,16 +36,16 @@ class ServiceLoaderSpliterator implements Spliterator> action) { - Provider next = new Provider<>(); + ServiceProvider next; try { if (!iterator.hasNext()) return false; - next.setServiceProvider(iterator.next()); + next = new ServiceProvider<>(iterator.next()); } catch (Throwable t) { - next.setError(t); + next = new ServiceProvider<>(t); } action.accept(next); @@ -70,18 +70,25 @@ class ServiceLoaderSpliterator implements Spliterator implements ServiceLoader.Provider + /** + * An implementation of the {@link ServiceLoader.Provider} which contains either an instance of the service or + * an error to be thrown when someone calls {@link #get()}. + * @param the service type. + */ + private static class ServiceProvider implements ServiceLoader.Provider { - private T serviceProvider; - private Throwable error; + private final T service; + private final Throwable error; - public void setServiceProvider(T serviceProvider) + public ServiceProvider(T service) { - this.serviceProvider = serviceProvider; + this.service = service; + this.error = null; } - public void setError(Throwable error) + public ServiceProvider(Throwable error) { + this.service = null; this.error = error; } @@ -95,9 +102,9 @@ class ServiceLoaderSpliterator implements Spliterator Stream providerMap(ServiceLoader.Provider provider) + public static Stream mapToService(ServiceLoader.Provider provider) { try { @@ -782,14 +782,14 @@ public class TypeUtil /** * Shortcut method combining {@link #serviceProviderStream(ServiceLoader)} with - * with {@link #providerMap(ServiceLoader.Provider)} using {@link Stream#flatMap(Function)}. + * with {@link #mapToService(ServiceLoader.Provider)} using {@link Stream#flatMap(Function)}. * @param serviceLoader the ServiceLoader instance to use. * @param the type of the service to load. * @return a stream of the service provider type which will not throw {@link ServiceConfigurationError}. */ public static Stream serviceStream(ServiceLoader serviceLoader) { - return serviceProviderStream(serviceLoader).flatMap(TypeUtil::providerMap); + return serviceProviderStream(serviceLoader).flatMap(TypeUtil::mapToService); } /** From 04cecaaaef2ed4579d516b2b5a4c5a6cc3dccc0f Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 20 Mar 2020 17:02:49 +1100 Subject: [PATCH 11/11] Issue #4340 - Change usages to more closely follow previous behaviours Signed-off-by: Lachlan Roberts --- .../client/ALPNClientConnectionFactory.java | 15 +++++++++++- .../server/ALPNServerConnectionFactory.java | 16 ++++++++++++- .../annotations/AnnotationConfiguration.java | 20 ++++++++++++++-- .../jetty/http/PreEncodedHttpField.java | 19 +++++++++++---- .../java/org/eclipse/jetty/util/TypeUtil.java | 11 +++++---- .../jetty/util/security/Credential.java | 5 +++- .../eclipse/jetty/webapp/Configurations.java | 24 ++++++++++++------- .../core/WebSocketExtensionRegistry.java | 16 ++++--------- .../eclipse/jetty/xml/XmlConfiguration.java | 4 +++- 9 files changed, 96 insertions(+), 34 deletions(-) diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index d7814d701b3..900013fa1f4 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -54,8 +54,21 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - TypeUtil.serviceStream(ServiceLoader.load(Client.class)).forEach((processor) -> + TypeUtil.serviceProviderStream(ServiceLoader.load(Client.class)).forEach(provider -> { + Client processor; + try + { + processor = provider.get(); + } + catch (Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug("Unable to load client processor", x); + failure.addSuppressed(x); + return; + } + try { processor.init(); diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 2b7ccab2af5..601d57dd548 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -51,8 +51,22 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - TypeUtil.serviceStream(ServiceLoader.load(Server.class)).forEach((processor) -> + TypeUtil.serviceProviderStream(ServiceLoader.load(Server.class)).forEach(provider -> { + Server processor; + try + { + processor = provider.get(); + } + catch (Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug(x.getMessage(), x); + if (x != failure) + failure.addSuppressed(x); + return; + } + try { processor.init(); diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index af242132af1..fcc31f19c53 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -39,6 +39,7 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.servlet.ServletContainerInitializer; import javax.servlet.annotation.HandlesTypes; @@ -815,8 +816,23 @@ public class AnnotationConfiguration extends AbstractConfiguration long start = 0; if (LOG.isDebugEnabled()) start = System.nanoTime(); - List scis = TypeUtil.serviceStream(ServiceLoader.load(ServletContainerInitializer.class)) - .collect(Collectors.toList()); + List scis = TypeUtil.serviceProviderStream(ServiceLoader.load(ServletContainerInitializer.class)).flatMap(provider -> + { + try + { + return Stream.of(provider.get()); + } + catch (Error e) + { + // Probably a SCI discovered on the system classpath that is hidden by the context classloader + if (LOG.isDebugEnabled()) + LOG.debug("Error: {} for {}", e.getMessage(), context, e); + else + LOG.info("Error: {} for {}", e.getMessage(), context); + return Stream.of(); + } + }).collect(Collectors.toList()); + if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index e4eaba063a8..6cc19ab8090 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -19,9 +19,9 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.List; import java.util.ServiceLoader; -import java.util.stream.Collectors; import org.eclipse.jetty.util.TypeUtil; import org.slf4j.Logger; @@ -43,9 +43,20 @@ public class PreEncodedHttpField extends HttpField static { - List encoders = TypeUtil.serviceStream(ServiceLoader.load(HttpFieldPreEncoder.class)) - .filter(encoder -> index(encoder.getHttpVersion()) >= 0) - .collect(Collectors.toList()); + List encoders = new ArrayList<>(); + TypeUtil.serviceProviderStream(ServiceLoader.load(HttpFieldPreEncoder.class)).forEach(provider -> + { + try + { + HttpFieldPreEncoder encoder = provider.get(); + if (index(encoder.getHttpVersion()) >= 0) + encoders.add(encoder); + } + catch (Error | RuntimeException e) + { + LOG.debug("Unable to add HttpFieldPreEncoder", e); + } + }); LOG.debug("HttpField encoders loaded: {}", encoders); int size = encoders.size(); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index bc49c4b6431..4dd7f21ef6d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -767,7 +767,7 @@ public class TypeUtil * @param provider The service provider to instantiate. * @return a stream of the loaded service providers. */ - public static Stream mapToService(ServiceLoader.Provider provider) + private static Stream mapToService(ServiceLoader.Provider provider) { try { @@ -781,11 +781,12 @@ public class TypeUtil } /** - * Shortcut method combining {@link #serviceProviderStream(ServiceLoader)} with - * with {@link #mapToService(ServiceLoader.Provider)} using {@link Stream#flatMap(Function)}. + * Utility method to provide a stream of the service type from a {@link ServiceLoader}. + * Log warnings will be given for any {@link ServiceConfigurationError}s which occur when loading or + * instantiating the services. * @param serviceLoader the ServiceLoader instance to use. * @param the type of the service to load. - * @return a stream of the service provider type which will not throw {@link ServiceConfigurationError}. + * @return a stream of the service type which will not throw {@link ServiceConfigurationError}. */ public static Stream serviceStream(ServiceLoader serviceLoader) { @@ -802,6 +803,6 @@ public class TypeUtil */ public static Stream> serviceProviderStream(ServiceLoader serviceLoader) { - return StreamSupport.stream(new ServiceLoaderSpliterator(serviceLoader), false); + return StreamSupport.stream(new ServiceLoaderSpliterator<>(serviceLoader), false); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 966d4e37e0a..46aad34040e 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -24,6 +24,7 @@ import java.security.MessageDigest; import java.util.List; import java.util.ServiceLoader; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.jetty.util.TypeUtil; import org.slf4j.Logger; @@ -44,7 +45,9 @@ public abstract class Credential implements Serializable { private static final long serialVersionUID = -7760551052768181572L; private static final Logger LOG = LoggerFactory.getLogger(Credential.class); - private static final List CREDENTIAL_PROVIDERS = TypeUtil.serviceStream(ServiceLoader.load(CredentialProvider.class)).collect(Collectors.toList()); + private static final List CREDENTIAL_PROVIDERS = TypeUtil.serviceProviderStream(ServiceLoader.load(CredentialProvider.class)) + .flatMap(p -> Stream.of(p.get())) + .collect(Collectors.toList()); /** * Check a credential diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java index df2936d0370..c43eac366bd 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configurations.java @@ -75,17 +75,25 @@ public class Configurations extends AbstractList implements Dumpa { if (__known.isEmpty()) { - TypeUtil.serviceStream(ServiceLoader.load(Configuration.class)).forEach(configuration -> + TypeUtil.serviceProviderStream(ServiceLoader.load(Configuration.class)).forEach(provider -> { - if (!configuration.isAvailable()) + try { - if (LOG.isDebugEnabled()) - LOG.debug("Configuration unavailable: " + configuration); - __unavailable.add(configuration); - return; + Configuration configuration = provider.get(); + if (!configuration.isAvailable()) + { + if (LOG.isDebugEnabled()) + LOG.debug("Configuration unavailable: " + configuration); + __unavailable.add(configuration); + return; + } + __known.add(configuration); + __knownByClassName.add(configuration.getClass().getName()); + } + catch (Throwable e) + { + LOG.warn("Unable to get known Configuration", e); } - __known.add(configuration); - __knownByClassName.add(configuration.getClass().getName()); }); sort(__known); diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketExtensionRegistry.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketExtensionRegistry.java index a9d225cc8a0..a6b55884f68 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketExtensionRegistry.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/WebSocketExtensionRegistry.java @@ -26,23 +26,17 @@ import java.util.Set; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; public class WebSocketExtensionRegistry implements Iterable> { - private Map> availableExtensions; + private Map> availableExtensions = new HashMap<>(); public WebSocketExtensionRegistry() { - // Load extensions from container loader - ServiceLoader extensionLoader = ServiceLoader.load(Extension.class, this.getClass().getClassLoader()); - availableExtensions = new HashMap<>(); - for (Extension ext : extensionLoader) - { - if (ext != null) - { - availableExtensions.put(ext.getName(), ext.getClass()); - } - } + // Load extensions from container loader. + TypeUtil.serviceStream(ServiceLoader.load(Extension.class, this.getClass().getClassLoader())) + .forEach(ext -> availableExtensions.put(ext.getName(), ext.getClass())); } public Map> getAvailableExtensions() diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 913b78975f9..cfe5d6a073e 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -53,6 +53,7 @@ import java.util.Queue; import java.util.ServiceLoader; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; @@ -97,7 +98,8 @@ public class XmlConfiguration { ArrayList.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class }; - private static final List PROCESSOR_FACTORIES = TypeUtil.serviceStream(ServiceLoader.load(ConfigurationProcessorFactory.class)) + private static final List PROCESSOR_FACTORIES = TypeUtil.serviceProviderStream(ServiceLoader.load(ConfigurationProcessorFactory.class)) + .flatMap(p -> Stream.of(p.get())) .collect(Collectors.toList()); private static final XmlParser PARSER = initParser(); public static final Comparator EXECUTABLE_COMPARATOR = (e1, e2) ->