/* * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.net.URLConnection; import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; import jdk.internal.misc.JavaLangAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.VM; import jdk.internal.module.ServicesCatalog; import jdk.internal.module.ServicesCatalog.ServiceProvider; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; /** * A simple service-provider loading facility. * *
A service is a well-known set of interfaces and (usually * abstract) classes. A service provider is a specific implementation * of a service. The classes in a provider typically implement the interfaces * and subclass the classes defined in the service itself. * Providers may be developed and deployed as modules and made available using * the application module path. Providers may alternatively be packaged as JAR * files and made available by adding them to the application class path. The * advantage of developing a provider as a module is that the provider can be * fully encapsulated to hide all details of its implementation. * *
For the purpose of loading, a service is represented by a single type, * that is, a single interface or abstract class. (A concrete class can be * used, but this is not recommended.) A provider of a given service contains * one or more concrete classes that extend this service type with data * and code specific to the provider. The provider class is typically * not the entire provider itself but rather a proxy which contains enough * information to decide whether the provider is able to satisfy a particular * request together with code that can create the actual provider on demand. * The details of provider classes tend to be highly service-specific; no * single class or interface could possibly unify them, so no such type is * defined here. * *
A service loader is created by invoking one of the static {@code load} * methods that {@code ServiceLoader} defines. The resulting service loader * can be used to locate and instantiate service provider implementations by * means of its {@link #iterator() iterator} ({@code ServiceLoader} implements * {@code Iterable}) or by consuming elements from its {@link #stream() stream}. * *
As an example, suppose the service type is {@code com.example.CodecSet} * and it defines two abstract methods to obtain encoders and decoders: *
{@code * package com.example; * public interface CodecSet { * Encoder getEncoder(String encodingName); * Decoder getDecoder(String encodingName); * } * }* With this example, the following uses the service loader's iterator to find * a provider that supports a specific encoding: *
{@code * public Encoder getEncoder(String encodingName) { * ServiceLoader* *loader = ServiceLoader.load(CodeSet.class); * for (CodecSet cs : loader) { * Encoder encoder = cs.getEncoder(encodingName); * if (encoder != null) * return encoder; * } * return null; * } * }
Selecting a provider or filtering providers will usually involve invoking * a provider method. In the {@code CodeSet} example, the {@code getEncoder} * method is used to select the implementation. Where selection or filtering based * on the provider class is needed then it can be done when consuming the elements * of the service loader's stream. As an example, the following collects the * {@code CodeSet} implementations that have a specific annotation: *
{@code * Set* *providers = ServiceLoader.load(CodecSet.class) * .stream() * .filter(p -> p.type().isAnnotationPresent(Managed.class)) * .map(Provider::get) * .collect(Collectors.toSet()); * }
Providers are located and instantiated lazily, that is, on demand. A * service loader maintains a cache of the providers that have been loaded so * far. Each invocation of the {@code iterator} method returns an iterator that * first yields all of the elements cached from previous iteration, in * instantiation order, and then lazily locates and instantiates any remaining * providers, adding each one to the cache in turn. Similarly, each invocation * of the {@code stream} method returns a stream that first processes all * providers loaded by previous stream operations, in load order, and then lazily * locates any remaining providers. Caches are cleared via the {@link #reload * reload} method. * *
A provider deployed as an explicit module must have an appropriate * provides clause in its module descriptor to declare that the module * provides an implementation of the service. * *
A provider deployed as an explicit module is instantiated by a * provider factory or directly via the provider's constructor. In the * module declaration then the class name specified in the provides clause * is a provider factory if it is public and explicitly declares a public static * no-args method named "{@code provider}". The return type of the method must be * assignable to the service type. If the class is not a provider factory * then it is public with a public zero-argument constructor. The requirement * that the provider factory or provider class be public helps to document the * intent that the provider will be instantiated by the service-provider loading * facility. * *
Providers deployed as {@link * java.lang.module.ModuleDescriptor#isAutomatic automatic-modules} on the * module path must have a public zero-argument constructor. If the provider * also declares a public static method named "{@code provider}" then it is * ignored. * *
As an example, suppose a module declares the following: * *
{@code * provides com.example.CodecSet with com.example.impl.StandardCodecs; * provides com.example.CodecSet with com.example.impl.ExtendedCodecsFactory; * }* * where *
For this example then {@code StandardCodecs}'s no-arg constructor will * be used to instantiate {@code StandardCodecs}. {@code ExtendedCodecsFactory} * will be treated as a provider factory and {@code * ExtendedCodecsFactory.provider()} will be invoked to obtain the provider. * *
A service provider that is packaged as a JAR file for
* the class path is identified by placing a provider-configuration file
* in the resource directory {@code META-INF/services}. The file's name is
* the fully-qualified binary name
* of the service's type. The file contains a list of fully-qualified binary
* names of concrete provider classes, one per line. Space and tab characters
* surrounding each name, as well as blank lines, are ignored. The comment
* character is {@code '#'} ('\u0023'
,
* NUMBER SIGN); on
* each line all characters following the first comment character are ignored.
* The file must be encoded in UTF-8.
* If a particular concrete provider class is named in more than one
* configuration file, or is named in the same configuration file more than
* once, then the duplicates are ignored. The configuration file naming a
* particular provider need not be in the same JAR file or other distribution
* unit as the provider itself. The provider must be visible from the same
* class loader that was initially queried to locate the configuration file;
* note that this is not necessarily the class loader from which the file was
* actually located.
*
*
For the example, then suppose {@code com.example.impl.StandardCodecs} is * packaged in a JAR file for the class path then the JAR file will contain a * file named: *
{@code * META-INF/services/com.example.CodecSet * }* that contains the line: *
{@code * com.example.impl.StandardCodecs # Standard codecs * }* *
An application or library using this loading facility and developed * and deployed as an explicit module must have an appropriate uses * clause in its module descriptor to declare that the module uses * implementations of the service. Combined with the requirement is that a * provider deployed as an explicit module must have an appropriate * provides clause allows consumers of a service to be linked * to modules containing providers of the service. * *
For the example, if code in a module uses a service loader to load * implementations of {@code com.example.CodecSet} then its module will declare * the usage with:
{@code uses com.example.CodecSet; }* *
When using the service loader's {@code iterator} then its {@link * Iterator#hasNext() hasNext} and {@link Iterator#next() next} methods will * fail with {@link ServiceConfigurationError} if an error occurs locating or * instantiating a provider. When processing the service loader's stream then * {@code ServiceConfigurationError} is thrown by whatever method causes a * provider class to be loaded. * *
When loading or instantiating a provider class in a named module then * {@code ServiceConfigurationError} can be thrown for the following reasons:
* *When reading a provider-configuration file, or loading or instantiating a * provider class named in a provider-configuration file, then {@code * ServiceConfigurationError} can be thrown for the following reasons: * *
Service loaders always execute in the security context of the caller * of the iterator or stream methods and may also be restricted by the security * context of the caller that created the service loader. * Trusted system code should typically invoke the methods in this class, and * the methods of the iterators which they return, from within a privileged * security context. * *
Instances of this class are not safe for use by multiple concurrent * threads. * *
Unless otherwise specified, passing a {@code null} argument to any
* method in this class will cause a {@link NullPointerException} to be thrown.
*
* @param When using a loader's {@link ServiceLoader#stream() stream()} method
* then the elements are of type {@code Provider}. This allows processing
* to select or filter on the provider class without instantiating the
* provider. When a module declares that the provider class is created by a
* provider factory then this method returns the return type of its
* public static "{@code provider()}" method.
*
* @return The provider type
*/
Class extends S> type();
/**
* Returns an instance of the provider.
*
* @return An instance of the provider.
*
* @throws ServiceConfigurationError
* If the service provider cannot be instantiated, or in the
* case of a provider factory, the public static
* "{@code provider()}" method returns {@code null} or throws
* an error or exception. The {@code ServiceConfigurationError}
* will carry an appropriate cause where possible.
*/
@Override S get();
}
/**
* Initializes a new instance of this class for locating service providers
* in a module layer.
*
* @throws ServiceConfigurationError
* If {@code svc} is not accessible to {@code caller} or the caller
* module does not use the service type.
*/
private ServiceLoader(Class> caller, ModuleLayer layer, Class The iterator returned by this method first yields all of the
* elements of the provider cache, in the order that they were loaded.
* It then lazily loads and instantiates any remaining providers,
* adding each one to the cache in turn.
*
* To achieve laziness the actual work of locating and instantiating
* providers must be done by the iterator itself. Its {@link
* java.util.Iterator#hasNext hasNext} and {@link java.util.Iterator#next
* next} methods can therefore throw a {@link ServiceConfigurationError}
* if a provider class cannot be loaded, doesn't have an appropriate static
* factory method or constructor, can't be assigned to the service type or
* if any other kind of exception or error is thrown as the next provider
* is located and instantiated. To write robust code it is only necessary
* to catch {@link ServiceConfigurationError} when using a service iterator.
*
* If such an error is thrown then subsequent invocations of the
* iterator will make a best effort to locate and instantiate the next
* available provider, but in general such recovery cannot be guaranteed.
*
* If this loader's provider caches are cleared by invoking the {@link
* #reload() reload} method then existing iterators for this service
* loader should be discarded.
* The {@link java.util.Iterator#hasNext() hasNext} and {@link
* java.util.Iterator#next() next} methods of the iterator throw {@link
* java.util.ConcurrentModificationException ConcurrentModificationException}
* if used after the provider cache has been cleared.
*
* The iterator returned by this method does not support removal.
* Invoking its {@link java.util.Iterator#remove() remove} method will
* cause an {@link UnsupportedOperationException} to be thrown.
*
* @return An iterator that lazily loads providers for this loader's
* service
*
* @revised 9
* @spec JPMS
*/
public Iterator When processing the stream then providers that were previously
* loaded by stream operations are processed first, in load order. It then
* lazily loads any remaining providers. If a provider class cannot be
* loaded, can't be assigned to the service type, or some other error is
* thrown when locating the provider then it is wrapped with a {@code
* ServiceConfigurationError} and thrown by whatever method caused the
* provider to be loaded. If this loader's provider caches are cleared by invoking the {@link
* #reload() reload} method then existing streams for this service loader
* should be discarded. The returned stream's source {@code Spliterator} is
* fail-fast and will throw {@link ConcurrentModificationException}
* if the provider cache has been cleared. The following examples demonstrate usage. The first example
* creates a stream of providers, the second example is the same except
* that it sorts the providers by provider class name (and so locate all
* providers).
* Service providers are located in named modules defined to the
* class loader, or any class loader that is reachable via parent
* delegation. Additionally, and with the exception of the bootstrap and {@linkplain
* ClassLoader#getPlatformClassLoader() platform} class loaders, if the
* class loader, or any class loader reachable via parent delegation,
* defines modules in a module layer then the providers in the module layer
* are located. For example, suppose there is a module layer where each
* module is defined to its own class loader (see {@link
* ModuleLayer#defineModulesWithManyLoaders defineModulesWithManyLoaders}).
* If this {@code ServiceLoader.load} method is invoked to locate providers
* using any of the class loaders created for this layer then it will locate
* all of the providers in that layer, irrespective of their defining class
* loader. A provider is an unnamed modules is located if its class
* name is listed in a service configuration file located by the the class
* loader's {@link ClassLoader#getResources(String) getResources} method.
* The provider class must be visible to the class loader. If a provider
* class is in a named module is listed then it is ignored (this is to
* avoid duplicates that would otherwise arise when a module has both a
* provides clause and a service configuration file in {@code
* META-INF/services} that lists the same provider). The ordering that the service loader's iterator and stream locate
* providers and yield elements is as follows:
*
* Providers in named modules are located before service
* providers in unnamed modules. When locating providers in named modules then the service
* loader will first locate any service providers in modules defined to
* the class loader, then its parent class loader, its parent parent,
* and so on to the bootstrap class loader. If a class loader or any
* class loader in the parent delegation chain, defines modules in a
* module layer then all providers in that layer are located
* (irrespective of their class loader) before providers in the parent
* class loader are located. The ordering of modules defined to the
* same class loader, or the ordering of modules in a layer, is not
* defined. If a named module declares more than one provider then the
* providers are located in the order that its module descriptor
* {@linkplain java.lang.module.ModuleDescriptor.Provides#providers()
* lists the providers}. Providers added dynamically by instrumentation
* agents (see {@link java.lang.instrument.Instrumentation#redefineModule
* redefineModule}) are always located after providers declared by the
* module. When locating providers in unnamed modules then the
* ordering is based on the order that the class loader's {@link
* ClassLoader#getResources(String) getResources} method finds the
* service configuration files and within that, the order that the class
* names are listed in the file. This activity is normal, although it may cause puzzling entries to be
* created in web-server logs. If a web server is not configured correctly,
* however, then this activity may cause the provider-loading algorithm to fail
* spuriously.
*
* A web server should return an HTTP 404 (Not Found) response when a
* requested resource does not exist. Sometimes, however, web servers are
* erroneously configured to return an HTTP 200 (OK) response along with a
* helpful HTML error page in such cases. This will cause a {@link
* ServiceConfigurationError} to be thrown when this class attempts to parse
* the HTML page as a provider-configuration file. The best solution to this
* problem is to fix the misconfigured web server to return the correct
* response code (HTTP 404) along with the HTML error page.
*
* @param An invocation of this convenience method of the form
* This convenience method is equivalent to: This method is intended for use when only installed providers are
* desired. The resulting service will only find and load providers that
* have been installed into the current Java virtual machine; providers on
* the application's module path or class path will be ignored.
*
* @param The ordering that the service loader's iterator and stream locate
* providers and yield elements is as follows:
*
* Providers are located in a module layer before locating providers
* in parent layers. Traversal of parent layers is depth-first with each
* layer visited at most once. For example, suppose L0 is the boot layer, L1
* and L2 are modules layers with L0 as their parent. Now suppose that L3 is
* created with L1 and L2 as the parents (in that order). Using a service
* loader to locate providers with L3 as the context will locate providers
* in the following order: L3, L1, L0, L2. If a named module declares more than one provider then the
* providers are located in the order that its module descriptor
* {@linkplain java.lang.module.ModuleDescriptor.Provides#providers()
* lists the providers}. Providers added dynamically by instrumentation
* agents are always located after providers declared by the module. The ordering of modules in a module layer is not defined. The following example loads the first available provider. If there
* are no providers deployed then it uses a default implementation.
* After invoking this method, subsequent invocations of the {@link
* #iterator() iterator} or {@link #stream() stream} methods will lazily
* look up providers (and instantiate in the case of {@code iterator})
* from scratch, just as is done by a newly-created loader.
*
* This method is intended for use in situations in which new providers
* can be installed into a running Java virtual machine.
*/
public void reload() {
lookupIterator1 = null;
instantiatedProviders.clear();
lookupIterator2 = null;
loadedProviders.clear();
loadedAllProviders = false;
// increment count to allow CME be thrown
reloadCount++;
}
/**
* Returns a string describing this service.
*
* @return A descriptive string
*/
public String toString() {
return "java.util.ServiceLoader[" + service.getName() + "]";
}
}
* The type of the service to be loaded by this loader
*
* @author Mark Reinhold
* @since 1.6
* @revised 9
* @spec JPMS
*/
public final class ServiceLoader
implements Iterable
{
// The class or interface representing the service being loaded
private final Class service;
// The class of the service type
private final String serviceName;
// The module layer used to locate providers; null when locating
// providers using a class loader
private final ModuleLayer layer;
// The class loader used to locate, load, and instantiate providers;
// null when locating provider using a module layer
private final ClassLoader loader;
// The access control context taken when the ServiceLoader is created
private final AccessControlContext acc;
// The lazy-lookup iterator for iterator operations
private Iterator instantiatedProviders = new ArrayList<>();
// The lazy-lookup iterator for stream operations
private Iterator The service type
* @since 9
* @spec JPMS
*/
public static interface Provider extends Supplier {
/**
* Returns the provider type. There is no guarantee that this type is
* accessible or that it has a public no-args constructor. The {@link
* #get() get()} method should be used to obtain the provider instance.
*
* svc) {
Objects.requireNonNull(caller);
Objects.requireNonNull(layer);
Objects.requireNonNull(svc);
checkCaller(caller, svc);
this.service = svc;
this.serviceName = svc.getName();
this.layer = layer;
this.loader = null;
this.acc = (System.getSecurityManager() != null)
? AccessController.getContext()
: null;
}
/**
* Initializes a new instance of this class for locating service providers
* via a class loader.
*
* @throws ServiceConfigurationError
* If {@code svc} is not accessible to {@code caller} or the caller
* module does not use the service type.
*/
private ServiceLoader(Class> caller, Class svc, ClassLoader cl) {
Objects.requireNonNull(svc);
if (VM.isBooted()) {
checkCaller(caller, svc);
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
} else {
// if we get here then it means that ServiceLoader is being used
// before the VM initialization has completed. At this point then
// only code in the java.base should be executing.
Module callerModule = caller.getModule();
Module base = Object.class.getModule();
Module svcModule = svc.getModule();
if (callerModule != base || svcModule != base) {
fail(svc, "not accessible to " + callerModule + " during VM init");
}
// restricted to boot loader during startup
cl = null;
}
this.service = svc;
this.serviceName = svc.getName();
this.layer = null;
this.loader = cl;
this.acc = (System.getSecurityManager() != null)
? AccessController.getContext()
: null;
}
/**
* Initializes a new instance of this class for locating service providers
* via a class loader.
*
* @apiNote For use by ResourceBundle
*
* @throws ServiceConfigurationError
* If the caller module does not use the service type.
*/
private ServiceLoader(Module callerModule, Class svc, ClassLoader cl) {
if (!callerModule.canUse(svc)) {
fail(svc, callerModule + " does not declare `uses`");
}
this.service = Objects.requireNonNull(svc);
this.serviceName = svc.getName();
this.layer = null;
this.loader = cl;
this.acc = (System.getSecurityManager() != null)
? AccessController.getContext()
: null;
}
/**
* Checks that the given service type is accessible to types in the given
* module, and check that the module declares that it uses the service type.
*/
private static void checkCaller(Class> caller, Class> svc) {
if (caller == null) {
fail(svc, "no caller to check if it declares `uses`");
}
// Check access to the service type
Module callerModule = caller.getModule();
int mods = svc.getModifiers();
if (!Reflection.verifyMemberAccess(caller, svc, null, mods)) {
fail(svc, "service type not accessible to " + callerModule);
}
// If the caller is in a named module then it should "uses" the
// service type
if (!callerModule.canUse(svc)) {
fail(svc, callerModule + " does not declare `uses`");
}
}
private static void fail(Class> service, String msg, Throwable cause)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg,
cause);
}
private static void fail(Class> service, String msg)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg);
}
private static void fail(Class> service, URL u, int line, String msg)
throws ServiceConfigurationError
{
fail(service, u + ":" + line + ": " + msg);
}
/**
* Returns {@code true} if the provider is in an explicit module
*/
private boolean inExplicitModule(Class> clazz) {
Module module = clazz.getModule();
return module.isNamed() && !module.getDescriptor().isAutomatic();
}
/**
* Returns the public static "provider" method if found.
*
* @throws ServiceConfigurationError if there is an error finding the
* provider method or there is more than one public static
* provider method
*/
private Method findStaticProviderMethod(Class> clazz) {
List implements Provider {
final Class service;
final Class extends S> type;
final Method factoryMethod; // factory method or null
final Constructor extends S> ctor; // public no-args constructor or null
final AccessControlContext acc;
ProviderImpl(Class service,
Class extends S> type,
Method factoryMethod,
AccessControlContext acc) {
this.service = service;
this.type = type;
this.factoryMethod = factoryMethod;
this.ctor = null;
this.acc = acc;
}
ProviderImpl(Class service,
Class extends S> type,
Constructor extends S> ctor,
AccessControlContext acc) {
this.service = service;
this.type = type;
this.factoryMethod = null;
this.ctor = ctor;
this.acc = acc;
}
@Override
public Class extends S> type() {
return type;
}
@Override
public S get() {
if (factoryMethod != null) {
return invokeFactoryMethod();
} else {
return newInstance();
}
}
/**
* Invokes the provider's "provider" method to instantiate a provider.
* When running with a security manager then the method runs with
* permissions that are restricted by the security context of whatever
* created this loader.
*/
private S invokeFactoryMethod() {
Object result = null;
Throwable exc = null;
if (acc == null) {
try {
result = factoryMethod.invoke(null);
} catch (Throwable x) {
exc = x;
}
} else {
PrivilegedExceptionAction> pa = new PrivilegedExceptionAction<>() {
@Override
public Object run() throws Exception {
return factoryMethod.invoke(null);
}
};
// invoke factory method with permissions restricted by acc
try {
result = AccessController.doPrivileged(pa, acc);
} catch (PrivilegedActionException pae) {
exc = pae.getCause();
}
}
if (exc != null) {
if (exc instanceof InvocationTargetException)
exc = exc.getCause();
fail(service, factoryMethod + " failed", exc);
}
if (result == null) {
fail(service, factoryMethod + " returned null");
}
@SuppressWarnings("unchecked")
S p = (S) result;
return p;
}
/**
* Invokes Constructor::newInstance to instantiate a provider. When running
* with a security manager then the constructor runs with permissions that
* are restricted by the security context of whatever created this loader.
*/
private S newInstance() {
S p = null;
Throwable exc = null;
if (acc == null) {
try {
p = ctor.newInstance();
} catch (Throwable x) {
exc = x;
}
} else {
PrivilegedExceptionAction pa = new PrivilegedExceptionAction<>() {
@Override
public S run() throws Exception {
return ctor.newInstance();
}
};
// invoke constructor with permissions restricted by acc
try {
p = AccessController.doPrivileged(pa, acc);
} catch (PrivilegedActionException pae) {
exc = pae.getCause();
}
}
if (exc != null) {
if (exc instanceof InvocationTargetException)
exc = exc.getCause();
String cn = ctor.getDeclaringClass().getName();
fail(service,
"Provider " + cn + " could not be instantiated", exc);
}
return p;
}
// For now, equals/hashCode uses the access control context to ensure
// that two Providers created with different contexts are not equal
// when running with a security manager.
@Override
public int hashCode() {
return Objects.hash(service, type, acc);
}
@Override
public boolean equals(Object ob) {
if (!(ob instanceof ProviderImpl))
return false;
@SuppressWarnings("unchecked")
ProviderImpl> that = (ProviderImpl>)ob;
return this.service == that.service
&& this.type == that.type
&& Objects.equals(this.acc, that.acc);
}
}
/**
* Loads a service provider in a module.
*
* Returns {@code null} if the service provider's module doesn't read
* the module with the service type.
*
* @throws ServiceConfigurationError if the class cannot be loaded or
* isn't the expected sub-type (or doesn't define a provider
* factory method that returns the expected type)
*/
private Provider loadProvider(ServiceProvider provider) {
Module module = provider.module();
if (!module.canRead(service.getModule())) {
// module does not read the module with the service type
return null;
}
String cn = provider.providerName();
Class> clazz = null;
if (acc == null) {
try {
clazz = Class.forName(module, cn);
} catch (LinkageError e) {
fail(service, "Unable to load " + cn, e);
}
} else {
PrivilegedExceptionAction(service, type, factoryMethod, acc);
}
}
// no factory method so must be a subtype
if (!service.isAssignableFrom(clazz)) {
fail(service, clazz.getName() + " not a subtype");
}
@SuppressWarnings("unchecked")
Class extends S> type = (Class extends S>) clazz;
@SuppressWarnings("unchecked")
Constructor extends S> ctor = (Constructor extends S> ) getConstructor(clazz);
return new ProviderImpl(service, type, ctor, acc);
}
/**
* Implements lazy service provider lookup of service providers that
* are provided by modules in a module layer (or parent layers)
*/
private final class LayerLookupIterator p = new ProviderImpl(service, type, ctor, acc);
nextProvider = (ProviderImpl next() {
if (first.hasNext()) {
return first.next();
} else if (second.hasNext()) {
return second.next();
} else {
throw new NoSuchElementException();
}
}
};
}
}
/**
* Lazily load and instantiate the available providers of this loader's
* service.
*
* Design Note
* Throwing an error in these cases may seem extreme. The rationale for
* this behavior is that a malformed provider-configuration file, like a
* malformed class file, indicates a serious problem with the way the Java
* virtual machine is configured or is being used. As such it is
* preferable to throw an error rather than try to recover or, even worse,
* fail silently.
*
* iterator() {
// create lookup iterator if needed
if (lookupIterator1 == null) {
lookupIterator1 = newLookupIterator();
}
return new Iterator() {
// record reload count
final int expectedReloadCount = ServiceLoader.this.reloadCount;
// index into the cached providers list
int index;
/**
* Throws ConcurrentModificationException if the list of cached
* providers has been cleared by reload.
*/
private void checkReloadCount() {
if (ServiceLoader.this.reloadCount != expectedReloadCount)
throw new ConcurrentModificationException();
}
@Override
public boolean hasNext() {
checkReloadCount();
if (index < instantiatedProviders.size())
return true;
return lookupIterator1.hasNext();
}
@Override
public S next() {
checkReloadCount();
S next;
if (index < instantiatedProviders.size()) {
next = instantiatedProviders.get(index);
} else {
next = lookupIterator1.next().get();
instantiatedProviders.add(next);
}
index++;
return next;
}
};
}
/**
* Returns a stream that lazily loads the available providers of this
* loader's service. The stream elements are of type {@link Provider
* Provider}, the {@code Provider}'s {@link Provider#get() get} method
* must be invoked to get or instantiate the provider.
*
* {@code
* Stream
*
* @return A stream that lazily loads providers for this loader's service
*
* @since 9
* @spec JPMS
*/
public Stream the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @param loader
* The class loader to be used to load provider-configuration files
* and provider classes, or {@code null} if the system class
* loader (or, failing that, the bootstrap class loader) is to be
* used
*
* @param callerModule
* The caller's module for which a new service loader is created
*
* @return A new service loader
*/
static ServiceLoader load(Class service,
ClassLoader loader,
Module callerModule)
{
return new ServiceLoader<>(callerModule, service, loader);
}
/**
* Creates a new service loader for the given service type and class
* loader. The service loader locates service providers in both named and
* unnamed modules:
*
*
*
*
*
*
*
* @apiNote If the class path of the class loader includes remote network
* URLs then those URLs may be dereferenced in the process of searching for
* provider-configuration files.
*
* the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @param loader
* The class loader to be used to load provider-configuration files
* and provider classes, or {@code null} if the system class
* loader (or, failing that, the bootstrap class loader) is to be
* used
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @revised 9
* @spec JPMS
*/
@CallerSensitive
public static ServiceLoader load(Class service,
ClassLoader loader)
{
return new ServiceLoader<>(Reflection.getCallerClass(), service, loader);
}
/**
* Creates a new service loader for the given service type, using the
* current thread's {@linkplain java.lang.Thread#getContextClassLoader
* context class loader}.
*
* {@code
* ServiceLoader.load(service)
* }
*
* is equivalent to
*
* {@code
* ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
* }
*
* @apiNote Service loader objects obtained with this method should not be
* cached VM-wide. For example, different applications in the same VM may
* have different thread context class loaders. A lookup by one application
* may locate a service provider that is only visible via its thread
* context class loader and so is not suitable to be located by the other
* application. Memory leaks can also arise. A thread local may be suited
* to some applications.
*
* @param the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @revised 9
* @spec JPMS
*/
@CallerSensitive
public static ServiceLoader load(Class service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
}
/**
* Creates a new service loader for the given service type, using the
* {@linkplain ClassLoader#getPlatformClassLoader() platform class loader}.
*
* {@code
* ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
* }
*
* the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @revised 9
* @spec JPMS
*/
@CallerSensitive
public static ServiceLoader loadInstalled(Class service) {
ClassLoader cl = ClassLoader.getPlatformClassLoader();
return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
}
/**
* Creates a new service loader for the given service type to load service
* providers from modules in the given module layer and its ancestors. It
* does not locate providers in unnamed modules.
*
*
*
*
* @apiNote Unlike the other load methods defined here, the service type
* is the second parameter. The reason for this is to avoid source
* compatibility issues for code that uses {@code load(S, null)}.
*
* @param the class of the service type
*
* @param layer
* The module layer
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @since 9
* @spec JPMS
*/
@CallerSensitive
public static ServiceLoader load(ModuleLayer layer, Class service) {
return new ServiceLoader<>(Reflection.getCallerClass(), layer, service);
}
/**
* Load the first available provider of this loader's service. This
* convenience method is equivalent to invoking the {@link #iterator()
* iterator()} method and obtaining the first element. It therefore
* returns the first element from the provider cache if possible, it
* otherwise attempts to load and instantiate the first provider.
*
* {@code
* CodecSet provider =
* ServiceLoader.load(CodecSet.class).findFirst().orElse(DEFAULT_CODECSET);
* }
* @return The first provider or empty {@code Optional} if no providers
* are located
*
* @throws ServiceConfigurationError
* If a provider class cannot be loaded, doesn't have the
* appropriate static factory method or constructor, can't be
* assigned to the service type, or if any other kind of exception
* or error is thrown when locating or instantiating the provider.
*
* @since 9
* @spec JPMS
*/
public Optional findFirst() {
Iterator iterator = iterator();
if (iterator.hasNext()) {
return Optional.of(iterator.next());
} else {
return Optional.empty();
}
}
/**
* Clear this loader's provider cache so that all providers will be
* reloaded.
*
*