/* * Copyright (C) 2014 The Android Open Source Project * Copyright (c) 2005, 2013, 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.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * 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. Service providers * can be installed in an implementation of the Java platform in the form of * extensions, that is, jar files placed into any of the usual extension * directories. Providers can also be made available by adding them to the * application's class path or by some other platform-specific means. * *
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. The only requirement enforced by this facility is that * provider classes must have a zero-argument constructor so that they can be * instantiated during loading. * *
A service provider is identified by placing a * provider-configuration file in the resource directory * 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 * '#' ('\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 accessible 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 loaded. * *
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 {@link #iterator iterator} method returns an * iterator that first yields all of the elements of the cache, in * instantiation order, and then lazily locates and instantiates any remaining * providers, adding each one to the cache in turn. The cache can be cleared * via the {@link #reload reload} method. * *
Service loaders always execute in the security context of the caller. * 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 null argument to any * method in this class will cause a {@link NullPointerException} to be thrown. * * *
Example * Suppose we have a service type com.example.CodecSet which is * intended to represent sets of encoder/decoder pairs for some protocol. In * this case it is an abstract class with two abstract methods: * *
* * Each method returns an appropriate object or null if the provider * does not support the given encoding. Typical providers support more than * one encoding. * ** public abstract Encoder getEncoder(String encodingName); * public abstract Decoder getDecoder(String encodingName);
If com.example.impl.StandardCodecs is an implementation of the * CodecSet service then its jar file also contains a file named * *
* ** META-INF/services/com.example.CodecSet
This file contains the single line: * *
* ** com.example.impl.StandardCodecs # Standard codecs
The CodecSet class creates and saves a single service instance * at initialization: * *
* ** private static ServiceLoader<CodecSet> codecSetLoader * = ServiceLoader.load(CodecSet.class);
To locate an encoder for a given encoding name it defines a static * factory method which iterates through the known and available providers, * returning only when it has located a suitable encoder or has run out of * providers. * *
* ** public static Encoder getEncoder(String encodingName) { * for (CodecSet cp : codecSetLoader) { * Encoder enc = cp.getEncoder(encodingName); * if (enc != null) * return enc; * } * return null; * }
A getDecoder method is defined similarly. * * *
Usage Note If * the class path of a class loader that is used for provider loading includes * remote network URLs then those URLs will be dereferenced in the process of * searching for provider-configuration files. * *
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 After invoking this method, subsequent invocations of the {@link
* #iterator() iterator} method will lazily look up and instantiate
* providers 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() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
private ServiceLoader(Class The iterator returned by this method first yields all of the
* elements of the provider cache, in instantiation order. It then lazily
* loads and instantiates any remaining providers, adding each one to the
* cache in turn.
*
* To achieve laziness the actual work of parsing the available
* provider-configuration files 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-configuration file
* violates the specified format, or if it names a provider class that
* cannot be found and instantiated, or if the result of instantiating the
* class is not assignable 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.
*
* 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.
*
* @implNote When adding providers to the cache, the {@link #iterator
* Iterator} processes resources in the order that the {@link
* java.lang.ClassLoader#getResources(java.lang.String)
* ClassLoader.getResources(String)} method finds the service configuration
* files.
*
* @return An iterator that lazily loads providers for this loader's
* service
*/
public Iterator An invocation of this convenience method of the form
*
* This convenience method simply locates the extension class loader,
* call it extClassLoader, and then returns
*
* If the extension class loader cannot be found then the system class
* loader is used; if there is no system class loader then the bootstrap
* class loader is used.
*
* 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 class path will be ignored.
*
* @param
* The type of the service to be loaded by this loader
*
* @author Mark Reinhold
* @since 1.6
*/
public final class ServiceLoader
implements Iterable
{
private static final String PREFIX = "META-INF/services/";
// The class or interface representing the service being loaded
private final Class service;
// The class loader used to locate, load, and instantiate providers
private final ClassLoader loader;
// The access control context taken when the ServiceLoader is created
// Android-changed: do not use legacy security code.
// private final AccessControlContext acc;
// Cached providers, in instantiation order
private LinkedHashMap svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
// Android-changed: Do not use legacy security code.
// On Android, System.getSecurityManager() is always null.
// acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
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);
}
// Parse a single line from the given configuration file, adding the name
// on the line to the names list.
//
private int parseLine(Class> service, URL u, BufferedReader r, int lc,
List
{
Class service;
ClassLoader loader;
Enumeration service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
// Android-changed: Let the ServiceConfigurationError have a cause.
"Provider " + cn + " not found", x);
// "Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
// Android-changed: Let the ServiceConfigurationError have a cause.
ClassCastException cce = new ClassCastException(
service.getCanonicalName() + " is not assignable from " + c.getCanonicalName());
fail(service,
"Provider " + cn + " not a subtype", cce);
// fail(service,
// "Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}
public boolean hasNext() {
// Android-changed: do not use legacy security code
/* if (acc == null) { */
return hasNextService();
/*
} else {
PrivilegedAction action = new PrivilegedAction() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
*/
}
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* Lazily loads 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() {
return new Iterator() {
Iterator 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 null if the system class
* loader (or, failing that, the bootstrap class loader) is to be
* used
*
* @return A new service loader
*/
public static ServiceLoader load(Class service,
ClassLoader loader)
{
return new ServiceLoader<>(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}.
*
*
*
* is equivalent to
*
*
* ServiceLoader.load(service)
*
* @param
* ServiceLoader.load(service,
* Thread.currentThread().getContextClassLoader())
the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*/
public static ServiceLoader load(Class service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
/**
* Creates a new service loader for the given service type, using the
* extension class loader.
*
*
*
*
* ServiceLoader.load(service, extClassLoader)
the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*/
public static ServiceLoader loadInstalled(Class service) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
ClassLoader prev = null;
while (cl != null) {
prev = cl;
cl = cl.getParent();
}
return ServiceLoader.load(service, prev);
}
// BEGIN Android-added: loadFromSystemProperty(), for internal use.
// Instantiates a class from a system property (used elsewhere in libcore).
/**
* Internal API to support built-in SPIs that check a system property first.
* Returns an instance specified by a property with the class' binary name, or null if
* no such property is set.
* @hide
*/
public static S loadFromSystemProperty(final Class service) {
try {
final String className = System.getProperty(service.getName());
if (className != null) {
Class> c = ClassLoader.getSystemClassLoader().loadClass(className);
return (S) c.newInstance();
}
return null;
} catch (Exception e) {
throw new Error(e);
}
}
// END Android-added: loadFromSystemProperty(), for internal use.
/**
* Returns a string describing this service.
*
* @return A descriptive string
*/
public String toString() {
return "java.util.ServiceLoader[" + service.getName() + "]";
}
}