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