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