001: /**
002: * What the hell is this doing in the sun.misc package?
003: * This mechanism is an official specification since Java 1.3!
004: */package clime.messadmin.providers;
005:
006: import java.io.*;
007: import java.net.URL;
008: import java.util.*;
009:
010: /**
011: * From JDK 1.3.1 / 1.4.2 / 1.5.0
012: * see http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider
013: *
014: * see javax.imageio.spi.ServiceRegistry (Java 1.4+)
015: * see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4640520
016: * see http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html (Java 6)
017: * @author Cédrik LIME
018: */
019: public final class Service {
020:
021: private static class LazyIterator implements Iterator {
022:
023: Class service;
024: ClassLoader loader;
025: Enumeration configs;
026: Iterator pending;
027: Set returned;
028: String nextName;
029:
030: public boolean hasNext() throws ServiceConfigurationError {
031: if (nextName != null)
032: return true;
033: if (configs == null)
034: try {
035: String s = prefix + service.getName();
036: if (loader == null)
037: configs = ClassLoader.getSystemResources(s);
038: else
039: configs = loader.getResources(s);
040: } catch (IOException ioe) {
041: Service.fail(service, ": " + ioe);
042: }
043: for (; pending == null || !pending.hasNext(); pending = Service
044: .parse(service, (URL) configs.nextElement(),
045: returned)) {
046: if (!configs.hasMoreElements())
047: return false;
048: }
049:
050: nextName = (String) pending.next();
051: return true;
052: }
053:
054: public Object next() throws ServiceConfigurationError {
055: if (!hasNext())
056: throw new NoSuchElementException();
057: String s = nextName;
058: nextName = null;
059: try {
060: return Class.forName(s, true, loader).newInstance();
061: } catch (ClassNotFoundException cnfe) {
062: Service.fail(service, "Provider " + s + " not found");
063: } catch (Exception exception) {
064: Service.fail(service, "Provider " + s
065: + " could not be instantiated: " + exception,
066: exception);
067: }
068: return null;
069: }
070:
071: public void remove() {
072: throw new UnsupportedOperationException();
073: }
074:
075: private LazyIterator(Class class1, ClassLoader classloader) {
076: configs = null;
077: pending = null;
078: returned = new TreeSet();
079: nextName = null;
080: service = class1;
081: loader = classloader;
082: }
083:
084: }
085:
086: private static final String prefix = "META-INF/services/";//$NON-NLS-1$
087:
088: private Service() {
089: }
090:
091: protected static void fail(Class class1, String s)
092: throws ServiceConfigurationError {
093: throw new ServiceConfigurationError(class1.getName() + ": " + s);
094: }
095:
096: protected static void fail(Class class1, URL url, int i, String s)
097: throws ServiceConfigurationError {
098: fail(class1, url + ":" + i + ": " + s);
099: }
100:
101: /**
102: * @since 1.4
103: */
104: protected static void fail(Class class1, String s,
105: Throwable throwable) throws ServiceConfigurationError {
106: ServiceConfigurationError serviceconfigurationerror = new ServiceConfigurationError(
107: class1.getName() + ": " + s);
108: // serviceconfigurationerror.initCause(throwable);
109: throw serviceconfigurationerror;
110: }
111:
112: private static int parseLine(Class class1, URL url,
113: BufferedReader bufferedreader, int i, List list, Set set)
114: throws IOException, ServiceConfigurationError {
115: String s = bufferedreader.readLine();
116: if (s == null)
117: return -1;
118: int j = s.indexOf('#');
119: if (j >= 0)
120: s = s.substring(0, j);
121: s = s.trim();
122: int k = s.length();
123: if (k != 0) {
124: if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0)
125: fail(class1, url, i,
126: "Illegal configuration-file syntax");
127: if (!Character.isJavaIdentifierStart(s.charAt(0)))
128: fail(class1, url, i, "Illegal provider-class name: "
129: + s);
130: for (int l = 1; l < k; ++l) {
131: char c = s.charAt(l);
132: if (!Character.isJavaIdentifierPart(c) && c != '.')
133: fail(class1, url, i,
134: "Illegal provider-class name: " + s);
135: }
136:
137: if (!set.contains(s)) {
138: list.add(s);
139: set.add(s);
140: }
141: }
142: return i + 1;
143: }
144:
145: protected static Iterator parse(Class class1, URL url, Set set)
146: throws ServiceConfigurationError {
147: InputStream inputstream = null;
148: BufferedReader bufferedreader = null;
149: ArrayList arraylist = new ArrayList();
150: try {
151: inputstream = url.openStream();
152: bufferedreader = new BufferedReader(new InputStreamReader(
153: inputstream, "utf-8"));//$NON-NLS-1$
154: for (int i = 1; (i = parseLine(class1, url, bufferedreader,
155: i, arraylist, set)) >= 0;)
156: ;
157: } catch (IOException ioexception) {
158: fail(class1, ": " + ioexception);
159: } finally {
160: try {
161: if (bufferedreader != null)
162: bufferedreader.close();
163: if (inputstream != null)
164: inputstream.close();
165: } catch (IOException ioexception1) {
166: fail(class1, ": " + ioexception1);
167: }
168: }
169: return arraylist.iterator();
170: }
171:
172: /**
173: * Lazily locates and instantiates the available providers for the given service class and class loader.
174: *
175: * @param service The interface or abstract class representing this service
176: * @param loader The class loader to be used to load provider-configuration files and provider classes, or null if the system class loader (or, failing that, the bootstrap class loader) is to be used
177: * @return An iterator that lazily locates and instantiates providers for this service
178: * @throws ServiceConfigurationError
179: */
180: public static Iterator providers(Class service, ClassLoader loader)
181: throws ServiceConfigurationError {
182: return new LazyIterator(service, loader);
183: }
184:
185: /**
186: * Lazily locates and instantiates the available providers for the given service class, using the current thread's context class loader.
187: *
188: * <p> An invocation of this convenience method of the form
189: *
190: * <blockquote><pre>
191: * Service.lookup(<i>service</i>)</pre></blockquote>
192: *
193: * is equivalent to
194: *
195: * <blockquote><pre>
196: * Service.lookup(<i>service</i>,
197: * Thread.currentThread().getContextClassLoader())</pre></blockquote>
198: *
199: * @param service The interface or abstract class representing this service
200: * @return An iterator that lazily locates and instantiates providers for this service
201: * @throws ServiceConfigurationError
202: */
203: public static Iterator providers(Class service)
204: throws ServiceConfigurationError {
205: ClassLoader classloader = Thread.currentThread()
206: .getContextClassLoader();
207: return providers(service, classloader);
208: }
209:
210: /**
211: * Lazily locates and instantiates the available providers for the given service class, using the extension class loader.
212: *
213: * <p> This convenience method simply locates the extension class loader,
214: * call it <tt><i>extClassLoader</i></tt>, and then returns
215: *
216: * <blockquote><pre>
217: * Service.lookup(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
218: *
219: * <p> If the extension class loader cannot be found then the system class
220: * loader is used; if there is no system class loader then the bootstrap
221: * class loader is used.
222: *
223: * <p> This method is intended for use when only installed providers are
224: * desired. The resulting service will only find and load providers that
225: * have been installed into the current Java virtual machine; providers on
226: * the application's class path will be ignored.
227: *
228: * @param service The interface or abstract class representing this service
229: * @return An iterator that lazily locates and instantiates providers for this service
230: * @throws ServiceConfigurationError
231: */
232: public static Iterator installedProviders(Class service)
233: throws ServiceConfigurationError {
234: ClassLoader classloader = ClassLoader.getSystemClassLoader();
235: ClassLoader extClassLoader = null;
236: for (; classloader != null; classloader = classloader
237: .getParent()) {
238: extClassLoader = classloader;
239: }
240: return providers(service, extClassLoader);
241: }
242: }
|