Return-Path:
Discover service instances,
+ * Discover service providers,
* with discovery and configuration features similar to that employed
- * by standard Java APIs such as JAXP.serviceImplName
implementation
- * class. If localOnly
is true
, try the
- * class loaders local to the caller: root finder class's (default
- * ServiceFinder) and system. If localOnly
is
- * false
, try each of the following class loaders:
- * thread context, caller's, spi's, root finder class's (default
- * ServiceFinder), and system.
+ * class. If systemOnly
is true
, try the
+ * 'system' class loaders: spi's, root finder class's (default is
+ * Discovery) and system. If systemOnly
is false
,
+ * try each of the following class loaders: thread context, caller's, spi's,
+ * root finder class's (default is Discovery), and system.
*
* @param serviceImplName Fully qualified name of the implementation class
- * @param localOnly Use only local class loader
+ * @param systemOnly Use only 'system' class loaders
* (do not try thread context class loader).
*
* @exception DiscoveryException if a suitable instance cannot be created,
* or if the class created is not an instance
* of spi
*/
- public Class findClass(String serviceImplName, boolean localOnly)
+ public Class findClass(String serviceImplName, boolean systemOnly)
throws DiscoveryException
{
Class clazz = ClassLoaderUtils.loadClass(serviceImplName,
- localOnly ? localLoaders : allLoaders);
+ systemOnly ? systemLoaders : allLoaders);
if (clazz != null && !spiContext.getSPI().isAssignableFrom(clazz)) {
throw new DiscoveryException("Class " + serviceImplName +
@@ -148,25 +165,37 @@
/**
* Return the specified resourceName
as an
- * InputStream
. If localOnly
is
- * true
, try the class loaders local to the caller:
- * root finder class's (default ServiceFinder) and system.
- * If localOnly
is false
, try each of
+ * InputStream
. If systemOnly
is
+ * true
, try the 'system' class loaders: spi's,
+ * root finder class's (default is Discovery), and system.
+ * If systemOnly
is false
, try each of
* the following class loaders: thread context, caller's, spi's,
- * root finder class's (default ServiceFinder), and system.
+ * root finder class's (default is Discovery), and system.
*
* @param resourceName name of the resource
- * @param localOnly Use only local class loader
+ * @param system Use only 'system' class loaders
* (do not try thread context class loader).
*
* @exception DiscoveryException if a suitable resource cannot be created.
*/
- public InputStream findResourceAsStream(String resourceName, boolean localOnly)
+ public InputStream findResourceAsStream(String resourceName)
throws DiscoveryException
{
- return ClassLoaderUtils.getResourceAsStream(spiContext.getSPI().getPackage().getName(),
- resourceName,
- localOnly ? localLoaders : allLoaders);
+ String name = spiContext.getSPI().getPackage().getName();
+
+ InputStream stream =
+ (groupContext == null)
+ ? null
+ : ClassLoaderUtils.getResourceAsStream(name,
+ groupContext + "." + resourceName,
+ allLoaders);
+
+ if (stream == null)
+ stream = ClassLoaderUtils.getResourceAsStream(name,
+ resourceName,
+ allLoaders);
+
+ return stream;
}
/**
@@ -289,16 +318,14 @@
}
/**
- * List of 'local' classes and class loaders.
- * By using ClassLoaderHolder to holder Class and ClassLoader objects,
- * we preserve the difference in behaviour between the two for loading
- * resources..
+ * List of 'system' class loaders to the SPI
*/
- private static final ClassLoader[] getLocalLoaders(SPIContext spiContext,
- Class rootFinderClass) {
+ private static final ClassLoader[] getSystemLoaders(SPIContext spiContext,
+ Class rootFinderClass) {
return ClassLoaderUtils.compactUniq(
- new ClassLoader[] {BootstrapLoader.wrap(rootFinderClass.getClassLoader()),
- spiContext.getSystemClassLoader()
+ new ClassLoader[] {BootstrapLoader.wrap(spiContext.getSPI().getClassLoader()),
+ BootstrapLoader.wrap(rootFinderClass.getClassLoader()),
+ ClassLoaderUtils.getSystemClassLoader()
});
}
@@ -309,7 +336,7 @@
getCallerClassLoader(rootFinderClass),
BootstrapLoader.wrap(spiContext.getSPI().getClassLoader()),
BootstrapLoader.wrap(rootFinderClass.getClassLoader()),
- spiContext.getSystemClassLoader()
+ ClassLoaderUtils.getSystemClassLoader()
});
}
}
1.2 +581 -334 jakarta-commons/discovery/src/java/org/apache/commons/discovery/Discovery.java
Index: Discovery.java
===================================================================
RCS file: /home/cvs/jakarta-commons/discovery/src/java/org/apache/commons/discovery/Discovery.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Discovery.java 18 Jul 2002 18:32:34 -0000 1.1
+++ Discovery.java 26 Jul 2002 22:35:05 -0000 1.2
@@ -71,13 +71,146 @@
/**
- *
In the context of this package, a service interface is defined by a + * Service Provider Interface (SPI). The SPI is expressed as a Java interface, + * abstract class, or (base) class that defines an expected programming + * interface. + *
+ * + *Discovery provides the find
methods for locating and
+ * instantiating an implementation of a service (SPI). Each form of
+ * find
varies slightly, but they all perform the same basic
+ * function. The Discovery find
methods proceed as follows:
+ *
Properties properties
property, if provided
+ * as a parameter, whose name is the same as the SPI's fully qualifed class
+ * name (as given by SPI.class.getName()).
+ * SPI.class.getName()
. This is implemented
+ * internally, so there is not a dependency on JDK 1.3+.
+ * defaultImplName
) is null,
+ * then an exception is thrown.
+ * defaultImplName
) is non-null,
+ * then load the default implementation class. The class loaded is the
+ * first class loaded by the following sequence of class loaders:
+ * + * This limits the scope in which the default class loader can be found + * to the SPI, Discovery, and System class loaders. The assumption here + * is that the default implementation is closely associated with the SPI + * or system, and is not defined in the user's application space. + *
+ *+ * An exception is thrown if the class cannot be loaded. + *
+ *Service
interface,
+ * then invoke the init(Properties)
method, passing in the
+ * Properties properties
parameter, if provided.
+ *
+ * Variances for various forms of the find
+ * methods are discussed with each such method.
+ * Variances include the following concepts:
+ *
Properties
may be specified
+ * directly, or by property file name. A property file is loaded using the
+ * same sequence of class loaders used to load the SPI implementation:
+ * The groupContext is used to qualify the name of the property file
+ * name: groupContext + '.' + propertiesFileName
. If that
+ * file is not found, then the unqualified propertyFileName is used.
+ *
In addition, groupContext is used to qualify the name of the system
+ * property used to find the service implementation by prepending the value
+ * of groupContext
to the property name:
+ * groupContext> + '.' + SPI.class.getName()
.
+ * Again, if a system property cannot be found by that name, then the
+ * unqualified property name is used.
+ *
+ * Other concepts + *
+ * *IMPLEMENTATION NOTE - This implementation is heavily * based on the SAXParserFactory and DocumentBuilderFactory implementations - * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
+ * (corresponding to the JAXP pluggability APIs) found in Apache Xerces. + * * * @author Richard A. Sitze * @author Craig R. McClanahan @@ -86,239 +219,105 @@ */ public class Discovery { /** - * Sets of previously encountered service interfaces (spis), keyed by the - * interface (Class
). Each element is a ServiceCache.
+ * Readable placeholder for a null value.
*/
- private static final Hashtable service_caches = new Hashtable(13);
+ private static final Properties nullProperties = null;
/**
- * Locate and instantiate a service. The service implementation - * class is located using the following ordered lookup:
- *spiContext.getSPI().getName()
.properties
parameter, having the same
- * name as the spi class: spiContext.getSPI().getName()
.spiContext.getSPI().getName()
.
- * Implemented internally, so there is not a hard
- * dependency on JDK 1.3+.defaultImplName
.In most cases, after class NAME is found, then a - * number of attempts are made to load the class using different - * class loaders, in the following sequence: - *
The default implementation is loaded using: - *
spiContext.getSPI().getName()
id's the (property)
- * name of the service implementation. Presumed to be an interface,
- * but there is nothing in the code that prevents it from
- * being an abstract base class, or even a class.
- *
- * @param properties used as one alternative to find name of service
- * implementation class, with property name specified by
- * spi.getName()
. If the implementation class found
- * for spi
implements the Service
- * interface, then spiInstance.init(properties)
is
- * called.
- *
- * @param defaultImplName Name of the default implementation class.
- *
- * @exception DiscoveryException if the implementation class
- * is not available,
- * cannot be instantiated,
- * or is not an instance of spi
.
- */
- private static Object find(ClassFinder classFinder,
- SPIContext spiContext,
- Properties properties,
- String defaultImplName)
- throws DiscoveryException
- {
- /**
- * Return previously registered service object (not class)
- * for this spi. Try each class loader in succession.
- */
- Object service = null;
- ClassLoader[] allLoaders = classFinder.getAllLoaders();
-
- for (int idx = 0; service == null && idx < allLoaders.length; idx++) {
- service = get(spiContext.getSPI().getName(), allLoaders[idx]);
- }
-
- if (service != null) {
- // First, try the system property
- Class clazz = classFinder.systemFindClass();
+ * Readable placeholder for a null value.
+ */
+ private static final String nullDefaultImplName = null;
- if (clazz == null) {
- // Second, try the properties parameter
- if (properties != null)
- clazz = classFinder.findClass(properties);
-
- if (clazz == null) {
- // Third, try to find a service by using the JDK1.3 jar
- // discovery mechanism.
- clazz = classFinder.jdk13FindClass();
-
- if (clazz == null) {
- // Fourth, try the fallback implementation class
- clazz = classFinder.findClass(defaultImplName, true);
-
- if (clazz == null) {
- throw new DiscoveryException
- ("No implementation defined for " +
- spiContext.getSPI().getName());
- }
- }
- }
- }
-
- if (clazz != null) {
- try {
- service = clazz.newInstance();
- put(spiContext.getSPI().getName(), clazz.getClassLoader(), service);
- } catch (Exception e) {
- throw new DiscoveryException("Unable to instantiate " + spiContext.getSPI().getName(), e);
- }
-
- if (service instanceof Service) {
- ((Service)service).init(properties);
- }
- }
- }
-
- return service;
- }
+ /**
+ * Readable placeholder for a null value.
+ */
+ private static final String nullGroupContext = null;
+
+
+ /********************** (RELATIVELY) SIMPLE FINDERS **********************
+ *
+ * These finders are suitable for direct use in components looking for a
+ * service. If you are not sure which finder(s) to use, you can narrow
+ * your search to one of these.
+ */
/**
- * Locate and instantiate a service. The service implementation - * class is located using the following ordered lookup:
- *spiContext.getSPI().getName()
.properties
parameter, having the same
- * name as the spi class: spiContext.getSPI().getName()
.spiContext.getSPI().getName()
.
- * Implemented internally, so there is not a hard
- * dependency on JDK 1.3+.defaultImplName
.In most cases, after class NAME is found, then a - * number of attempts are made to load the class using different - * class loaders, in the following sequence: - *
The default implementation is loaded using: - *
spiContext.getSPI().getName()
id's the (property)
- * name of the service implementation. Presumed to be an interface,
- * but there is nothing in the code that prevents it from
- * being an abstract base class, or even a class.
- *
- * @param properties used as one alternative to find name of service
- * implementation class, with property name specified by
- * spi.getName()
. If the implementation class found
- * for spi
implements the Service
- * interface, then spiInstance.init(properties)
is
- * called.
+ * Find implementation of SPI.
*
- * @param defaultImplName Name of the default implementation class.
- *
- * @exception DiscoveryException if the implementation class
- * is not available,
- * cannot be instantiated,
- * or is not an instance of spi
.
+ * @param spi Service Provider Interface Class.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
- public static Object find(Class rootFinderClass,
- SPIContext spiContext,
- Properties properties,
- String defaultImplName)
+ public static Object find(Class spi)
throws DiscoveryException
{
- // thread context can change on each call,
- // so establish context for this one call.
- ClassFinder classFinder = new ClassFinder(spiContext, rootFinderClass);
- return find(classFinder, spiContext, properties, defaultImplName);
+ return find(Discovery.class, spi);
}
-
+
/**
- * Equivalent to
- * find(ServiceFinder.class, spiContext, properties, defaultImplName)
.
+ * Find implementation of SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
- public static Object find(SPIContext spiContext,
- Properties properties,
- String defaultImplName)
+ public static Object find(Class spi, Properties properties)
throws DiscoveryException
{
- return find(Discovery.class, spiContext, properties, defaultImplName);
+ return find(Discovery.class, spi, properties);
}
-
+
/**
- * Equivalent to
- * find(new SPIContext(spi), properties, defaultImplName)
.
+ * Find implementation of SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
- public static Object find(Class rootFinderClass,
- Class spi,
- Properties properties,
- String defaultImplName)
+ public static Object find(Class spi, String defaultImplName)
throws DiscoveryException
{
- return find(rootFinderClass, new SPIContext(spi), properties, defaultImplName);
+ return find(Discovery.class, spi, defaultImplName);
}
/**
- * Equivalent to
- * find(ServiceFinder.class, spi, properties, defaultImplName)
.
+ * Find implementation of SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
public static Object find(Class spi,
Properties properties,
@@ -327,200 +326,439 @@
{
return find(Discovery.class, spi, properties, defaultImplName);
}
-
+
/**
- * Load properties file, and call
- * find(rootFinderClass, spiContext, properties, defaultImplName)
.
+ * Find implementation of SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param propertiesFileName The property file name.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
- public static Object find(Class rootFinderClass,
- SPIContext spiContext,
- String overloadPrefix,
+ public static Object find(Class spi,
String propertiesFileName,
String defaultImplName)
throws DiscoveryException
{
- // thread context can change on each call,
- // so establish context for this one call.
- ClassFinder classFinder = new ClassFinder(spiContext, rootFinderClass);
-
- Properties properties = null;
-
- if (propertiesFileName != null) {
- try {
- InputStream stream =
- (overloadPrefix == null)
- ? null
- : classFinder.findResourceAsStream(overloadPrefix + "." + propertiesFileName, false);
-
- if (stream == null)
- stream = classFinder.findResourceAsStream(propertiesFileName, false);
-
- if (stream != null) {
- properties = new Properties();
- try {
- properties.load(stream);
- } finally {
- stream.close();
- }
- }
- } catch (IOException e) {
- } catch (SecurityException e) {
- }
- }
-
- return find(classFinder, spiContext, properties, defaultImplName);
+ return find(Discovery.class, spi, propertiesFileName, defaultImplName);
}
/**
- * Load properties file, and call
- * find(ServiceFinder.class, spiContext, propertiesFileName, defaultImplName)
.
- */
- public static Object find(SPIContext spiContext,
- String overloadPrefix,
- String propertiesFileName,
+ * Find implementation of SPI.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param groupContext qualifier for the name of the system property
+ * used to find the service implementation. If a system property
+ * cannot be found by that name, then the unqualified property
+ * name is used.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class spi,
+ String groupContext,
+ Properties properties,
String defaultImplName)
throws DiscoveryException
{
- return find(Discovery.class, spiContext, overloadPrefix, propertiesFileName, defaultImplName);
+ return find(Discovery.class, spi, groupContext, properties, defaultImplName);
}
/**
- * Equivalent to
- * find(rootFinderClass, new SPIContext(spi), propertiesFileName, defaultImplName)
.
+ * Find implementation of SPI unique to a group context.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param groupContext qualifier for the property file name and for
+ * the system property name used to find the service implementation.
+ * If not found, the unqualified names are used.
+ *
+ * @param propertiesFileName The (qualified and unqualified) property file
+ * name.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
- public static Object find(Class rootFinderClass,
- Class spi,
- String overloadPrefix,
+ public static Object find(Class spi,
+ String groupContext,
String propertiesFileName,
String defaultImplName)
throws DiscoveryException
{
- return find(rootFinderClass, new SPIContext(spi), overloadPrefix, propertiesFileName, defaultImplName);
+ return find(Discovery.class, spi, groupContext, propertiesFileName, defaultImplName);
}
+
+
+ /*************** FINDERS FOR USE IN FACTORY/HELPER METHODS ***************
+ *
+ * These finders provide a rootFinderClass. The root finder is the wrapper
+ * class (factories or helper classes) that invoke the Discovery find
+ * methods, presumably providing (default) values for propertiesFileName
+ * and defaultImplName. Having access to this wrapper class provides a
+ * way to determine the 'real' caller, and hence the caller's class loader.
+ * Thus preserving knowledge that is relevant to finding the
+ * correct/expected implementation class.
+ */
+
/**
- * Equivalent to
- * find(new SPIContext(spi), propertiesFileName, defaultImplName)
.
- */
- public static Object find(Class spi,
- String overloadPrefix,
- String propertiesFileName,
- String defaultImplName)
+ * Find implementation of SPI.
+ *
+ * @param rootFinderClass Wrapper class used by end-user, that ultimately
+ * calls this finder method.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded, or if
+ * the resulting class does not implement the SPI.
+ */
+ public static Object find(Class rootFinderClass, Class spi)
throws DiscoveryException
{
- return find(new SPIContext(spi), overloadPrefix, propertiesFileName, defaultImplName);
+ return find(rootFinderClass, spi, nullProperties, nullDefaultImplName);
}
/**
- * Load properties file, and call
- * find(rootFinderClass, spiContext, properties, defaultImplName)
.
- */
- public static Object find(Class rootFinderClass,
- SPIContext spiContext,
- String propertiesFileName,
- String defaultImplName)
+ * Find implementation of SPI.
+ *
+ * @param rootFinderClass Wrapper class used by end-user, that ultimately
+ * calls this finder method.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class rootFinderClass, Class spi, Properties properties)
throws DiscoveryException
{
- return find(rootFinderClass, spiContext, (String)null, propertiesFileName, defaultImplName);
+ return find(rootFinderClass, spi, properties, nullDefaultImplName);
}
-
+
/**
- * Load properties file, and call
- * find(ServiceFinder.class, spiContext, propertiesFileName, defaultImplName)
.
- */
- public static Object find(SPIContext spiContext,
- String propertiesFileName,
- String defaultImplName)
+ * Find implementation of SPI.
+ *
+ * @param rootFinderClass Wrapper class used by end-user, that ultimately
+ * calls this finder method.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class rootFinderClass, Class spi, String defaultImplName)
throws DiscoveryException
{
- return find(Discovery.class, spiContext, (String)null, propertiesFileName, defaultImplName);
+ return find(rootFinderClass, spi, nullProperties, defaultImplName);
}
-
+
/**
- * Equivalent to
- * find(rootFinderClass, new SPIContext(spi), propertiesFileName, defaultImplName)
.
- */
+ * Find implementation of SPI.
+ *
+ * @param rootFinderClass Wrapper class used by end-user, that ultimately
+ * calls this finder method.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
public static Object find(Class rootFinderClass,
Class spi,
- String propertiesFileName,
+ Properties properties,
String defaultImplName)
throws DiscoveryException
{
- return find(rootFinderClass, new SPIContext(spi), propertiesFileName, defaultImplName);
+ return loadClass(new ClassFinder(spi, nullGroupContext, rootFinderClass),
+ properties, defaultImplName);
}
/**
- * Equivalent to
- * find(new SPIContext(spi), propertiesFileName, defaultImplName)
.
+ * Find implementation of SPI.
+ *
+ * @param rootFinderClass Wrapper class used by end-user, that ultimately
+ * calls this finder method.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param propertiesFileName The property file name.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
- public static Object find(Class spi,
+ public static Object find(Class rootFinderClass,
+ Class spi,
String propertiesFileName,
String defaultImplName)
throws DiscoveryException
{
- return find(new SPIContext(spi), propertiesFileName, defaultImplName);
+ ClassFinder classFinder = new ClassFinder(spi, nullGroupContext, rootFinderClass);
+ return loadClass(classFinder,
+ loadProperties(classFinder, propertiesFileName),
+ defaultImplName);
}
/**
* Find implementation of SPI.
- * Equivalent to find(rootFinderClass, spi, (Properties)null, defaultImplName);
- */
- public static Object find(Class rootFinderClass, Class spi, String defaultImplName)
+ *
+ * @param rootFinderClass Wrapper class used by end-user, that ultimately
+ * calls this finder method.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param groupContext qualifier for the property file name and for
+ * the system property name used to find the service implementation.
+ * If not found, the unqualified names are used.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class rootFinderClass,
+ Class spi,
+ String groupContext,
+ Properties properties,
+ String defaultImplName)
throws DiscoveryException
{
- return find(rootFinderClass, spi, (Properties)null, defaultImplName);
+ return loadClass(new ClassFinder(spi, groupContext, rootFinderClass),
+ properties, defaultImplName);
}
/**
* Find implementation of SPI.
- * Equivalent to find(spi, (Properties)null, defaultImplName);
- */
- public static Object find(Class spi, String defaultImplName)
+ *
+ * @param rootFinderClass Wrapper class used by end-user, that ultimately
+ * calls this finder method.
+ *
+ * @param spi Service Provider Interface Class.
+ *
+ * @param groupContext qualifier for the property file name and for
+ * the system property name used to find the service implementation.
+ * If not found, the unqualified names are used.
+ *
+ * @param propertiesFileName The property file name.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ public static Object find(Class rootFinderClass,
+ Class spi,
+ String groupContext,
+ String propertiesFileName,
+ String defaultImplName)
throws DiscoveryException
{
- return find(spi, (Properties)null, defaultImplName);
+ ClassFinder classFinder = new ClassFinder(spi, groupContext, rootFinderClass);
+ return loadClass(classFinder,
+ loadProperties(classFinder, propertiesFileName),
+ defaultImplName);
}
- /**
- * Find implementation of SPI.
- * Equivalent to find(rootFinderClass, spi, properties, null);
+
+ /************************* CORE LOADERS *************************
*/
- public static Object find(Class rootFinderClass, Class spi, Properties properties)
- throws DiscoveryException
- {
- return find(rootFinderClass, spi, properties, null);
- }
-
+
/**
- * Find implementation of SPI.
- * Equivalent to find(spi, properties, null);
+ * Load implementation of SPI.
+ *
+ * @param ClassFinder Represents the spiContext, class loaders
+ * (including root finder class), and the groupContext.
+ *
+ * @param properties Used to determine name of SPI implementation,
+ * and passed to implementation.init() method if
+ * implementation implements Service interface.
+ *
+ * @param defaultImplName Default implementation name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
*/
- public static Object find(Class spi, Properties properties)
+ private static Object loadClass(ClassFinder classFinder,
+ Properties properties,
+ String defaultImplName)
throws DiscoveryException
{
- return find(spi, properties, null);
- }
+ /**
+ * Return previously registered service object (not class)
+ * for this spi. Try each class loader in succession.
+ */
+ Object service = null;
+ ClassLoader[] allLoaders = classFinder.getAllLoaders();
- /**
- * Find implementation of SPI.
- * Equivalent to find(rootFinderClass, spi, (Properties)null, null);
- */
- public static Object find(Class rootFinderClass, Class spi)
- throws DiscoveryException
- {
- return find(rootFinderClass, spi, (Properties)null, null);
- }
+ for (int idx = 0; service == null && idx < allLoaders.length; idx++) {
+ service = get(classFinder.getSPIContext().getSPI().getName(), allLoaders[idx]);
+ }
+ if (service != null) {
+ // First, try the system property
+ Class clazz = classFinder.systemFindClass();
+
+ if (clazz == null) {
+ // Second, try the properties parameter
+ if (properties != null)
+ clazz = classFinder.findClass(properties);
+
+ if (clazz == null) {
+ // Third, try to find a service by using the JDK1.3 jar
+ // discovery mechanism.
+ clazz = classFinder.jdk13FindClass();
+
+ if (clazz == null) {
+ // Fourth, try the fallback implementation class,
+ // but limit loaders to 'system' loaders, in an
+ // attempt to ensure that the default picked up is
+ // the one that one intended.
+ clazz = classFinder.findClass(defaultImplName, true);
+
+ if (clazz == null) {
+ throw new DiscoveryException
+ ("No implementation defined for " +
+ classFinder.getSPIContext().getSPI().getName());
+ }
+ }
+ }
+ }
+
+ if (clazz != null) {
+ try {
+ service = clazz.newInstance();
+ put(classFinder.getSPIContext().getSPI().getName(), clazz.getClassLoader(), service);
+ } catch (Exception e) {
+ throw new DiscoveryException("Unable to instantiate " + classFinder.getSPIContext().getSPI().getName(), e);
+ }
+
+ if (service instanceof Service) {
+ ((Service)service).init(properties);
+ }
+ }
+ }
+
+ return service;
+ }
+
/**
- * Find implementation of SPI.
- * Equivalent to find(spi, (Properties)null, null);
- */
- public static Object find(Class spi)
+ * Load property file (qualified by groupContext param to classFinder).
+ *
+ * @param ClassFinder Represents the spiContext, class loaders
+ * (including root finder class), and the groupContext.
+ *
+ * @param propertiesFileName The property file name.
+ *
+ * @return Instance of a class implementing the SPI.
+ *
+ * @exception DiscoveryException Thrown if the name of a class implementing
+ * the SPI cannot be found, if the class cannot be loaded and
+ * instantiated, or if the resulting class does not implement
+ * (or extend) the SPI.
+ */
+ private static Properties loadProperties(ClassFinder classFinder,
+ String propertiesFileName)
throws DiscoveryException
{
- return find(spi, (Properties)null, null);
+ Properties properties = null;
+
+ if (propertiesFileName != null) {
+ try {
+ InputStream stream =
+ classFinder.findResourceAsStream(propertiesFileName);
+
+ if (stream != null) {
+ properties = new Properties();
+ try {
+ properties.load(stream);
+ } finally {
+ stream.close();
+ }
+ }
+ } catch (IOException e) {
+ } catch (SecurityException e) {
+ }
+ }
+
+ return properties;
}
-
+
+
+ /************************* SPI LIFE-CYCLE SUPPORT *************************/
+
/**
* Release any internal references to previously created service instances,
* after calling the instance method release()
on each of them.
@@ -559,6 +797,15 @@
}
}
}
+
+
+ /************************* SPI CACHE SUPPORT *************************/
+
+ /**
+ * Sets of previously encountered service interfaces (spis), keyed by the
+ * interface (Class
). Each element is a ServiceCache.
+ */
+ private static final Hashtable service_caches = new Hashtable(13);
/**
* Get service keyed by spi & classLoader.
1.4 +60 -36 jakarta-commons/discovery/src/java/org/apache/commons/discovery/ClassLoaderUtils.java
Index: ClassLoaderUtils.java
===================================================================
RCS file: /home/cvs/jakarta-commons/discovery/src/java/org/apache/commons/discovery/ClassLoaderUtils.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ClassLoaderUtils.java 18 Jul 2002 18:32:34 -0000 1.3
+++ ClassLoaderUtils.java 26 Jul 2002 22:35:05 -0000 1.4
@@ -82,6 +82,12 @@
* @author Costin Manolache
*/
public class ClassLoaderUtils {
+ /**
+ * This doesn't change across threads... so cache the value.
+ */
+ private static final ClassLoader systemClassLoader
+ = findSystemClassLoader();
+
private static final boolean debug = false;
/**
@@ -363,42 +369,52 @@
}
/**
- * Return the system class loader if available.
- * Otherwise return null. If the system class loader
- * is the bootstrap classloader, then it is 'wrapped'
+ * Return the thread context class loader if available.
+ * Otherwise return null. If the thread context class
+ * loader is the bootstrap classloader, then it is 'wrapped'
* (see BootstrapLoader). Therefore this method only
- * returns 'null' if a system class loader could not
+ * returns 'null' if a thread context class loader could not
* be identified.
*
- * The system class loader is available for JDK 1.2
+ * The thread context class loader is available for JDK 1.2
* or later, if certain security conditions are met.
*
* @exception DiscoveryException if a suitable class loader
- * cannot be identified.
+ * cannot be identified.
*/
- public static ClassLoader findSystemClassLoader()
+ public static ClassLoader getThreadContextClassLoader()
throws DiscoveryException
{
ClassLoader classLoader = null;
try {
// Are we running on a JDK 1.2 or later system?
- Method method = ClassLoader.class.getMethod("getSystemClassLoader", null);
+ Method method = Thread.class.getMethod("getContextClassLoader", null);
- // Get the system class loader (if there is one)
+ // Get the thread context class loader (if there is one)
try {
classLoader =
- BootstrapLoader.wrap((ClassLoader)method.invoke(null, null));
+ BootstrapLoader.wrap((ClassLoader)method.invoke(Thread.currentThread(), null));
} catch (IllegalAccessException e) {
throw new DiscoveryException("Unexpected IllegalAccessException", e);
} catch (InvocationTargetException e) {
/**
* InvocationTargetException is thrown by 'invoke' when
- * the method being invoked (ClassLoader.getSystemClassLoader)
+ * the method being invoked (Thread.getContextClassLoader)
* throws an exception.
*
- * ClassLoader.getSystemClassLoader() throws SecurityException
- * if security permissions are restricted.
+ * Thread.getContextClassLoader() throws SecurityException
+ * when the context class loader isn't an ancestor of the
+ * calling class's class loader, or if security permissions
+ * are restricted.
+ *
+ * In the first case (the context class loader isn't an
+ * ancestor of the calling class's class loader), we want
+ * to ignore and keep going. We cannot help but also ignore
+ * the second case (restricted security permissions) with
+ * the logic below, but other calls elsewhere (to obtain
+ * a class loader) will re-trigger this exception where
+ * we can make a distinction.
*/
if (e.getTargetException() instanceof SecurityException) {
classLoader = null; // ignore
@@ -418,54 +434,62 @@
// Return the selected class loader
return classLoader;
}
+
+ /**
+ * Return the system class loader if available.
+ * Otherwise return null. If the system class loader
+ * is the bootstrap classloader, then it is 'wrapped'
+ * (see BootstrapLoader). Therefore this method only
+ * returns 'null' if a system class loader could not
+ * be identified.
+ *
+ * The system class loader is available for JDK 1.2
+ * or later, if certain security conditions are met.
+ *
+ * @exception DiscoveryException if a suitable class loader
+ * cannot be identified.
+ */
+ public static ClassLoader getSystemClassLoader() {
+ return systemClassLoader;
+ }
/**
- * Return the thread context class loader if available.
- * Otherwise return null. If the thread context class
- * loader is the bootstrap classloader, then it is 'wrapped'
+ * Return the system class loader if available.
+ * Otherwise return null. If the system class loader
+ * is the bootstrap classloader, then it is 'wrapped'
* (see BootstrapLoader). Therefore this method only
- * returns 'null' if a thread context class loader could not
+ * returns 'null' if a system class loader could not
* be identified.
*
- * The thread context class loader is available for JDK 1.2
+ * The system class loader is available for JDK 1.2
* or later, if certain security conditions are met.
*
* @exception DiscoveryException if a suitable class loader
- * cannot be identified.
+ * cannot be identified.
*/
- public static ClassLoader findThreadContextClassLoader()
+ private static ClassLoader findSystemClassLoader()
throws DiscoveryException
{
ClassLoader classLoader = null;
try {
// Are we running on a JDK 1.2 or later system?
- Method method = Thread.class.getMethod("getContextClassLoader", null);
+ Method method = ClassLoader.class.getMethod("getSystemClassLoader", null);
- // Get the thread context class loader (if there is one)
+ // Get the system class loader (if there is one)
try {
classLoader =
- BootstrapLoader.wrap((ClassLoader)method.invoke(Thread.currentThread(), null));
+ BootstrapLoader.wrap((ClassLoader)method.invoke(null, null));
} catch (IllegalAccessException e) {
throw new DiscoveryException("Unexpected IllegalAccessException", e);
} catch (InvocationTargetException e) {
/**
* InvocationTargetException is thrown by 'invoke' when
- * the method being invoked (Thread.getContextClassLoader)
+ * the method being invoked (ClassLoader.getSystemClassLoader)
* throws an exception.
*
- * Thread.getContextClassLoader() throws SecurityException
- * when the context class loader isn't an ancestor of the
- * calling class's class loader, or if security permissions
- * are restricted.
- *
- * In the first case (the context class loader isn't an
- * ancestor of the calling class's class loader), we want
- * to ignore and keep going. We cannot help but also ignore
- * the second case (restricted security permissions) with
- * the logic below, but other calls elsewhere (to obtain
- * a class loader) will re-trigger this exception where
- * we can make a distinction.
+ * ClassLoader.getSystemClassLoader() throws SecurityException
+ * if security permissions are restricted.
*/
if (e.getTargetException() instanceof SecurityException) {
classLoader = null; // ignore
--
To unsubscribe, e-mail: