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: * $Header:$
018: */
019: package org.apache.beehive.netui.util.internal;
020:
021: import org.apache.beehive.netui.util.logging.Logger;
022:
023: import java.io.IOException;
024: import java.io.BufferedReader;
025: import java.io.InputStreamReader;
026: import java.io.InputStream;
027: import java.util.Enumeration;
028: import java.util.ArrayList;
029: import java.util.Map;
030: import java.net.URL;
031:
032: /**
033: * Utility methods for discovering implementor classes on the classpath. An implementor class is declared in the
034: * standard way, in a file within META-INF/services where the file name is the class name of the desired interface, and
035: * the file contains the class name of the implementation. For example, to declare test.MyServiceImpl as a
036: * test.MyService implementation, the file META-INF/services/test.MyService is put on classpath (e.g., in a JAR),
037: * with contents "test.MyServiceImpl".
038: */
039: public class DiscoveryUtils {
040: private static final Logger _log = Logger
041: .getInstance(DiscoveryUtils.class);
042:
043: /**
044: * Get the ClassLoader from which implementor classes will be discovered and loaded.
045: */
046: public static ClassLoader getClassLoader() {
047: try {
048: ClassLoader cl = Thread.currentThread()
049: .getContextClassLoader();
050: if (cl != null)
051: return cl;
052: } catch (SecurityException e) {
053: if (_log.isDebugEnabled()) {
054: _log.debug("Could not get thread context classloader.",
055: e);
056: }
057: }
058:
059: if (_log.isTraceEnabled()) {
060: _log
061: .trace("Can't use thread context classloader; using classloader for "
062: + DiscoveryUtils.class.getName());
063: }
064:
065: return DiscoveryUtils.class.getClassLoader();
066: }
067:
068: /**
069: * Get all implementor classes (on the context classpath) that implement a given interface.
070: *
071: * @param interfaceType the Class that represents the interface.
072: * @return an array of Classes that are implementations of <code>interfaceType</code>.
073: */
074: public static Class[] getImplementorClasses(Class interfaceType) {
075: String interfaceName = interfaceType.getName();
076: ArrayList/*< Class >*/classes = new ArrayList/*< Class >*/();
077: ClassLoader classLoader = getClassLoader();
078:
079: try {
080: Enumeration e = classLoader
081: .getResources("META-INF/services/" + interfaceName);
082:
083: while (e.hasMoreElements()) {
084: URL url = (URL) e.nextElement();
085:
086: if (_log.isTraceEnabled()) {
087: _log.trace("Found implementor entry for interface "
088: + interfaceName + " at " + url);
089: }
090:
091: InputStream is = null;
092: String className = null;
093:
094: try {
095: is = url.openStream();
096: BufferedReader reader = new BufferedReader(
097: new InputStreamReader(is));
098: className = reader.readLine().trim();
099: Class implementorClass = loadImplementorClass(
100: className, interfaceType, classLoader);
101: if (implementorClass != null)
102: classes.add(implementorClass);
103: } catch (IOException ioe) {
104: _log
105: .error("Could not read implementor class entry at + "
106: + url);
107: } finally {
108: if (is != null)
109: is.close();
110: }
111: }
112: } catch (IOException e) {
113: _log.error("Could not discover implementors for "
114: + interfaceName, e);
115: }
116:
117: return (Class[]) classes.toArray(new Class[0]);
118: }
119:
120: public static Object newImplementorInstance(String className,
121: Class interfaceType) {
122: Class implementorClass = loadImplementorClass(className,
123: interfaceType);
124:
125: if (implementorClass != null) {
126: try {
127: return implementorClass.newInstance();
128: } catch (IllegalAccessException e) {
129: _log.error("Could not instantiate " + className
130: + " for interface " + interfaceType.getName(),
131: e);
132: } catch (InstantiationException e) {
133: _log.error("Could not instantiate " + className
134: + " for interface " + interfaceType.getName(),
135: e);
136: }
137: }
138:
139: return null;
140: }
141:
142: /**
143: * Load an implementor class from the context classloader.
144: *
145: * @param className the name of the implementor class.
146: * @param interfaceType the interface that the given class should implement.
147: * @return the implementor Class, or <code>null</code> if an error occurred (the error will be logged).
148: */
149: public static Class loadImplementorClass(String className,
150: Class interfaceType) {
151: return loadImplementorClass(className, interfaceType,
152: getClassLoader());
153: }
154:
155: /**
156: * Load an implementor class from the context classloader.
157: *
158: * @param className the name of the implementor class.
159: * @param interfaceType the interface that the given class should implement.
160: * @param classLoader the ClassLoader from which to load the implementor class.
161: * @return the implementor Class, or <code>null</code> if an error occurred (the error will be logged).
162: */
163: private static Class loadImplementorClass(String className,
164: Class interfaceType, ClassLoader classLoader) {
165: try {
166: if (_log.isDebugEnabled()) {
167: _log
168: .debug("Trying to load implementor class for interface "
169: + interfaceType.getName()
170: + ": "
171: + className);
172: }
173:
174: Class implementorClass = classLoader.loadClass(className);
175:
176: if (interfaceType.isAssignableFrom(implementorClass)) {
177: return implementorClass;
178: } else {
179: _log.error("Implementor class " + className
180: + " does not implement interface "
181: + interfaceType.getName());
182: }
183: } catch (ClassNotFoundException cnfe) {
184: //
185: // This will happen when the user class was built against an out-of-date interface.
186: //
187: _log
188: .error("Could not find implementor class "
189: + className + " for interface "
190: + interfaceType.getName(), cnfe);
191: } catch (LinkageError le) {
192: _log.error("Linkage error when loading implementor class "
193: + className + " for interface "
194: + interfaceType.getName(), le);
195: }
196:
197: return null;
198: }
199: }
|