ServiceLoader.java 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /* ServiceLoader.java -- Allows loading of plug-in services.
  2. Copyright (C) 2006, 2007 Free Software Foundation
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package java.util;
  32. import gnu.classpath.ServiceFactory;
  33. /**
  34. * <p>
  35. * Facilities for loading service providers. A service is
  36. * defined by a set of interfaces or abstract classes, and
  37. * a service provider gives a concrete implementation of this.
  38. * Service providers may be installed as part of the runtime
  39. * environment using JAR files in the extension directories,
  40. * or may be simply supplied on the classpath.
  41. * </p>
  42. * <p>
  43. * In terms of loading a service, the service is defined by
  44. * a single interface or abstract class which the provider
  45. * implements. This may not constitute the entire service,
  46. * but is simply a mechanism by which a provider of the
  47. * service can be loaded and its capabilities determined.
  48. * The variety of possible services means that no more
  49. * requirements are made of the service provider other than
  50. * that it must have an accessible zero argument constructor
  51. * in order to allow an instance to be created.
  52. * </p>
  53. * <p>
  54. * Service providers are listed in a file named after the
  55. * service type in the directory <code>META-INF/services</code>.
  56. * The file contains a list of classes, and must be encoded
  57. * using UTF-8. Whitespace is ignored. Comments can be
  58. * included by using a <code>'#'</code> prefix; anything occurring
  59. * on the same line after this symbol is ignored. Duplicate classes
  60. * are ignored.
  61. * </p>
  62. * <p>
  63. * The classes are loaded using the same classloader that was
  64. * queried in order to locate the configuration file. As a result,
  65. * the providers do not need to reside in the same JAR file as the
  66. * resource; they merely have to be accessible to this classloader,
  67. * which may differ from the one that loaded the file itself.
  68. * </p>
  69. * <p>
  70. * Providers are located and instantiated lazily, as calls to the
  71. * {@link #iterator()} are made. Providers are cached, and those in
  72. * the cache are returned first. The cache may be cleared by calling
  73. * {@link #reload()}. Service loaders always execute in the security
  74. * context of the caller, so ideally calls should be made from a trusted
  75. * source.
  76. * </p>
  77. * <p>
  78. * Note that this class is not thread-safe, and that strange errors may
  79. * occur as the result of the use of remote URLs occurring on the classpath,
  80. * which lead to erroneous web pages.
  81. * </p>
  82. *
  83. * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  84. * @since 1.6
  85. */
  86. public final class ServiceLoader<S>
  87. implements Iterable<S>
  88. {
  89. /**
  90. * The class of the service provider.
  91. */
  92. private Class<S> spi;
  93. /**
  94. * The class loader for the service provider.
  95. */
  96. private ClassLoader loader;
  97. /**
  98. * The cache of service providers.
  99. */
  100. private List<S> cache;
  101. /**
  102. * The {@link gnu.classpath.ServiceFactory} iterator
  103. * from which providers are obtained.
  104. */
  105. private Iterator<S> serviceIt;
  106. /**
  107. * Constructs a new {@link ServiceLoader} with
  108. * the specified provider and class loader.
  109. *
  110. * @param spi the service to load.
  111. * @param loader the class loader to use.
  112. */
  113. private ServiceLoader(Class<S> spi, ClassLoader loader)
  114. {
  115. this.spi = spi;
  116. this.loader = loader;
  117. cache = new ArrayList<S>();
  118. }
  119. /**
  120. * Lazily loads the available providers. The iterator first returns
  121. * providers from the cache, in instantiation order, followed by any
  122. * remaining providers, which are added to the cache after loading.
  123. * The actual loading and parsing of the configuration file takes
  124. * place in the {@link Iterator#hasNext()} and {@link Iterator#next()}
  125. * methods, which means that they may result in a
  126. * {@link ServiceConfigurationError} being thrown. If such an error
  127. * does occur, subsequent invocations will attempt to recover.
  128. * The {@link remove()} method is not supported and instead throws
  129. * an {@link UnsupportedOperationException}.
  130. *
  131. * @return an iterator that lazily loads service providers.
  132. */
  133. public Iterator<S> iterator()
  134. {
  135. return new Iterator<S>()
  136. {
  137. /**
  138. * The cache iterator.
  139. */
  140. private Iterator<S> cacheIt = cache.iterator();
  141. public boolean hasNext()
  142. {
  143. if (cacheIt.hasNext())
  144. return true;
  145. if (serviceIt == null)
  146. serviceIt =
  147. ServiceFactory.lookupProviders(spi, loader, true);
  148. return serviceIt.hasNext();
  149. }
  150. public S next()
  151. {
  152. if (cacheIt.hasNext())
  153. return cacheIt.next();
  154. if (serviceIt == null)
  155. serviceIt =
  156. ServiceFactory.lookupProviders(spi, loader, true);
  157. S nextService = serviceIt.next();
  158. cache.add(nextService);
  159. return nextService;
  160. }
  161. public void remove()
  162. {
  163. throw new UnsupportedOperationException();
  164. }
  165. };
  166. }
  167. /**
  168. * Creates a new service loader for the given service,
  169. * using the context class loader of the current thread.
  170. * This is equivalent to calling <code>ServiceLoader.load(service,
  171. * Thread.currentThread().getContextClassLoader())</code>.
  172. *
  173. * @param service the interface or abstract class that represents
  174. * the service.
  175. * @return a new {@link ServiceLoader} instance.
  176. */
  177. public static <S> ServiceLoader<S> load(Class<S> service)
  178. {
  179. return load(service,
  180. Thread.currentThread().getContextClassLoader());
  181. }
  182. /**
  183. * Creates a new service loader for the given service,
  184. * using the specified class loader. The class loader is
  185. * used to access the configuration file and the service
  186. * provider instances themselves. If the loader is
  187. * <code>null</code>, the system class loader (or, if
  188. * this is also <code>null</code>, the bootstrap class
  189. * loader).
  190. *
  191. * @param service the interface or abstract class that represents
  192. * the service.
  193. * @param loader the class loader used to load the configuration
  194. * file and service providers.
  195. * @return a new {@link ServiceLoader} instance.
  196. */
  197. public static <S> ServiceLoader<S> load(Class<S> service,
  198. ClassLoader loader)
  199. {
  200. if (loader == null)
  201. loader = ClassLoader.getSystemClassLoader();
  202. return new ServiceLoader(service, loader);
  203. }
  204. /**
  205. * Creates a new service loader for the given service,
  206. * using the extension class loader. If the extension
  207. * class loader can not be found, the system class loader
  208. * is used (or, if this is <code>null</code>, the
  209. * bootstrap class loader). The primary use of this method
  210. * is to only obtain installed services, ignoring any which
  211. * may appear on the classpath. This is equivalent to calling
  212. * <code>load(service, extClassLoader)</code> where
  213. * <code>extClassLoader</code> is the extension class loader
  214. * (or <code>null</code> if this is unavailable).
  215. *
  216. * @param service the interface or abstract class that represents
  217. * the service.
  218. * @return a new {@link ServiceLoader} instance.
  219. */
  220. public static <S> ServiceLoader<S> loadInstalled(Class<S> service)
  221. {
  222. /* We expect the extension class loader to be the parent
  223. * of the system class loader, as in
  224. * ClassLoader.getDefaultSystemClassLoader() */
  225. return load(service,
  226. ClassLoader.getSystemClassLoader().getParent());
  227. }
  228. /**
  229. * Clears the cache of the provider, so that all providers
  230. * are again read from the configuration file and instantiated.
  231. */
  232. public void reload()
  233. {
  234. cache.clear();
  235. }
  236. /**
  237. * Returns a textual representation of this
  238. * {@link ServiceLoader}.
  239. *
  240. * @return a textual representation of the
  241. * service loader.
  242. */
  243. public String toString()
  244. {
  245. return getClass().getName() +
  246. "[spi=" + spi +
  247. ",loader=" + loader +
  248. "]";
  249. }
  250. }