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/sun/misc/Service.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/misc/Service.java+426−0
@@ -0,0 +1,426 @@
1+/*
2+ * Copyright (c) 1999, 2003, 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 sun.misc;
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+import java.util.Set;
39+import java.util.TreeSet;
40+
41+
42+/**
43+ * A simple service-provider lookup mechanism. A <i>service</i> is a
44+ * well-known set of interfaces and (usually abstract) classes. A <i>service
45+ * provider</i> is a specific implementation of a service. The classes in a
46+ * provider typically implement the interfaces and subclass the classes defined
47+ * in the service itself. Service providers may be installed in an
48+ * implementation of the Java platform in the form of extensions, that is, jar
49+ * files placed into any of the usual extension directories. Providers may
50+ * also be made available by adding them to the applet or application class
51+ * path or by some other platform-specific means.
52+ *
53+ * <p> In this lookup mechanism a service is represented by an interface or an
54+ * abstract class. (A concrete class may be used, but this is not
55+ * recommended.) A provider of a given service contains one or more concrete
56+ * classes that extend this <i>service class</i> with data and code specific to
57+ * the provider. This <i>provider class</i> will typically not be the entire
58+ * provider itself but rather a proxy that contains enough information to
59+ * decide whether the provider is able to satisfy a particular request together
60+ * with code that can create the actual provider on demand. The details of
61+ * provider classes tend to be highly service-specific; no single class or
62+ * interface could possibly unify them, so no such class has been defined. The
63+ * only requirement enforced here is that provider classes must have a
64+ * zero-argument constructor so that they may be instantiated during lookup.
65+ *
66+ * <p> A service provider identifies itself by placing a provider-configuration
67+ * file in the resource directory <tt>META-INF/services</tt>. The file's name
68+ * should consist of the fully-qualified name of the abstract service class.
69+ * The file should contain a list of fully-qualified concrete provider-class
70+ * names, one per line. Space and tab characters surrounding each name, as
71+ * well as blank lines, are ignored. The comment character is <tt>'#'</tt>
72+ * (<tt>0x23</tt>); on each line all characters following the first comment
73+ * character are ignored. The file must be encoded in UTF-8.
74+ *
75+ * <p> If a particular concrete provider class is named in more than one
76+ * configuration file, or is named in the same configuration file more than
77+ * once, then the duplicates will be ignored. The configuration file naming a
78+ * particular provider need not be in the same jar file or other distribution
79+ * unit as the provider itself. The provider must be accessible from the same
80+ * class loader that was initially queried to locate the configuration file;
81+ * note that this is not necessarily the class loader that found the file.
82+ *
83+ * <p> <b>Example:</b> Suppose we have a service class named
84+ * <tt>java.io.spi.CharCodec</tt>. It has two abstract methods:
85+ *
86+ * <pre>
87+ * public abstract CharEncoder getEncoder(String encodingName);
88+ * public abstract CharDecoder getDecoder(String encodingName);
89+ * </pre>
90+ *
91+ * Each method returns an appropriate object or <tt>null</tt> if it cannot
92+ * translate the given encoding. Typical <tt>CharCodec</tt> providers will
93+ * support more than one encoding.
94+ *
95+ * <p> If <tt>sun.io.StandardCodec</tt> is a provider of the <tt>CharCodec</tt>
96+ * service then its jar file would contain the file
97+ * <tt>META-INF/services/java.io.spi.CharCodec</tt>. This file would contain
98+ * the single line:
99+ *
100+ * <pre>
101+ * sun.io.StandardCodec # Standard codecs for the platform
102+ * </pre>
103+ *
104+ * To locate an encoder for a given encoding name, the internal I/O code would
105+ * do something like this:
106+ *
107+ * <pre>
108+ * CharEncoder getEncoder(String encodingName) {
109+ * Iterator ps = Service.providers(CharCodec.class);
110+ * while (ps.hasNext()) {
111+ * CharCodec cc = (CharCodec)ps.next();
112+ * CharEncoder ce = cc.getEncoder(encodingName);
113+ * if (ce != null)
114+ * return ce;
115+ * }
116+ * return null;
117+ * }
118+ * </pre>
119+ *
120+ * The provider-lookup mechanism always executes in the security context of the
121+ * caller. Trusted system code should typically invoke the methods in this
122+ * class from within a privileged security context.
123+ *
124+ * @author Mark Reinhold
125+ * @since 1.3
126+ */
127+
128+public final class Service {
129+
130+ private static final String prefix = "META-INF/services/";
131+
132+ private Service() { }
133+
134+ private static void fail(Class service, String msg, Throwable cause)
135+ throws ServiceConfigurationError
136+ {
137+ ServiceConfigurationError sce
138+ = new ServiceConfigurationError(service.getName() + ": " + msg);
139+ sce.initCause(cause);
140+ throw sce;
141+ }
142+
143+ private static void fail(Class service, String msg)
144+ throws ServiceConfigurationError
145+ {
146+ throw new ServiceConfigurationError(service.getName() + ": " + msg);
147+ }
148+
149+ private static void fail(Class service, URL u, int line, String msg)
150+ throws ServiceConfigurationError
151+ {
152+ fail(service, u + ":" + line + ": " + msg);
153+ }
154+
155+ /**
156+ * Parse a single line from the given configuration file, adding the name
157+ * on the line to both the names list and the returned set iff the name is
158+ * not already a member of the returned set.
159+ */
160+ private static int parseLine(Class service, URL u, BufferedReader r, int lc,
161+ List names, Set returned)
162+ throws IOException, ServiceConfigurationError
163+ {
164+ String ln = r.readLine();
165+ if (ln == null) {
166+ return -1;
167+ }
168+ int ci = ln.indexOf('#');
169+ if (ci >= 0) ln = ln.substring(0, ci);
170+ ln = ln.trim();
171+ int n = ln.length();
172+ if (n != 0) {
173+ if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
174+ fail(service, u, lc, "Illegal configuration-file syntax");
175+ int cp = ln.codePointAt(0);
176+ if (!Character.isJavaIdentifierStart(cp))
177+ fail(service, u, lc, "Illegal provider-class name: " + ln);
178+ for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
179+ cp = ln.codePointAt(i);
180+ if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
181+ fail(service, u, lc, "Illegal provider-class name: " + ln);
182+ }
183+ if (!returned.contains(ln)) {
184+ names.add(ln);
185+ returned.add(ln);
186+ }
187+ }
188+ return lc + 1;
189+ }
190+
191+ /**
192+ * Parse the content of the given URL as a provider-configuration file.
193+ *
194+ * @param service
195+ * The service class for which providers are being sought;
196+ * used to construct error detail strings
197+ *
198+ * @param url
199+ * The URL naming the configuration file to be parsed
200+ *
201+ * @param returned
202+ * A Set containing the names of provider classes that have already
203+ * been returned. This set will be updated to contain the names
204+ * that will be yielded from the returned <tt>Iterator</tt>.
205+ *
206+ * @return A (possibly empty) <tt>Iterator</tt> that will yield the
207+ * provider-class names in the given configuration file that are
208+ * not yet members of the returned set
209+ *
210+ * @throws ServiceConfigurationError
211+ * If an I/O error occurs while reading from the given URL, or
212+ * if a configuration-file format error is detected
213+ */
214+ private static Iterator parse(Class service, URL u, Set returned)
215+ throws ServiceConfigurationError
216+ {
217+ InputStream in = null;
218+ BufferedReader r = null;
219+ ArrayList names = new ArrayList();
220+ try {
221+ in = u.openStream();
222+ r = new BufferedReader(new InputStreamReader(in, "utf-8"));
223+ int lc = 1;
224+ while ((lc = parseLine(service, u, r, lc, names, returned)) >= 0);
225+ } catch (IOException x) {
226+ fail(service, ": " + x);
227+ } finally {
228+ try {
229+ if (r != null) r.close();
230+ if (in != null) in.close();
231+ } catch (IOException y) {
232+ fail(service, ": " + y);
233+ }
234+ }
235+ return names.iterator();
236+ }
237+
238+
239+ /**
240+ * Private inner class implementing fully-lazy provider lookup
241+ */
242+ private static class LazyIterator implements Iterator {
243+
244+ Class service;
245+ ClassLoader loader;
246+ Enumeration configs = null;
247+ Iterator pending = null;
248+ Set returned = new TreeSet();
249+ String nextName = null;
250+
251+ private LazyIterator(Class service, ClassLoader loader) {
252+ this.service = service;
253+ this.loader = loader;
254+ }
255+
256+ public boolean hasNext() throws ServiceConfigurationError {
257+ if (nextName != null) {
258+ return true;
259+ }
260+ if (configs == null) {
261+ try {
262+ String fullName = prefix + service.getName();
263+ if (loader == null)
264+ configs = ClassLoader.getSystemResources(fullName);
265+ else
266+ configs = loader.getResources(fullName);
267+ } catch (IOException x) {
268+ fail(service, ": " + x);
269+ }
270+ }
271+ while ((pending == null) || !pending.hasNext()) {
272+ if (!configs.hasMoreElements()) {
273+ return false;
274+ }
275+ pending = parse(service, (URL)configs.nextElement(), returned);
276+ }
277+ nextName = (String)pending.next();
278+ return true;
279+ }
280+
281+ public Object next() throws ServiceConfigurationError {
282+ if (!hasNext()) {
283+ throw new NoSuchElementException();
284+ }
285+ String cn = nextName;
286+ nextName = null;
287+ try {
288+ return Class.forName(cn, true, loader).newInstance();
289+ } catch (ClassNotFoundException x) {
290+ fail(service,
291+ "Provider " + cn + " not found");
292+ } catch (Exception x) {
293+ fail(service,
294+ "Provider " + cn + " could not be instantiated: " + x,
295+ x);
296+ }
297+ return null; /* This cannot happen */
298+ }
299+
300+ public void remove() {
301+ throw new UnsupportedOperationException();
302+ }
303+
304+ }
305+
306+
307+ /**
308+ * Locates and incrementally instantiates the available providers of a
309+ * given service using the given class loader.
310+ *
311+ * <p> This method transforms the name of the given service class into a
312+ * provider-configuration filename as described above and then uses the
313+ * <tt>getResources</tt> method of the given class loader to find all
314+ * available files with that name. These files are then read and parsed to
315+ * produce a list of provider-class names. The iterator that is returned
316+ * uses the given class loader to lookup and then instantiate each element
317+ * of the list.
318+ *
319+ * <p> Because it is possible for extensions to be installed into a running
320+ * Java virtual machine, this method may return different results each time
321+ * it is invoked. <p>
322+ *
323+ * @param service
324+ * The service's abstract service class
325+ *
326+ * @param loader
327+ * The class loader to be used to load provider-configuration files
328+ * and instantiate provider classes, or <tt>null</tt> if the system
329+ * class loader (or, failing that the bootstrap class loader) is to
330+ * be used
331+ *
332+ * @return An <tt>Iterator</tt> that yields provider objects for the given
333+ * service, in some arbitrary order. The iterator will throw a
334+ * <tt>ServiceConfigurationError</tt> if a provider-configuration
335+ * file violates the specified format or if a provider class cannot
336+ * be found and instantiated.
337+ *
338+ * @throws ServiceConfigurationError
339+ * If a provider-configuration file violates the specified format
340+ * or names a provider class that cannot be found and instantiated
341+ *
342+ * @see #providers(java.lang.Class)
343+ * @see #installedProviders(java.lang.Class)
344+ */
345+ public static Iterator providers(Class service, ClassLoader loader)
346+ throws ServiceConfigurationError
347+ {
348+ return new LazyIterator(service, loader);
349+ }
350+
351+
352+ /**
353+ * Locates and incrementally instantiates the available providers of a
354+ * given service using the context class loader. This convenience method
355+ * is equivalent to
356+ *
357+ * <pre>
358+ * ClassLoader cl = Thread.currentThread().getContextClassLoader();
359+ * return Service.providers(service, cl);
360+ * </pre>
361+ *
362+ * @param service
363+ * The service's abstract service class
364+ *
365+ * @return An <tt>Iterator</tt> that yields provider objects for the given
366+ * service, in some arbitrary order. The iterator will throw a
367+ * <tt>ServiceConfigurationError</tt> if a provider-configuration
368+ * file violates the specified format or if a provider class cannot
369+ * be found and instantiated.
370+ *
371+ * @throws ServiceConfigurationError
372+ * If a provider-configuration file violates the specified format
373+ * or names a provider class that cannot be found and instantiated
374+ *
375+ * @see #providers(java.lang.Class, java.lang.ClassLoader)
376+ */
377+ public static Iterator providers(Class service)
378+ throws ServiceConfigurationError
379+ {
380+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
381+ return Service.providers(service, cl);
382+ }
383+
384+
385+ /**
386+ * Locates and incrementally instantiates the available providers of a
387+ * given service using the extension class loader. This convenience method
388+ * simply locates the extension class loader, call it
389+ * <tt>extClassLoader</tt>, and then does
390+ *
391+ * <pre>
392+ * return Service.providers(service, extClassLoader);
393+ * </pre>
394+ *
395+ * If the extension class loader cannot be found then the system class
396+ * loader is used; if there is no system class loader then the bootstrap
397+ * class loader is used.
398+ *
399+ * @param service
400+ * The service's abstract service class
401+ *
402+ * @return An <tt>Iterator</tt> that yields provider objects for the given
403+ * service, in some arbitrary order. The iterator will throw a
404+ * <tt>ServiceConfigurationError</tt> if a provider-configuration
405+ * file violates the specified format or if a provider class cannot
406+ * be found and instantiated.
407+ *
408+ * @throws ServiceConfigurationError
409+ * If a provider-configuration file violates the specified format
410+ * or names a provider class that cannot be found and instantiated
411+ *
412+ * @see #providers(java.lang.Class, java.lang.ClassLoader)
413+ */
414+ public static Iterator installedProviders(Class service)
415+ throws ServiceConfigurationError
416+ {
417+ ClassLoader cl = ClassLoader.getSystemClassLoader();
418+ ClassLoader prev = null;
419+ while (cl != null) {
420+ prev = cl;
421+ cl = cl.getParent();
422+ }
423+ return Service.providers(service, prev);
424+ }
425+
426+}