001/* ServiceLoader.java -- Allows loading of plug-in services.
002   Copyright (C) 2006, 2007  Free Software Foundation
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package java.util;
039
040import gnu.classpath.ServiceFactory;
041
042/**
043 * <p>
044 * Facilities for loading service providers.  A service is
045 * defined by a set of interfaces or abstract classes, and
046 * a service provider gives a concrete implementation of this.
047 * Service providers may be installed as part of the runtime
048 * environment using JAR files in the extension directories,
049 * or may be simply supplied on the classpath.
050 * </p>
051 * <p>
052 * In terms of loading a service, the service is defined by
053 * a single interface or abstract class which the provider
054 * implements.  This may not constitute the entire service,
055 * but is simply a mechanism by which a provider of the
056 * service can be loaded and its capabilities determined.
057 * The variety of possible services means that no more
058 * requirements are made of the service provider other than
059 * that it must have an accessible zero argument constructor
060 * in order to allow an instance to be created.
061 * </p>
062 * <p>
063 * Service providers are listed in a file named after the
064 * service type in the directory <code>META-INF/services</code>.
065 * The file contains a list of classes, and must be encoded
066 * using UTF-8.  Whitespace is ignored.  Comments can be
067 * included by using a <code>'#'</code> prefix; anything occurring
068 * on the same line after this symbol is ignored. Duplicate classes
069 * are ignored.
070 * </p>
071 * <p>
072 * The classes are loaded using the same classloader that was
073 * queried in order to locate the configuration file.  As a result,
074 * the providers do not need to reside in the same JAR file as the
075 * resource; they merely have to be accessible to this classloader,
076 * which may differ from the one that loaded the file itself.
077 * </p>
078 * <p>
079 * Providers are located and instantiated lazily, as calls to the
080 * {@link #iterator()} are made.  Providers are cached, and those in
081 * the cache are returned first.  The cache may be cleared by calling
082 * {@link #reload()}.  Service loaders always execute in the security
083 * context of the caller, so ideally calls should be made from a trusted
084 * source.
085 * </p>
086 * <p>
087 * Note that this class is not thread-safe, and that strange errors may
088 * occur as the result of the use of remote URLs occurring on the classpath,
089 * which lead to erroneous web pages.
090 * </p>
091 *
092 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
093 * @since 1.6
094 */
095public final class ServiceLoader<S>
096  implements Iterable<S>
097{
098
099  /**
100   * The class of the service provider.
101   */
102  private Class<S> spi;
103
104  /**
105   * The class loader for the service provider.
106   */
107  private ClassLoader loader;
108
109  /**
110   * The cache of service providers.
111   */
112  private List<S> cache;
113
114  /**
115   * The {@link gnu.classpath.ServiceFactory} iterator
116   * from which providers are obtained.
117   */
118  private Iterator<S> serviceIt;
119
120  /**
121   * Constructs a new {@link ServiceLoader} with
122   * the specified provider and class loader.
123   *
124   * @param spi the service to load.
125   * @param loader the class loader to use.
126   */
127  private ServiceLoader(Class<S> spi, ClassLoader loader)
128  {
129    this.spi = spi;
130    this.loader = loader;
131    cache = new ArrayList<S>();
132  }
133
134  /**
135   * Lazily loads the available providers.  The iterator first returns
136   * providers from the cache, in instantiation order, followed by any
137   * remaining providers, which are added to the cache after loading.
138   * The actual loading and parsing of the configuration file takes
139   * place in the {@link Iterator#hasNext()} and {@link Iterator#next()}
140   * methods, which means that they may result in a
141   * {@link ServiceConfigurationError} being thrown.  If such an error
142   * does occur, subsequent invocations will attempt to recover.
143   * The {@link remove()} method is not supported and instead throws
144   * an {@link UnsupportedOperationException}.
145   *
146   * @return an iterator that lazily loads service providers.
147   */
148  public Iterator<S> iterator()
149  {
150    return new Iterator<S>()
151      {
152        /**
153         * The cache iterator.
154         */
155        private Iterator<S> cacheIt = cache.iterator();
156
157        public boolean hasNext()
158        {
159          if (cacheIt.hasNext())
160            return true;
161          if (serviceIt == null)
162            serviceIt =
163              ServiceFactory.lookupProviders(spi, loader, true);
164          return serviceIt.hasNext();
165        }
166
167        public S next()
168        {
169          if (cacheIt.hasNext())
170            return cacheIt.next();
171          if (serviceIt == null)
172            serviceIt =
173              ServiceFactory.lookupProviders(spi, loader, true);
174          S nextService = serviceIt.next();
175          cache.add(nextService);
176          return nextService;
177        }
178
179        public void remove()
180        {
181          throw new UnsupportedOperationException();
182        }
183      };
184  }
185
186  /**
187   * Creates a new service loader for the given service,
188   * using the context class loader of the current thread.
189   * This is equivalent to calling <code>ServiceLoader.load(service,
190   * Thread.currentThread().getContextClassLoader())</code>.
191   *
192   * @param service the interface or abstract class that represents
193   *                the service.
194   * @return a new {@link ServiceLoader} instance.
195   */
196  public static <S> ServiceLoader<S> load(Class<S> service)
197  {
198    return load(service,
199                Thread.currentThread().getContextClassLoader());
200  }
201
202  /**
203   * Creates a new service loader for the given service,
204   * using the specified class loader.  The class loader is
205   * used to access the configuration file and the service
206   * provider instances themselves.  If the loader is
207   * <code>null</code>, the system class loader (or, if
208   * this is also <code>null</code>, the bootstrap class
209   * loader).
210   *
211   * @param service the interface or abstract class that represents
212   *                the service.
213   * @param loader the class loader used to load the configuration
214   *               file and service providers.
215   * @return a new {@link ServiceLoader} instance.
216   */
217  public static <S> ServiceLoader<S> load(Class<S> service,
218                                          ClassLoader loader)
219  {
220    if (loader == null)
221      loader = ClassLoader.getSystemClassLoader();
222    return new ServiceLoader(service, loader);
223  }
224
225  /**
226   * Creates a new service loader for the given service,
227   * using the extension class loader.  If the extension
228   * class loader can not be found, the system class loader
229   * is used (or, if this is <code>null</code>, the
230   * bootstrap class loader).  The primary use of this method
231   * is to only obtain installed services, ignoring any which
232   * may appear on the classpath.  This is equivalent to calling
233   * <code>load(service, extClassLoader)</code> where
234   * <code>extClassLoader</code> is the extension class loader
235   * (or <code>null</code> if this is unavailable).
236   *
237   * @param service the interface or abstract class that represents
238   *                the service.
239   * @return a new {@link ServiceLoader} instance.
240   */
241  public static <S> ServiceLoader<S> loadInstalled(Class<S> service)
242  {
243    /* We expect the extension class loader to be the parent
244     * of the system class loader, as in
245     * ClassLoader.getDefaultSystemClassLoader() */
246    return load(service,
247                ClassLoader.getSystemClassLoader().getParent());
248  }
249
250  /**
251   * Clears the cache of the provider, so that all providers
252   * are again read from the configuration file and instantiated.
253   */
254  public void reload()
255  {
256    cache.clear();
257  }
258
259  /**
260   * Returns a textual representation of this
261   * {@link ServiceLoader}. 
262   * 
263   * @return a textual representation of the
264   *         service loader.
265   */
266  public String toString()
267  {
268    return getClass().getName() +
269      "[spi=" + spi +
270      ",loader=" + loader +
271      "]";
272  }
273
274}