You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rs...@apache.org on 2002/06/28 23:28:13 UTC

cvs commit: jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery ClassLoaderUtils.java SPIContext.java ClassFinder.java ServiceFinder.java

rsitze      2002/06/28 14:28:12

  Modified:    discovery/src/java/org/apache/commons/service/discovery
                        SPIContext.java ClassFinder.java ServiceFinder.java
  Added:       discovery/src/java/org/apache/commons/service/discovery
                        ClassLoaderUtils.java
  Log:
  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:
  
  - Thread Context Class Loader
  - Caller's Class Loader
  - SPI's Class Loader
  - ServiceFinder's (this class) Class Loader
  - System Class Loader
  
  The default implementation is loaded using:
  - ServiceFinder's (this class) Class Loader
  - System Class Loader
  
  Revision  Changes    Path
  1.2       +65 -2     jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/SPIContext.java
  
  Index: SPIContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/SPIContext.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SPIContext.java	26 Jun 2002 15:50:15 -0000	1.1
  +++ SPIContext.java	28 Jun 2002 21:28:12 -0000	1.2
  @@ -83,10 +83,16 @@
       /**
        * Thread context class loader or null if not available (JDK 1.1).
        */
  -    private ClassLoader threadContextClassLoader =
  +    private final ClassLoader threadContextClassLoader =
           findThreadContextClassLoader();
   
       /**
  +     * System class loader or null if not available (JDK 1.1).
  +     */
  +    private final ClassLoader systemClassLoader =
  +        findSystemClassLoader();
  +
  +    /**
        * The service programming interface: intended to be
        * an interface or abstract class, but not limited
        * to those two.
  @@ -101,6 +107,10 @@
           return threadContextClassLoader;
       }
       
  +    public ClassLoader getSystemClassLoader() {
  +        return systemClassLoader;
  +    }
  +    
       public Class getSPI() {
           return spi;
       }
  @@ -112,7 +122,7 @@
        * The thread context class loader is available for JDK 1.2
        * or later, if certain security conditions are met.
        * 
  -     * @exception SecurityException if a suitable class loader
  +     * @exception ServiceException if a suitable class loader
        * cannot be identified.
        */
       private static ClassLoader findThreadContextClassLoader()
  @@ -148,6 +158,59 @@
                    * 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
  +                } else {
  +                    // Capture 'e.getTargetException()' exception for details
  +                    // alternate: log 'e.getTargetException()', and pass back 'e'.
  +                    throw new ServiceException
  +                        ("Unexpected InvocationTargetException",
  +                         e.getTargetException());
  +                }
  +            }
  +        } catch (NoSuchMethodException e) {
  +            // Assume we are running on JDK 1.1
  +            classLoader = null;
  +        }
  +    
  +        // Return the selected class loader
  +        return classLoader;
  +    }
  +
  +    /**
  +     * Return the system class loader if available.
  +     * Otherwise return null.
  +     * 
  +     * The system class loader is available for JDK 1.2
  +     * or later, if certain security conditions are met.
  +     * 
  +     * @exception ServiceException if a suitable class loader
  +     * cannot be identified.
  +     */
  +    private static ClassLoader findSystemClassLoader()
  +        throws ServiceException
  +    {
  +        ClassLoader classLoader = null;
  +        
  +        try {
  +            // Are we running on a JDK 1.2 or later system?
  +            Method method = ClassLoader.class.getMethod("getSystemClassLoader", null);
  +    
  +            // Get the system class loader (if there is one)
  +            try {
  +                classLoader =
  +                    (ClassLoader)method.invoke(null, null);
  +            } catch (IllegalAccessException e) {
  +                throw new ServiceException("Unexpected IllegalAccessException", e);
  +            } catch (InvocationTargetException e) {
  +                /**
  +                 * InvocationTargetException is thrown by 'invoke' when
  +                 * the method being invoked (ClassLoader.getSystemClassLoader)
  +                 * throws an exception.
  +                 * 
  +                 * ClassLoader.getSystemClassLoader() throws SecurityException
  +                 * if security permissions are restricted.
                    */
                   if (e.getTargetException() instanceof SecurityException) {
                       classLoader = null;  // ignore
  
  
  
  1.2       +50 -72    jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ClassFinder.java
  
  Index: ClassFinder.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ClassFinder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ClassFinder.java	26 Jun 2002 15:50:15 -0000	1.1
  +++ ClassFinder.java	28 Jun 2002 21:28:12 -0000	1.2
  @@ -90,79 +90,27 @@
        * looking for an implementation of.
        */
       private final SPIContext spiContext;
  +    private final Class      finderClass;
       
  -    public ClassFinder(SPIContext spiContext) {
  +    private final ClassLoader[] localLoaders;
  +    private final ClassLoader[] allLoaders;
  +
  +    public ClassFinder(SPIContext spiContext, Class finderClass) {
           this.spiContext = spiContext;
  +        this.finderClass = finderClass;
  +        this.localLoaders = getLocalLoaders(spiContext, finderClass);
  +        this.allLoaders = getAllLoaders(spiContext, finderClass);
  +
           //System.out.println("Finding '" + spiContext.getSPI().getName() + "'");
       }
       
  -    public ClassFinder(Class spi) {
  +    public ClassFinder(Class spi, Class finderClass) {
           this.spiContext = new SPIContext(spi);
  -        //System.out.println("Finding '" + spi.getName() + "'");
  -    }
  -    
  -    public ClassLoader getThreadContextClassLoader() {
  -        return spiContext.getThreadContextClassLoader();
  -    }
  -
  -    /**
  -     * Load the class serviceImplName.
  -     * First try to load the class with the thread context class loader,
  -     * and failing that try the local class loader.
  -     * 
  -     * @param serviceImplName The name of the class to load.
  -     */
  -    public static Class load(String serviceImplName,
  -                             ClassLoader threadContextClassLoader,
  -                             ClassLoader localClassLoader)
  -        throws ServiceException
  -    {
  -        //System.out.println("Loading '" + serviceImplName + "'");
  +        this.finderClass = finderClass;
  +        this.localLoaders = getLocalLoaders(spiContext, finderClass);
  +        this.allLoaders = getAllLoaders(spiContext, finderClass);
   
  -        Class clazz = null;
  -        
  -        if (serviceImplName != null  &&  serviceImplName.length() > 0) {
  -            if (threadContextClassLoader != null) {
  -                try {
  -                    // first the thread class loader
  -                    clazz = threadContextClassLoader.loadClass(serviceImplName);
  -                } catch (ClassNotFoundException e) {
  -                    clazz = null;
  -                }
  -            }
  -    
  -            if (clazz == null  &&
  -                localClassLoader != null  &&
  -                localClassLoader != threadContextClassLoader) {
  -                // if threadContextClassLoder was null or if it failed
  -                // (i.e. no implementation is found in the webapp), try
  -                // the local loader if we haven't already...
  -                try {
  -                    // clazz = spi.getClassLoader().loadClass(serviceImplName);
  -                    clazz = localClassLoader.loadClass(serviceImplName);
  -                } catch (ClassNotFoundException e) {
  -                    clazz = null;
  -                }
  -            }
  -        }
  -        
  -        return clazz;
  -    }
  -
  -    /**
  -     * Load the class serviceImplName.
  -     * First try to load the class with the SPI context's
  -     * thread context class loader, and failing that try
  -     * the class loader that loaded the SPI.
  -     * 
  -     * @param serviceImplName The name of the class to load.
  -     */
  -    public static Class load(String serviceImplName, SPIContext spiContext)
  -        throws ServiceException
  -    {
  -        return load(serviceImplName,
  -                    spiContext.getThreadContextClassLoader(),
  -                    spiContext.getSPI().getClassLoader());
  +        //System.out.println("Finding '" + spi.getName() + "'");
       }
       
       /**
  @@ -181,9 +129,8 @@
       public Class find(String serviceImplName, boolean localOnly)
           throws ServiceException
       {
  -        Class clazz = load(serviceImplName,
  -                           localOnly ? null : getThreadContextClassLoader(),
  -                           spiContext.getSPI().getClassLoader());
  +        Class clazz = ClassLoaderUtils.loadUniq(serviceImplName,
  +                           localOnly ? localLoaders : allLoaders);
               
           if (clazz != null  &&  !spiContext.getSPI().isAssignableFrom(clazz)) {
               throw new ServiceException("Class " + serviceImplName +
  @@ -260,10 +207,13 @@
   
           // Name of J2EE application file that identifies the service implementation.
           String servicePropertyFile = SERVICE_HOME + spiContext.getSPI().getName();
  +        
  +        ClassLoader contextLoader = spiContext.getThreadContextClassLoader();
       
  -        InputStream is = (getThreadContextClassLoader() == null
  +        InputStream is = (contextLoader == null
                             ? ClassLoader.getSystemResourceAsStream(servicePropertyFile)
  -                          : getThreadContextClassLoader().getResourceAsStream(servicePropertyFile));
  +                          : contextLoader.getResourceAsStream(servicePropertyFile));
  +                          
           if( is != null ) {
               try {
                   try {
  @@ -277,7 +227,6 @@
                           rd = new BufferedReader(new InputStreamReader(is));
                       }
                           
  -                
                       try {
                           serviceImplName = rd.readLine();
                       } finally {
  @@ -292,5 +241,34 @@
           }
           
           return serviceImplName;
  +    }
  +    
  +    /**
  +     * MAGIC: as in, I don't have a clue how to go about this...
  +     * SecurityManager.getClassContext() is out of reach at best,
  +     * and getting to it in a J2EE environment is likely to be beyond
  +     * hopeless....
  +     */
  +    private static final ClassLoader getCallerClassLoader(Class finderClass) {
  +        return null;
  +    }
  +
  +    private static final ClassLoader[] getLocalLoaders(SPIContext spiContext,
  +                                                       Class finderClass) {
  +        return ClassLoaderUtils.compactUniq(new ClassLoader[] {    
  +                                finderClass.getClassLoader(),
  +                                spiContext.getSystemClassLoader()
  +                          });
  +    }
  +    
  +    private static final ClassLoader[] getAllLoaders(SPIContext spiContext,
  +                                                     Class finderClass) {
  +        return ClassLoaderUtils.compactUniq(new ClassLoader[] {    
  +                                spiContext.getThreadContextClassLoader(),
  +                                getCallerClassLoader(finderClass),
  +                                spiContext.getSPI().getClassLoader(),
  +                                finderClass.getClassLoader(),
  +                                spiContext.getSystemClassLoader()
  +                            });
       }
   }
  
  
  
  1.2       +108 -7    jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ServiceFinder.java
  
  Index: ServiceFinder.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ServiceFinder.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ServiceFinder.java	26 Jun 2002 15:50:15 -0000	1.1
  +++ ServiceFinder.java	28 Jun 2002 21:28:12 -0000	1.2
  @@ -93,7 +93,7 @@
       
       /**
        * <p>Locate and instantiate a service.  The service implementation
  -     * class is located using the following ordered lookup procedure:</p>
  +     * 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:
  @@ -111,9 +111,28 @@
        * 
        * <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 finderClass  The root finder class, which may not
  +     *        be 'ServiceFinder' if a wrapper class is used.
  +     * 
        * @param spiContext The SPI Context identifies the SPI and the
        *        thread context class loader.
        *        <code>spiContext.getSPI().getName()</code> id's the (property)
  @@ -135,21 +154,22 @@
        *            cannot be instantiated,
        *            or is not an instance of <code>spi</code>.
        */
  -    public static Object find(SPIContext spiContext,
  +    public static Object find(Class finderClass,
  +                              SPIContext spiContext,
                                 Properties properties,
                                 String defaultImplName)
           throws ServiceException
       {
           // thread context can change on each call,
           // so establish context for this one call.
  -        ClassFinder classFinder = new ClassFinder(spiContext);
  +        ClassFinder classFinder = new ClassFinder(spiContext, finderClass);
   
           /**
            * Return previously registered service object (not class)
            * for this spi.  Try contextClassLoader first, and if that
            * fails then try the local class loader.
            */
  -        Object service = (classFinder.getThreadContextClassLoader() == null)
  +        Object service = (spiContext.getThreadContextClassLoader() == null)
                   ? null
                   : get(spiContext.getSPI().getName(), spiContext.getThreadContextClassLoader());
           
  @@ -204,21 +224,47 @@
       
       /**
        * Equivalent to
  +     * <code>find(ServiceFinder.class, spiContext, properties, defaultImplName)</code>.
  +     */
  +    public static Object find(SPIContext spiContext,
  +                              Properties properties,
  +                              String defaultImplName)
  +        throws ServiceException
  +    {
  +        return find(ServiceFinder.class, spiContext, properties, defaultImplName);
  +    }
  +    
  +    /**
  +     * Equivalent to
        * <code>find(new SPIContext(spi), properties, defaultImplName)</code>.
        */
  +    public static Object find(Class finderClass,
  +                              Class spi,
  +                              Properties properties,
  +                              String defaultImplName)
  +        throws ServiceException
  +    {
  +        return find(finderClass, new SPIContext(spi), properties, defaultImplName);
  +    }
  +
  +    /**
  +     * Equivalent to
  +     * <code>find(ServiceFinder.class, spi, properties, defaultImplName)</code>.
  +     */
       public static Object find(Class spi,
                                 Properties properties,
                                 String defaultImplName)
           throws ServiceException
       {
  -        return find(new SPIContext(spi), properties, defaultImplName);
  +        return find(ServiceFinder.class, spi, properties, defaultImplName);
       }
   
       /**
        * Load properties file, and call
        * <code>find(spiContext, properties, defaultImplName)</code>.
        */    
  -    public static Object find(SPIContext spiContext,
  +    public static Object find(Class finderClass,
  +                              SPIContext spiContext,
                                 String propertiesFileName,
                                 String defaultImplName)
           throws ServiceException
  @@ -243,10 +289,35 @@
               }
           }
           
  -        return find(spiContext, properties, defaultImplName);
  +        return find(finderClass, spiContext, properties, defaultImplName);
       }
   
       /**
  +     * Load properties file, and call
  +     * <code>find(ServiceFinder.class, spiContext, propertiesFileName, defaultImplName)</code>.
  +     */    
  +    public static Object find(SPIContext spiContext,
  +                              String propertiesFileName,
  +                              String defaultImplName)
  +        throws ServiceException
  +    {
  +        return find(ServiceFinder.class, spiContext, propertiesFileName, defaultImplName);
  +    }
  +    
  +    /**
  +     * Equivalent to
  +     * <code>find(finderClass, new SPIContext(spi), propertiesFileName, defaultImplName)</code>.
  +     */    
  +    public static Object find(Class finderClass,
  +                              Class spi,
  +                              String propertiesFileName,
  +                              String defaultImplName)
  +        throws ServiceException
  +    {
  +        return find(finderClass, new SPIContext(spi), propertiesFileName, defaultImplName);
  +    }
  +    
  +    /**
        * Equivalent to
        * <code>find(new SPIContext(spi), propertiesFileName, defaultImplName)</code>.
        */    
  @@ -260,6 +331,16 @@
   
       /**
        * Find implementation of SPI.
  +     * Equivalent to find(finderClass, spi, (Properties)null, defaultImplName);
  +     */
  +    public static Object find(Class finderClass, Class spi, String defaultImplName)
  +        throws ServiceException
  +    {
  +        return find(finderClass, spi, (Properties)null, defaultImplName);
  +    }
  +
  +    /**
  +     * Find implementation of SPI.
        * Equivalent to find(spi, (Properties)null, defaultImplName);
        */
       public static Object find(Class spi, String defaultImplName)
  @@ -270,12 +351,32 @@
   
       /**
        * Find implementation of SPI.
  +     * Equivalent to find(finderClass, spi, properties, null);
  +     */
  +    public static Object find(Class finderClass, Class spi, Properties properties)
  +        throws ServiceException
  +    {
  +        return find(finderClass, spi, properties, null);
  +    }
  +
  +    /**
  +     * Find implementation of SPI.
        * Equivalent to find(spi, properties, null);
        */
       public static Object find(Class spi, Properties properties)
           throws ServiceException
       {
           return find(spi, properties, null);
  +    }
  +
  +    /**
  +     * Find implementation of SPI.
  +     * Equivalent to find(finderClass, spi, (Properties)null, null);
  +     */
  +    public static Object find(Class finderClass, Class spi)
  +        throws ServiceException
  +    {
  +        return find(finderClass, spi, (Properties)null, null);
       }
   
       /**
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ClassLoaderUtils.java
  
  Index: ClassLoaderUtils.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.service.discovery;
  
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.util.Properties;
  import java.lang.reflect.Array;
  
  
  /**
   * Mechanisms to locate and load a class.
   * The load methods locate a class only.
   * The find methods locate a class and verify that the
   * class implements an given interface or extends a given class.
   * 
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   */
  public class ClassLoaderUtils {
      private static final boolean debug = false;
      
      /**
       * Load the class serviceImplName, no safety checking
       * 
       * @param serviceImplName The name of the class to load.
       */
      private static Class rawLoad(String serviceImplName, ClassLoader loader)
          throws ServiceException
      {
          Class clazz = null;
  
          try {
              // first the thread class loader
              clazz = loader.loadClass(serviceImplName);
          } catch (ClassNotFoundException e) {
              clazz = null;
          }
          
          return clazz;
      }
      
      /**
       * Load the class serviceImplName.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class load(String serviceImplName, ClassLoader loader)
          throws ServiceException
      {
          if (debug)
              System.out.println("Loading '" + serviceImplName + "'");
  
          return (loader != null  &&
                  serviceImplName != null  &&
                  serviceImplName.length() > 0
                  )
                  ? rawLoad(serviceImplName, loader)
                  : null;
      }
      
      
      /**
       * Load the class serviceImplName.
       * Try each classloader in succession,
       * until first succeeds, or all fail.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class loadUniq(String serviceImplName, ClassLoader[] uniqLoaders, int length)
          throws ServiceException
      {
          if (debug)
              System.out.println("Loading '" + serviceImplName + "'");
  
          Class clazz = null;
          
          if (serviceImplName != null  &&  serviceImplName.length() > 0) {
              for (int i = 0; i < length && clazz == null; i++)
              {
                  clazz = (uniqLoaders[i] != null)
                          ? rawLoad(serviceImplName, uniqLoaders[i])
                          : null;
              }
          }
          
          return clazz;
      }
  
      /**
       * Load the class serviceImplName.
       * Try each classloader in succession,
       * until first succeeds, or all fail.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class loadUniq(String serviceImplName, ClassLoader[] uniqLoaders)
          throws ServiceException
      {
          return loadUniq(serviceImplName, uniqLoaders, uniqLoaders.length);
      }
      
      /**
       * Load the class serviceImplName.
       * Try each classloader in succession,
       * until first succeeds, or all fail.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class load(String serviceImplName, ClassLoader[] loaders)
          throws ServiceException
      {
          ClassLoader[] uniqLoaders = new ClassLoader[loaders.length];
          int length = uniq(loaders, uniqLoaders);
          
          return loadUniq(serviceImplName, uniqLoaders, length);
      }
  
      /**
       * Load the class serviceImplName.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class load(String serviceImplName,
                               ClassLoader loaderA,
                               ClassLoader loaderB)
          throws ServiceException
      {
          return load(serviceImplName,
                      new ClassLoader[] { loaderA, loaderB });
      }
  
      /**
       * Load the class serviceImplName.
       * First try to load the class with the SPI context's
       * thread context class loader, and failing that try
       * the class loader that loaded the SPI.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class load(String serviceImplName, SPIContext spiContext)
          throws ServiceException
      {
          return load(serviceImplName,
                      spiContext.getThreadContextClassLoader(),
                      spiContext.getSPI().getClassLoader());
      }
      
      /***
       * Remove duplicate Objects (as opposed to equivalent) from
       * array.  Also checks previous class loader parents..
       * 
       * Assumes that array is short, so (n^2)*m isn't a problem...
       * 
       * This is exposed to allow a unique array to be computed once,
       * and passed in for different tasks...
       */
      public static int uniq(ClassLoader[] array, ClassLoader[] uneek) {
          int len = 0;
          for (int lookForward = 0; lookForward < array.length; lookForward++) {
              ClassLoader fore = array[lookForward];
              
              if (fore != null) {
                  boolean seen = false;
                  
                  for (int lookBack = 0; !seen && lookBack < len; lookBack++) {
                      ClassLoader back = uneek[lookBack];
                      
                      /**
                       * Look to see if the current ClassLoader (fore)
                       * is already in the list.  Also review parent
                       * class loaders of those already in the list.
                       */
                      while (!seen  &&  back != null) {
                          if (back == fore) {
                              seen = true;
                          }
                          back = back.getParent();
                      }
                  }
                  
                  if (!seen) {
                      uneek[len++] = fore;
                  }
              }
          }
          return len;
      }
  
      public static final ClassLoader[] compactUniq(ClassLoader[] array) {        
          ClassLoader[] uniqLoaders = new ClassLoader[array.length];
          
          int length = ClassLoaderUtils.uniq(array, uniqLoaders);
          
          ClassLoader[] loaders = new ClassLoader[length];
          
          System.arraycopy(uniqLoaders, 0, loaders, 0, length);
          
          return loaders;
      }
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>