History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/util/ServiceLoader.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/util/ServiceLoader.java+538−0
@@ -0,0 +1,538 @@
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+}