001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.util;
020:
021: import java.io.BufferedReader;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.InputStreamReader;
025: import java.io.Reader;
026: import java.net.URL;
027: import java.util.ArrayList;
028: import java.util.Enumeration;
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.List;
032:
033: /**
034: * This class handles looking up service providers on the class path.
035: * It implements the system described in:
036: *
037: * <a href='http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service Provider'>JAR
038: * File Specification Under Service Provider</a>. Note that this
039: * interface is very similar to the one they describe which seems to
040: * be missing in the JDK.
041: *
042: * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
043: * @version $Id: Service.java 522271 2007-03-25 14:42:45Z dvholten $
044: */
045: public class Service {
046:
047: // Remember providers we have looked up before.
048: static HashMap providerMap = new HashMap();
049:
050: /**
051: * Returns an iterator where each element should implement the
052: * interface (or subclass the baseclass) described by cls. The
053: * Classes are found by searching the classpath for service files
054: * named: 'META-INF/services/<fully qualified classname> that list
055: * fully qualifted classnames of classes that implement the
056: * service files classes interface. These classes must have
057: * default constructors.
058: *
059: * @param cls The class/interface to search for providers of.
060: */
061: public static synchronized Iterator providers(Class cls) {
062: String serviceFile = "META-INF/services/" + cls.getName();
063:
064: // System.out.println("File: " + serviceFile);
065:
066: List l = (List) providerMap.get(serviceFile);
067: if (l != null)
068: return l.iterator();
069:
070: l = new ArrayList();
071: providerMap.put(serviceFile, l);
072:
073: ClassLoader cl = null;
074: try {
075: cl = cls.getClassLoader();
076: } catch (SecurityException se) {
077: // Ooops! can't get his class loader.
078: }
079: // Can always request your own class loader. But it might be 'null'.
080: if (cl == null)
081: cl = Service.class.getClassLoader();
082:
083: // No class loader so we can't find 'serviceFile'.
084: if (cl == null)
085: return l.iterator();
086:
087: Enumeration e;
088: try {
089: e = cl.getResources(serviceFile);
090: } catch (IOException ioe) {
091: return l.iterator();
092: }
093:
094: while (e.hasMoreElements()) {
095: InputStream is = null;
096: Reader r = null;
097: BufferedReader br = null;
098: try {
099: URL u = (URL) e.nextElement();
100: // System.out.println("URL: " + u);
101:
102: is = u.openStream();
103: r = new InputStreamReader(is, "UTF-8");
104: br = new BufferedReader(r);
105:
106: String line = br.readLine();
107: while (line != null) {
108: try {
109: // First strip any comment...
110: int idx = line.indexOf('#');
111: if (idx != -1)
112: line = line.substring(0, idx);
113:
114: // Trim whitespace.
115: line = line.trim();
116:
117: // If nothing left then loop around...
118: if (line.length() == 0) {
119: line = br.readLine();
120: continue;
121: }
122: // System.out.println("Line: " + line);
123:
124: // Try and load the class
125: Object obj = cl.loadClass(line).newInstance();
126: // stick it into our vector...
127: l.add(obj);
128: } catch (Exception ex) {
129: // Just try the next line
130: }
131: line = br.readLine();
132: }
133: } catch (Exception ex) {
134: // Just try the next file...
135: } catch (LinkageError le) {
136: // Just try the next file...
137: } finally {
138: // close and release all io-resources to avoid leaks
139: if (is != null) {
140: try {
141: is.close();
142: } catch (IOException ignored) {
143: }
144: is = null;
145: }
146: if (r != null) {
147: try {
148: r.close();
149: } catch (IOException ignored) {
150: }
151: r = null;
152: }
153: if (br == null) {
154: try {
155: br.close();
156: } catch (IOException ignored) {
157: }
158: br = null;
159: }
160: }
161: }
162: return l.iterator();
163: }
164: }
|