rt/emul/compact/src/main/java/java/util/ServiceLoader.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 565 emul/compact/src/main/java/java/util/ServiceLoader.java@4d76e93fd886
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
     1 /*
     2  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 package java.util;
    27 
    28 import java.io.BufferedReader;
    29 import java.io.IOException;
    30 import java.io.InputStream;
    31 import java.io.InputStreamReader;
    32 import java.net.URL;
    33 import java.util.ArrayList;
    34 import java.util.Enumeration;
    35 import java.util.Iterator;
    36 import java.util.List;
    37 import java.util.NoSuchElementException;
    38 
    39 
    40 /**
    41  * A simple service-provider loading facility.
    42  *
    43  * <p> A <i>service</i> is a well-known set of interfaces and (usually
    44  * abstract) classes.  A <i>service provider</i> is a specific implementation
    45  * of a service.  The classes in a provider typically implement the interfaces
    46  * and subclass the classes defined in the service itself.  Service providers
    47  * can be installed in an implementation of the Java platform in the form of
    48  * extensions, that is, jar files placed into any of the usual extension
    49  * directories.  Providers can also be made available by adding them to the
    50  * application's class path or by some other platform-specific means.
    51  *
    52  * <p> For the purpose of loading, a service is represented by a single type,
    53  * that is, a single interface or abstract class.  (A concrete class can be
    54  * used, but this is not recommended.)  A provider of a given service contains
    55  * one or more concrete classes that extend this <i>service type</i> with data
    56  * and code specific to the provider.  The <i>provider class</i> is typically
    57  * not the entire provider itself but rather a proxy which contains enough
    58  * information to decide whether the provider is able to satisfy a particular
    59  * request together with code that can create the actual provider on demand.
    60  * The details of provider classes tend to be highly service-specific; no
    61  * single class or interface could possibly unify them, so no such type is
    62  * defined here.  The only requirement enforced by this facility is that
    63  * provider classes must have a zero-argument constructor so that they can be
    64  * instantiated during loading.
    65  *
    66  * <p><a name="format"> A service provider is identified by placing a
    67  * <i>provider-configuration file</i> in the resource directory
    68  * <tt>META-INF/services</tt>.  The file's name is the fully-qualified <a
    69  * href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
    70  * The file contains a list of fully-qualified binary names of concrete
    71  * provider classes, one per line.  Space and tab characters surrounding each
    72  * name, as well as blank lines, are ignored.  The comment character is
    73  * <tt>'#'</tt> (<tt>'&#92;u0023'</tt>, <font size="-1">NUMBER SIGN</font>); on
    74  * each line all characters following the first comment character are ignored.
    75  * The file must be encoded in UTF-8.
    76  *
    77  * <p> If a particular concrete provider class is named in more than one
    78  * configuration file, or is named in the same configuration file more than
    79  * once, then the duplicates are ignored.  The configuration file naming a
    80  * particular provider need not be in the same jar file or other distribution
    81  * unit as the provider itself.  The provider must be accessible from the same
    82  * class loader that was initially queried to locate the configuration file;
    83  * note that this is not necessarily the class loader from which the file was
    84  * actually loaded.
    85  *
    86  * <p> Providers are located and instantiated lazily, that is, on demand.  A
    87  * service loader maintains a cache of the providers that have been loaded so
    88  * far.  Each invocation of the {@link #iterator iterator} method returns an
    89  * iterator that first yields all of the elements of the cache, in
    90  * instantiation order, and then lazily locates and instantiates any remaining
    91  * providers, adding each one to the cache in turn.  The cache can be cleared
    92  * via the {@link #reload reload} method.
    93  *
    94  * <p> Service loaders always execute in the security context of the caller.
    95  * Trusted system code should typically invoke the methods in this class, and
    96  * the methods of the iterators which they return, from within a privileged
    97  * security context.
    98  *
    99  * <p> Instances of this class are not safe for use by multiple concurrent
   100  * threads.
   101  *
   102  * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
   103  * method in this class will cause a {@link NullPointerException} to be thrown.
   104  *
   105  *
   106  * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
   107  * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
   108  * intended to represent sets of encoder/decoder pairs for some protocol.  In
   109  * this case it is an abstract class with two abstract methods:
   110  *
   111  * <blockquote><pre>
   112  * public abstract Encoder getEncoder(String encodingName);
   113  * public abstract Decoder getDecoder(String encodingName);</pre></blockquote>
   114  *
   115  * Each method returns an appropriate object or <tt>null</tt> if the provider
   116  * does not support the given encoding.  Typical providers support more than
   117  * one encoding.
   118  *
   119  * <p> If <tt>com.example.impl.StandardCodecs</tt> is an implementation of the
   120  * <tt>CodecSet</tt> service then its jar file also contains a file named
   121  *
   122  * <blockquote><pre>
   123  * META-INF/services/com.example.CodecSet</pre></blockquote>
   124  *
   125  * <p> This file contains the single line:
   126  *
   127  * <blockquote><pre>
   128  * com.example.impl.StandardCodecs    # Standard codecs</pre></blockquote>
   129  *
   130  * <p> The <tt>CodecSet</tt> class creates and saves a single service instance
   131  * at initialization:
   132  *
   133  * <blockquote><pre>
   134  * private static ServiceLoader&lt;CodecSet&gt; codecSetLoader
   135  *     = ServiceLoader.load(CodecSet.class);</pre></blockquote>
   136  *
   137  * <p> To locate an encoder for a given encoding name it defines a static
   138  * factory method which iterates through the known and available providers,
   139  * returning only when it has located a suitable encoder or has run out of
   140  * providers.
   141  *
   142  * <blockquote><pre>
   143  * public static Encoder getEncoder(String encodingName) {
   144  *     for (CodecSet cp : codecSetLoader) {
   145  *         Encoder enc = cp.getEncoder(encodingName);
   146  *         if (enc != null)
   147  *             return enc;
   148  *     }
   149  *     return null;
   150  * }</pre></blockquote>
   151  *
   152  * <p> A <tt>getDecoder</tt> method is defined similarly.
   153  *
   154  *
   155  * <p><span style="font-weight: bold; padding-right: 1em">Usage Note</span> If
   156  * the class path of a class loader that is used for provider loading includes
   157  * remote network URLs then those URLs will be dereferenced in the process of
   158  * searching for provider-configuration files.
   159  *
   160  * <p> This activity is normal, although it may cause puzzling entries to be
   161  * created in web-server logs.  If a web server is not configured correctly,
   162  * however, then this activity may cause the provider-loading algorithm to fail
   163  * spuriously.
   164  *
   165  * <p> A web server should return an HTTP 404 (Not Found) response when a
   166  * requested resource does not exist.  Sometimes, however, web servers are
   167  * erroneously configured to return an HTTP 200 (OK) response along with a
   168  * helpful HTML error page in such cases.  This will cause a {@link
   169  * ServiceConfigurationError} to be thrown when this class attempts to parse
   170  * the HTML page as a provider-configuration file.  The best solution to this
   171  * problem is to fix the misconfigured web server to return the correct
   172  * response code (HTTP 404) along with the HTML error page.
   173  *
   174  * @param  <S>
   175  *         The type of the service to be loaded by this loader
   176  *
   177  * @author Mark Reinhold
   178  * @since 1.6
   179  */
   180 
   181 public final class ServiceLoader<S>
   182     implements Iterable<S>
   183 {
   184 
   185     private static final String PREFIX = "META-INF/services/";
   186 
   187     // The class or interface representing the service being loaded
   188     private Class<S> service;
   189 
   190     // The class loader used to locate, load, and instantiate providers
   191     private ClassLoader loader;
   192 
   193     // Cached providers, in instantiation order
   194     private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
   195 
   196     // The current lazy-lookup iterator
   197     private LazyIterator lookupIterator;
   198 
   199     /**
   200      * Clear this loader's provider cache so that all providers will be
   201      * reloaded.
   202      *
   203      * <p> After invoking this method, subsequent invocations of the {@link
   204      * #iterator() iterator} method will lazily look up and instantiate
   205      * providers from scratch, just as is done by a newly-created loader.
   206      *
   207      * <p> This method is intended for use in situations in which new providers
   208      * can be installed into a running Java virtual machine.
   209      */
   210     public void reload() {
   211         providers.clear();
   212         lookupIterator = new LazyIterator(service, loader);
   213     }
   214 
   215     private ServiceLoader(Class<S> svc, ClassLoader cl) {
   216         service = svc;
   217         loader = cl;
   218         reload();
   219     }
   220 
   221     private static void fail(Class service, String msg, Throwable cause)
   222         throws ServiceConfigurationError
   223     {
   224         throw new ServiceConfigurationError(service.getName() + ": " + msg,
   225                                             cause);
   226     }
   227 
   228     private static void fail(Class service, String msg)
   229         throws ServiceConfigurationError
   230     {
   231         throw new ServiceConfigurationError(service.getName() + ": " + msg);
   232     }
   233 
   234     private static void fail(Class service, URL u, int line, String msg)
   235         throws ServiceConfigurationError
   236     {
   237         fail(service, u + ":" + line + ": " + msg);
   238     }
   239 
   240     // Parse a single line from the given configuration file, adding the name
   241     // on the line to the names list.
   242     //
   243     private int parseLine(Class service, URL u, BufferedReader r, int lc,
   244                           List<String> names)
   245         throws IOException, ServiceConfigurationError
   246     {
   247         String ln = r.readLine();
   248         if (ln == null) {
   249             return -1;
   250         }
   251         int ci = ln.indexOf('#');
   252         if (ci >= 0) ln = ln.substring(0, ci);
   253         ln = ln.trim();
   254         int n = ln.length();
   255         if (n != 0) {
   256             if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
   257                 fail(service, u, lc, "Illegal configuration-file syntax");
   258             int cp = ln.codePointAt(0);
   259             if (!Character.isJavaIdentifierStart(cp))
   260                 fail(service, u, lc, "Illegal provider-class name: " + ln);
   261             for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
   262                 cp = ln.codePointAt(i);
   263                 if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
   264                     fail(service, u, lc, "Illegal provider-class name: " + ln);
   265             }
   266             if (!providers.containsKey(ln) && !names.contains(ln))
   267                 names.add(ln);
   268         }
   269         return lc + 1;
   270     }
   271 
   272     // Parse the content of the given URL as a provider-configuration file.
   273     //
   274     // @param  service
   275     //         The service type for which providers are being sought;
   276     //         used to construct error detail strings
   277     //
   278     // @param  u
   279     //         The URL naming the configuration file to be parsed
   280     //
   281     // @return A (possibly empty) iterator that will yield the provider-class
   282     //         names in the given configuration file that are not yet members
   283     //         of the returned set
   284     //
   285     // @throws ServiceConfigurationError
   286     //         If an I/O error occurs while reading from the given URL, or
   287     //         if a configuration-file format error is detected
   288     //
   289     private Iterator<String> parse(Class service, URL u)
   290         throws ServiceConfigurationError
   291     {
   292         InputStream in = null;
   293         BufferedReader r = null;
   294         ArrayList<String> names = new ArrayList<>();
   295         try {
   296             in = u.openStream();
   297             r = new BufferedReader(new InputStreamReader(in, "utf-8"));
   298             int lc = 1;
   299             while ((lc = parseLine(service, u, r, lc, names)) >= 0);
   300         } catch (IOException x) {
   301             fail(service, "Error reading configuration file", x);
   302         } finally {
   303             try {
   304                 if (r != null) r.close();
   305                 if (in != null) in.close();
   306             } catch (IOException y) {
   307                 fail(service, "Error closing configuration file", y);
   308             }
   309         }
   310         return names.iterator();
   311     }
   312 
   313     // Private inner class implementing fully-lazy provider lookup
   314     //
   315     private class LazyIterator
   316         implements Iterator<S>
   317     {
   318 
   319         Class<S> service;
   320         ClassLoader loader;
   321         Enumeration<URL> configs = null;
   322         Iterator<String> pending = null;
   323         String nextName = null;
   324 
   325         private LazyIterator(Class<S> service, ClassLoader loader) {
   326             this.service = service;
   327             this.loader = loader;
   328         }
   329 
   330         public boolean hasNext() {
   331             if (nextName != null) {
   332                 return true;
   333             }
   334             if (configs == null) {
   335                 try {
   336                     String fullName = PREFIX + service.getName();
   337                     if (loader == null)
   338                         configs = ClassLoader.getSystemResources(fullName);
   339                     else
   340                         configs = loader.getResources(fullName);
   341                 } catch (IOException x) {
   342                     fail(service, "Error locating configuration files", x);
   343                 }
   344             }
   345             while ((pending == null) || !pending.hasNext()) {
   346                 if (!configs.hasMoreElements()) {
   347                     return false;
   348                 }
   349                 pending = parse(service, configs.nextElement());
   350             }
   351             nextName = pending.next();
   352             return true;
   353         }
   354 
   355         public S next() {
   356             if (!hasNext()) {
   357                 throw new NoSuchElementException();
   358             }
   359             String cn = nextName;
   360             nextName = null;
   361             try {
   362                 S p = service.cast(Class.forName(cn, true, loader)
   363                                    .newInstance());
   364                 providers.put(cn, p);
   365                 return p;
   366             } catch (ClassNotFoundException x) {
   367                 fail(service,
   368                      "Provider " + cn + " not found");
   369             } catch (Throwable x) {
   370                 fail(service,
   371                      "Provider " + cn + " could not be instantiated: " + x,
   372                      x);
   373             }
   374             throw new Error();          // This cannot happen
   375         }
   376 
   377         public void remove() {
   378             throw new UnsupportedOperationException();
   379         }
   380 
   381     }
   382 
   383     /**
   384      * Lazily loads the available providers of this loader's service.
   385      *
   386      * <p> The iterator returned by this method first yields all of the
   387      * elements of the provider cache, in instantiation order.  It then lazily
   388      * loads and instantiates any remaining providers, adding each one to the
   389      * cache in turn.
   390      *
   391      * <p> To achieve laziness the actual work of parsing the available
   392      * provider-configuration files and instantiating providers must be done by
   393      * the iterator itself.  Its {@link java.util.Iterator#hasNext hasNext} and
   394      * {@link java.util.Iterator#next next} methods can therefore throw a
   395      * {@link ServiceConfigurationError} if a provider-configuration file
   396      * violates the specified format, or if it names a provider class that
   397      * cannot be found and instantiated, or if the result of instantiating the
   398      * class is not assignable to the service type, or if any other kind of
   399      * exception or error is thrown as the next provider is located and
   400      * instantiated.  To write robust code it is only necessary to catch {@link
   401      * ServiceConfigurationError} when using a service iterator.
   402      *
   403      * <p> If such an error is thrown then subsequent invocations of the
   404      * iterator will make a best effort to locate and instantiate the next
   405      * available provider, but in general such recovery cannot be guaranteed.
   406      *
   407      * <blockquote style="font-size: smaller; line-height: 1.2"><span
   408      * style="padding-right: 1em; font-weight: bold">Design Note</span>
   409      * Throwing an error in these cases may seem extreme.  The rationale for
   410      * this behavior is that a malformed provider-configuration file, like a
   411      * malformed class file, indicates a serious problem with the way the Java
   412      * virtual machine is configured or is being used.  As such it is
   413      * preferable to throw an error rather than try to recover or, even worse,
   414      * fail silently.</blockquote>
   415      *
   416      * <p> The iterator returned by this method does not support removal.
   417      * Invoking its {@link java.util.Iterator#remove() remove} method will
   418      * cause an {@link UnsupportedOperationException} to be thrown.
   419      *
   420      * @return  An iterator that lazily loads providers for this loader's
   421      *          service
   422      */
   423     public Iterator<S> iterator() {
   424         return new Iterator<S>() {
   425 
   426             Iterator<Map.Entry<String,S>> knownProviders
   427                 = providers.entrySet().iterator();
   428 
   429             public boolean hasNext() {
   430                 if (knownProviders.hasNext())
   431                     return true;
   432                 return lookupIterator.hasNext();
   433             }
   434 
   435             public S next() {
   436                 if (knownProviders.hasNext())
   437                     return knownProviders.next().getValue();
   438                 return lookupIterator.next();
   439             }
   440 
   441             public void remove() {
   442                 throw new UnsupportedOperationException();
   443             }
   444 
   445         };
   446     }
   447 
   448     /**
   449      * Creates a new service loader for the given service type and class
   450      * loader.
   451      *
   452      * @param  service
   453      *         The interface or abstract class representing the service
   454      *
   455      * @param  loader
   456      *         The class loader to be used to load provider-configuration files
   457      *         and provider classes, or <tt>null</tt> if the system class
   458      *         loader (or, failing that, the bootstrap class loader) is to be
   459      *         used
   460      *
   461      * @return A new service loader
   462      */
   463     public static <S> ServiceLoader<S> load(Class<S> service,
   464                                             ClassLoader loader)
   465     {
   466         return new ServiceLoader<>(service, loader);
   467     }
   468 
   469     /**
   470      * Creates a new service loader for the given service type, using the
   471      * current thread's {@linkplain java.lang.Thread#getContextClassLoader
   472      * context class loader}.
   473      *
   474      * <p> An invocation of this convenience method of the form
   475      *
   476      * <blockquote><pre>
   477      * ServiceLoader.load(<i>service</i>)</pre></blockquote>
   478      *
   479      * is equivalent to
   480      *
   481      * <blockquote><pre>
   482      * ServiceLoader.load(<i>service</i>,
   483      *                    Thread.currentThread().getContextClassLoader())</pre></blockquote>
   484      *
   485      * @param  service
   486      *         The interface or abstract class representing the service
   487      *
   488      * @return A new service loader
   489      */
   490     public static <S> ServiceLoader<S> load(Class<S> service) {
   491         ClassLoader cl = null; // XXX: Thread.currentThread().getContextClassLoader();
   492         return ServiceLoader.load(service, cl);
   493     }
   494 
   495     /**
   496      * Creates a new service loader for the given service type, using the
   497      * extension class loader.
   498      *
   499      * <p> This convenience method simply locates the extension class loader,
   500      * call it <tt><i>extClassLoader</i></tt>, and then returns
   501      *
   502      * <blockquote><pre>
   503      * ServiceLoader.load(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
   504      *
   505      * <p> If the extension class loader cannot be found then the system class
   506      * loader is used; if there is no system class loader then the bootstrap
   507      * class loader is used.
   508      *
   509      * <p> This method is intended for use when only installed providers are
   510      * desired.  The resulting service will only find and load providers that
   511      * have been installed into the current Java virtual machine; providers on
   512      * the application's class path will be ignored.
   513      *
   514      * @param  service
   515      *         The interface or abstract class representing the service
   516      *
   517      * @return A new service loader
   518      */
   519     public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
   520         ClassLoader cl = ClassLoader.getSystemClassLoader();
   521         ClassLoader prev = null;
   522         while (cl != null) {
   523             prev = cl;
   524             cl = cl.getParent();
   525         }
   526         return ServiceLoader.load(service, prev);
   527     }
   528 
   529     /**
   530      * Returns a string describing this service.
   531      *
   532      * @return  A descriptive string
   533      */
   534     public String toString() {
   535         return "java.util.ServiceLoader[" + service.getName() + "]";
   536     }
   537 
   538 }