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