Save This Page
Home » openjdk-7 » java » util » [javadoc | source]
    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 = 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   }

Save This Page
Home » openjdk-7 » java » util » [javadoc | source]