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 }