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/09/01 06:12:50 UTC

cvs commit: jakarta-commons/discovery/sandbox/test/META-INF/services org.apache.commons.discovery.test.TestInterface2

rsitze      2002/08/31 21:12:49

  Added:       discovery/sandbox/java/org/apache/commons/discovery/resource
                        ResourceDiscoverImpl.java ClassLoaders.java
                        DiscoverResources.java
               discovery/sandbox/java/org/apache/commons/discovery/listeners
                        FirstResourceListener.java
                        FirstResourceClassListener.java
                        GatherResourceNamesListener.java
                        FirstResourceNameListener.java
                        GatherResourcesListener.java
                        GatherResourceClassesListener.java
               discovery/sandbox/java/org/apache/commons/discovery
                        DiscoveryException.java ResourceClass.java
                        ResourceNameListener.java package.html
                        ResourceDiscover.java ResourceClassDiscover.java
                        ResourceListener.java Resource.java
                        ResourceClassListener.java
                        ResourceNameDiscover.java
               discovery/sandbox/java/org/apache/commons/discovery/resource/names
                        DiscoverNamesInDictionary.java
                        DiscoverServiceNames.java
                        ResourceNameDiscoverImpl.java
                        DiscoverNamesInFile.java
                        DiscoverNamesInManagedProperties.java
                        DiscoverNamesInSystemProperties.java
                        NameDiscoverers.java
               discovery/sandbox/java/org/apache/commons/discovery/jdk
                        JDK11Hooks.java JDKHooks.java JDK12Hooks.java
                        PsuedoSystemClassLoader.java
               discovery/sandbox/test/org/apache/commons/discovery/test
                        TestInterface1.java TestImpl1_1.java
                        TestImpl2_1.java TestInterface2.java TestAll.java
                        TestImpl1_2.java TestImpl2_2.java
                        TestInterface.properties
               discovery/sandbox/java/org/apache/commons/discovery/tools
                        DiscoverSingleton.java SPInterface.java
                        ResourceUtils.java ManagedProperties.java
                        DefaultClassHolder.java DiscoverClass.java
                        ClassUtils.java Service.java EnvironmentCache.java
                        PropertiesHolder.java
               discovery/sandbox/java/org/apache/commons/discovery/resource/classes
                        DiscoverClasses.java ResourceClassDiscoverImpl.java
               discovery/sandbox README
               discovery/sandbox/conf MANIFEST.MF
               discovery/sandbox/java/org/apache/commons/discovery/log
                        DiscoveryLogFactory.java SimpleLog.java
               discovery/sandbox/java/org/apache/commons/discovery/ant
                        ServiceDiscoveryTask.java
               discovery/sandbox/test/META-INF/services
                        org.apache.commons.discovery.test.TestInterface2
  Log:
  Similar structure to what is in 'src', but turned up-side-down.  This
  uses a 'listener' model, rather than iterators, to get data.  It has
  it's own problems... but gave me an opportunity to do some performance
  checking and convince me that it doesn't really matter...  This one is,
  maybe, 3-5% faster.  Not enough for even me to worry about.
  
  1.  This is NOT a full publish/subscribe model.  It was important to
  me that a 'listener' be able to communicate that it didn't need anymore:
  halt processing (this is the alternative to defered processing that I was
  using via iterators).  This type of logic doesn't come cheap if you allow
  multiple subscribers... so it's limited to just one (though that could be
  a hook if anyone WANTs to allow multiple subscribes).
  
  2.  The code is much cleaner and easier to write...
  
  4.  It's MUCH easier to build up 'chains', simply connect each Discoverer
  to the next (each is implemented as a 'listener').
  
  3.  Depending upon your point of view, it's not as convenient to 'get'
  the data (data is 'pushed' to you via a listener, rather than 'pulled'
  by you from an iterator).  There are utility 'listeners' in
  'o.a.c.d.listeners' for gathering all data, or just getting the first
  (this means the 'first' non-null result from the last in the chain,
  which is much nicer than monitoring the whole 'machine' as was done
  when using Enumerations).
  
  I think it's pretty cool... so I dumping it into a separate sandbox if
  anyone wants to look at it.
  
  We can figure out later which is the better direction.
  
  Revision  Changes    Path
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/ResourceDiscoverImpl.java
  
  Index: ResourceDiscoverImpl.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource;
  
  import org.apache.commons.discovery.*;
  import org.apache.commons.discovery.Resource;
  import org.apache.commons.discovery.ResourceDiscover;
  
  
  /**
   * Helper class for methods implementing the ResourceDiscover interface.
   * 
   * @author Richard A. Sitze
   */
  public abstract class ResourceDiscoverImpl implements ResourceDiscover
  {
      private ClassLoaders classLoaders;
      private ResourceListener listener = null;
  
      
      /**
       * Construct a new resource discoverer
       */
      public ResourceDiscoverImpl() {
          this(new ClassLoaders());
      }
      
      /**
       *  Construct a new resource discoverer
       */
      public ResourceDiscoverImpl(ClassLoaders classLoaders) {
          setClassLoaders(classLoaders);
      }
  
      /**
       * Specify set of class loaders to be used in searching.
       */
      public void setClassLoaders(ClassLoaders loaders) {
          classLoaders = loaders;
      }
  
      /**
       * Specify a new class loader to be used in searching.
       * The order of loaders determines the order of the result.
       * It is recommended to add the most specific loaders first.
       */
      public void addClassLoader(ClassLoader loader) {
          classLoaders.put(loader);
      }
      
      protected ClassLoaders getClassLoaders() {
          return classLoaders;
      }
      
      public void setListener(ResourceListener listener) {
          this.listener = listener;
      }
  
      protected boolean notifyListener(Resource resource) {
          return (listener == null) ? true : listener.found(resource);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/ClassLoaders.java
  
  Index: ClassLoaders.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource;
  
  import java.util.Vector;
  
  import org.apache.commons.discovery.jdk.JDKHooks;
  
  
  /**
   * There are many different contexts in which
   * loaders can be used.  This provides a holder
   * for a set of class loaders, so that they
   * don't have to be build back up everytime...
   *
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   */
  public class ClassLoaders
  {
      protected Vector classLoaders = new Vector();
      
      /** Construct a new class loader set
       */
      public ClassLoaders() {
      }
      
      public int size() {
          return classLoaders.size();
      }
      
      public ClassLoader get(int idx) {
          return (ClassLoader)classLoaders.elementAt(idx);
      }
  
      /**
       * Specify a new class loader to be used in searching.
       * The order of loaders determines the order of the result.
       * It is recommended to add the most specific loaders first.
       */
      public void put(ClassLoader classLoader) {
          if (classLoader != null) {
              classLoaders.addElement(classLoader);
          }
      }
      
  
      /**
       * Specify a new class loader to be used in searching.
       * The order of loaders determines the order of the result.
       * It is recommended to add the most specific loaders first.
       * 
       * @param prune if true, verify that the class loader is
       *              not an Ancestor (@see isAncestor) before
       *              adding it to our list.
       */
      public void put(ClassLoader classLoader, boolean prune) {
          if (classLoader != null  &&  !(prune && isAncestor(classLoader))) {
              classLoaders.addElement(classLoader);
          }
      }
      
      
      /**
       * Check to see if <code>classLoader</code> is an
       * ancestor of any contained class loader.
       * 
       * This can be used to eliminate redundant class loaders
       * IF all class loaders defer to parent class loaders
       * before resolving a class.
       * 
       * It may be that this is not always true.  Therefore,
       * this check is not done internally to eliminate
       * redundant class loaders, but left to the discretion
       * of the user.
       */
      public boolean isAncestor(final ClassLoader classLoader) {
          /* bootstrap classloader, at root of all trees! */
          if (classLoader == null)
              return true;
  
          for (int idx = 0; idx < size(); idx++) {
              for(ClassLoader walker = get(idx);
                  walker != null;
                  walker = walker.getParent())
              {
                  if (walker == classLoader) {
                      return true;
                  }
              }
          }
          return false;
      }
  
  
      /**
       * Utility method.  Returns a preloaded ClassLoaders instance
       * containing the following class loaders, in order:
       * 
       * <ul>
       *   <li>spi.getClassLoader</li>
       *   <li>seeker.getClassLoader</li>
       *   <li>System Class Loader</li>
       * </ul>
       * 
       * Note that the thread context class loader is NOT present.
       * This is a reasonable set of loaders to try if the resource to be found
       * should be restricted to a libraries containing the SPI and Factory.
       * 
       * @param spi WHAT is being looked for (an implementation of this class,
       *            a default property file related to this class).
       * @param factory WHO is performing the lookup.
       * @param prune Determines if ancestors are allowed to be loaded or not.
       */    
      public static ClassLoaders getLibLoaders(Class spi, Class factory, boolean prune) {
          ClassLoaders loaders = new ClassLoaders();
          
          loaders.put(spi.getClassLoader());
          loaders.put(factory.getClassLoader(), prune);
          loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), prune);
          
          return loaders;
      }
      
      /**
       * Utility method.  Returns a preloaded ClassLoaders instance
       * containing the following class loaders, in order:
       * 
       * <ul>
       *   <li>Thread Context Class Loader</li>
       *   <li>spi.getClassLoader</li>
       *   <li>seeker.getClassLoader</li>
       *   <li>System Class Loader</li>
       * </ul>
       * 
       * Note that the thread context class loader IS  present.
       * This is a reasonable set of loaders to try if the resource to be found
       * may be provided by an application.
       * 
       * @param spi WHAT is being looked for (an implementation of this class,
       *            a default property file related to this class).
       * @param factory WHO is performing the lookup (factory).
       * @param prune Determines if ancestors are allowed to be loaded or not.
       */    
      public static ClassLoaders getAppLoaders(Class spi, Class factory, boolean prune) {
          ClassLoaders loaders = new ClassLoaders();
  
          loaders.put(JDKHooks.getJDKHooks().getThreadContextClassLoader());
          loaders.put(spi.getClassLoader(), prune);
          loaders.put(factory.getClassLoader(), prune);
          loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), prune);
          
          return loaders;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/DiscoverResources.java
  
  Index: DiscoverResources.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource;
  
  import java.io.IOException;
  import java.net.URL;
  import java.util.Enumeration;
  
  import org.apache.commons.discovery.Resource;
  import org.apache.commons.discovery.ResourceDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  import org.apache.commons.discovery.jdk.JDKHooks;
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.logging.Log;
  
  
  /**
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @author James Strachan
   */
  public class DiscoverResources extends ResourceDiscoverImpl
      implements ResourceDiscover, ResourceNameListener
  {
      private static Log log = DiscoveryLogFactory.newLog(DiscoverResources.class);
      public static void setLog(Log _log) {
          log = _log;
      }
      
      /**
       * Construct a new resource discoverer
       */
      public DiscoverResources() {
          super();
      }
      
      /**
       *  Construct a new resource discoverer
       */
      public DiscoverResources(ClassLoaders classLoaders) {
          super(classLoaders);
      }
  
      /**
       * @return ResourceIterator
       */
      public boolean find(String resourceName) {
          if (log.isDebugEnabled())
              log.debug("find: resourceName='" + resourceName + "'");
  
          for (int idx = 0; idx < getClassLoaders().size(); idx++) {
              ClassLoader loader = getClassLoaders().get(idx);
              if (log.isDebugEnabled())
                  log.debug("find: search using ClassLoader '" + loader + "'");
  
              try {
                  Enumeration resources =
                      JDKHooks.getJDKHooks().getResources(loader, resourceName);
  
                  if (resources != null) {
                      while(resources.hasMoreElements()) {
                          if (!notifyListener(new Resource(resourceName,
                                                           (URL)resources.nextElement(),
                                                           loader))) {
                              return false;
                          }
                      }
                  }
              } catch( IOException ex ) {
                  log.warn("find: Ignoring Exception", ex);
              }
          }
          return true;
      }
      
      public boolean found(String resourceName) {
          return find(resourceName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/listeners/FirstResourceListener.java
  
  Index: FirstResourceListener.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.discovery.listeners;
  
  import org.apache.commons.discovery.Resource;
  import org.apache.commons.discovery.ResourceListener;
  
  
  public class FirstResourceListener implements ResourceListener {
      private Resource first = null;
  
      public Resource getFirst() {
          return first;
      }
  
      public boolean found(Resource resource) {
          first = resource;
          return false; // only get first.
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/listeners/FirstResourceClassListener.java
  
  Index: FirstResourceClassListener.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.discovery.listeners;
  
  import org.apache.commons.discovery.ResourceClass;
  import org.apache.commons.discovery.ResourceClassListener;
  
  
  public class FirstResourceClassListener implements ResourceClassListener {
      private ResourceClass first = null;
  
      public ResourceClass getFirst() {
          return first;
      }
  
      public boolean found(ResourceClass resource) {
          first = resource;
          return false; // only get first.
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/listeners/GatherResourceNamesListener.java
  
  Index: GatherResourceNamesListener.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.discovery.listeners;
  
  import java.util.Vector;
  
  import org.apache.commons.discovery.ResourceNameListener;
  
  
  public class GatherResourceNamesListener implements ResourceNameListener {
      private Vector results = new Vector();  // Resource
  
      public Vector getResourceNames() {
          return results;
      }
  
      public boolean found(String resource) {
          results.add(resource);
          return true; // only get first.
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/listeners/FirstResourceNameListener.java
  
  Index: FirstResourceNameListener.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.discovery.listeners;
  
  import org.apache.commons.discovery.ResourceNameListener;
  
  
  public class FirstResourceNameListener implements ResourceNameListener {
      private String first = null;
  
      public String getFirst() {
          return first;
      }
  
      public boolean found(String resource) {
          first = resource;
          return false; // only get first.
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/listeners/GatherResourcesListener.java
  
  Index: GatherResourcesListener.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.discovery.listeners;
  
  import java.util.Vector;
  
  import org.apache.commons.discovery.Resource;
  import org.apache.commons.discovery.ResourceListener;
  
  
  public class GatherResourcesListener implements ResourceListener {
      private Vector results = new Vector();  // Resource
  
      public Vector getResources() {
          return results;
      }
  
      public boolean found(Resource resource) {
          results.add(resource);
          return true; // only get first.
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/listeners/GatherResourceClassesListener.java
  
  Index: GatherResourceClassesListener.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.discovery.listeners;
  
  import java.util.Vector;
  
  import org.apache.commons.discovery.ResourceClass;
  import org.apache.commons.discovery.ResourceClassListener;
  
  
  public class GatherResourceClassesListener implements ResourceClassListener {
      private Vector results = new Vector();  // ResourceClass
  
      public Vector getResourceClasses() {
          return results;
      }
  
      public boolean found(ResourceClass resource) {
          results.add(resource);
          return true; // only get first.
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/DiscoveryException.java
  
  Index: DiscoveryException.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.discovery;
  
  
  /**
   * <p>An exception that is thrown only if a suitable service
   * instance cannot be created by <code>ServiceFactory</code></p>
   * 
   * <p>Copied from LogConfigurationException<p>
   *
   * @author Craig R. McClanahan
   * @version $Revision$ $Date$
   */
  public class DiscoveryException extends RuntimeException {
  
  
      /**
       * Construct a new exception with <code>null</code> as its detail message.
       */
      public DiscoveryException() {
          super();
      }
  
      /**
       * Construct a new exception with the specified detail message.
       *
       * @param message The detail message
       */
      public DiscoveryException(String message) {
          super(message);
      }
  
      /**
       * Construct a new exception with the specified cause and a derived
       * detail message.
       *
       * @param cause The underlying cause
       */
      public DiscoveryException(Throwable cause) {
          this((cause == null) ? null : cause.toString(), cause);
      }
  
      /**
       * Construct a new exception with the specified detail message and cause.
       *
       * @param message The detail message
       * @param cause The underlying cause
       */
      public DiscoveryException(String message, Throwable cause) {
          super(message);
          this.cause = cause; // Two-argument version requires JDK 1.4 or later
      }
  
      /**
       * The underlying cause of this exception.
       */
      protected Throwable cause = null;
  
      /**
       * Return the underlying cause of this exception (if any).
       */
      public Throwable getCause() {
          return this.cause;
      }
      
      public String toString() {
          String ls = System.getProperty("line.separator");
          String str = super.toString();
          if (cause != null) {
              str = str + ls +
                    "*****" + ls +
                    stackToString(cause);
          }
          return str;
      }
  
      private static String stackToString(Throwable e){
        java.io.StringWriter sw= new java.io.StringWriter(1024); 
        java.io.PrintWriter pw= new java.io.PrintWriter(sw); 
        e.printStackTrace(pw);
        pw.close();
        return sw.toString();
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ResourceClass.java
  
  Index: ResourceClass.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  import java.net.URL;
  
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.logging.Log;
  
  
  /**
   * 'Resource' located by discovery.
   * Naming of methods becomes a real pain ('getClass()')
   * so I've patterned this after ClassLoader...
   * 
   * I think it works well as it will give users a point-of-reference.
   * 
   * @author Richard A. Sitze
   */
  public class ResourceClass extends Resource
  {
      private static Log log = DiscoveryLogFactory.newLog(ResourceClass.class);
      public static void setLog(Log _log) {
          log = _log;
      }
      protected Class       resourceClass;
  
      public ResourceClass(Class resourceClass, URL resource) {
          super(resourceClass.getName(), resource, resourceClass.getClassLoader());
          this.resourceClass = resourceClass;
      }
  
      public ResourceClass(String resourceName, URL resource, ClassLoader loader) {
          super(resourceName, resource, loader);
          this.resourceClass = resourceClass;
      }
      
      /**
       * Get the value of resourceClass.
       * @return value of resourceClass.
       */
      public Class loadClass() {
          if (resourceClass == null  &&  getClassLoader() != null) {
              if (log.isDebugEnabled())
                  log.debug("loadClass: Loading class '" + getName() + "' with " + getClassLoader());
  
              try {
                  resourceClass = getClassLoader().loadClass(getName());
              } catch (ClassNotFoundException e) {
                  resourceClass = null;
              }
          }
          return resourceClass;
      }
      
      public String toString() {
          return "ResourceClass[name='" + getName() +  "', url='" + getResource() + "', loader='" + getClassLoader() + "']";
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ResourceNameListener.java
  
  Index: ResourceNameListener.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  
  /**
   * @author Richard A. Sitze
   */
  public interface ResourceNameListener
  {
      public boolean found(String resourceName);
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/package.html
  
  Index: package.html
  ===================================================================
  <p>
  Highlights:
  <ul>
  <li>JDK 1.3 Service discovery</li>
  <li>Discovery supports JDK 1.1.8 and up
  (@see org.apache.commons.discover.jdk.JDKHooks).
  </li>
  </ul>
  </p>
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ResourceDiscover.java
  
  Index: ResourceDiscover.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  import org.apache.commons.discovery.resource.ClassLoaders;
  
  
  /**
   * @author Richard A. Sitze
   */
  public interface ResourceDiscover
  {
      /**
       * Specify set of class loaders to be used in searching.
       */
      public void setClassLoaders(ClassLoaders loaders);
  
      /**
       * Specify a new class loader to be used in searching.
       * The order of loaders determines the order of the result.
       * It is recommended to add the most specific loaders first.
       */
      public void addClassLoader(ClassLoader loader);
  
  
      public void setListener(ResourceListener listener);
  
  
      /**
       * Find named resources that are loadable by a class loader.
       * Listener is notified of each resource found.
       * 
       * @return FALSE if listener terminates discovery prematurely by
       *         returning false, otherwise TRUE.
       */
      public boolean find(String resourceName);
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ResourceClassDiscover.java
  
  Index: ResourceClassDiscover.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  import org.apache.commons.discovery.resource.ClassLoaders;
  import org.apache.commons.discovery.resource.classes.*;
  
  
  /**
   * @author Richard A. Sitze
   */
  public interface ResourceClassDiscover
  {
      /**
       * Specify set of class loaders to be used in searching.
       */
      public void setClassLoaders(ClassLoaders loaders);
  
      /**
       * Specify a new class loader to be used in searching.
       * The order of loaders determines the order of the result.
       * It is recommended to add the most specific loaders first.
       */
      public void addClassLoader(ClassLoader loader);
  
      
      public void setListener(ResourceClassListener listener);
  
  
      /**
       * Find named class resources that are loadable by a class loader.
       * Listener is notified of each resource found.
       * 
       * @return FALSE if listener terminates discovery prematurely by
       *         returning false, otherwise TRUE.
       */
      public boolean find(String className);
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ResourceListener.java
  
  Index: ResourceListener.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  
  /**
   * @author Richard A. Sitze
   */
  public interface ResourceListener
  {
      public boolean found(Resource resource);
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/Resource.java
  
  Index: Resource.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.URL;
  
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.discovery.resource.DiscoverResources;
  import org.apache.commons.logging.Log;
  
  
  /**
   * 'Resource' located by discovery.
   * Naming of methods becomes a real pain ('getClass()')
   * so I've patterned this after ClassLoader...
   * 
   * I think it works well as it will give users a point-of-reference.
   * 
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @author Richard A. Sitze
   */
  public class Resource
  {
      private static Log log = DiscoveryLogFactory.newLog(DiscoverResources.class);
      public static void setLog(Log _log) {
          log = _log;
      }
      protected final String      name;
      protected final URL         resource;
      protected final ClassLoader loader;
  
      public Resource(String resourceName, URL resource, ClassLoader loader) {
          this.name = resourceName;
          this.resource = resource;
          this.loader = loader;
  
          if (log.isDebugEnabled())
              log.debug("new " + this);
      }
  
      /**
       * Get the value of resourceName.
       * @return value of resourceName.
       */
      public String getName() {
          return name;
      }
      
      /**
       * Get the value of URL.
       * @return value of URL.
       */
      public URL getResource() {
          return resource;
      }
      
      /**
       * Get the value of URL.
       * @return value of URL.
       */
      public InputStream getResourceAsStream() {
          try {
              return resource.openStream();
          } catch (IOException e) {
              return null;  // ignore
          }
      }
      
      /**
       * Get the value of loader.
       * @return value of loader.
       */
      public ClassLoader getClassLoader() {
          return loader ;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ResourceClassListener.java
  
  Index: ResourceClassListener.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  
  /**
   * @author Richard A. Sitze
   */
  public interface ResourceClassListener
  {
      public boolean found(ResourceClass resourceClass);
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ResourceNameDiscover.java
  
  Index: ResourceNameDiscover.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery;
  
  
  /**
   * Interface representing a mapping
   * from a set of source resource names
   * to a resultant set of resource names.
   * 
   * @author Richard A. Sitze
   * @author Costin Manolache
   */
  public interface ResourceNameDiscover
  {
      public void setListener(ResourceNameListener listener);
  
      /**
       * Find resource names.
       * Listener is notified of each resource name found.
       * 
       * @return FALSE if listener terminates discovery prematurely by
       *         returning false, otherwise TRUE.
       */
      public boolean find(String resourceName);
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/names/DiscoverNamesInDictionary.java
  
  Index: DiscoverNamesInDictionary.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.names;
  
  import java.util.Dictionary;
  import java.util.Hashtable;
  
  import org.apache.commons.discovery.ResourceNameDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.logging.Log;
  
  
  /**
   * Recover resources from a Dictionary.  This covers Properties as well,
   * since <code>Properties extends Hashtable extends Dictionary</code>.
   * 
   * The recovered value is expected to be either a <code>String</code>
   * or a <code>String[]</code>.
   * 
   * @author Richard A. Sitze
   */
  public class DiscoverNamesInDictionary extends ResourceNameDiscoverImpl
      implements ResourceNameDiscover, ResourceNameListener
  {
      private static Log log = DiscoveryLogFactory.newLog(DiscoverNamesInDictionary.class);
      public static void setLog(Log _log) {
          log = _log;
      }
  
      private Dictionary dictionary;
      
      /** Construct a new resource discoverer
       */
      public DiscoverNamesInDictionary() {
          this(new Hashtable());
      }
      
      /** Construct a new resource discoverer
       */
      public DiscoverNamesInDictionary(Dictionary dictionary) {
          setDictionary(dictionary);
      }
  
      protected Dictionary getDictionary() {
          return dictionary;
      }
  
      /**
       * Specify set of class loaders to be used in searching.
       */
      public void setDictionary(Dictionary table) {
          this.dictionary = dictionary;
      }
      
      public void addResource(String resourceName, String resource) {
          dictionary.put(resourceName, resource);
      }
      
      public void addResource(String resourceName, String[] resources) {
          dictionary.put(resourceName, resources);
      }
  
      /**
       * @return Enumeration of ResourceInfo
       */
      public boolean find(String resourceName) {
          if (log.isDebugEnabled())
              log.debug("find: resourceName='" + resourceName + "'");
  
          Object baseResource = dictionary.get(resourceName);
  
          if (baseResource instanceof String) {
              return notifyListener((String)baseResource);
          } else if (baseResource instanceof String[]) {
              String[] resources = (String[])baseResource;
              for (int i = 0; i < resources.length; i++) {
                  if (!notifyListener(resources[i])) {
                      return false;
                  }
              }
          }
          return true;
      }
      
      public boolean found(String resourceName) {
          return find(resourceName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/names/DiscoverServiceNames.java
  
  Index: DiscoverServiceNames.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.names;
  
  import org.apache.commons.discovery.ResourceNameDiscover;
  import org.apache.commons.discovery.resource.ClassLoaders;
  
  
  /**
   * Provide JDK 1.3 style service discovery...
   * 
   * The caller will first configure the discoverer by creating a
   * root Discoverer for the files.
   *
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @author James Strachan
   */
  public class DiscoverServiceNames extends DiscoverNamesInFile
      implements ResourceNameDiscover
  {
      protected static final String SERVICE_HOME = "META-INF/services/";
      
      /** Construct a new service discoverer
       */
      public DiscoverServiceNames() {
          super();
      }
      
      /**
       *  Construct a new resource discoverer
       */
      public DiscoverServiceNames(ClassLoaders loaders) {
          super(loaders);
      }
      
      /**
       * @return Enumeration of ServiceInfo
       */
      public boolean find(String serviceName) {
          return super.find(SERVICE_HOME + serviceName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/names/ResourceNameDiscoverImpl.java
  
  Index: ResourceNameDiscoverImpl.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.names;
  
  import org.apache.commons.discovery.ResourceNameDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  
  
  /**
   * Helper class for methods implementing the ResourceNameDiscover interface.
   * 
   * @author Richard A. Sitze
   */
  public abstract class ResourceNameDiscoverImpl
      implements ResourceNameDiscover
  {
      private ResourceNameListener listener = null;
      
      protected ResourceNameListener getListener() {
          return listener;
      }
      
      protected boolean notifyListener(String resourceName) {
          return (listener == null) ? true : listener.found(resourceName);
      }
  
      public void setListener(ResourceNameListener listener) {
          this.listener = listener;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/names/DiscoverNamesInFile.java
  
  Index: DiscoverNamesInFile.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.names;
  
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  
  import org.apache.commons.discovery.Resource;
  import org.apache.commons.discovery.ResourceDiscover;
  import org.apache.commons.discovery.ResourceListener;
  import org.apache.commons.discovery.ResourceNameDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.discovery.resource.ClassLoaders;
  import org.apache.commons.discovery.resource.DiscoverResources;
  import org.apache.commons.logging.Log;
  
  
  
  /**
   * Discover ALL files of a given name, and return resource names
   * contained within the set of files:
   * <ul>
   *   <li>one resource name per line,</li>
   *   <li>whitespace ignored,</li>
   *   <li>comments begin with '#'</li>
   * </ul>
   * 
   * Default discoverer is DiscoverClassLoaderResources,
   * but it can be set to any other.
   *
   * @author Richard A. Sitze
   * @author Costin Manolache
   * @author James Strachan
   */
  public class DiscoverNamesInFile extends ResourceNameDiscoverImpl
      implements ResourceNameDiscover, ResourceNameListener, ResourceListener
  {
      private static Log log = DiscoveryLogFactory.newLog(DiscoverNamesInFile.class);
      public static void setLog(Log _log) {
          log = _log;
      }
      
      private ResourceDiscover discoverResources;
      
      /**
       *  Construct a new resource discoverer
       */
      public DiscoverNamesInFile() {
          this.discoverResources = new DiscoverResources();
          this.discoverResources.setListener(this);
      }
      
      /**
       *  Construct a new resource discoverer
       */
      public DiscoverNamesInFile(ClassLoaders loaders) {
          this.discoverResources = new DiscoverResources(loaders);
          this.discoverResources.setListener(this);
      }
  
      /**
       * Specify set of class loaders to be used in searching.
       */
      public void setClassLoaders(ClassLoaders loaders) {
          discoverResources.setClassLoaders(loaders);
      }
  
      /**
       */
      public boolean find(String fileName) {
          if (log.isDebugEnabled())
              log.debug("find: fileName='" + fileName + "'");
              
          return discoverResources.find(fileName);
      }
      
      public boolean found(String resourceName) {
          return find(resourceName);
      }
      
      /**
       * Read everything, no defering here..
       * Ensure that files are closed before we leave.
       */
      public boolean found(Resource info) {
          InputStream is = info.getResourceAsStream();
          
          if( is != null ) {
              try {
                  try {
                      // This code is needed by EBCDIC and other
                      // strange systems.  It's a fix for bugs
                      // reported in xerces
                      BufferedReader rd;
                      try {
                          rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                      } catch (java.io.UnsupportedEncodingException e) {
                          rd = new BufferedReader(new InputStreamReader(is));
                      }
                      
                      try {
                          String resourceName;
                          while( (resourceName = rd.readLine()) != null) {
                              int idx = resourceName.indexOf('#');
                              if (idx >= 0) {
                                  resourceName = resourceName.substring(0, idx);
                              }
                              resourceName = resourceName.trim();
      
                              if (resourceName.length() != 0) {
                                  if (log.isDebugEnabled())
                                      log.debug("readResourceNames: found '" + resourceName + "'");
  
                                  if (!notifyListener(resourceName)) {
                                      return false;
                                  }
                              }
                          }
                      } finally {
                          rd.close();
                      }
                  } finally {
                      is.close();
                  }
              } catch (IOException e) {
                  // ignore
              }
          }
          
          return true;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/names/DiscoverNamesInManagedProperties.java
  
  Index: DiscoverNamesInManagedProperties.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.names;
  
  import org.apache.commons.discovery.ResourceNameDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.discovery.tools.ManagedProperties;
  import org.apache.commons.logging.Log;
  
  
  /**
   * Recover resource name from Managed Properties.
   * @see org.apache.commons.discovery.tools.ManagedProperties
   * 
   * @author Richard A. Sitze
   */
  public class DiscoverNamesInManagedProperties extends ResourceNameDiscoverImpl
      implements ResourceNameDiscover, ResourceNameListener
  {
      private static Log log = DiscoveryLogFactory.newLog(DiscoverNamesInManagedProperties.class);
      public static void setLog(Log _log) {
          log = _log;
      }
      
      /** Construct a new resource discoverer
       */
      public DiscoverNamesInManagedProperties() {
          super();
      }
  
      /**
       * @return Enumeration of ResourceInfo
       */
      public boolean find(String resourceName) {
          if (log.isDebugEnabled())
              log.debug("find: resourceName='" + resourceName + "'");
  
          return notifyListener(ManagedProperties.getProperty(resourceName));
      }
      
      public boolean found(String resourceName) {
          return find(resourceName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/names/DiscoverNamesInSystemProperties.java
  
  Index: DiscoverNamesInSystemProperties.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.names;
  
  import org.apache.commons.discovery.ResourceNameDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.logging.Log;
  
  
  /**
   * Recover resource name from System Properties.
   * 
   * @author Richard A. Sitze
   */
  public class DiscoverNamesInSystemProperties extends ResourceNameDiscoverImpl
      implements ResourceNameDiscover, ResourceNameListener
  {
      private static Log log = DiscoveryLogFactory.newLog(DiscoverNamesInSystemProperties.class);
      public static void setLog(Log _log) {
          log = _log;
      }
      
      /** Construct a new resource discoverer
       */
      public DiscoverNamesInSystemProperties() {
          super();
      }
  
      /**
       * @return Enumeration of ResourceInfo
       */
      public boolean find(String resourceName) {
          if (log.isDebugEnabled())
              log.debug("find: resourceName='" + resourceName + "'");
  
          return notifyListener(System.getProperty(resourceName));
      }
      
      public boolean found(String resourceName) {
          return find(resourceName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/names/NameDiscoverers.java
  
  Index: NameDiscoverers.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.names;
  
  import java.util.Vector;
  
  import org.apache.commons.discovery.ResourceNameDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.logging.Log;
  
  
  /**
   * Holder for multiple ResourceNameDiscover instances.
   * The result is the union of the results from each
   * (not a chained sequence, where results feed the next in line.
   *
   * @author Richard A. Sitze
   */
  public class NameDiscoverers extends ResourceNameDiscoverImpl
      implements ResourceNameDiscover, ResourceNameListener
  {
      private static Log log = DiscoveryLogFactory.newLog(NameDiscoverers.class);
      public static void setLog(Log _log) {
          log = _log;
      }
  
      private Vector discoverers = new Vector();  // ResourceNameDiscover
      
      /**
       *  Construct a new resource name discoverer
       */
      public NameDiscoverers() {
      }
      
      /**
       * Specify an additional class loader to be used in searching.
       * The order of loaders determines the order of the result.
       * It is recommended to add the most specific loaders first.
       */
      public void addResourceNameDiscover(ResourceNameDiscover discover) {
          if (discover != null) {
              discover.setListener(getListener());
              discoverers.addElement(discover);
          }
      }
      
      public void setListener(ResourceNameListener listener) {
          super.setListener(listener);
          for (int i = 0; i < discoverers.size(); i++) {
              ((ResourceNameDiscover)discoverers.get(i)).setListener(listener);
          }
      }
      
      protected ResourceNameDiscover getResourceNameDiscover(int idx) {
          return (ResourceNameDiscover)discoverers.get(idx);
      }
  
      protected int size() {
          return discoverers.size();
      }
  
      /**
       * Set of results of all discoverers.
       * 
       * @return ResourceIterator
       */
      public boolean find(String resourceName) {
          if (log.isDebugEnabled())
              log.debug("find: resourceName='" + resourceName + "'");
  
          for (int i = 0; i < discoverers.size(); i++) {
              if (!((ResourceNameDiscover)discoverers.get(i)).find(resourceName)) {
                  return false;
              }
          }
          return true;
      }
      
      public boolean found(String resourceName) {
          return find(resourceName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/jdk/JDK11Hooks.java
  
  Index: JDK11Hooks.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.discovery.jdk;
  
  import java.util.Enumeration;
  import java.io.IOException;
  
  
  /**
   * @author Richard A. Sitze
   */
  class JDK11Hooks extends JDKHooks {
      private static final ClassLoader systemClassLoader
          = new PsuedoSystemClassLoader();
  
  
      /**
       * The thread context class loader is available for JDK 1.2
       * or later, if certain security conditions are met.
       * 
       * @return The thread context class loader, if available.
       *         Otherwise return null.
       */
      public ClassLoader getThreadContextClassLoader() {
          return null;
      }
      
      /**
       * The system class loader is available for JDK 1.2
       * or later, if certain security conditions are met.
       * 
       * @return The system class loader, if available.
       *         Otherwise return null.
       */
      public ClassLoader getSystemClassLoader() {
          return systemClassLoader;
      }
  
      /**
       * Implement ClassLoader.getResources for JDK 1.1
       * 
       * On JDK1.1 there is no getResources() method. We emulate this by
       * using introspection and doing the lookup ourself, using the list
       * of URLs, via getURLs().
       */
      public Enumeration getResources(ClassLoader loader,
                                      String resourceName)
          throws IOException
      {
          /**
           * Not yet implemented...
           */
          return null;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/jdk/JDKHooks.java
  
  Index: JDKHooks.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.discovery.jdk;
  
  import java.util.Enumeration;
  import java.io.IOException;
  
  
  /**
   * @author Richard A. Sitze
   */
  public abstract class JDKHooks {
      private static final JDKHooks jdkHooks;
      
      static {
          jdkHooks = new JDK12Hooks();
      }
      
      protected JDKHooks() { }
      
      /**
       * Return singleton object representing JVM hooks/tools.
       * 
       * TODO: add logic to detect JDK level.
       */
      public static final JDKHooks getJDKHooks() {
          return jdkHooks;
      }
  
      /**
       * The thread context class loader is available for JDK 1.2
       * or later, if certain security conditions are met.
       * 
       * @return The thread context class loader, if available.
       *         Otherwise return null.
       */
      public abstract ClassLoader getThreadContextClassLoader();
  
      /**
       * The system class loader is available for JDK 1.2
       * or later, if certain security conditions are met.
       * 
       * @return The system class loader, if available.
       *         Otherwise return null.
       */
      public abstract ClassLoader getSystemClassLoader();
      
      public abstract Enumeration getResources(ClassLoader loader,
                                               String resourceName)
          throws IOException;
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/jdk/JDK12Hooks.java
  
  Index: JDK12Hooks.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.discovery.jdk;
  
  import java.util.Enumeration;
  import java.io.IOException;
  
  
  /**
   * @author Richard A. Sitze
   */
  class JDK12Hooks extends JDKHooks {
      /**
       * The thread context class loader is available for JDK 1.2
       * or later, if certain security conditions are met.
       * 
       * @return The thread context class loader, if available.
       *         Otherwise return null.
       */
      public ClassLoader getThreadContextClassLoader() {
          ClassLoader classLoader;
          
          try {
              classLoader = Thread.currentThread().getContextClassLoader();
          } catch (SecurityException e) {
              /**
               * SecurityException is thrown when
               * a) the context class loader isn't an ancestor of the
               *    calling class's class loader, or
               * b) if security permissions are restricted.
               * 
               * For (a), ignore and keep going.  We cannot help but also
               * ignore (b) 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 = null;  // ignore
          }
          
          // Return the selected class loader
          return classLoader;
      }
      
      /**
       * The system class loader is available for JDK 1.2
       * or later, if certain security conditions are met.
       * 
       * @return The system class loader, if available.
       *         Otherwise return null.
       */
      public ClassLoader getSystemClassLoader() {
          ClassLoader classLoader;
          
          try {
              classLoader = ClassLoader.getSystemClassLoader();
          } catch (SecurityException e) {
              /**
               * Ignore and keep going.
               */
              classLoader = null;  // ignore
          }
          
          // Return the selected class loader
          return classLoader;
      }
  
      /**
       * Implement ClassLoader.getResources for JDK 1.1
       */
      public Enumeration getResources(ClassLoader loader,
                                      String resourceName)
          throws IOException
      {
          return loader.getResources(resourceName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/jdk/PsuedoSystemClassLoader.java
  
  Index: PsuedoSystemClassLoader.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.discovery.jdk;
  
  import java.io.InputStream;
  import java.net.URL;
  
  
  /**
   * JDK 1.1.x compatible?
   * There is no direct way to get the system class loader
   * in 1.1.x, but this should be a good work around...
   */
  class PsuedoSystemClassLoader extends ClassLoader {
      protected Class loadClass(String className, boolean resolve)
          throws ClassNotFoundException
      {
          return findSystemClass(className);
      }
      
      public URL getResource(String resName) {
          return getSystemResource(resName);
      }
      
      public InputStream getResourceAsStream(String resName) {
          return getSystemResourceAsStream(resName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestInterface1.java
  
  Index: TestInterface1.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 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.discovery.test;
  
  
  /**
    * @author Richard A. Sitze
    * @version $Revision$
   */
  public interface TestInterface1 {
      public void method();
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestImpl1_1.java
  
  Index: TestImpl1_1.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 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.discovery.test;
  
  
  /**
    * @author Richard A. Sitze
    * @version $Revision$
   */
  public class TestImpl1_1 implements TestInterface1 {
      public TestImpl1_1() {
      }
  
      public void method() {
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestImpl2_1.java
  
  Index: TestImpl2_1.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 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.discovery.test;
  
  
  /**
    * @author Richard A. Sitze
    * @version $Revision$
   */
  public class TestImpl2_1 implements TestInterface2 {
      public TestImpl2_1() {
      }
  
      public void method() {
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestInterface2.java
  
  Index: TestInterface2.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 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.discovery.test;
  
  
  /**
    * @author Richard A. Sitze
    * @version $Revision$
   */
  public interface TestInterface2 {
      public void method();
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestAll.java
  
  Index: TestAll.java
  ===================================================================
  /*
   * $Header$
   * $Revision: 1.2 $
   * $Date: 2002/01/17 22:55:43 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 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.discovery.test;
  
  
  import java.util.Properties;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  import org.apache.commons.discovery.tools.DefaultClassHolder;
  import org.apache.commons.discovery.tools.DiscoverSingleton;
  import org.apache.commons.discovery.tools.ManagedProperties;
  import org.apache.commons.discovery.tools.PropertiesHolder;
  import org.apache.commons.discovery.tools.SPInterface;
  
  
  /**
    * @author Richard A. Sitze
    * @version $Revision: 1.2 $
   */
  public class TestAll extends TestCase {
      private static final int logLevel =
          org.apache.commons.discovery.log.SimpleLog.LOG_LEVEL_INFO;
  
      
      public TestAll(String testName) {
          super(testName);
      }
      
      public static Test suite() {
          return new TestSuite(TestAll.class);
      }
  
      public void testFindDefaultImpl_1() {
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface1 ti = null;
          
          try {
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class,
                                                          TestImpl1_1.class.getName());
  
              assertTrue(ti.getClass().getName() + "!=" + TestImpl1_1.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_1.class.getName()));
          } finally {
              DiscoverSingleton.release();
          }
      }
      
      public void testFindDefaultImpl_2() {
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface1 ti = null;
  
          try {
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class,
                                                          TestImpl1_2.class.getName());
  
              assertTrue(ti.getClass().getName() + "!=" + TestImpl1_2.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_2.class.getName()));
          } finally {
              DiscoverSingleton.release();
          }
      }
      
      public void testCache() {
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface1 ti = null;
          
          try {
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class,
                                                          TestImpl1_1.class.getName());
  
              assertTrue("1. " + ti.getClass().getName() + "!=" + TestImpl1_1.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_1.class.getName()));
              
              // no release, should get cached value..
              
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class,
                                                          TestImpl1_2.class.getName());
  
              // factory should be cached
              assertTrue("2. " + ti.getClass().getName() + "!=" + TestImpl1_1.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_1.class.getName()));
          } finally {
              DiscoverSingleton.release();
          }
      }
      
      public void testRelease() {
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface1 ti = null;
          
          try {
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class,
                                                          TestImpl1_1.class.getName());
  
              assertTrue("1. " + ti.getClass().getName() + "!=" + TestImpl1_1.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_1.class.getName()));
              
              DiscoverSingleton.release();
              
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class,
                                                          TestImpl1_2.class.getName());
  
              // factory should be cached
              assertTrue("2. " + ti.getClass().getName() + "!=" + TestImpl1_2.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_2.class.getName()));
          } finally {
              DiscoverSingleton.release();
          }
      }
      
      public void testFindPropertyImpl_1() {
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface1 ti = null;
  
          try {
              Properties props = new Properties();
              
              props.setProperty(TestInterface1.class.getName(),
                                TestImpl1_2.class.getName());
              
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class, props);
  
              assertTrue(ti.getClass().getName() + "!=" + TestImpl1_2.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_2.class.getName()));
          } finally {
              DiscoverSingleton.release();
          }
      }
      
      public void testMyFactoryManagedProperty() {
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface1 ti = null;
  
          try {
              ManagedProperties.setProperty(TestInterface1.class.getName(),
                                            TestImpl1_2.class.getName());
                                
              ti = (TestInterface1)DiscoverSingleton.find(TestInterface1.class);
  
              assertTrue(ti.getClass().getName() + "!=" + TestImpl1_2.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_2.class.getName()));
          } finally {
              DiscoverSingleton.release();
              
              /**
               * Cleanup, don't want to affect next test..
               */
              ManagedProperties.setProperty(TestInterface1.class.getName(), null);
          }
      }
      
  
      public void testFindPropFileDefault() {
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface1 ti = null;
          
          try {
              ti = (TestInterface1)DiscoverSingleton.find(null,
                                     new SPInterface(TestInterface1.class),
                                     new PropertiesHolder("TestInterface.properties"),
                                     new DefaultClassHolder(TestImpl1_2.class.getName()));
  
              assertTrue(ti.getClass().getName() + "!=" + TestImpl1_1.class.getName(),
                         ti.getClass().getName().equals(TestImpl1_1.class.getName()));
          } finally {
              DiscoverSingleton.release();
          }
      }
  
      public void testFindServiceFileDefault() {
  //        org.apache.commons.discovery.log.SimpleLog.setLevel(org.apache.commons.discovery.log.SimpleLog.LOG_LEVEL_DEBUG);
          org.apache.commons.discovery.log.SimpleLog.setLevel(logLevel);
  
          TestInterface2 ti = null;
          
          try {
              ti = (TestInterface2)DiscoverSingleton.find(null,
                                     new SPInterface(TestInterface2.class),
                                     null,
                                     new DefaultClassHolder(TestImpl2_2.class.getName()));
  
              assertTrue(ti.getClass().getName() + "!=" + TestImpl2_1.class.getName(),
                         ti.getClass().getName().equals(TestImpl2_1.class.getName()));
          } finally {
              DiscoverSingleton.release();
          }
      }
  
      /**
       * This allows the tests to run as a standalone application.
       */
      public static void main(String args[]) {
          String[] testCaseName = { TestAll.class.getName() };
          junit.textui.TestRunner.main(testCaseName);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestImpl1_2.java
  
  Index: TestImpl1_2.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 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.discovery.test;
  
  
  /**
    * @author Richard A. Sitze
    * @version $Revision$
   */
  public class TestImpl1_2 implements TestInterface1 {
      public TestImpl1_2() {
      }
  
      public void method() {
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestImpl2_2.java
  
  Index: TestImpl2_2.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 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.discovery.test;
  
  
  /**
    * @author Richard A. Sitze
    * @version $Revision$
   */
  public class TestImpl2_2 implements TestInterface2 {
      public TestImpl2_2() {
      }
  
      public void method() {
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/org/apache/commons/discovery/test/TestInterface.properties
  
  Index: TestInterface.properties
  ===================================================================
  org.apache.commons.discovery.test.TestInterface1=org.apache.commons.discovery.test.TestImpl1_1
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/DiscoverSingleton.java
  
  Index: DiscoverSingleton.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.discovery.tools;
  
  import java.util.HashMap;
  import java.util.Properties;
  
  import org.apache.commons.discovery.DiscoveryException;
  import org.apache.commons.discovery.jdk.JDKHooks;
  import org.apache.commons.discovery.resource.ClassLoaders;
  
  
  /**
   * <p>Discover singleton service providers.
   * This 
   * </p>
   * 
   * <p>DiscoverSingleton instances are cached by the Discovery service,
   * keyed by a combination of
   * <ul>
   *   <li>thread context class loader,</li>
   *   <li>groupContext, and</li>
   *   <li>SPI.</li>
   * </ul>
   * This DOES allow multiple instances of a given <i>singleton</i> class
   * to exist for different class loaders and different group contexts.
   * </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>DiscoverSingleton provides the <code>find</code> methods for locating and
   * instantiating a singleton instance of an implementation of a service (SPI).
   * Each form of <code>find</code> varies slightly, but they all perform the
   * same basic function.
   * 
   * The simplest <code>find</code> methods are intended for direct use by
   * components looking for a service.  If you are not sure which finder(s)
   * to use, you can narrow your search to one of these:
   * <ul>
   * <li>static Object find(Class spi);</li>
   * <li>static Object find(Class spi, Properties properties);</li>
   * <li>static Object find(Class spi, String defaultImpl);</li>
   * <li>static Object find(Class spi,
   *                        Properties properties, String defaultImpl);</li>
   * <li>static Object find(Class spi,
   *                        String propertiesFileName, String defaultImpl);</li>
   * <li>static Object find(String groupContext, Class spi,
   *                        Properties properties, String defaultImpl);</li>
   * <li>static Object find(String groupContext, Class spi,
   *                        String propertiesFileName, String defaultImpl);</li>
   * </ul>
   * 
   * The <code>DiscoverSingleton.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>
   *     <li>
   *     The value of the (scoped) system property whose name is the same as
   *     the SPI's fully qualified class name (as given by SPI.class.getName()).
   *     The <code>ScopedProperties</code> class provides a way to bind
   *     properties by classloader, in a secure hierarchy similar in concept
   *     to the way classloader find class and resource files.
   *     See <code>ScopedProperties</code> for more details.
   *     <p>If the ScopedProperties are not set by users, then behaviour
   *     is equivalent to <code>System.getProperty()</code>.
   *     </p>
   *     </li>
   *     <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>DiscoverSingleton's Caller's Class Loader</li>
   *     <li>SPI's Class Loader</li>
   *     <li>DiscoverSingleton's (this class or wrapper) 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 (<code>defaultImpl</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 (<code>defaultImpl</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>DiscoverSingleton's (this class or wrapper) 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, DiscoverSingleton, 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>
   *   Create an instance of the class.
   *   </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>DiscoverSingleton's Caller's Class Loader</li>
   *     <li>SPI's Class Loader</li>
   *     <li>DiscoverSingleton'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><strong>IMPLEMENTATION NOTE</strong> - This implementation is modelled
   * after the SAXParserFactory and DocumentBuilderFactory implementations
   * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
   * </p>
   * 
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @version $Revision$ $Date$
   */
  public class DiscoverSingleton {
      /********************** (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.
       */
      
      /**
       * Find implementation of SPI.
       * 
       * @param spiClass 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 spiClass)
          throws DiscoveryException
      {
          return find(null,
                      new SPInterface(spiClass),
                      DiscoverClass.nullProperties,
                      DiscoverClass.nullDefaultImpl);
      }
  
      /**
       * Find implementation of SPI.
       * 
       * @param spiClass 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 spiClass, Properties properties)
          throws DiscoveryException
      {
          return find(null,
                      new SPInterface(spiClass),
                      new PropertiesHolder(properties),
                      DiscoverClass.nullDefaultImpl);
      }
  
      /**
       * Find implementation of SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @param defaultImpl Default implementation.
       * 
       * @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 spiClass, String defaultImpl)
          throws DiscoveryException
      {
          return find(null,
                      new SPInterface(spiClass),
                      DiscoverClass.nullProperties,
                      new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Find implementation of SPI.
       * 
       * @param spiClass 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 defaultImpl Default implementation.
       * 
       * @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 spiClass,
                                Properties properties,
                                String defaultImpl)
          throws DiscoveryException
      {
          return find(null,
                      new SPInterface(spiClass),
                      new PropertiesHolder(properties),
                      new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Find implementation of SPI.
       * 
       * @param spiClass 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 defaultImpl Default implementation.
       * 
       * @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 spiClass,
                                String propertiesFileName,
                                String defaultImpl)
          throws DiscoveryException
      {
          return find(null,
                      new SPInterface(spiClass),
                      new PropertiesHolder(propertiesFileName),
                      new DefaultClassHolder(defaultImpl));
      }
      
      /*************** FINDERS FOR USE IN FACTORY/HELPER METHODS ***************
       */
  
  
      /**
       * Find implementation of SPI.
       * 
       * @param spiClass 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 defaultImpl Default implementation.
       * 
       * @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(ClassLoaders loaders,
                                SPInterface spi,
                                PropertiesHolder properties,
                                DefaultClassHolder defaultImpl)
          throws DiscoveryException
      {
          ClassLoader contextLoader = JDKHooks.getJDKHooks().getThreadContextClassLoader();
  
          Object obj = get(contextLoader, spi.getSPName());
  
          if (obj == null) {
              try {
                  obj = DiscoverClass.newInstance(loaders, spi, properties, defaultImpl);
                  
                  if (obj != null) {
                      put(contextLoader, spi.getSPName(), obj);
                  }
              } catch (DiscoveryException de) {
                  throw de;
              } catch (Exception e) {
                  throw new DiscoveryException("Unable to instantiate implementation class for " + spi.getSPName(), e);
              }
          }
          
          return obj;
      }
  
      /********************** CACHE-MANAGEMENT SUPPORT **********************/
      
      /**
       * Release all internal references to previously created service
       * instances associated with the current thread context class loader.
       * The <code>release()</code> method is called for service instances that
       * implement the <code>Service</code> interface.
       *
       * This is useful in environments like servlet containers,
       * which implement application reloading by throwing away a ClassLoader.
       * Dangling references to objects in that class loader would prevent
       * garbage collection.
       */
      public static synchronized void release() {
          root_cache.release();
      }
  
      /**
       * Release any internal references to a previously created service
       * instance associated with the current thread context class loader.
       * If the SPI instance implements <code>Service</code>, then call
       * <code>release()</code>.
       */
      public static synchronized void release(Class spiClass) {
          HashMap spis = (HashMap)root_cache.get(JDKHooks.getJDKHooks().getThreadContextClassLoader());
          
          if (spis != null) {
              spis.remove(spiClass.getName());
          }
      }
      
      
      /************************* SPI CACHE SUPPORT *************************
       * 
       * Cache services by a 'key' unique to the requesting class/environment:
       * 
       * When we 'release', it is expected that the caller of the 'release'
       * have the same thread context class loader... as that will be used
       * to identify all cached entries to be released.
       * 
       * We will manage synchronization directly, so all caches are implemented
       * as HashMap (unsynchronized).
       * 
       * - ClassLoader::groupContext::SPI::Instance Cache
       *         Cache : HashMap
       *         Key   : Thread Context Class Loader (<code>ClassLoader</code>).
       *         Value : groupContext::SPI Cache (<code>HashMap</code>).
       * 
       * - groupContext::SPI::Instance Cache
       *         Cache : HashMap
       *         Key   : groupContext (<code>String</code>).
       *         Value : SPI Cache (<code>HashMap</code>).
       * 
       * - SPI::Instance Cache
       *         Cache : HashMap
       *         Key   : SPI Class Name (<code>String</code>).
       *         Value : SPI Instance/Implementation (<code>Object</code>.
       */
  
      /**
       * Implements first two levels of the cache (loader & groupContext).
       * Allows null keys, important as default groupContext is null.
       */
      private static final EnvironmentCache root_cache = new EnvironmentCache();
  
      /**
       * Get service keyed by spi & classLoader.
       */
      private static synchronized Object get(ClassLoader classLoader,
                                             String spiName)
      {
          HashMap spis = (HashMap)root_cache.get(classLoader);
          
          return (spis != null)
                 ? spis.get(spiName)
                 : null;
      }
      
      /**
       * Put service keyed by spi & classLoader.
       */
      private static synchronized void put(ClassLoader classLoader,
                                           String spiName,
                                           Object service)
      {
          if (service != null)
          {
              HashMap spis = (HashMap)root_cache.get(classLoader);
              
              if (spis == null) {
                  spis = new HashMap(root_cache.smallHashSize);
                  root_cache.put(classLoader, spis);
              }
              
              spis.put(spiName, service);
          }
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/SPInterface.java
  
  Index: SPInterface.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.discovery.tools;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  
  import org.apache.commons.discovery.DiscoveryException;
  
  
  /**
   * Represents a Service Programming Interface (spi).
   * - SPI's name
   * - SPI's (provider) class
   * - SPI's (alternate) override property name
   * 
   * In addition, while there are many cases where this is NOT
   * usefull, for those in which it is:
   * 
   * - expected constructor argument types and parameters values.
   * 
   * @author Richard A. Sitze
   */
  public class SPInterface {
      /**
       * The service programming interface: intended to be
       * an interface or abstract class, but not limited
       * to those two.
       */        
      private final Class spi;
      
      /**
       * The property name to be used for finding the name of
       * the SPI implementation class.
       */
      private final String propertyName;
      
      
      private Class  paramClasses[] = null;
      private Object params[] = null;
  
  
      /**
       * Construct object representing Class <code>provider</code>.
       * 
       * @param provider The SPI class
       */
      public SPInterface(Class provider) {
          this(provider, provider.getName());
      }
      
      /**
       * Construct object representing Class <code>provider</code>.
       * 
       * @param provider The SPI class
       * 
       * @param propertyName when looking for the name of a class implementing
       *        the provider class, a discovery strategy may involve looking for
       *        (system or other) properties having either the name of the class
       *        (provider) or the <code>propertyName</code>.
       */
      public SPInterface(Class spi, String propertyName) {
          this.spi = spi;
          this.propertyName = propertyName;
      }
  
      /**
       * Construct object representing Class <code>provider</code>.
       * 
       * @param provider The SPI class
       * 
       * @param constructorParamClasses classes representing the
       *        constructor argument types.
       * 
       * @param constructorParams objects representing the
       *        constructor arguments.
       */
      public SPInterface(Class provider,
                         Class constructorParamClasses[],
                         Object constructorParams[])
      {
          this(provider,
               provider.getName(),
               constructorParamClasses,
               constructorParams);
      }
      
      /**
       * Construct object representing Class <code>provider</code>.
       * 
       * @param provider The SPI class
       * 
       * @param propertyName when looking for the name of a class implementing
       *        the provider class, a discovery strategy may involve looking for
       *        (system or other) properties having either the name of the class
       *        (provider) or the <code>propertyName</code>.
       * 
       * @param constructorParamClasses classes representing the
       *        constructor argument types.
       * 
       * @param constructorParams objects representing the
       *        constructor arguments.
       */
      public SPInterface(Class spi,
                         String propertyName,
                         Class constructorParamClasses[],
                         Object constructorParams[])
      {
          this.spi = spi;
          this.propertyName = propertyName;
          this.paramClasses = constructorParamClasses;
          this.params = constructorParams;
      }
  
      public String getSPName() {
          return spi.getName();
      }
  
      public Class getSPClass() {
          return spi;
      }
      
      public String getPropertyName() {
          return propertyName;
      }
  
      /**
       * Instantiate a new 
       */    
      public Object newInstance(Class impl)
          throws DiscoveryException,
                 InstantiationException,
                 IllegalAccessException,
                 NoSuchMethodException,
                 InvocationTargetException
      {
          if (impl == null) {
              throw new DiscoveryException("No implementation defined for " + getSPName());
          }
  
          verifyAncestory(impl);            
  
          if (paramClasses == null || params == null) {
              return impl.newInstance();
          } else {
              Constructor constructor = impl.getConstructor(paramClasses);
              return constructor.newInstance(params);
          }
      }
      
      /**
       * Throws exception if <code>impl</code> does not
       * implement or extend the SPI.
       */
      public void verifyAncestory(Class impl) {
          if (!getSPClass().isAssignableFrom(impl)) {
              throw new DiscoveryException("Class " + impl.getName() +
                                           " does not implement " + getSPName());
          }
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/ResourceUtils.java
  
  Index: ResourceUtils.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.discovery.tools;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.Properties;
  
  import org.apache.commons.discovery.DiscoveryException;
  import org.apache.commons.discovery.Resource;
  import org.apache.commons.discovery.listeners.FirstResourceListener;
  import org.apache.commons.discovery.resource.ClassLoaders;
  import org.apache.commons.discovery.resource.DiscoverResources;
  
  
  /**
   * 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 ResourceUtils {
      /**
       * Get package name.
       * Not all class loaders 'keep' package information,
       * in which case Class.getPackage() returns null.
       * This means that calling Class.getPackage().getName()
       * is unreliable at best.
       */
      public static String getPackageName(Class clazz) {
          Package clazzPackage = clazz.getPackage();
          String packageName;
          if (clazzPackage != null) {
              packageName = clazzPackage.getName();
          } else {
              String clazzName = clazz.getName();
              packageName = new String(clazzName.toCharArray(), 0, clazzName.lastIndexOf('.'));
          }
          return packageName;
      }
      
      
      /**
       * Load the resource <code>resourceName</code>.
       * Try each classloader in succession,
       * until first succeeds, or all fail.
       * If all fail and <code>resouceName</code> is not absolute
       * (doesn't start with '/' character), then retry with
       * <code>packageName/resourceName</code> after changing all
       * '.' to '/'.
       * 
       * @param resourceName The name of the resource to load.
       */
      public static Resource getResource(Class spi,
                                         String resourceName,
                                         ClassLoaders loaders)
          throws DiscoveryException
      {
          FirstResourceListener listener = new FirstResourceListener();
          
          DiscoverResources explorer = new DiscoverResources(loaders);
          explorer.setListener(listener);
          explorer.find(resourceName);
          
          if (spi != null  &&
              (listener.getFirst() == null)  &&
              resourceName.charAt(0) != '/')
          {
              /**
               * If we didn't find the resource, and if the resourceName
               * isn't an 'absolute' path name, then qualify with
               * package name of the spi.
               */
              explorer.find(getPackageName(spi).replace('.','/') + "/" + resourceName);
          }
          
          return listener.getFirst();
      }
      
      /**
       * Load named property file, optionally qualifed by spi's package name
       * as per Class.getResource.
       * 
       * A property file is loaded using the following sequence of class loaders:
       *   <ul>
       *     <li>Thread Context Class Loader</li>
       *     <li>DiscoverSingleton's Caller's Class Loader</li>
       *     <li>SPI's Class Loader</li>
       *     <li>DiscoverSingleton's (this class) Class Loader</li>
       *     <li>System Class Loader</li>
       *   </ul>
       * 
       * @param
       * @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.
       */    
      public static Properties loadProperties(Class spi,
                                              String propertiesFileName,
                                              ClassLoaders classLoaders)
          throws DiscoveryException
      {
          Properties properties = null;
          
          if (propertiesFileName != null) {
              try {
                  Resource resource = getResource(spi, propertiesFileName, classLoaders);
                  if (resource != null) {
                      InputStream stream = resource.getResourceAsStream();
          
                      if (stream != null) {
                          properties = new Properties();
                          try {
                              properties.load(stream);
                          } finally {
                              stream.close();
                          }
                      }
                  }
              } catch (IOException e) {
                  ;  // ignore
              } catch (SecurityException e) {
                  ;  // ignore
              }
          }
          
          return properties;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/ManagedProperties.java
  
  Index: ManagedProperties.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2001 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 acknowledgment:
   *       "This product includes software developed by the
   *    Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Axis" 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 name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * 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.discovery.tools;
  
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.Hashtable;
  import java.util.Map;
  import java.util.Properties;
  
  import org.apache.commons.discovery.jdk.JDKHooks;
  
  
  
  /**
   * <p>This class may disappear in the future, or be moved to another project..
   * </p>
   * 
   * <p>Extend the concept of System properties to a hierarchical scheme
   * based around class loaders.  System properties are global in nature,
   * so using them easily violates sound architectural and design principles
   * for maintaining separation between components and runtime environments.
   * Nevertheless, there is a need for properties broader in scope than
   * class or class instance scope.
   * </p>
   * 
   * <p>This class is one solution.
   * </p>
   * 
   * <p>Manage properties according to a secure
   * scheme similar to that used by classloaders:
   * <ul>
   *   <li><code>ClassLoader</code>s are organized in a tree hierarchy.</li>
   *   <li>each <code>ClassLoader</code> has a reference
   *       to a parent <code>ClassLoader</code>.</li>
   *   <li>the root of the tree is the bootstrap <code>ClassLoader</code>er.</li>
   *   <li>the youngest decendent is the thread context class loader.</li>
   *   <li>properties are bound to a <code>ClassLoader</code> instance
   *   <ul>
   *     <li><i>non-default</i> properties bound to a parent <code>ClassLoader</code>
   *         instance take precedence over all properties of the same name bound
   *         to any decendent.
   *         Just to confuse the issue, this is the default case.</li>
   *     <li><i>default</i> properties bound to a parent <code>ClassLoader</code>
   *         instance may be overriden by (default or non-default) properties of
   *         the same name bound to any decendent.
   *         </li>
   *   </ul>
   *   </li>
   *   <li>System properties take precedence over all other properties</li>
   * </ul>
   * </p>
   * 
   * <p>This is not a perfect solution, as it is possible that
   * different <code>ClassLoader</code>s load different instances of
   * <code>ScopedProperties</code>.  The 'higher' this class is loaded
   * within the <code>ClassLoader</code> hierarchy, the more usefull
   * it will be.
   * </p>
   * 
   * @author Richard A. Sitze
   */
  public class ManagedProperties {
      /**
       * Cache of Properties, keyed by (thread-context) class loaders.
       * Use <code>HashMap</code> because it allows 'null' keys, which
       * allows us to account for the (null) bootstrap classloader.
       */
      private static final HashMap propertiesCache = new HashMap();
      
                                                          
      /**
       * Get value for property bound to the current thread context class loader.
       * 
       * @param property property name.
       * @return property value if found, otherwise default.
       */
      public static String getProperty(String propertyName) {
          return getProperty(getThreadContextClassLoader(), propertyName);
      }
      
      /**
       * Get value for property bound to the current thread context class loader.
       * If not found, then return default.
       * 
       * @param property property name.
       * @param dephault default value.
       * @return property value if found, otherwise default.
       */
      public static String getProperty(String propertyName, String dephault) {
          return getProperty(getThreadContextClassLoader(), propertyName, dephault);
      }
      
      /**
       * Get value for property bound to the class loader.
       * 
       * @param classLoader
       * @param property property name.
       * @return property value if found, otherwise default.
       */
      public static String getProperty(ClassLoader classLoader, String propertyName) {
          String value = System.getProperty(propertyName);
          if (value == null) {
              Value val = getValueProperty(classLoader, propertyName);
              if (val != null) {
                  value = val.value;
              }
          }
          return value;
      }
      
      /**
       * Get value for property bound to the class loader.
       * If not found, then return default.
       * 
       * @param classLoader
       * @param property property name.
       * @param dephault default value.
       * @return property value if found, otherwise default.
       */
      public static String getProperty(ClassLoader classLoader, String propertyName, String dephault) {
          String value = getProperty(classLoader, propertyName);
          return (value == null) ? dephault : value;
      }
  
      /**
       * Set value for property bound to the current thread context class loader.
       * @param property property name
       * @param value property value (non-default)  If null, remove the property.
       */
      public static void setProperty(String propertyName, String value) {
          setProperty(propertyName, value, false);
      }
      
      /**
       * Set value for property bound to the current thread context class loader.
       * @param property property name
       * @param value property value.  If null, remove the property.
       * @param isDefault determines if property is default or not.
       *        A non-default property cannot be overriden.
       *        A default property can be overriden by a property
       *        (default or non-default) of the same name bound to
       *        a decendent class loader.
       */
      public static void setProperty(String propertyName, String value, boolean isDefault) {
          if (propertyName != null) {
              synchronized (propertiesCache) {
                  ClassLoader classLoader = getThreadContextClassLoader();
                  HashMap properties = (HashMap)propertiesCache.get(classLoader);
                  
                  if (value == null) {
                      properties.remove(propertyName);
                  } else {
                      if (properties == null) {
                          properties = new HashMap();
                          propertiesCache.put(classLoader, properties);
                      }
                  
                      properties.put(propertyName, new Value(value, isDefault));
                  }
              }
          }
      }
      
      /**
       * Set property values for <code>Properties</code> bound to the
       * current thread context class loader.
       * 
       * @param newProperties name/value pairs to be bound
       */
      public static void setProperties(Map newProperties) {
          setProperties(newProperties, false);
      }
      
      
      /**
       * Set property values for <code>Properties</code> bound to the
       * current thread context class loader.
       * 
       * @param newProperties name/value pairs to be bound
       * @param isDefault determines if properties are default or not.
       *        A non-default property cannot be overriden.
       *        A default property can be overriden by a property
       *        (default or non-default) of the same name bound to
       *        a decendent class loader.
       */
      public static void setProperties(Map newProperties, boolean isDefault) {
          java.util.Iterator it = newProperties.entrySet().iterator();
  
          /**
           * Each entry must be mapped to a Property.
           * 'setProperty' does this for us.
           */
          while (it.hasNext()) {
              Map.Entry entry = (Map.Entry)it.next();
              setProperty( String.valueOf(entry.getKey()),
                           String.valueOf(entry.getValue()),
                           isDefault);
          }
      }
  
      
      /**
       * Return list of all property names.  This is an expensive
       * operation: ON EACH CALL it walks through all property lists 
       * associated with the current context class loader upto
       * and including the bootstrap class loader.
       */
      public static Enumeration propertyNames() {
          Hashtable allProps = new Hashtable();
  
          ClassLoader classLoader = getThreadContextClassLoader();
  
          /**
           * Order doesn't matter, we are only going to use
           * the set of all keys...
           */
          while (true) {
              HashMap properties = null;
  
              synchronized (propertiesCache) {
                  properties = (HashMap)propertiesCache.get(classLoader);
              }
  
              if (properties != null) {
                  allProps.putAll(properties);
              }
  
              if (classLoader == null) break;
              
              classLoader = getParent(classLoader);
          }
          
          return allProps.keys();
      }
      
      /**
       * This is an expensive operation.
       * ON EACH CALL it walks through all property lists 
       * associated with the current context class loader upto
       * and including the bootstrap class loader.
       * 
       * @return Returns a <code>java.util.Properties</code> instance
       * that is equivalent to the current state of the scoped
       * properties, in that getProperty() will return the same value.
       * However, this is a copy, so setProperty on the
       * returned value will not effect the scoped properties.
       */
      public static Properties getProperties() {
          Properties p = new Properties();
          
          Enumeration names = propertyNames();
          while (names.hasMoreElements()) {
              String name = (String)names.nextElement();
              p.put(name, getProperty(name));
          }
          
          return p;
      }
  
  
      /***************** INTERNAL IMPLEMENTATION *****************/
  
      private static class Value {
          final String value;
          final boolean isDefault;
          
          Value(String value, boolean isDefault) {
              this.value = value;
              this.isDefault = isDefault;
          }
      }
  
      /**
       * Get value for properties bound to the class loader.
       * Explore up the tree first, as higher-level class
       * loaders take precedence over lower-level class loaders.
       */
      private static final Value getValueProperty(ClassLoader classLoader, String propertyName) {
          Value value = null;
  
          if (propertyName != null) {
              /**
               * If classLoader isn't bootstrap loader (==null),
               * then get up-tree value.
               */
              if (classLoader != null) {
                  value = getValueProperty(getParent(classLoader), propertyName);
              }
              
              if (value == null  ||  value.isDefault) {
                  synchronized (propertiesCache) {
                      HashMap properties = (HashMap)propertiesCache.get(classLoader);
                          
                      if (properties != null) {
                          Value altValue = (Value)properties.get(propertyName);
                          
                          // set value only if override exists..
                          // otherwise pass default (or null) on..
                          if (altValue != null)
                              value = altValue;
                      }
                  }
              }
          }
          
          return value;
      }
      
      private static final ClassLoader getThreadContextClassLoader() {
          return JDKHooks.getJDKHooks().getThreadContextClassLoader();
      }
  
      private static final ClassLoader getParent(final ClassLoader classLoader) {
          return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction() {
                      public Object run() {
                          return classLoader.getParent();
                      }
                  });
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/DefaultClassHolder.java
  
  Index: DefaultClassHolder.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.discovery.tools;
  
  import org.apache.commons.discovery.ResourceClass;
  import org.apache.commons.discovery.ResourceClassListener;
  import org.apache.commons.discovery.resource.ClassLoaders;
  import org.apache.commons.discovery.resource.classes.DiscoverClasses;
  
  
  /**
   * Holder for a default class.
   * 
   * Class may be specified by name (String) or class (Class).
   * Using the holder complicates the users job, but minimized # of API's.
   * 
   * @author Richard A. Sitze
   */
  public class DefaultClassHolder {
      private Class        defaultClass;
      private final String defaultName;
      
      public DefaultClassHolder(Class defaultClass) {
          this.defaultClass = defaultClass;
          this.defaultName = defaultClass.getName();
      }
      
      public DefaultClassHolder(String defaultName) {
          this.defaultClass = null;
          this.defaultName = defaultName;
      }
  
      /**
       * @param spi non-null SPI
       * @param loaders Used only if class needs to be loaded.
       * 
       * @return Default Class.  Load the class if necessary,
       *         and verify that it implements the SPI.
       *         (this forces the check, no way out..).
       */
      public Class getDefaultClass(SPInterface spi, ClassLoaders loaders) {
          if (defaultClass == null) {
              ResourceClassListener listener =
                  new ResourceClassListener() {
                      public boolean found(ResourceClass resource) {
                          defaultClass = resource.loadClass();
                          return false; // only get first.
                      }
                  };
              DiscoverClasses classDiscovery = new DiscoverClasses(loaders);
              classDiscovery.setListener(listener);
              classDiscovery.find(getDefaultName());
          }
          
          if (defaultClass != null) {
              spi.verifyAncestory(defaultClass);
          }
  
          return defaultClass;
      }
  
      public String getDefaultName() {
          return defaultName;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/DiscoverClass.java
  
  Index: DiscoverClass.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.discovery.tools;
  
  import java.lang.reflect.InvocationTargetException;
  import java.util.Properties;
  import java.util.Vector;
  
  import org.apache.commons.discovery.DiscoveryException;
  import org.apache.commons.discovery.ResourceClass;
  import org.apache.commons.discovery.listeners.FirstResourceClassListener;
  import org.apache.commons.discovery.resource.ClassLoaders;
  import org.apache.commons.discovery.resource.classes.DiscoverClasses;
  import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
  
  
  /**
   * <p>Discover class that implements a given service interface,
   * with discovery and configuration features similar to that employed
   * 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>DiscoverClass provides the <code>find</code> methods for locating a
   * class that implements a service interface (SPI).  Each form of
   * <code>find</code> varies slightly, but they all perform the same basic
   * function.
   * 
   * The <code>DiscoverClass.find</code> methods proceed as follows:
   * </p>
   * <ul>
   *   <p><li>
   *   Get the name of an implementation class.  The name is the first
   *   non-null value obtained from the following resources:
   *   <ul>
   *     <li>
   *     The value of the (scoped) system property whose name is the same as
   *     the SPI's fully qualified class name (as given by SPI.class.getName()).
   *     The <code>ScopedProperties</code> class provides a way to bind
   *     properties by classloader, in a secure hierarchy similar in concept
   *     to the way classloader find class and resource files.
   *     See <code>ScopedProperties</code> for more details.
   *     <p>If the ScopedProperties are not set by users, then behaviour
   *     is equivalent to <code>System.getProperty()</code>.
   *     </p>
   *     </li>
   *     <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>DiscoverSingleton's Caller's Class Loader</li>
   *     <li>SPI's Class Loader</li>
   *     <li>DiscoverSingleton's (this class or wrapper) 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>defaultImpl</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 (<code>defaultImpl</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>DiscoverSingleton's (this class or wrapper) 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, DiscoverSingleton, 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>
   * </ul>
   * </p>
   *
   * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is modelled
   * after the SAXParserFactory and DocumentBuilderFactory implementations
   * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
   * </p>
   * 
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @version $Revision$ $Date$
   */
  public class DiscoverClass {
      /**
       * Readable placeholder for a null value.
       */
      public static final DefaultClassHolder nullDefaultImpl = null;
  
      /**
       * Readable placeholder for a null value.
       */
      public static final PropertiesHolder nullProperties = null;
      
      
      private ClassLoaders classLoaders = null;
  
  
      /**
       * Create a class instance with dynamic environment
       * (thread context class loader is determined on each call).
       * 
       * Dynamically construct class loaders on each call.
       */    
      public DiscoverClass() {
          this(null);
      }
  
      /**
       * Create a class instance with dynamic environment
       * (thread context class loader is determined on each call).
       * 
       * Cache static list of class loaders for each call.
       */    
      public DiscoverClass(ClassLoaders classLoaders) {
          this.classLoaders = classLoaders;
      }
      
      
      public ClassLoaders getClassLoaders(Class spiClass) {
          return classLoaders;
      }
  
  
      /**
       * Find class implementing SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @return 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 (or extend) the SPI.
       */
      public Class find(Class spiClass)
          throws DiscoveryException
      {
          return find(getClassLoaders(spiClass),
                      new SPInterface(spiClass),
                      nullProperties,
                      nullDefaultImpl);
      }
  
      /**
       * Find class implementing SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @param properties Used to determine name of SPI implementation.
       * 
       * @return 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 (or extend) the SPI.
       */
      public Class find(Class spiClass, Properties properties)
          throws DiscoveryException
      {
          return find(getClassLoaders(spiClass),
                      new SPInterface(spiClass),
                      new PropertiesHolder(properties),
                      nullDefaultImpl);
      }
  
      /**
       * Find class implementing SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @param defaultImpl Default implementation name.
       * 
       * @return 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 (or extend) the SPI.
       */
      public Class find(Class spiClass, String defaultImpl)
          throws DiscoveryException
      {
          return find(getClassLoaders(spiClass),
                      new SPInterface(spiClass),
                      nullProperties,
                      new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Find class implementing SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @param properties Used to determine name of SPI implementation,.
       * 
       * @param defaultImpl Default implementation class.
       * 
       * @return 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 (or extend) the SPI.
       */
      public Class find(Class spiClass, Properties properties, String defaultImpl)
          throws DiscoveryException
      {
          return find(getClassLoaders(spiClass),
                      new SPInterface(spiClass),
                      new PropertiesHolder(properties),
                      new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Find class implementing SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @param properties Used to determine name of SPI implementation,.
       * 
       * @param defaultImpl Default implementation class.
       * 
       * @return 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 (or extend) the SPI.
       */
      public Class find(Class spiClass, String propertiesFileName, String defaultImpl)
          throws DiscoveryException
      {
          return find(getClassLoaders(spiClass),
                      new SPInterface(spiClass),
                      new PropertiesHolder(propertiesFileName),
                      new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Find class implementing SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @param properties Used to determine name of SPI implementation,.
       * 
       * @param defaultImpl Default implementation class.
       * 
       * @return 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 (or extend) the SPI.
       */
      public static Class find(ClassLoaders loaders,
                               SPInterface spi,
                               PropertiesHolder properties,
                               DefaultClassHolder defaultImpl)
          throws DiscoveryException
      {
          if (loaders == null) {
              loaders = ClassLoaders.getLibLoaders(spi.getSPClass(),
                                                   DiscoverClass.class,
                                                   true);
          }
  
          FirstResourceClassListener listener =
              new FirstResourceClassListener();
          
          DiscoverClasses classDiscovery = new DiscoverClasses(loaders);
          classDiscovery.setListener(listener);
  
          String[] classNames =
              discoverClassNames(spi,
                                 (properties == null)
                                 ? null
                                 : properties.getProperties(spi, loaders));
          
          if (classNames.length > 0) {
              classDiscovery.find(classNames[0]);
  
              // If it's set as a property.. it had better be there!
              ResourceClass resource = listener.getFirst();
              return (resource == null) ? null : resource.loadClass();
          } else {
              DiscoverServiceNames discoverServices = new DiscoverServiceNames(loaders);
      
              /**
               * Feed service (name) discovery to classDiscovery
               */
              discoverServices.setListener(classDiscovery);
  
              discoverServices.find(spi.getSPName());
              ResourceClass resource = listener.getFirst();
  
              Class clazz = (resource == null) ? null : resource.loadClass();
  
              if (clazz != null) {
                  return clazz;
              }
              
              if (defaultImpl != null) {
                  return defaultImpl.getDefaultClass(spi, loaders);
              }
          }
          
          throw new DiscoveryException("No implementation defined for " + spi.getSPName());
      }
      
      /**
       * Create new instance of class implementing SPI.
       * 
       * @param spiClass 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 Object newInstance(Class spiClass)
          throws DiscoveryException,
                 InstantiationException,
                 IllegalAccessException,
                 NoSuchMethodException,
                 InvocationTargetException
      {
          return newInstance(getClassLoaders(spiClass),
                             new SPInterface(spiClass),
                             nullProperties,
                             nullDefaultImpl);
      }
  
      /**
       * Create new instance of class implementing SPI.
       * 
       * @param spiClass 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 Object newInstance(Class spiClass, Properties properties)
          throws DiscoveryException,
                 InstantiationException,
                 IllegalAccessException,
                 NoSuchMethodException,
                 InvocationTargetException
      {
          return newInstance(getClassLoaders(spiClass),
                             new SPInterface(spiClass),
                             new PropertiesHolder(properties),
                             nullDefaultImpl);
      }
  
      /**
       * Create new instance of class implementing SPI.
       * 
       * @param spiClass Service Provider Interface Class.
       * 
       * @param defaultImpl Default implementation.
       * 
       * @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 Object newInstance(Class spiClass, String defaultImpl)
          throws DiscoveryException,
                 InstantiationException,
                 IllegalAccessException,
                 NoSuchMethodException,
                 InvocationTargetException
      {
          return newInstance(getClassLoaders(spiClass),
                             new SPInterface(spiClass),
                             nullProperties,
                             new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Create new instance of class implementing SPI.
       * 
       * @param spiClass 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 defaultImpl Default implementation.
       * 
       * @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 Object newInstance(Class spiClass, Properties properties, String defaultImpl)
          throws DiscoveryException,
                 InstantiationException,
                 IllegalAccessException,
                 NoSuchMethodException,
                 InvocationTargetException
      {
          return newInstance(getClassLoaders(spiClass),
                             new SPInterface(spiClass),
                             new PropertiesHolder(properties),
                             new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Create new instance of class implementing SPI.
       * 
       * @param spiClass 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 defaultImpl Default implementation.
       * 
       * @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 Object newInstance(Class spiClass, String propertiesFileName, String defaultImpl)
          throws DiscoveryException,
                 InstantiationException,
                 IllegalAccessException,
                 NoSuchMethodException,
                 InvocationTargetException
      {
          return newInstance(getClassLoaders(spiClass),
                             new SPInterface(spiClass),
                             new PropertiesHolder(propertiesFileName),
                             new DefaultClassHolder(defaultImpl));
      }
  
      /**
       * Create new instance of class implementing SPI.
       * 
       * @param spiClass 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 defaultImpl Default implementation.
       * 
       * @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 newInstance(ClassLoaders loaders,
                                       SPInterface spi,
                                       PropertiesHolder properties,
                                       DefaultClassHolder defaultImpl)
          throws DiscoveryException,
                 InstantiationException,
                 IllegalAccessException,
                 NoSuchMethodException,
                 InvocationTargetException
      {
          return spi.newInstance(find(loaders, spi, properties, defaultImpl));
      }
  
      /**
       * <p>Discover names of SPI implementation Classes from properties.
       * The names are the non-null values, in order, obtained from the following
       * resources:
       *   <ul>
       *     <li>ManagedProperty.getProperty(SPI.class.getName());</li>
       *     <li>properties.getProperty(SPI.class.getName());</li>
       *   </ul>
       * 
       * @param properties Properties that may define the implementation
       *                   class name(s).
       * 
       * @return String[] Name of classes implementing the SPI.
       * 
       * @exception DiscoveryException Thrown if the name of a class implementing
       *            the SPI cannot be found.
       */
      public static String[] discoverClassNames(SPInterface spi,
                                                Properties properties)
      {
          Vector names = new Vector();
          
          String spiName = spi.getSPName();
          String propertyName = spi.getPropertyName();
  
          boolean includeAltProperty = !spiName.equals(propertyName);
          
          // Try the (managed) system property spiName
          String className = getManagedProperty(spiName);
          if (className != null) names.addElement(className);
          
          if (includeAltProperty) {
              // Try the (managed) system property propertyName
              className = getManagedProperty(propertyName);
              if (className != null) names.addElement(className);
          }
  
          if (properties != null) {
              // Try the properties parameter spiName
              className = properties.getProperty(spiName);
              if (className != null) names.addElement(className);
  
              if (includeAltProperty) {
                  // Try the properties parameter propertyName
                  className = properties.getProperty(propertyName);
                  if (className != null) names.addElement(className);
              }
          }
  
          String[] results = new String[names.size()];
          names.copyInto(results);        
  
          return results;
      }
  
  
      /**
       * Load the class whose name is given by the value of a (Managed)
       * System Property.
       * 
       * @see ManagedProperties
       * 
       * @param attribute the name of the system property whose value is
       *        the name of the class to load.
       */
      public static String getManagedProperty(String propertyName) {
          String value;
          try {
              value = ManagedProperties.getProperty(propertyName);
          } catch (SecurityException e) {
              value = null;
          }
          return value;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/ClassUtils.java
  
  Index: ClassUtils.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.discovery.tools;
  
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.logging.Log;
  
  
  /**
   * @author Richard A. Sitze
   */
  public class ClassUtils {
      private static Log log = DiscoveryLogFactory.newLog(ClassUtils.class);
      public static void setLog(Log _log) {
          log = _log;
      }
  
      /**
       * Get package name.
       * Not all class loaders 'keep' package information,
       * in which case Class.getPackage() returns null.
       * This means that calling Class.getPackage().getName()
       * is unreliable at best.
       */
      public static String getPackageName(Class clazz) {
          Package clazzPackage = clazz.getPackage();
          String packageName;
          if (clazzPackage != null) {
              packageName = clazzPackage.getName();
          } else {
              String clazzName = clazz.getName();
              packageName = new String(clazzName.toCharArray(), 0, clazzName.lastIndexOf('.'));
          }
          return packageName;
      }
      
      /**
       * @return Method 'public static returnType methodName(paramTypes)',
       *         if found to be <strong>directly</strong> implemented by clazz.
       */
      public static Method findPublicStaticMethod(Class clazz,
                                                  Class returnType,
                                                  String methodName,
                                                  Class[] paramTypes) {
          boolean problem = false;
          Method method = null;
  
          // verify '<methodName>(<paramTypes>)' is directly in class.
          try {
              method = clazz.getDeclaredMethod(methodName, paramTypes);
          } catch(NoSuchMethodException e) {
              problem = true;
              log.debug("Class " + clazz.getName() + ": missing method '" + methodName + "(...)", e);
          }
          
          // verify 'public static <returnType>'
          if (!problem  &&
              !(Modifier.isPublic(method.getModifiers()) &&
                Modifier.isStatic(method.getModifiers()) &&
                method.getReturnType() == returnType)) {
              if (log.isDebugEnabled()) {
                  if (!Modifier.isPublic(method.getModifiers())) {
                      log.debug(methodName + "() is not public");
                  }
                  if (!Modifier.isStatic(method.getModifiers())) {
                      log.debug(methodName + "() is not static");
                  }
                  if (method.getReturnType() != returnType) {
                      log.debug("Method returns: " + method.getReturnType().getName() + "@@" + method.getReturnType().getClassLoader());
                      log.debug("Should return:  " + returnType.getName() + "@@" + returnType.getClassLoader());
                  }
              }
              problem = true;
              method = null;
          }
          
          return method;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/Service.java
  
  Index: Service.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.tools;
  
  import java.util.Enumeration;
  import java.util.Vector;
  
  import org.apache.commons.discovery.ResourceClass;
  import org.apache.commons.discovery.listeners.GatherResourceClassesListener;
  import org.apache.commons.discovery.resource.ClassLoaders;
  import org.apache.commons.discovery.resource.classes.DiscoverClasses;
  import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
  
  
  /**
   * [this was ServiceDiscovery12... the 1.1 versus 1.2 issue
   * has been abstracted to org.apache.commons.discover.jdk.JDKHooks]
   * 
   * <p>Implement the JDK1.3 'Service Provider' specification.
   * ( http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html )
   * </p>
   *
   * This class supports any VM, including JDK1.1, via
   * org.apache.commons.discover.jdk.JDKHooks.
   *
   * The caller will first configure the discoverer by adding ( in the desired
   * order ) all the places to look for the META-INF/services. Currently
   * we support loaders.
   *
   * The findResources() method will check every loader.
   *
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @author James Strachan
   */
  public class Service
  {
      /** Construct a new service discoverer
       */
      protected Service() {
      }
      
      /**
       * as described in
       * sun/jdk1.3.1/docs/guide/jar/jar.html#Service Provider,
       * Except this uses <code>Enumeration</code>
       * instead of <code>Interator</code>.
       * 
       * @return Enumeration of class instances (<code>Object</code>)
       */
      public static Enumeration providers(Class spiClass) {
          return providers(new SPInterface(spiClass), null);
      }
      
      /**
       * This version lets you specify constructor arguments..
       * 
       * @param spi SPI to look for and load.
       * @param classLoaders loaders to use in search.
       *        If <code>null</code> then use ClassLoaders.getAppLoaders().
       */
      public static Enumeration providers(final SPInterface spi,
                                          ClassLoaders loaders)
      {
          if (loaders == null) {
              loaders = ClassLoaders.getAppLoaders(spi.getSPClass(),
                                                   Service.class,
                                                   true);
          }
          
          
          GatherResourceClassesListener listener = new GatherResourceClassesListener();
  
          DiscoverClasses classDiscovery = new DiscoverClasses(loaders);
          classDiscovery.setListener(listener);
  
          DiscoverServiceNames discoverServices = new DiscoverServiceNames(loaders);
          discoverServices.setListener(classDiscovery);
          discoverServices.find(spi.getSPName());
  
          final Vector results = listener.getResourceClasses();
          
          return new Enumeration() {
              private Object obj = null;
              private int idx = 0;
              
              public boolean hasMoreElements() {
                  if (obj == null) {
                      obj = getNextElement();
                  }
                  return obj != null;
              }
              
              public Object nextElement() {
                  Object o = obj;
                  obj = null;
                  return o;
              }
              
              private Object getNextElement() {
                  while (idx < results.size()) {
                      try {
                          return spi.newInstance(((ResourceClass)results.get(idx++)).loadClass());
                      } catch (Exception e) {
                          // ignore, retry
                      }
                  }
                  return null;
              }
          };
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/EnvironmentCache.java
  
  Index: EnvironmentCache.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.discovery.tools;
  
  import java.util.HashMap;
  
  import org.apache.commons.discovery.jdk.JDKHooks;
  
  
  /**
   * Cache by a 'key' unique to the environment:
   * 
   * - ClassLoader::groupContext::Object Cache
   *         Cache : HashMap
   *         Key   : Thread Context Class Loader (<code>ClassLoader</code>)
   *         Value : groupContext::SPI Cache (<code>HashMap</code>)
   * 
   * //- groupContext::Object Cache
   * //         Cache : HashMap
   * //         Key   : groupContext (<code>String</code>)
   * //        Value : <code>Object</code>
   * 
   * When we 'release', it is expected that the caller of the 'release'
   * have the same thread context class loader... as that will be used
   * to identify cached entries to be released.
   * 
   * @author Richard A. Sitze
   */
  public class EnvironmentCache {
      /**
       * Allows null key, important as default groupContext is null.
       * 
       * We will manage synchronization directly, so all caches are implemented
       * as HashMap (unsynchronized).
       * 
       */
      private static final HashMap root_cache = new HashMap();
  
      /**
       * Initial hash size for SPI's, default just seem TO big today..
       */
      public static final int smallHashSize = 13;
      
      /**
       * Get object keyed by classLoader.
       */
      public static synchronized Object get(ClassLoader classLoader)
      {
          /**
           * 'null' (bootstrap/system class loader) thread context class loader
           * is ok...  Until we learn otherwise.
           */
          return root_cache.get(classLoader);
      }
      
      /**
       * Put service keyed by spi & classLoader.
       */
      public static synchronized void put(ClassLoader classLoader, Object object)
      {
          /**
           * 'null' (bootstrap/system class loader) thread context class loader
           * is ok...  Until we learn otherwise.
           */
          if (object != null) {
              root_cache.put(classLoader, object);
          }
      }
  
  
      /********************** CACHE-MANAGEMENT SUPPORT **********************/
      
      /**
       * Release all internal references to previously created service
       * instances associated with the current thread context class loader.
       * The <code>release()</code> method is called for service instances that
       * implement the <code>Service</code> interface.
       *
       * This is useful in environments like servlet containers,
       * which implement application reloading by throwing away a ClassLoader.
       * Dangling references to objects in that class loader would prevent
       * garbage collection.
       */
      public static synchronized void release() {
          /**
           * 'null' (bootstrap/system class loader) thread context class loader
           * is ok...  Until we learn otherwise.
           */
          root_cache.remove(JDKHooks.getJDKHooks().getThreadContextClassLoader());
      }
      
      
      /**
       * Release any internal references to a previously created service
       * instance associated with the current thread context class loader.
       * If the SPI instance implements <code>Service</code>, then call
       * <code>release()</code>.
       */
      public static synchronized void release(ClassLoader classLoader) {
          /**
           * 'null' (bootstrap/system class loader) thread context class loader
           * is ok...  Until we learn otherwise.
           */
          root_cache.remove(classLoader);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/tools/PropertiesHolder.java
  
  Index: PropertiesHolder.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.discovery.tools;
  
  import java.util.Properties;
  
  import org.apache.commons.discovery.resource.ClassLoaders;
  
  
  /**
   * Holder for a default class.
   * 
   * Class may be specified by name (String) or class (Class).
   * Using the holder complicates the users job, but minimized # of API's.
   * 
   * @author Richard A. Sitze
   */
  public class PropertiesHolder {
      private Properties   properties;
      private final String propertiesFileName;
      
      public PropertiesHolder(Properties properties) {
          this.properties = properties;
          this.propertiesFileName = null;
      }
      
      public PropertiesHolder(String propertiesFileName) {
          this.properties = null;
          this.propertiesFileName = propertiesFileName;
      }
  
      /**
       * @param spi Optional SPI (may be null).
       *            If provided, an attempt is made to load the
       *            property file as-per Class.getResource().
       * 
       * @param loaders Used only if properties need to be loaded.
       * 
       * @return Properties.  Load the properties if necessary.
       */
      public Properties getProperties(SPInterface spi, ClassLoaders loaders) {
          if (properties == null) {
              properties = ResourceUtils.loadProperties(spi.getSPClass(), getPropertiesFileName(), loaders);
          }
          return properties;
      }
  
      public String getPropertiesFileName() {
          return propertiesFileName;
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/classes/DiscoverClasses.java
  
  Index: DiscoverClasses.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.classes;
  
  import java.net.URL;
  import java.util.Vector;
  
  import org.apache.commons.discovery.ResourceClass;
  import org.apache.commons.discovery.ResourceClassDiscover;
  import org.apache.commons.discovery.ResourceNameListener;
  import org.apache.commons.discovery.log.DiscoveryLogFactory;
  import org.apache.commons.discovery.resource.ClassLoaders;
  import org.apache.commons.logging.Log;
  
  
  /**
   * The findResources() method will check every loader.
   *
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @author James Strachan
   */
  public class DiscoverClasses extends ResourceClassDiscoverImpl
      implements ResourceClassDiscover, ResourceNameListener
  {
      private static Log log = DiscoveryLogFactory.newLog(DiscoverClasses.class);
      public static void setLog(Log _log) {
          log = _log;
      }
  
      /** Construct a new resource discoverer
       */
      public DiscoverClasses() {
          super();
      }
      
      /** Construct a new resource discoverer
       */
      public DiscoverClasses(ClassLoaders classLoaders) {
          super(classLoaders);
      }
      
      public boolean find(String className) {
          final String resourceName = className.replace('.','/') + ".class";
          
          if (log.isDebugEnabled())
              log.debug("find: className='" + className + "'");
  
          Vector history = new Vector();
  
          for (int idx = 0; idx < getClassLoaders().size(); idx++) {
              ClassLoader loader = getClassLoaders().get(idx);
              URL url = loader.getResource(resourceName);
              if (url != null) {
                  if (!history.contains(url)) {
                      history.addElement(url);
                      if (!notifyListener(new ResourceClass(className,
                                                            url,
                                                            loader)))
                          return false;
                  } else {
                      if (log.isDebugEnabled())
                          log.debug("find: duplicate URL='" + url + "'");
                  }
              } else {
                  if (log.isDebugEnabled())
                      log.debug("find: '" + resourceName + "' not found with loader: " + loader);
              }
          }
          
          return true;
      }
      
      public boolean found(String className) {
          return find(className);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/resource/classes/ResourceClassDiscoverImpl.java
  
  Index: ResourceClassDiscoverImpl.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.resource.classes;
  
  import org.apache.commons.discovery.*;
  import org.apache.commons.discovery.ResourceClass;
  import org.apache.commons.discovery.ResourceClassDiscover;
  import org.apache.commons.discovery.resource.ClassLoaders;
  
  
  /**
   * @author Richard A. Sitze
   */
  public abstract class ResourceClassDiscoverImpl implements ResourceClassDiscover
  {
      private ClassLoaders classLoaders;
      private ResourceClassListener listener = null;
  
      
      /**
       * Construct a new resource discoverer
       */
      public ResourceClassDiscoverImpl() {
          this(new ClassLoaders());
      }
      
      /**
       *  Construct a new resource discoverer
       */
      public ResourceClassDiscoverImpl(ClassLoaders classLoaders) {
          setClassLoaders(classLoaders);
      }
  
      /**
       * Specify set of class loaders to be used in searching.
       */
      public void setClassLoaders(ClassLoaders loaders) {
          classLoaders = loaders;
      }
  
      /**
       * Specify a new class loader to be used in searching.
       * The order of loaders determines the order of the result.
       * It is recommended to add the most specific loaders first.
       */
      public void addClassLoader(ClassLoader loader) {
          classLoaders.put(loader);
      }
      
      protected ClassLoaders getClassLoaders() {
          return classLoaders;
      }
      
      public void setListener(ResourceClassListener listener) {
          this.listener = listener;
      }
  
      protected boolean notifyListener(ResourceClass resource) {
          return (listener == null) ? true : listener.found(resource);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/README
  
  Index: README
  ===================================================================
  Similar structure to what is in 'src', but turned up-side-down.  This
  uses a 'listener' model, rather than iterators, to get data.  It has
  it's own problems... but gave me an opportunity to do some performance
  checking and convince me that it doesn't really matter...  This one is,
  maybe, 3-5% faster.  Not enough for even me to worry about.
  
  1.  This is NOT a full publish/subscribe model.  It was important to
  me that a 'listener' be able to communicate that it didn't need anymore:
  halt processing (this is the alternative to defered processing that I was
  using via iterators).  This type of logic doesn't come cheap if you allow
  multiple subscribers... so it's limited to just one (though that could be
  a hook if anyone WANTs to allow multiple subscribes).
  
  2.  The code is much cleaner and easier to write...
  
  4.  It's MUCH easier to build up 'chains', simply connect each Discoverer
  to the next (each is implemented as a 'listener').
  
  3.  Depending upon your point of view, it's not as convenient to 'get'
  the data (data is 'pushed' to you via a listener, rather than 'pulled'
  by you from an iterator).  There are utility 'listeners' in
  'o.a.c.d.listeners' for gathering all data, or just getting the first
  (this means the 'first' non-null result from the last in the chain,
  which is much nicer than monitoring the whole 'machine' as was done
  when using Enumerations).
  
  I think it's pretty cool... so I dumping it into a separate sandbox if
  anyone wants to look at it.
  
  We can figure out later which is the better direction.
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/conf/MANIFEST.MF
  
  Index: MANIFEST.MF
  ===================================================================
  Extension-Name: @package@
  Specification-Vendor: Apache Software Foundation
  Specification-Version: 1.0
  Implementation-Vendor: Apache Software Foundation
  Implementation-Version: @version@
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/log/DiscoveryLogFactory.java
  
  Index: DiscoveryLogFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/impl/SimpleLog.java,v 1.4 2002/06/15 20:54:48 craigmcc Exp $
   * $Revision: 1.4 $
   * $Date: 2002/06/15 20:54:48 $
   *
   * ====================================================================
   *
   * 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.discovery.log;
  
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.util.Enumeration;
  import java.util.Hashtable;
  
  import org.apache.commons.discovery.DiscoveryException;
  import org.apache.commons.discovery.tools.ClassUtils;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  
  /**
   * <p>Simple implementation of Log that sends all enabled log messages,
   * for all defined loggers, to System.err.
   * </p>
   * 
   * <p>Hacked from commons-logging SimpleLog for use in discovery.
   * This is intended to be enough of a Log implementation to bootstrap
   * Discovery.
   * </p>
   * 
   * <p>One property: <code>org.apache.commons.discovery.log.level</code>.
   * valid values: all, trace, debug, info, warn, error, fatal, off.
   * </p>
   * 
   * @author Richard A. Sitze
   * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
   * @author Rod Waldhoff
   * @author Robert Burrell Donkin
   *
   * @version $Id: SimpleLog.java,v 1.4 2002/06/15 20:54:48 craigmcc Exp $
   */
  public class DiscoveryLogFactory {
      private static LogFactory logFactory = null;
      private static final Hashtable  classRegistry = new Hashtable();
      private static final Class[] setLogParamClasses = new Class[] { Log.class };
  
      /**
       * Above fields must be initialied before this one..
       */
      private static Log log = DiscoveryLogFactory._newLog(DiscoveryLogFactory.class);
  
      /**
       */    
      public static Log newLog(Class clazz) {
          /**
           * Required to implement 'public static void setLog(Log)'
           */
          try {
              Method setLog = ClassUtils.findPublicStaticMethod(clazz,
                                                                void.class,
                                                                "setLog",
                                                                setLogParamClasses);
              
              if (setLog == null) {
                  String msg = "Internal Error: " + clazz.getName() + " required to implement 'public static void setLog(Log)'";
                  log.fatal(msg);
                  throw new DiscoveryException(msg);
              }
          } catch (SecurityException se) {
              String msg = "Required Security Permissions not present";
              log.fatal(msg, se);
              throw new DiscoveryException(msg, se);
          }
  
          if (log.isDebugEnabled())
              log.debug("Class meets requirements: " + clazz.getName());
  
          return _newLog(clazz);
      }
  
      /**
       * This method MUST not invoke any logging..
       */
      public static Log _newLog(Class clazz) {
          classRegistry.put(clazz, clazz);
  
          return (logFactory == null)
                 ? new SimpleLog(clazz.getName())
                 : logFactory.getInstance(clazz.getName());
      }
      
      public static void setLog(Log _log) {
          log = _log;
      }
  
      /**
       * Set logFactory, works ONLY on first call.
       */
      public static void setFactory(LogFactory factory) {
          if (logFactory == null) {
              // for future generations.. if any
              logFactory = factory;
              
              // now, go back and reset loggers for all current classes..
              Enumeration elements = classRegistry.elements();
              while (elements.hasMoreElements()) {
                  Class clazz = (Class)elements.nextElement();
  
                  if (log.isDebugEnabled())
                      log.debug("Reset Log for: " + clazz.getName());
                  
                  Method setLog = null;
                  
                  // invoke 'setLog(Log)'.. we already know it's 'public static',
                  // have verified parameters, and return type..
                  try {
                      setLog = clazz.getMethod("setLog", setLogParamClasses);
                  } catch(Exception e) {
                      String msg = "Internal Error: pre-check for " + clazz.getName() + " failed?!";
                      log.fatal(msg, e);
                      throw new DiscoveryException(msg, e);
                  }
      
                  Object[] setLogParam = new Object[] { factory.getInstance(clazz.getName()) };
                  
                  try {
                      setLog.invoke(null, setLogParam);
                  } catch(Exception e) {
                      String msg = "Internal Error: setLog failed for " + clazz.getName();
                      log.fatal(msg, e);
                      throw new DiscoveryException(msg, e);
                  }
              }
          }
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/log/SimpleLog.java
  
  Index: SimpleLog.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/impl/SimpleLog.java,v 1.4 2002/06/15 20:54:48 craigmcc Exp $
   * $Revision: 1.4 $
   * $Date: 2002/06/15 20:54:48 $
   *
   * ====================================================================
   *
   * 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.discovery.log;
  
  import java.io.PrintStream;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  
  import org.apache.commons.logging.Log;
  
  
  /**
   * <p>Simple implementation of Log that sends all enabled log messages,
   * for all defined loggers, to System.err.
   * </p>
   * 
   * <p>Hacked from commons-logging SimpleLog for use in discovery.
   * This is intended to be enough of a Log implementation to bootstrap
   * Discovery.
   * </p>
   * 
   * <p>One property: <code>org.apache.commons.discovery.log.level</code>.
   * valid values: all, trace, debug, info, warn, error, fatal, off.
   * </p>
   * 
   * @author Richard A. Sitze
   * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
   * @author Rod Waldhoff
   * @author Robert Burrell Donkin
   *
   * @version $Id: SimpleLog.java,v 1.4 2002/06/15 20:54:48 craigmcc Exp $
   */
  public class SimpleLog implements Log {
        // ---------------------------------------------------- Log Level Constants
  
      /** "Trace" level logging. */
      public static final int LOG_LEVEL_TRACE  = 1;
      /** "Debug" level logging. */
      public static final int LOG_LEVEL_DEBUG  = 2;
      /** "Info" level logging. */
      public static final int LOG_LEVEL_INFO   = 3;
      /** "Warn" level logging. */
      public static final int LOG_LEVEL_WARN   = 4;
      /** "Error" level logging. */
      public static final int LOG_LEVEL_ERROR  = 5;
      /** "Fatal" level logging. */
      public static final int LOG_LEVEL_FATAL  = 6;
  
      /** Enable all logging levels */
      public static final int LOG_LEVEL_ALL    = (LOG_LEVEL_TRACE - 1);
  
      /** Enable no logging levels */
      public static final int LOG_LEVEL_OFF    = (LOG_LEVEL_FATAL + 1);
  
      // ------------------------------------------------------- Class Attributes
  
      static protected final String PROP_LEVEL =
          "org.apache.commons.discovery.log.level";
  
      /** Include the instance name in the log message? */
      static protected boolean showLogName = false;
  
      /** Include the short name ( last component ) of the logger in the log
          message. Default to true - otherwise we'll be lost in a flood of
          messages without knowing who sends them.
      */
      static protected boolean showShortName = true;
  
      /** Include the current time in the log message */
      static protected boolean showDateTime = false;
  
      /** Used to format times */
      static protected DateFormat dateFormatter = null;
  
      /** The current log level */
      static protected int logLevel = LOG_LEVEL_INFO;
      
      
      /**
       * Use 'out' instead of 'err' for logging
       * to keep in-sync with test messages.
       */
      static private PrintStream out = System.out;
  
      // ------------------------------------------------------------ Initializer
  
      // initialize class attributes
      static {
          if(showDateTime) {
              dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:SSS zzz");
          }
  
          // set log level from properties
          String lvl = System.getProperty(PROP_LEVEL);
  
          if("all".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_ALL);
          } else if("trace".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_TRACE);
          } else if("debug".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_DEBUG);
          } else if("info".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_INFO);
          } else if("warn".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_WARN);
          } else if("error".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_ERROR);
          } else if("fatal".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_FATAL);
          } else if("off".equalsIgnoreCase(lvl)) {
              setLevel(SimpleLog.LOG_LEVEL_OFF);
          }
      }
  
      // -------------------------------------------------------- Properties
  
      /**
       * <p> Set logging level. </p>
       *
       * @param level new logging level
       */
      public static void setLevel(int currentLogLevel) {
          logLevel = currentLogLevel;
      }
  
      /**
       * <p> Get logging level. </p>
       */
      public static int getLevel() {
          return logLevel;
      }
  
      /**
       * Is the given log level currently enabled?
       *
       * @param logLevel is this level enabled?
       */
      protected static boolean isLevelEnabled(int level) {
          // log level are numerically ordered so can use simple numeric
          // comparison
          return (level >= getLevel());
      }
  
  
  
      // ------------------------------------------------------------- Attributes
  
      /** The name of this simple log instance */
      protected String logName = null;
  
      private String prefix=null;
  
      
      // ------------------------------------------------------------ Constructor
      
      /**
       * Construct a simple log with given name.
       *
       * @param name log name
       */
      public SimpleLog(String name) {
          logName = name;
      }
  
  
      // -------------------------------------------------------- Logging Methods
  
  
      /**
       * <p> Do the actual logging.
       * This method assembles the message
       * and then prints to <code>System.err</code>.</p>
       */
      protected void log(int type, Object message, Throwable t) {
          // use a string buffer for better performance
          StringBuffer buf = new StringBuffer();
  
          // append date-time if so configured
          if(showDateTime) {
              buf.append(dateFormatter.format(new Date()));
              buf.append(" ");
          }
  
          // append a readable representation of the log leve
          switch(type) {
              case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break;
              case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break;
              case SimpleLog.LOG_LEVEL_INFO:  buf.append("[INFO ] "); break;
              case SimpleLog.LOG_LEVEL_WARN:  buf.append("[WARN ] "); break;
              case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break;
              case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break;
          }
  
          // append the name of the log instance if so configured
       	if( showShortName) {
              if( prefix==null ) {
                  // cut all but the last component of the name for both styles
                  prefix = logName.substring( logName.lastIndexOf(".") +1) + " - ";
                  prefix = prefix.substring( prefix.lastIndexOf("/") +1) + "-";
              }
              buf.append( prefix );
          } else if(showLogName) {
              buf.append(String.valueOf(logName)).append(" - ");
          }
  
          // append the message
          buf.append(String.valueOf(message));
  
          // append stack trace if not null
          if(t != null) {
              buf.append(" <");
              buf.append(t.toString());
              buf.append(">");
          }
  
          // print to System.err
          out.println(buf.toString());
          
          if (t != null)
              t.printStackTrace(System.err);
      }
  
  
      // -------------------------------------------------------- Log Implementation
  
  
      /**
       * <p> Log a message with debug log level.</p>
       */
      public final void debug(Object message) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
              log(SimpleLog.LOG_LEVEL_DEBUG, message, null);
          }
      }
  
  
      /**
       * <p> Log an error with debug log level.</p>
       */
      public final void debug(Object message, Throwable t) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
              log(SimpleLog.LOG_LEVEL_DEBUG, message, t);
          }
      }
  
  
      /**
       * <p> Log a message with debug log level.</p>
       */
      public final void trace(Object message) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
              log(SimpleLog.LOG_LEVEL_TRACE, message, null);
          }
      }
  
  
      /**
       * <p> Log an error with debug log level.</p>
       */
      public final void trace(Object message, Throwable t) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
              log(SimpleLog.LOG_LEVEL_TRACE, message, t);
          }
      }
  
  
      /**
       * <p> Log a message with info log level.</p>
       */
      public final void info(Object message) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
              log(SimpleLog.LOG_LEVEL_INFO,message,null);
          }
      }
  
  
      /**
       * <p> Log an error with info log level.</p>
       */
      public final void info(Object message, Throwable t) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
              log(SimpleLog.LOG_LEVEL_INFO, message, t);
          }
      }
  
  
      /**
       * <p> Log a message with warn log level.</p>
       */
      public final void warn(Object message) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
              log(SimpleLog.LOG_LEVEL_WARN, message, null);
          }
      }
  
  
      /**
       * <p> Log an error with warn log level.</p>
       */
      public final void warn(Object message, Throwable t) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
              log(SimpleLog.LOG_LEVEL_WARN, message, t);
          }
      }
  
  
      /**
       * <p> Log a message with error log level.</p>
       */
      public final void error(Object message) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
              log(SimpleLog.LOG_LEVEL_ERROR, message, null);
          }
      }
  
  
      /**
       * <p> Log an error with error log level.</p>
       */
      public final void error(Object message, Throwable t) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
              log(SimpleLog.LOG_LEVEL_ERROR, message, t);
          }
      }
  
  
      /**
       * <p> Log a message with fatal log level.</p>
       */
      public final void fatal(Object message) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
              log(SimpleLog.LOG_LEVEL_FATAL, message, null);
          }
      }
  
  
      /**
       * <p> Log an error with fatal log level.</p>
       */
      public final void fatal(Object message, Throwable t) {
          if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
              log(SimpleLog.LOG_LEVEL_FATAL, message, t);
          }
      }
  
  
      /**
       * <p> Are debug messages currently enabled? </p>
       *
       * <p> This allows expensive operations such as <code>String</code>
       * concatenation to be avoided when the message will be ignored by the
       * logger. </p>
       */
      public final boolean isDebugEnabled() {
          return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG);
      }
  
  
      /**
       * <p> Are error messages currently enabled? </p>
       *
       * <p> This allows expensive operations such as <code>String</code>
       * concatenation to be avoided when the message will be ignored by the
       * logger. </p>
       */
      public final boolean isErrorEnabled() {
          return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR);
      }
  
  
      /**
       * <p> Are fatal messages currently enabled? </p>
       *
       * <p> This allows expensive operations such as <code>String</code>
       * concatenation to be avoided when the message will be ignored by the
       * logger. </p>
       */
      public final boolean isFatalEnabled() {
          return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL);
      }
  
  
      /**
       * <p> Are info messages currently enabled? </p>
       *
       * <p> This allows expensive operations such as <code>String</code>
       * concatenation to be avoided when the message will be ignored by the
       * logger. </p>
       */
      public final boolean isInfoEnabled() {
          return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO);
      }
  
  
      /**
       * <p> Are trace messages currently enabled? </p>
       *
       * <p> This allows expensive operations such as <code>String</code>
       * concatenation to be avoided when the message will be ignored by the
       * logger. </p>
       */
      public final boolean isTraceEnabled() {
          return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE);
      }
  
  
      /**
       * <p> Are warn messages currently enabled? </p>
       *
       * <p> This allows expensive operations such as <code>String</code>
       * concatenation to be avoided when the message will be ignored by the
       * logger. </p>
       */
      public final boolean isWarnEnabled() {
          return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN);
      }
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/java/org/apache/commons/discovery/ant/ServiceDiscoveryTask.java
  
  Index: ServiceDiscoveryTask.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.discovery.ant;
  
  import java.util.Vector;
  
  import org.apache.commons.discovery.Resource;
  import org.apache.commons.discovery.jdk.JDKHooks;
  import org.apache.commons.discovery.listeners.GatherResourcesListener;
  import org.apache.commons.discovery.resource.DiscoverResources;
  
  
  /**
   * Small ant task that will use discovery to locate a particular impl.
   * and display all values.
   *
   * You can execute this and save it with an id, then other classes can use it.
   *
   * @author Costin Manolache
   */
  public class ServiceDiscoveryTask
  {
      String name;
      int debug=0;
      String[] drivers = null;
          
      public void setServiceName(String name ) {
          this.name=name;
      }
  
      public void setDebug(int i) {
          this.debug=debug;
      }
  
      public String[] getServiceInfo() {
          return drivers;
      }
  
      public void execute() throws Exception {
          System.out.println("XXX ");
          
          GatherResourcesListener listener = new GatherResourcesListener();
          DiscoverResources disc = new DiscoverResources();
          disc.addClassLoader( JDKHooks.getJDKHooks().getThreadContextClassLoader() );
          disc.addClassLoader( this.getClass().getClassLoader() );
          disc.setListener(listener);
          disc.find(name);
  
          Vector vector = listener.getResources();
          drivers = new String[vector.size()];
          for (int i = 0; i < vector.size(); i++) {
              drivers[i] = ((Resource)vector.get(i)).getName();
              if( debug > 0 ) {
                  System.out.println("Found " + drivers[i]);
              }
          }
      }
          
  }
  
  
  
  1.1                  jakarta-commons/discovery/sandbox/test/META-INF/services/org.apache.commons.discovery.test.TestInterface2
  
  Index: org.apache.commons.discovery.test.TestInterface2
  ===================================================================
  # comment
  
  org.apache.commons.discovery.test.TestImpl2_1   # EOL comment
  
  # comments & blank lines
  
  
  #
  
  
  
  

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