commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rsi...@apache.org
Subject cvs commit: jakarta-commons/discovery/src/java/org/apache/commons/discovery SPIContext.java ClassFinder.java Discovery.java ClassLoaderUtils.java
Date Fri, 26 Jul 2002 22:35:05 GMT
rsitze      2002/07/26 15:35:05

  Modified:    discovery/src/java/org/apache/commons/discovery
                        SPIContext.java ClassFinder.java Discovery.java
                        ClassLoaderUtils.java
  Log:
  Cleaned up javadoc & code organization.
  Introduced 'groupContext', which is used to qualify property names,
  and property file names.  It will also be used to qualify cached
  services, so each group (as defined by groupContext) can have it's
  own instance of a service.
  
  Revision  Changes    Path
  1.3       +2 -20     jakarta-commons/discovery/src/java/org/apache/commons/discovery/SPIContext.java
  
  Index: SPIContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/discovery/src/java/org/apache/commons/discovery/SPIContext.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SPIContext.java	17 Jul 2002 22:03:06 -0000	1.2
  +++ SPIContext.java	26 Jul 2002 22:35:05 -0000	1.3
  @@ -70,13 +70,6 @@
    * to include an spi and the Thread Context Class Loader for
    * the thread that created an instance of this object.
    * 
  - * These matters are, for the most part, trivial.  Bundling
  - * these two together is a convenience, but more importantly
  - * it gives a home to a portable mechanism for determining
  - * the thread context class loader.  JDK 1.1 does not support
  - * the thread context class loader, yet the code below must
  - * be able to compile & execute in such an environment.
  - * 
    * @author Richard A. Sitze
    */
   public class SPIContext {
  @@ -85,14 +78,7 @@
        * Wrapped bootstrap classloader if classLoader == null.
        */
       private final ClassLoader threadContextClassLoader =
  -        ClassLoaderUtils.findThreadContextClassLoader();
  -
  -    /**
  -     * System class loader or null if not available (JDK 1.1).
  -     * Wrapped bootstrap classloader if classLoader == null.
  -     */
  -    private final ClassLoader systemClassLoader =
  -        ClassLoaderUtils.findSystemClassLoader();
  +        ClassLoaderUtils.getThreadContextClassLoader();
   
       /**
        * List of class loaders
  @@ -111,15 +97,11 @@
           this.loaders = ClassLoaderUtils.compactUniq(
               new ClassLoader[] { threadContextClassLoader,
                                   BootstrapLoader.wrap(spi.getClassLoader()),
  -                                systemClassLoader });
  +                                ClassLoaderUtils.getSystemClassLoader() });
       }
       
       public ClassLoader getThreadContextClassLoader() {
           return threadContextClassLoader;
  -    }
  -    
  -    public ClassLoader getSystemClassLoader() {
  -        return systemClassLoader;
       }
       
       public ClassLoader[] getClassLoaders() {
  
  
  
  1.5       +60 -33    jakarta-commons/discovery/src/java/org/apache/commons/discovery/ClassFinder.java
  
  Index: ClassFinder.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/discovery/src/java/org/apache/commons/discovery/ClassFinder.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ClassFinder.java	18 Jul 2002 18:32:34 -0000	1.4
  +++ ClassFinder.java	26 Jul 2002 22:35:05 -0000	1.5
  @@ -90,53 +90,70 @@
        * looking for an implementation of.
        */
       private final SPIContext spiContext;
  +    private final String     groupContext;
       private final Class      rootFinderClass;
       
  -    private final ClassLoader[] localLoaders;
  +    /**
  +     * This is NOT the same as spiContext.getClassLoaders(),
  +     * which includes the thread context class loader.
  +     */
  +    private final ClassLoader[] systemLoaders;
  +    
       private final ClassLoader[] allLoaders;
       
       ClassLoader[] getAllLoaders() { return allLoaders; }
   
  -    public ClassFinder(SPIContext spiContext, Class rootFinderClass) {
  +    public ClassFinder(SPIContext spiContext,
  +                       String groupContext,
  +                       Class rootFinderClass)
  +    {
           this.spiContext = spiContext;
  +        this.groupContext = groupContext;
           this.rootFinderClass = rootFinderClass;
  -        this.localLoaders = getLocalLoaders(spiContext, rootFinderClass);
  +        this.systemLoaders = getSystemLoaders(spiContext, rootFinderClass);
           this.allLoaders = getAllLoaders(spiContext, rootFinderClass);
   
           //System.out.println("Finding '" + spiContext.getSPI().getName() + "'");
       }
       
  -    public ClassFinder(Class spi, Class rootFinderClass) {
  +    public ClassFinder(Class spi,
  +                       String groupContext,
  +                       Class rootFinderClass)
  +    {
           this.spiContext = new SPIContext(spi);
  +        this.groupContext = groupContext;
           this.rootFinderClass = rootFinderClass;
  -        this.localLoaders = getLocalLoaders(spiContext, rootFinderClass);
  +        this.systemLoaders = getSystemLoaders(spiContext, rootFinderClass);
           this.allLoaders = getAllLoaders(spiContext, rootFinderClass);
   
           //System.out.println("Finding '" + spi.getName() + "'");
       }
       
  +    
  +    public SPIContext getSPIContext() { return spiContext; }
  +    
  +    
       /**
        * Return the specified <code>serviceImplName</code> implementation
  -     * class.  If <code>localOnly</code> is <code>true</code>, try the
  -     * class loaders local to the caller: root finder class's (default
  -     * ServiceFinder) and system.  If <code>localOnly</code> is
  -     * <code>false</code>, try each of the following class loaders:
  -     * thread context, caller's, spi's, root finder class's (default
  -     * ServiceFinder), and system.
  +     * class.  If <code>systemOnly</code> is <code>true</code>, try the
  +     * 'system' class loaders: spi's, root finder class's (default is
  +     * Discovery) and system.  If <code>systemOnly</code> is <code>false</code>,
  +     * 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 <code>spi</code>
        */
  -    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 <code>resourceName</code> as an
  -     * <code>InputStream</code>.  If <code>localOnly</code> is
  -     * <code>true</code>, try the class loaders local to the caller:
  -     * root finder class's (default ServiceFinder) and system.
  -     * If <code>localOnly</code> is <code>false</code>, try each of
  +     * <code>InputStream</code>.  If <code>systemOnly</code> is
  +     * <code>true</code>, try the 'system' class loaders: spi's,
  +     * root finder class's (default is Discovery), and system.
  +     * If <code>systemOnly</code> is <code>false</code>, 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 @@
   
   
   /**
  - * <p>Discover service instances,
  + * <p>Discover service providers,
    * with discovery and configuration features similar to that employed
  - * by standard Java APIs such as JAXP.</p>
  - *
  + * by standard Java APIs such as JAXP.
  + * </p>
  + * 
  + * <p>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.
  + * </p>
  + * 
  + * <p>Discovery provides the <code>find</code> methods for locating and
  + * instantiating an implementation of a service (SPI).  Each form of
  + * <code>find</code> varies slightly, but they all perform the same basic
  + * function.  The Discovery <code>find</code> methods proceed as follows:
  + * </p>
  + * <ul>
  + *   <p><li>
  + *   Examine an internal cache to determine if the desired service was
  + *   previously identified and instantiated.  If found in cache, return it.
  + *   </li></p>
  + *   <p><li>
  + *   Get the name of an implementation class.  The name is the first
  + *   non-null value obtained from the following resources:
  + *   <ul>
  + *     <p><li>
  + *     The value of the system property whose name is the same as the SPI's
  + *     fully qualified class name (as given by SPI.class.getName()).
  + *     </li></p>
  + *     <p><li>
  + *     The value of a <code>Properties properties</code> 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()).
  + *     </li></p>
  + *     <p><li>
  + *     The value obtained using the JDK1.3+ 'Service Provider' specification
  + *     (http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html) to locate a
  + *     service named <code>SPI.class.getName()</code>.  This is implemented
  + *     internally, so there is not a dependency on JDK 1.3+.
  + *     </li></p>
  + *   </ul>
  + *   </li></p>
  + *   <p><li>
  + *   If the name of the implementation class is non-null, load that class.
  + *   The class loaded is the first class loaded by the following sequence
  + *   of class loaders:
  + *   <ul>
  + *     <li>Thread Context Class Loader</li>
  + *     <li>Discovery's Caller's Class Loader</li>
  + *     <li>SPI's Class Loader</li>
  + *     <li>Discovery's (this class) Class Loader</li>
  + *     <li>System Class Loader</li>
  + *   </ul>
  + *   An exception is thrown if the class cannot be loaded.
  + *   </li></p>
  + *   <p><li>
  + *   If the name of the implementation class is null, AND the default
  + *   implementation class name (<code>defaultImplName</code>) is null,
  + *   then an exception is thrown.
  + *   </li></p>
  + *   <p><li>
  + *   If the name of the implementation class is null, AND the default
  + *   implementation class name (<code>defaultImplName</code>) is non-null,
  + *   then load the default implementation class.  The class loaded is the
  + *   first class loaded by the following sequence of class loaders:
  + *   <ul>
  + *     <li>SPI's Class Loader</li>
  + *     <li>Discovery's (this class) Class Loader</li>
  + *     <li>System Class Loader</li>
  + *   </ul>
  + *   <p>
  + *   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.
  + *   </p>
  + *   <p>
  + *   An exception is thrown if the class cannot be loaded.
  + *   </p>
  + *   </li></p>
  + *   <p><li>
  + *   Verify that the loaded class implements the SPI: an exception is thrown
  + *   if the loaded class does not implement the SPI.
  + *   </li></p>
  + *   <p><li>
  + *   If the loaded class implements the <code>Service</code> interface,
  + *   then invoke the <code>init(Properties)</code> method, passing in the
  + *   <code>Properties properties</code> parameter, if provided.
  + *   </li></p>
  + * <ul>
  + * 
  + * <p>
  + * Variances for various forms of the <code>find</code>
  + * methods are discussed with each such method.
  + * Variances include the following concepts:
  + * <ul>
  + *   <li><b>rootFinderClass</b> - a wrapper encapsulating a finder method
  + *   (factory or other helper class).  The root finder class is used to
  + *   determine the 'real' caller, and hence the caller's class loader -
  + *   thereby preserving knowledge that is relevant to finding the
  + *   correct/expected implementation class.
  + *   </li>
  + *   <li><b>propertiesFileName</b> - <code>Properties</code> 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:
  + *   <ul>
  + *     <li>Thread Context Class Loader</li>
  + *     <li>Discovery's Caller's Class Loader</li>
  + *     <li>SPI's Class Loader</li>
  + *     <li>Discovery's (this class) Class Loader</li>
  + *     <li>System Class Loader</li>
  + *   </ul>
  + *   </li>
  + *   <li><b>groupContext</b> - differentiates service providers for different
  + *   logical groups of service users, that might otherwise be forced to share
  + *   a common service and, more importantly, a common configuration of that
  + *   service.
  + *   <p>The groupContext is used to qualify the name of the property file
  + *   name: <code>groupContext + '.' + propertiesFileName</code>.  If that
  + *   file is not found, then the unqualified propertyFileName is used.
  + *   </p>
  + *   <p>In addition, groupContext is used to qualify the name of the system
  + *   property used to find the service implementation by prepending the value
  + *   of <code>groupContext</code> to the property name:
  + *   <code>groupContext&gt; + '.' + SPI.class.getName()</code>.
  + *   Again, if a system property cannot be found by that name, then the
  + *   unqualified property name is used.
  + *   </p>
  + *   </li>
  + * </ul>
  + * </p>
  + * 
  + * <p>
  + * Other concepts
  + * </p>
  + * 
    * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily
    * based on the SAXParserFactory and DocumentBuilderFactory implementations
  - * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.</p>
  + * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
  + * </p>
    * 
    * @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 (<code>Class</code>).  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;
       
       /**
  -     * <p>Locate and instantiate a service.  The service implementation
  -     * class is located using the following ordered lookup:</p>
  -     * <ul>
  -     * <li>Try to load a class with the name obtained from the system
  -     *     property, having the same name as the spi class:
  -     *     <code>spiContext.getSPI().getName()</code>.</li>
  -     * 
  -     * <li>Try to load a class with the name obtained from the
  -     *     <code>properties</code> parameter, having the same
  -     *     name as the spi class: <code>spiContext.getSPI().getName()</code>.</li>
  -     * 
  -     * <li>Use the JDK1.3+ 'Service Provider' specification
  -     *     (http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html)
  -     *     to locate a service named <code>spiContext.getSPI().getName()</code>.
  -     *     Implemented internally, so there is not a hard
  -     *     dependency on JDK 1.3+.</li>
  -     * 
  -     * <li>Fall back to a default implementation class, as specified by
  -     *     non-null <code>defaultImplName</code>.</li>
  -     * </ul>
  -     * 
  -     * <p>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:
  -     * <ul>
  -     * <li>Thread Context Class Loader</li>
  -     * <li>Caller's Class Loader</li>
  -     * <li>SPI's Class Loader</li>
  -     * <li>ServiceFinder's (this class) Class Loader</li>
  -     * <li>System Class Loader</li>
  -     * </ul>
  -     * 
  -     * <p>The default implementation is loaded using:
  -     * <ul>
  -     * <li>ServiceFinder's (this class) Class Loader</li>
  -     * <li>System Class Loader</li>
  -     * </ul>
  -     * 
  -     * @param ClassFinder  Represents the class loaders provided 
  -     *        by a root finder class, and the spiContext.
  -     * 
  -     * @param spiContext The SPI Context identifies the SPI and the
  -     *        thread context class loader.
  -     *        <code>spiContext.getSPI().getName()</code> 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
  -     *        <code>spi.getName()</code>.  If the implementation class found
  -     *        for <code>spi</code> implements the <code>Service</code>
  -     *        interface, then <code>spiInstance.init(properties)</code> 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 <code>spi</code>.
  -     */
  -    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.
  +     */
       
       /**
  -     * <p>Locate and instantiate a service.  The service implementation
  -     * class is located using the following ordered lookup:</p>
  -     * <ul>
  -     * <li>Try to load a class with the name obtained from the system
  -     *     property, having the same name as the spi class:
  -     *     <code>spiContext.getSPI().getName()</code>.</li>
  -     * 
  -     * <li>Try to load a class with the name obtained from the
  -     *     <code>properties</code> parameter, having the same
  -     *     name as the spi class: <code>spiContext.getSPI().getName()</code>.</li>
  -     * 
  -     * <li>Use the JDK1.3+ 'Service Provider' specification
  -     *     (http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html)
  -     *     to locate a service named <code>spiContext.getSPI().getName()</code>.
  -     *     Implemented internally, so there is not a hard
  -     *     dependency on JDK 1.3+.</li>
  -     * 
  -     * <li>Fall back to a default implementation class, as specified by
  -     *     non-null <code>defaultImplName</code>.</li>
  -     * </ul>
  -     * 
  -     * <p>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:
  -     * <ul>
  -     * <li>Thread Context Class Loader</li>
  -     * <li>Caller's Class Loader</li>
  -     * <li>SPI's Class Loader</li>
  -     * <li>ServiceFinder's (this class) Class Loader</li>
  -     * <li>System Class Loader</li>
  -     * </ul>
  -     * 
  -     * <p>The default implementation is loaded using:
  -     * <ul>
  -     * <li>ServiceFinder's (this class) Class Loader</li>
  -     * <li>System Class Loader</li>
  -     * </ul>
  -     * 
  -     * @param rootFinderClass  The root finder class.
  -     *        If a wrapper/factory class is used around 'ServiceFinder',
  -     *        then this will be that wrapper/factory class.
  -     * 
  -     * @param spiContext The SPI Context identifies the SPI and the
  -     *        thread context class loader.
  -     *        <code>spiContext.getSPI().getName()</code> 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
  -     *        <code>spi.getName()</code>.  If the implementation class found
  -     *        for <code>spi</code> implements the <code>Service</code>
  -     *        interface, then <code>spiInstance.init(properties)</code> 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 <code>spi</code>.
  +     * @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
  -     * <code>find(ServiceFinder.class, spiContext, properties, defaultImplName)</code>.
  +     * 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
  -     * <code>find(new SPIContext(spi), properties, defaultImplName)</code>.
  +     * 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
  -     * <code>find(ServiceFinder.class, spi, properties, defaultImplName)</code>.
  +     * 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
  -     * <code>find(rootFinderClass, spiContext, properties, defaultImplName)</code>.
  +     * 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
  -     * <code>find(ServiceFinder.class, spiContext, propertiesFileName, defaultImplName)</code>.
  -     */    
  -    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
  -     * <code>find(rootFinderClass, new SPIContext(spi), propertiesFileName, defaultImplName)</code>.
  +     * 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
  -     * <code>find(new SPIContext(spi), propertiesFileName, defaultImplName)</code>.
  -     */    
  -    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
  -     * <code>find(rootFinderClass, spiContext, properties, defaultImplName)</code>.
  -     */    
  -    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
  -     * <code>find(ServiceFinder.class, spiContext, propertiesFileName, defaultImplName)</code>.
  -     */    
  -    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
  -     * <code>find(rootFinderClass, new SPIContext(spi), propertiesFileName, defaultImplName)</code>.
  -     */    
  +     * 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
  -     * <code>find(new SPIContext(spi), propertiesFileName, defaultImplName)</code>.
  +     * 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 <code>release()</code> on each of them.
  @@ -559,6 +797,15 @@
               }
           }
       }
  +
  +    
  +    /************************* SPI CACHE SUPPORT *************************/
  +
  +    /**
  +     * Sets of previously encountered service interfaces (spis), keyed by the
  +     * interface (<code>Class</code>).  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:   <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>


Mime
View raw message