001    /* ServiceLoader.java -- Allows loading of plug-in services.
002       Copyright (C) 2006, 2007  Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package java.util;
039    
040    import 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     */
095    public 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    }