1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/emul/compact/src/main/java/java/util/ServiceLoader.java Wed Jan 23 22:32:27 2013 +0100
1.3 @@ -0,0 +1,538 @@
1.4 +/*
1.5 + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package java.util;
1.30 +
1.31 +import java.io.BufferedReader;
1.32 +import java.io.IOException;
1.33 +import java.io.InputStream;
1.34 +import java.io.InputStreamReader;
1.35 +import java.net.URL;
1.36 +import java.util.ArrayList;
1.37 +import java.util.Enumeration;
1.38 +import java.util.Iterator;
1.39 +import java.util.List;
1.40 +import java.util.NoSuchElementException;
1.41 +
1.42 +
1.43 +/**
1.44 + * A simple service-provider loading facility.
1.45 + *
1.46 + * <p> A <i>service</i> is a well-known set of interfaces and (usually
1.47 + * abstract) classes. A <i>service provider</i> is a specific implementation
1.48 + * of a service. The classes in a provider typically implement the interfaces
1.49 + * and subclass the classes defined in the service itself. Service providers
1.50 + * can be installed in an implementation of the Java platform in the form of
1.51 + * extensions, that is, jar files placed into any of the usual extension
1.52 + * directories. Providers can also be made available by adding them to the
1.53 + * application's class path or by some other platform-specific means.
1.54 + *
1.55 + * <p> For the purpose of loading, a service is represented by a single type,
1.56 + * that is, a single interface or abstract class. (A concrete class can be
1.57 + * used, but this is not recommended.) A provider of a given service contains
1.58 + * one or more concrete classes that extend this <i>service type</i> with data
1.59 + * and code specific to the provider. The <i>provider class</i> is typically
1.60 + * not the entire provider itself but rather a proxy which contains enough
1.61 + * information to decide whether the provider is able to satisfy a particular
1.62 + * request together with code that can create the actual provider on demand.
1.63 + * The details of provider classes tend to be highly service-specific; no
1.64 + * single class or interface could possibly unify them, so no such type is
1.65 + * defined here. The only requirement enforced by this facility is that
1.66 + * provider classes must have a zero-argument constructor so that they can be
1.67 + * instantiated during loading.
1.68 + *
1.69 + * <p><a name="format"> A service provider is identified by placing a
1.70 + * <i>provider-configuration file</i> in the resource directory
1.71 + * <tt>META-INF/services</tt>. The file's name is the fully-qualified <a
1.72 + * href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
1.73 + * The file contains a list of fully-qualified binary names of concrete
1.74 + * provider classes, one per line. Space and tab characters surrounding each
1.75 + * name, as well as blank lines, are ignored. The comment character is
1.76 + * <tt>'#'</tt> (<tt>'\u0023'</tt>, <font size="-1">NUMBER SIGN</font>); on
1.77 + * each line all characters following the first comment character are ignored.
1.78 + * The file must be encoded in UTF-8.
1.79 + *
1.80 + * <p> If a particular concrete provider class is named in more than one
1.81 + * configuration file, or is named in the same configuration file more than
1.82 + * once, then the duplicates are ignored. The configuration file naming a
1.83 + * particular provider need not be in the same jar file or other distribution
1.84 + * unit as the provider itself. The provider must be accessible from the same
1.85 + * class loader that was initially queried to locate the configuration file;
1.86 + * note that this is not necessarily the class loader from which the file was
1.87 + * actually loaded.
1.88 + *
1.89 + * <p> Providers are located and instantiated lazily, that is, on demand. A
1.90 + * service loader maintains a cache of the providers that have been loaded so
1.91 + * far. Each invocation of the {@link #iterator iterator} method returns an
1.92 + * iterator that first yields all of the elements of the cache, in
1.93 + * instantiation order, and then lazily locates and instantiates any remaining
1.94 + * providers, adding each one to the cache in turn. The cache can be cleared
1.95 + * via the {@link #reload reload} method.
1.96 + *
1.97 + * <p> Service loaders always execute in the security context of the caller.
1.98 + * Trusted system code should typically invoke the methods in this class, and
1.99 + * the methods of the iterators which they return, from within a privileged
1.100 + * security context.
1.101 + *
1.102 + * <p> Instances of this class are not safe for use by multiple concurrent
1.103 + * threads.
1.104 + *
1.105 + * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
1.106 + * method in this class will cause a {@link NullPointerException} to be thrown.
1.107 + *
1.108 + *
1.109 + * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
1.110 + * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
1.111 + * intended to represent sets of encoder/decoder pairs for some protocol. In
1.112 + * this case it is an abstract class with two abstract methods:
1.113 + *
1.114 + * <blockquote><pre>
1.115 + * public abstract Encoder getEncoder(String encodingName);
1.116 + * public abstract Decoder getDecoder(String encodingName);</pre></blockquote>
1.117 + *
1.118 + * Each method returns an appropriate object or <tt>null</tt> if the provider
1.119 + * does not support the given encoding. Typical providers support more than
1.120 + * one encoding.
1.121 + *
1.122 + * <p> If <tt>com.example.impl.StandardCodecs</tt> is an implementation of the
1.123 + * <tt>CodecSet</tt> service then its jar file also contains a file named
1.124 + *
1.125 + * <blockquote><pre>
1.126 + * META-INF/services/com.example.CodecSet</pre></blockquote>
1.127 + *
1.128 + * <p> This file contains the single line:
1.129 + *
1.130 + * <blockquote><pre>
1.131 + * com.example.impl.StandardCodecs # Standard codecs</pre></blockquote>
1.132 + *
1.133 + * <p> The <tt>CodecSet</tt> class creates and saves a single service instance
1.134 + * at initialization:
1.135 + *
1.136 + * <blockquote><pre>
1.137 + * private static ServiceLoader<CodecSet> codecSetLoader
1.138 + * = ServiceLoader.load(CodecSet.class);</pre></blockquote>
1.139 + *
1.140 + * <p> To locate an encoder for a given encoding name it defines a static
1.141 + * factory method which iterates through the known and available providers,
1.142 + * returning only when it has located a suitable encoder or has run out of
1.143 + * providers.
1.144 + *
1.145 + * <blockquote><pre>
1.146 + * public static Encoder getEncoder(String encodingName) {
1.147 + * for (CodecSet cp : codecSetLoader) {
1.148 + * Encoder enc = cp.getEncoder(encodingName);
1.149 + * if (enc != null)
1.150 + * return enc;
1.151 + * }
1.152 + * return null;
1.153 + * }</pre></blockquote>
1.154 + *
1.155 + * <p> A <tt>getDecoder</tt> method is defined similarly.
1.156 + *
1.157 + *
1.158 + * <p><span style="font-weight: bold; padding-right: 1em">Usage Note</span> If
1.159 + * the class path of a class loader that is used for provider loading includes
1.160 + * remote network URLs then those URLs will be dereferenced in the process of
1.161 + * searching for provider-configuration files.
1.162 + *
1.163 + * <p> This activity is normal, although it may cause puzzling entries to be
1.164 + * created in web-server logs. If a web server is not configured correctly,
1.165 + * however, then this activity may cause the provider-loading algorithm to fail
1.166 + * spuriously.
1.167 + *
1.168 + * <p> A web server should return an HTTP 404 (Not Found) response when a
1.169 + * requested resource does not exist. Sometimes, however, web servers are
1.170 + * erroneously configured to return an HTTP 200 (OK) response along with a
1.171 + * helpful HTML error page in such cases. This will cause a {@link
1.172 + * ServiceConfigurationError} to be thrown when this class attempts to parse
1.173 + * the HTML page as a provider-configuration file. The best solution to this
1.174 + * problem is to fix the misconfigured web server to return the correct
1.175 + * response code (HTTP 404) along with the HTML error page.
1.176 + *
1.177 + * @param <S>
1.178 + * The type of the service to be loaded by this loader
1.179 + *
1.180 + * @author Mark Reinhold
1.181 + * @since 1.6
1.182 + */
1.183 +
1.184 +public final class ServiceLoader<S>
1.185 + implements Iterable<S>
1.186 +{
1.187 +
1.188 + private static final String PREFIX = "META-INF/services/";
1.189 +
1.190 + // The class or interface representing the service being loaded
1.191 + private Class<S> service;
1.192 +
1.193 + // The class loader used to locate, load, and instantiate providers
1.194 + private ClassLoader loader;
1.195 +
1.196 + // Cached providers, in instantiation order
1.197 + private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
1.198 +
1.199 + // The current lazy-lookup iterator
1.200 + private LazyIterator lookupIterator;
1.201 +
1.202 + /**
1.203 + * Clear this loader's provider cache so that all providers will be
1.204 + * reloaded.
1.205 + *
1.206 + * <p> After invoking this method, subsequent invocations of the {@link
1.207 + * #iterator() iterator} method will lazily look up and instantiate
1.208 + * providers from scratch, just as is done by a newly-created loader.
1.209 + *
1.210 + * <p> This method is intended for use in situations in which new providers
1.211 + * can be installed into a running Java virtual machine.
1.212 + */
1.213 + public void reload() {
1.214 + providers.clear();
1.215 + lookupIterator = new LazyIterator(service, loader);
1.216 + }
1.217 +
1.218 + private ServiceLoader(Class<S> svc, ClassLoader cl) {
1.219 + service = svc;
1.220 + loader = cl;
1.221 + reload();
1.222 + }
1.223 +
1.224 + private static void fail(Class service, String msg, Throwable cause)
1.225 + throws ServiceConfigurationError
1.226 + {
1.227 + throw new ServiceConfigurationError(service.getName() + ": " + msg,
1.228 + cause);
1.229 + }
1.230 +
1.231 + private static void fail(Class service, String msg)
1.232 + throws ServiceConfigurationError
1.233 + {
1.234 + throw new ServiceConfigurationError(service.getName() + ": " + msg);
1.235 + }
1.236 +
1.237 + private static void fail(Class service, URL u, int line, String msg)
1.238 + throws ServiceConfigurationError
1.239 + {
1.240 + fail(service, u + ":" + line + ": " + msg);
1.241 + }
1.242 +
1.243 + // Parse a single line from the given configuration file, adding the name
1.244 + // on the line to the names list.
1.245 + //
1.246 + private int parseLine(Class service, URL u, BufferedReader r, int lc,
1.247 + List<String> names)
1.248 + throws IOException, ServiceConfigurationError
1.249 + {
1.250 + String ln = r.readLine();
1.251 + if (ln == null) {
1.252 + return -1;
1.253 + }
1.254 + int ci = ln.indexOf('#');
1.255 + if (ci >= 0) ln = ln.substring(0, ci);
1.256 + ln = ln.trim();
1.257 + int n = ln.length();
1.258 + if (n != 0) {
1.259 + if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
1.260 + fail(service, u, lc, "Illegal configuration-file syntax");
1.261 + int cp = ln.codePointAt(0);
1.262 + if (!Character.isJavaIdentifierStart(cp))
1.263 + fail(service, u, lc, "Illegal provider-class name: " + ln);
1.264 + for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
1.265 + cp = ln.codePointAt(i);
1.266 + if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
1.267 + fail(service, u, lc, "Illegal provider-class name: " + ln);
1.268 + }
1.269 + if (!providers.containsKey(ln) && !names.contains(ln))
1.270 + names.add(ln);
1.271 + }
1.272 + return lc + 1;
1.273 + }
1.274 +
1.275 + // Parse the content of the given URL as a provider-configuration file.
1.276 + //
1.277 + // @param service
1.278 + // The service type for which providers are being sought;
1.279 + // used to construct error detail strings
1.280 + //
1.281 + // @param u
1.282 + // The URL naming the configuration file to be parsed
1.283 + //
1.284 + // @return A (possibly empty) iterator that will yield the provider-class
1.285 + // names in the given configuration file that are not yet members
1.286 + // of the returned set
1.287 + //
1.288 + // @throws ServiceConfigurationError
1.289 + // If an I/O error occurs while reading from the given URL, or
1.290 + // if a configuration-file format error is detected
1.291 + //
1.292 + private Iterator<String> parse(Class service, URL u)
1.293 + throws ServiceConfigurationError
1.294 + {
1.295 + InputStream in = null;
1.296 + BufferedReader r = null;
1.297 + ArrayList<String> names = new ArrayList<>();
1.298 + try {
1.299 + in = u.openStream();
1.300 + r = new BufferedReader(new InputStreamReader(in, "utf-8"));
1.301 + int lc = 1;
1.302 + while ((lc = parseLine(service, u, r, lc, names)) >= 0);
1.303 + } catch (IOException x) {
1.304 + fail(service, "Error reading configuration file", x);
1.305 + } finally {
1.306 + try {
1.307 + if (r != null) r.close();
1.308 + if (in != null) in.close();
1.309 + } catch (IOException y) {
1.310 + fail(service, "Error closing configuration file", y);
1.311 + }
1.312 + }
1.313 + return names.iterator();
1.314 + }
1.315 +
1.316 + // Private inner class implementing fully-lazy provider lookup
1.317 + //
1.318 + private class LazyIterator
1.319 + implements Iterator<S>
1.320 + {
1.321 +
1.322 + Class<S> service;
1.323 + ClassLoader loader;
1.324 + Enumeration<URL> configs = null;
1.325 + Iterator<String> pending = null;
1.326 + String nextName = null;
1.327 +
1.328 + private LazyIterator(Class<S> service, ClassLoader loader) {
1.329 + this.service = service;
1.330 + this.loader = loader;
1.331 + }
1.332 +
1.333 + public boolean hasNext() {
1.334 + if (nextName != null) {
1.335 + return true;
1.336 + }
1.337 + if (configs == null) {
1.338 + try {
1.339 + String fullName = PREFIX + service.getName();
1.340 + if (loader == null)
1.341 + configs = ClassLoader.getSystemResources(fullName);
1.342 + else
1.343 + configs = loader.getResources(fullName);
1.344 + } catch (IOException x) {
1.345 + fail(service, "Error locating configuration files", x);
1.346 + }
1.347 + }
1.348 + while ((pending == null) || !pending.hasNext()) {
1.349 + if (!configs.hasMoreElements()) {
1.350 + return false;
1.351 + }
1.352 + pending = parse(service, configs.nextElement());
1.353 + }
1.354 + nextName = pending.next();
1.355 + return true;
1.356 + }
1.357 +
1.358 + public S next() {
1.359 + if (!hasNext()) {
1.360 + throw new NoSuchElementException();
1.361 + }
1.362 + String cn = nextName;
1.363 + nextName = null;
1.364 + try {
1.365 + S p = service.cast(Class.forName(cn, true, loader)
1.366 + .newInstance());
1.367 + providers.put(cn, p);
1.368 + return p;
1.369 + } catch (ClassNotFoundException x) {
1.370 + fail(service,
1.371 + "Provider " + cn + " not found");
1.372 + } catch (Throwable x) {
1.373 + fail(service,
1.374 + "Provider " + cn + " could not be instantiated: " + x,
1.375 + x);
1.376 + }
1.377 + throw new Error(); // This cannot happen
1.378 + }
1.379 +
1.380 + public void remove() {
1.381 + throw new UnsupportedOperationException();
1.382 + }
1.383 +
1.384 + }
1.385 +
1.386 + /**
1.387 + * Lazily loads the available providers of this loader's service.
1.388 + *
1.389 + * <p> The iterator returned by this method first yields all of the
1.390 + * elements of the provider cache, in instantiation order. It then lazily
1.391 + * loads and instantiates any remaining providers, adding each one to the
1.392 + * cache in turn.
1.393 + *
1.394 + * <p> To achieve laziness the actual work of parsing the available
1.395 + * provider-configuration files and instantiating providers must be done by
1.396 + * the iterator itself. Its {@link java.util.Iterator#hasNext hasNext} and
1.397 + * {@link java.util.Iterator#next next} methods can therefore throw a
1.398 + * {@link ServiceConfigurationError} if a provider-configuration file
1.399 + * violates the specified format, or if it names a provider class that
1.400 + * cannot be found and instantiated, or if the result of instantiating the
1.401 + * class is not assignable to the service type, or if any other kind of
1.402 + * exception or error is thrown as the next provider is located and
1.403 + * instantiated. To write robust code it is only necessary to catch {@link
1.404 + * ServiceConfigurationError} when using a service iterator.
1.405 + *
1.406 + * <p> If such an error is thrown then subsequent invocations of the
1.407 + * iterator will make a best effort to locate and instantiate the next
1.408 + * available provider, but in general such recovery cannot be guaranteed.
1.409 + *
1.410 + * <blockquote style="font-size: smaller; line-height: 1.2"><span
1.411 + * style="padding-right: 1em; font-weight: bold">Design Note</span>
1.412 + * Throwing an error in these cases may seem extreme. The rationale for
1.413 + * this behavior is that a malformed provider-configuration file, like a
1.414 + * malformed class file, indicates a serious problem with the way the Java
1.415 + * virtual machine is configured or is being used. As such it is
1.416 + * preferable to throw an error rather than try to recover or, even worse,
1.417 + * fail silently.</blockquote>
1.418 + *
1.419 + * <p> The iterator returned by this method does not support removal.
1.420 + * Invoking its {@link java.util.Iterator#remove() remove} method will
1.421 + * cause an {@link UnsupportedOperationException} to be thrown.
1.422 + *
1.423 + * @return An iterator that lazily loads providers for this loader's
1.424 + * service
1.425 + */
1.426 + public Iterator<S> iterator() {
1.427 + return new Iterator<S>() {
1.428 +
1.429 + Iterator<Map.Entry<String,S>> knownProviders
1.430 + = providers.entrySet().iterator();
1.431 +
1.432 + public boolean hasNext() {
1.433 + if (knownProviders.hasNext())
1.434 + return true;
1.435 + return lookupIterator.hasNext();
1.436 + }
1.437 +
1.438 + public S next() {
1.439 + if (knownProviders.hasNext())
1.440 + return knownProviders.next().getValue();
1.441 + return lookupIterator.next();
1.442 + }
1.443 +
1.444 + public void remove() {
1.445 + throw new UnsupportedOperationException();
1.446 + }
1.447 +
1.448 + };
1.449 + }
1.450 +
1.451 + /**
1.452 + * Creates a new service loader for the given service type and class
1.453 + * loader.
1.454 + *
1.455 + * @param service
1.456 + * The interface or abstract class representing the service
1.457 + *
1.458 + * @param loader
1.459 + * The class loader to be used to load provider-configuration files
1.460 + * and provider classes, or <tt>null</tt> if the system class
1.461 + * loader (or, failing that, the bootstrap class loader) is to be
1.462 + * used
1.463 + *
1.464 + * @return A new service loader
1.465 + */
1.466 + public static <S> ServiceLoader<S> load(Class<S> service,
1.467 + ClassLoader loader)
1.468 + {
1.469 + return new ServiceLoader<>(service, loader);
1.470 + }
1.471 +
1.472 + /**
1.473 + * Creates a new service loader for the given service type, using the
1.474 + * current thread's {@linkplain java.lang.Thread#getContextClassLoader
1.475 + * context class loader}.
1.476 + *
1.477 + * <p> An invocation of this convenience method of the form
1.478 + *
1.479 + * <blockquote><pre>
1.480 + * ServiceLoader.load(<i>service</i>)</pre></blockquote>
1.481 + *
1.482 + * is equivalent to
1.483 + *
1.484 + * <blockquote><pre>
1.485 + * ServiceLoader.load(<i>service</i>,
1.486 + * Thread.currentThread().getContextClassLoader())</pre></blockquote>
1.487 + *
1.488 + * @param service
1.489 + * The interface or abstract class representing the service
1.490 + *
1.491 + * @return A new service loader
1.492 + */
1.493 + public static <S> ServiceLoader<S> load(Class<S> service) {
1.494 + ClassLoader cl = Thread.currentThread().getContextClassLoader();
1.495 + return ServiceLoader.load(service, cl);
1.496 + }
1.497 +
1.498 + /**
1.499 + * Creates a new service loader for the given service type, using the
1.500 + * extension class loader.
1.501 + *
1.502 + * <p> This convenience method simply locates the extension class loader,
1.503 + * call it <tt><i>extClassLoader</i></tt>, and then returns
1.504 + *
1.505 + * <blockquote><pre>
1.506 + * ServiceLoader.load(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
1.507 + *
1.508 + * <p> If the extension class loader cannot be found then the system class
1.509 + * loader is used; if there is no system class loader then the bootstrap
1.510 + * class loader is used.
1.511 + *
1.512 + * <p> This method is intended for use when only installed providers are
1.513 + * desired. The resulting service will only find and load providers that
1.514 + * have been installed into the current Java virtual machine; providers on
1.515 + * the application's class path will be ignored.
1.516 + *
1.517 + * @param service
1.518 + * The interface or abstract class representing the service
1.519 + *
1.520 + * @return A new service loader
1.521 + */
1.522 + public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
1.523 + ClassLoader cl = ClassLoader.getSystemClassLoader();
1.524 + ClassLoader prev = null;
1.525 + while (cl != null) {
1.526 + prev = cl;
1.527 + cl = cl.getParent();
1.528 + }
1.529 + return ServiceLoader.load(service, prev);
1.530 + }
1.531 +
1.532 + /**
1.533 + * Returns a string describing this service.
1.534 + *
1.535 + * @return A descriptive string
1.536 + */
1.537 + public String toString() {
1.538 + return "java.util.ServiceLoader[" + service.getName() + "]";
1.539 + }
1.540 +
1.541 +}