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

cvs commit: jakarta-commons-sandbox/discovery/src/conf MANIFEST.MF

rsitze      2002/06/26 08:50:15

  Added:       discovery PROPOSAL.html LICENSE build.xml
               discovery/src/java/org/apache/commons/service/discovery
                        SPIContext.java ServiceCache.java
                        ServiceException.java ClassFinder.java
                        ServiceFinder.java Service.java
               discovery/src/test/org/apache/commons/service/discovery
                        TestAll.java
               discovery/src/conf MANIFEST.MF
  Log:
  Service discovery mechanism.
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/discovery/PROPOSAL.html
  
  Index: PROPOSAL.html
  ===================================================================
  <html>
  <head>
  <title>Proposal for Service Discovery</title>
  </head>
  <body bgcolor="white">
  
  <div align="center">
  <h1>Proposal for <em>Service Discovery</em> Package</h1>
  </div>
  
  <h3>(0) Rationale</h3>
  
  <p>
  Service Discovery provides fundamental discovery pattern used in many projects.
  </p>
  <p>
  It also provides the resources to make such discovery easily adaptable
  for use within a project whenever/wherever a pluggable interface is
  to be introduced.
  </p>
  
  <h3>(1) Scope of the Package</h3>
  
  <p>
  This is not indended to be a replacement to be used by the user, but rather
  a replacement to be used directly by projects.  Use by the user is also reasonable,
  but limited due to 'keeping this simple'.  In particular, there is no configuration
  for this discovery service, it relies soley on usage patterns.
  </p>
  
  <p>
  Given a java.lang.Class parameter 'package.Class' that represents a
  fundamental service as either an interface, an abstract class
  (or even a regular class), find an implementation of that class:
  <ul>
  <li>Look for system property named 'package.Class', the value of which is the
      name of an implementation.</li>
  <li>Look for a 'local' property named 'package.Class'...</li>
  <li>Attempt JDK 1.3+ style discovery</li>
  <li>Attempt to load a default implementation</li>
  </ul>
  In all cases, verify that the discovered implementation <b>implements</b>
  'package.Class'.
  </p>
  
  <p>
  The package should :
  <ul>
  <li>Have an API which should be as simple to use as possible</li>
  <li>Be based on usage patterns, not specific configuration file</li>
  <li>Represent proper discovery & class-loading principles</li>
  <li>Be reasonably portable across JDK levels (1.1.8+?)</li>
  </ul>
  </p>
  
  <h3>(1.5) Interaction With Other Packages</h3>
  
  <p><em>Services</em> relies on:
  </p>
  
  <ul>
    <li>Java Development Kit (Version 1.1 or later)</li>
    <li>[by design] Nothing Else, particularly anything that would be classified as a 'service'.</li>
  </ul>
  
  <h3>(2) Required Jakarta-Commons Resources</h3>
  
  <ul>
  
  <li>CVS Repository - New directory <code>discovery</code> in the 
  <code>jakarta-commons-sandbox</code> CVS repository.</li>
  
  <li>Initial Committers - The list is provided below. </li>
  
  <li>Mailing List - Discussions will take place on the general
  <em>commons-dev@jakarta.apache.org</em> mailing list. To help list
  subscribers identify messages of interest, it is suggested that the
  message subject of messages about this component be prefixed with
  [discovery].</li>
  
  <li>Bugzilla - New component "discovery" under the "Commons" product
  category, with appropriate version identifiers as needed.</li>
  
  <li>Jyve FAQ - New category "discovery" (when available).</li>
  </ul>
  
  
  <h3>(4) Initial Committers</h3>
  
  <p>The initial committers on the Service Discovery component shall be:</p>
  
  <ul>
    <li>Richard A. Sitze</li>
    <li>Costin M.</li>
    <li>Craig R. McClanahan</li>
  </ul>
  
  </body>
  </html>
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/LICENSE
  
  Index: LICENSE
  ===================================================================
  /*
   * 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 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/>.
   */
  
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/build.xml
  
  Index: build.xml
  ===================================================================
  <project name="Discovery" default="compile" basedir=".">
  
  
  <!--
          Simple "Service Discovery" component of the Jakarta Commons Subproject
          $Id$
  -->
  
  
  <!-- ========== Initialize Properties ===================================== -->
  
  
    <property file="build.properties"/>                <!-- Component local   -->
    <property file="../build.properties"/>             <!-- Commons local     -->
    <property file="${user.home}/build.properties"/>   <!-- User local        -->
  
  
  <!-- ========== External Dependencies ===================================== -->
  
  
    <!-- The directories corresponding to your necessary dependencies -->
    <property name="junit.jar"               value="../../junit3.7/junit.jar"/>
    <property name="logger.jar"               value="../../jakarta-commons/logging/target/commons-logging.jar"/>
  
  
  <!-- ========== Component Declarations ==================================== -->
  
  
    <!-- The name of this component -->
    <property name="component.name"          value="service.discovery"/>
  
    <!-- The primary package name of this component -->
    <property name="component.package"       value="org.apache.commons.service.discovery"/>
  
    <!-- The title of this component -->
    <property name="component.title"         value="Service Discovery"/>
  
    <!-- The current version number of this component -->
    <property name="component.version"       value="1.0-dev"/>
  
    <!-- The base directory for compilation targets -->
    <property name="build.home"              value="target"/>
  
    <!-- The base directory for component configuration files -->
    <property name="conf.home"               value="src/conf"/>
  
    <!-- The base directory for distribution targets -->
    <property name="dist.home"               value="dist"/>
  
    <!-- The base directory for component sources -->
    <property name="source.home"             value="src/java"/>
  
    <!-- The base directory for unit test sources -->
    <property name="test.home"               value="src/test"/>
  
  <!-- ========== Compiler Defaults ========================================= -->
  
  
    <!-- Should Java compilations set the 'debug' compiler option? -->
    <property name="compile.debug"           value="true"/>
  
    <!-- Should Java compilations set the 'deprecation' compiler option? -->
    <property name="compile.deprecation"     value="false"/>
  
    <!-- Should Java compilations set the 'optimize' compiler option? -->
    <property name="compile.optimize"        value="true"/>
  
    <!-- Construct compile classpath -->
    <path id="compile.classpath">
    </path>
  
    <!-- Construct unit test classpath -->
    <path id="test.classpath">
      <pathelement location="${build.home}/classes"/>
      <pathelement location="${build.home}/tests"/>
      <pathelement location="${logger.jar}"/>
      <pathelement location="${junit.jar}"/>
    </path>
  
    <!-- Should all tests fail if one does? -->
    <property name="test.failonerror"        value="true"/>
  
    <!-- The test runner to execute -->
    <property name="test.runner"             value="junit.textui.TestRunner"/>
  
  <!-- ========== Executable Targets ======================================== -->
  
  
    <target name="init" description="Initialize and evaluate conditionals">
      <echo message="-------- ${component.title} ${component.version} --------"/>
      <filter  token="name"                  value="${component.name}"/>
      <filter  token="package"               value="${component.package}"/>
      <filter  token="version"               value="${component.version}"/>
    </target>
  
  
    <target name="prepare" depends="init" description="Prepare build directory">
      <mkdir dir="${build.home}"/>
      <mkdir dir="${build.home}/classes"/>
      <mkdir dir="${build.home}/conf"/>
      <mkdir dir="${build.home}/docs"/>
      <mkdir dir="${build.home}/docs/api"/>
      <mkdir dir="${build.home}/tests"/>
      <tstamp/>
      <copy todir="${build.home}/conf" filtering="on">
        <fileset dir="${conf.home}" includes="*.MF"/>
      </copy>
    </target>
  
   
    <target name="compile" depends="prepare" description="Compile shareable components">
      <javac  srcdir="${source.home}"
             destdir="${build.home}/classes"
               debug="${compile.debug}"
         deprecation="${compile.deprecation}"
            optimize="${compile.optimize}">
        <classpath refid="compile.classpath"/>
      </javac>
      <copy    todir="${build.home}/classes" filtering="on">
        <fileset dir="${source.home}" excludes="**/*.java"/>
      </copy>
    </target>
  
  
    <target name="clean"
     description="Clean build and distribution directories">
      <delete    dir="${build.home}"/>
      <delete    dir="${dist.home}"/>
    </target>
  
  
    <target name="all" depends="clean,compile"
     description="Clean and compile all components"/>
  
  
    <target name="javadoc" depends="compile"
     description="Create component Javadoc documentation">
      <mkdir      dir="${dist.home}"/>
      <mkdir      dir="${dist.home}/docs"/>
      <mkdir      dir="${dist.home}/docs/api"/>
      <javadoc sourcepath="${source.home}"
                  destdir="${dist.home}/docs/api"
             packagenames="org.apache.commons.*"
                   author="true"
                  private="true"
                  version="true"
                 doctitle="&lt;h1&gt;${component.title}&lt;/h1&gt;"
              windowtitle="${component.title} (Version ${component.version})"
                   bottom="Copyright (c) 2001 - Apache Software Foundation">
        <classpath refid="compile.classpath"/>
      </javadoc>
    </target>
  
  
    <target name="dist" depends="compile,javadoc"
     description="Create binary distribution">
      <!-- TODO: top level files like LICENSE and README -->
      <mkdir      dir="${dist.home}"/>
      <copy      file="../LICENSE"
                todir="${dist.home}"/>
      <mkdir      dir="${build.home}/classes/META-INF"/>
      <copy      file="../LICENSE"
               tofile="${build.home}/classes/META-INF/LICENSE.txt"/>
      <jar    jarfile="${dist.home}/commons-${component.name}.jar"
              basedir="${build.home}/classes"
             manifest="${build.home}/conf/MANIFEST.MF"/>
    </target>
  
  <!-- ========== Testing section ======================================== -->
  
    <target name="compile.tests" depends="compile" description="Compile unit test cases">
      <javac  srcdir="${test.home}"
             destdir="${build.home}/tests"
               debug="${compile.debug}"
         deprecation="${compile.deprecation}"
            optimize="${compile.optimize}">
        <classpath refid="test.classpath"/>
      </javac>
      <copy    todir="${build.home}/tests" filtering="on">
        <fileset dir="${test.home}" excludes="**/*.java"/>
      </copy>
    </target>
  
    <target name="test.discovery" depends="compile.tests"
     description="Run basic Service unit tests ...">
      <echo message="Running basic Service tests ..."/>
      <java classname="${test.runner}" fork="yes"
          failonerror="${test.failonerror}">
        <arg value="org.apache.commons.service.discovery.TestAll"/>
        <classpath refid="test.classpath"/>
      </java>
    </target>
  
  
  </project>
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/SPIContext.java
  
  Index: SPIContext.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.service.discovery;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  
  
  /**
   * Represents a Service Programming Interface (spi) context,
   * to include an spi and the Thread Context Class Loader for
   * the thread that created an instance of this object.
   * 
   * These matters are, for the most part, trivial.  Bundling
   * these two together is a convenience, but more importantly
   * it gives a home to a portable mechanism for determining
   * the thread context class loader.  JDK 1.1 does not support
   * the thread context class loader, yet the code below must
   * be able to compile & execute in such an environment.
   * 
   * @author Richard A. Sitze
   */
  public class SPIContext {
      /**
       * Thread context class loader or null if not available (JDK 1.1).
       */
      private ClassLoader threadContextClassLoader =
          findThreadContextClassLoader();
  
      /**
       * The service programming interface: intended to be
       * an interface or abstract class, but not limited
       * to those two.
       */        
      private Class spi;
  
      public SPIContext(Class spi) {
          this.spi = spi;
      }
      
      public ClassLoader getThreadContextClassLoader() {
          return threadContextClassLoader;
      }
      
      public Class getSPI() {
          return spi;
      }
  
      /**
       * Return the thread context class loader if available.
       * Otherwise return null.
       * 
       * The thread context class loader is available for JDK 1.2
       * or later, if certain security conditions are met.
       * 
       * @exception SecurityException if a suitable class loader
       * cannot be identified.
       */
      private static ClassLoader findThreadContextClassLoader()
          throws ServiceException
      {
          ClassLoader classLoader = null;
          
          try {
              // Are we running on a JDK 1.2 or later system?
              Method method = Thread.class.getMethod("getContextClassLoader", null);
      
              // Get the thread context class loader (if there is one)
              try {
                  classLoader =
                      (ClassLoader)method.invoke(Thread.currentThread(), null);
              } catch (IllegalAccessException e) {
                  throw new ServiceException("Unexpected IllegalAccessException", e);
              } catch (InvocationTargetException e) {
                  /**
                   * InvocationTargetException is thrown by 'invoke' when
                   * the method being invoked (Thread.getContextClassLoader)
                   * throws an exception.
                   * 
                   * Thread.getContextClassLoader() throws SecurityException
                   * when the context class loader isn't an ancestor of the
                   * calling class's class loader, or if security permissions
                   * are restricted.
                   * 
                   * In the first case (the context class loader isn't an
                   * ancestor of the calling class's class loader), we want
                   * to ignore and keep going.  We cannot help but also ignore
                   * the second case (restricted security permissions) with
                   * the logic below, but other calls elsewhere (to obtain
                   * a class loader) will re-trigger this exception where
                   * we can make a distinction.
                   */
                  if (e.getTargetException() instanceof SecurityException) {
                      classLoader = null;  // ignore
                  } else {
                      // Capture 'e.getTargetException()' exception for details
                      // alternate: log 'e.getTargetException()', and pass back 'e'.
                      throw new ServiceException
                          ("Unexpected InvocationTargetException",
                           e.getTargetException());
                  }
              }
          } catch (NoSuchMethodException e) {
              // Assume we are running on JDK 1.1
              classLoader = null;
          }
      
          // Return the selected class loader
          return classLoader;
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ServiceCache.java
  
  Index: ServiceCache.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.service.discovery;
  
  import java.util.Hashtable;
  import java.util.Enumeration;
  
  
  
  /**
   * Cache of previously discovered implementations of SPI's.
   * 
   * @author Richard A. Sitze
   */
  public class ServiceCache
  {
      /**
       * Previously encountered service interfaces (spis), keyed by the
       * <code>ClassLoader</code> with which it was created.
       */
      private Hashtable services = new Hashtable(13);
      
      /**
       * Get service keyed by classLoader.
       */
      public Object get(ClassLoader classLoader)
      {
          return (classLoader == null)
                  ? null
                  : services.get(classLoader);
      }
      
      /**
       * Put service keyed by classLoader.
       */
      public void put(ClassLoader classLoader, Object service)
      {
          if (classLoader != null  &&  service != null) {
              services.put(classLoader, service);
          }
      }
  
      /**
       * Release any internal references to previously created service instances,
       * after calling the instance method <code>release()</code> on each of them.
       *
       * This is useful 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 void releaseAll() {
          Enumeration elements = services.elements();
          while (elements.hasMoreElements()) {
              Object service = elements.nextElement();
              
              if (service instanceof Service)
                  ((Service)service).release();
          }
          services.clear();
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ServiceException.java
  
  Index: ServiceException.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.service.discovery;
  
  
  /**
   * <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 ServiceException extends RuntimeException {
  
  
      /**
       * Construct a new exception with <code>null</code> as its detail message.
       */
      public ServiceException() {
          super();
      }
  
      /**
       * Construct a new exception with the specified detail message.
       *
       * @param message The detail message
       */
      public ServiceException(String message) {
          super(message);
      }
  
      /**
       * Construct a new exception with the specified cause and a derived
       * detail message.
       *
       * @param cause The underlying cause
       */
      public ServiceException(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 ServiceException(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;
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ClassFinder.java
  
  Index: ClassFinder.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.service.discovery;
  
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.util.Properties;
  
  
  /**
   * 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 ClassFinder {
      /**
       * JDK1.3+ 'Service Provider' specification 
       * ( http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html )
       */
      private static final String SERVICE_HOME = "META-INF/services/";
  
      /**
       * The SPI (and thread context) for which we are (presumably)
       * looking for an implementation of.
       */
      private final SPIContext spiContext;
      
      public ClassFinder(SPIContext spiContext) {
          this.spiContext = spiContext;
          //System.out.println("Finding '" + spiContext.getSPI().getName() + "'");
      }
      
      public ClassFinder(Class spi) {
          this.spiContext = new SPIContext(spi);
          //System.out.println("Finding '" + spi.getName() + "'");
      }
      
      public ClassLoader getThreadContextClassLoader() {
          return spiContext.getThreadContextClassLoader();
      }
  
      /**
       * Load the class serviceImplName.
       * First try to load the class with the thread context class loader,
       * and failing that try the local class loader.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class load(String serviceImplName,
                               ClassLoader threadContextClassLoader,
                               ClassLoader localClassLoader)
          throws ServiceException
      {
          //System.out.println("Loading '" + serviceImplName + "'");
  
          Class clazz = null;
          
          if (serviceImplName != null  &&  serviceImplName.length() > 0) {
              if (threadContextClassLoader != null) {
                  try {
                      // first the thread class loader
                      clazz = threadContextClassLoader.loadClass(serviceImplName);
                  } catch (ClassNotFoundException e) {
                      clazz = null;
                  }
              }
      
              if (clazz == null  &&
                  localClassLoader != null  &&
                  localClassLoader != threadContextClassLoader) {
                  // if threadContextClassLoder was null or if it failed
                  // (i.e. no implementation is found in the webapp), try
                  // the local loader if we haven't already...
                  try {
                      // clazz = spi.getClassLoader().loadClass(serviceImplName);
                      clazz = localClassLoader.loadClass(serviceImplName);
                  } catch (ClassNotFoundException e) {
                      clazz = null;
                  }
              }
          }
          
          return clazz;
      }
  
      /**
       * Load the class serviceImplName.
       * First try to load the class with the SPI context's
       * thread context class loader, and failing that try
       * the class loader that loaded the SPI.
       * 
       * @param serviceImplName The name of the class to load.
       */
      public static Class load(String serviceImplName, SPIContext spiContext)
          throws ServiceException
      {
          return load(serviceImplName,
                      spiContext.getThreadContextClassLoader(),
                      spiContext.getSPI().getClassLoader());
      }
      
      /**
       * Return a new instance of the specified <code>serviceImplName</code>
       * implementation class, loaded by the context class loader.
       * If that fails, try the spi's class loader.
       *
       * @param serviceImplName Fully qualified name of the implementation class
       * @param localOnly Use only local class loader
       *                  (do not try thread context class loader).
       *
       * @exception ServiceException if a suitable instance cannot be created,
       *                             or if the class created is not an instance
       *                             of <code>spi</code>
       */
      public Class find(String serviceImplName, boolean localOnly)
          throws ServiceException
      {
          Class clazz = load(serviceImplName,
                             localOnly ? null : getThreadContextClassLoader(),
                             spiContext.getSPI().getClassLoader());
              
          if (clazz != null  &&  !spiContext.getSPI().isAssignableFrom(clazz)) {
              throw new ServiceException("Class " + serviceImplName +
                            " does not implement " + spiContext.getSPI().getName());
          }
          
          return clazz;
      }
      
      /**
       * Load the class whose name is given by the value of a System Property.
       * 
       * @param attribute the name of the system property whose value is
       *        the name of the class to load.
       */
      public Class systemFind(String attribute) {
          String value;
          try {
              value = System.getProperty(attribute);
          } catch (SecurityException e) {
              value = null;
          }
          return find(value, false);
      }
  
      /**
       * Load the class whose name is given by the value of a System Property,
       * whose name is the fully qualified name of the SPI class.
       */
      public Class systemFind() {
          return systemFind(spiContext.getSPI().getName());
      }
  
      /**
       * Load the class whose name is given by the value of a property.
       * 
       * @param properties the properties set.
       * @param attribute the name of the property whose value is
       *        the name of the class to load.
       */
      public Class find(Properties properties, String attribute) {
          return find(properties.getProperty(attribute), false);
      }
  
      /**
       * Load the class whose name is given by the value of a property.
       * whose name is the fully qualified name of the SPI class.
       * 
       * @param properties the properties set.
       */
      public Class find(Properties properties) {
          return find(properties, spiContext.getSPI().getName());
      }
  
      /**
       * Load the class implementing the SPI using the JDK 1.3
       * location discovery mechanism.
       * This will allow users to plug a service implementation by just
       * placing it in the META-INF/services directory of the webapp
       * (or in CLASSPATH or equivalent).
       */
      public Class jdk13Find() {
          return find(getJDKImplClassName(), false);
      }
  
      /**
       * Find the name of a service using the JDK 1.3 jar discovery mechanism.
       * This will allow users to plug a service implementation by just
       * placing it in the META-INF/services directory of the webapp
       * (or in CLASSPATH or equivalent).
       */
      private String getJDKImplClassName() {
          String serviceImplName = null;
  
          // Name of J2EE application file that identifies the service implementation.
          String servicePropertyFile = SERVICE_HOME + spiContext.getSPI().getName();
      
          InputStream is = (getThreadContextClassLoader() == null
                            ? ClassLoader.getSystemResourceAsStream(servicePropertyFile)
                            : getThreadContextClassLoader().getResourceAsStream(servicePropertyFile));
          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 {
                          serviceImplName = rd.readLine();
                      } finally {
                          rd.close();
                      }
                  } finally {
                      is.close();
                  }
              } catch (IOException ioe) {
                  ; // ignore
              }
          }
          
          return serviceImplName;
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/ServiceFinder.java
  
  Index: ServiceFinder.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.service.discovery;
  
  import java.util.Enumeration;
  import java.util.Hashtable;
  import java.util.Properties;
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  
  
  /**
   * <p>Service factory for discovery and creation of service instances,
   * with discovery and configuration features similar to that employed
   * by standard Java APIs such as JAXP.</p>
   *
   * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily
   * based on the SAXParserFactory and DocumentBuilderFactory implementations
   * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.</p>
   * 
   * @author Richard A. Sitze
   * @author Craig R. McClanahan
   * @author Costin Manolache
   * @version $Revision$ $Date$
   */
  public class ServiceFinder {
      /**
       * Sets of previously encountered service interfaces (spis), keyed by the
       * interface (<code>Class</code>).  Each element is a ServiceCache.
       */
      private static final Hashtable service_caches = new Hashtable(13);
      
      /**
       * <p>Locate and instantiate a service.  The service implementation
       * class is located using the following ordered lookup procedure:</p>
       * <ul>
       * <li>Try to load a class with the name obtained from the system
       *     property, having the same name as the spi class:
       *     <code>spiContext.getSPI().getName()</code>.</li>
       * 
       * <li>Try to load a class with the name obtained from the
       *     <code>properties</code> parameter, having the same
       *     name as the spi class: <code>spiContext.getSPI().getName()</code>.</li>
       * 
       * <li>Use the JDK1.3+ 'Service Provider' specification
       *     (http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html)
       *     to locate a service named <code>spiContext.getSPI().getName()</code>.
       *     Implemented internally, so there is not a hard
       *     dependency on JDK 1.3+.</li>
       * 
       * <li>Fall back to a default implementation class, as specified by
       *     non-null <code>defaultImplName</code>.</li>
       * 
       * </ul>
       * 
       * @param spiContext The SPI Context identifies the SPI and the
       *        thread context class loader.
       *        <code>spiContext.getSPI().getName()</code> id's the (property)
       *        name of the service implementation.  Presumed to be an interface,
       *        but there is nothing in the code that prevents it from
       *        being an abstract base class, or even a class.
       * 
       * @param properties used as one alternative to find name of service
       *        implementation class, with property name specified by
       *        <code>spi.getName()</code>.  If the implementation class found
       *        for <code>spi</code> implements the <code>Service</code>
       *        interface, then <code>spiInstance.init(properties)</code> is
       *        called.
       * 
       * @param defaultImplName Name of the default implementation class.
       *
       * @exception ServiceException if the implementation class
       *            is not available,
       *            cannot be instantiated,
       *            or is not an instance of <code>spi</code>.
       */
      public static Object find(SPIContext spiContext,
                                Properties properties,
                                String defaultImplName)
          throws ServiceException
      {
          // thread context can change on each call,
          // so establish context for this one call.
          ClassFinder classFinder = new ClassFinder(spiContext);
  
          /**
           * Return previously registered service object (not class)
           * for this spi.  Try contextClassLoader first, and if that
           * fails then try the local class loader.
           */
          Object service = (classFinder.getThreadContextClassLoader() == null)
                  ? null
                  : get(spiContext.getSPI().getName(), spiContext.getThreadContextClassLoader());
          
          if (service == null) {
              service = get(spiContext.getSPI().getName(),
                            spiContext.getSPI().getClassLoader());
          }
          
          if (service == null) {
              // First, try the system property
              Class clazz = classFinder.systemFind();
      
              if (clazz == null) {
                  // Second, try the properties parameter
                  if (properties != null)
                      clazz = classFinder.find(properties);
              
                  if (clazz == null) {
                      // Third, try to find a service by using the JDK1.3 jar
                      // discovery mechanism.
                      clazz = classFinder.jdk13Find();
                  
                      if (clazz == null) {
                          // Fourth, try the fallback implementation class
                          clazz = classFinder.find(defaultImplName, true);
                          
                          if (clazz == null) {
                              throw new ServiceException
                                  ("No implementation defined for " +
                                   spiContext.getSPI().getName());
                          }
                      }
                  }
              }
              
              if (clazz != null) {
                  try {
                      service = clazz.newInstance();
                      put(spiContext.getSPI().getName(), clazz.getClassLoader(), service);
                  } catch (Exception e) {
                      throw new ServiceException("Unable to instantiate " + spiContext.getSPI().getName(), e);
                  }
                  
                  if (service instanceof Service) {
                      ((Service)service).init(properties);
                  }
              }
          }
  
          return service;
      }
      
      /**
       * Equivalent to
       * <code>find(new SPIContext(spi), properties, defaultImplName)</code>.
       */
      public static Object find(Class spi,
                                Properties properties,
                                String defaultImplName)
          throws ServiceException
      {
          return find(new SPIContext(spi), properties, defaultImplName);
      }
  
      /**
       * Load properties file, and call
       * <code>find(spiContext, properties, defaultImplName)</code>.
       */    
      public static Object find(SPIContext spiContext,
                                String propertiesFileName,
                                String defaultImplName)
          throws ServiceException
      {
          Properties properties = null;
          
          if (propertiesFileName != null) {
              try {
                  InputStream stream =
                      spiContext.getThreadContextClassLoader().getResourceAsStream(propertiesFileName);
      
                  if (stream != null) {
                      properties = new Properties();
                      try {
                          properties.load(stream);
                      } finally {
                          stream.close();
                      }
                  }
              } catch (IOException e) {
              } catch (SecurityException e) {
              }
          }
          
          return find(spiContext, properties, defaultImplName);
      }
  
      /**
       * Equivalent to
       * <code>find(new SPIContext(spi), propertiesFileName, defaultImplName)</code>.
       */    
      public static Object find(Class spi,
                                String propertiesFileName,
                                String defaultImplName)
          throws ServiceException
      {
          return find(new SPIContext(spi), propertiesFileName, defaultImplName);
      }
  
      /**
       * Find implementation of SPI.
       * Equivalent to find(spi, (Properties)null, defaultImplName);
       */
      public static Object find(Class spi, String defaultImplName)
          throws ServiceException
      {
          return find(spi, (Properties)null, defaultImplName);
      }
  
      /**
       * Find implementation of SPI.
       * Equivalent to find(spi, properties, null);
       */
      public static Object find(Class spi, Properties properties)
          throws ServiceException
      {
          return find(spi, properties, null);
      }
  
      /**
       * Find implementation of SPI.
       * Equivalent to find(spi, (Properties)null, null);
       */
      public static Object find(Class spi)
          throws ServiceException
      {
          return find(spi, (Properties)null, null);
      }
  
      /**
       * Release any internal references to previously created service instances,
       * after calling the instance method <code>release()</code> on each of them.
       *
       * This is useful 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 void releaseAll() {
          synchronized (service_caches) {
              Enumeration cache = service_caches.elements();
              while (cache.hasMoreElements()) {
                  ((ServiceCache)cache.nextElement()).releaseAll();
              }
              service_caches.clear();
          }
      }
      
      /**
       * Release any internal references to previously created instances of SPI,
       * after calling the instance method <code>release()</code> on each of them.
       *
       * This is useful 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 void releaseAll(Class spi) {
          if (spi != null) {
              synchronized (service_caches) {
                  ServiceCache cache = (ServiceCache)service_caches.get(spi.getName());
                  if (cache != null) {
                      cache.releaseAll();
                  }
              }
          }
      }
      
      /**
       * Get service keyed by spi & classLoader.
       */
      private static Object get(String spi, ClassLoader classLoader)
      {
          ServiceCache cache = (spi == null)
                               ? null
                               : (ServiceCache)service_caches.get(spi);
          
          return (cache == null)
                  ? null
                  : cache.get(classLoader);
      }
      
      /**
       * Put service keyed by spi & classLoader.
       */
      private static void put(String spi, ClassLoader classLoader, Object service)
      {
          if (spi != null  &&  classLoader != null  &&  service != null) {
              ServiceCache cache = (ServiceCache)service_caches.get(spi);
              
              if (cache == null) {
                  cache = new ServiceCache();
                  service_caches.put(spi, cache);
              }
              
              cache.put(classLoader, service);
          }
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/java/org/apache/commons/service/discovery/Service.java
  
  Index: Service.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.service.discovery;
  
  import java.util.Properties;
  
  
  /**
   * <p>Optional Service interface to facilitate life-cycle management.<p>
   * 
   * <p>A service is not required to implement this interface, but if
   * it does then the service is notified when it is being initialized
   * and released by ServiceFinder.</p>
   * 
   * @author Richard A. Sitze
   * @version $Revision$ $Date$
   */
  public interface Service {
      public void init(Properties properties);
  
      public void release();
  }
  
  
  
  1.1                  jakarta-commons-sandbox/discovery/src/test/org/apache/commons/service/discovery/TestAll.java
  
  Index: TestAll.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/logging/src/test/org/apache/commons/logging/TestAll.java,v 1.2 2002/01/17 22:55:43 rdonkin Exp $
   * $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.service.discovery;
  import java.util.Properties;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.apache.commons.logging.impl.LogFactoryImpl;
  import org.apache.commons.logging.impl.SimpleLog;
  
  import junit.framework.*;
  
  
  /**
    * <p> The build script calls just one <code>TestSuite</code> - this one!
    * All tests should be written into separate <code>TestSuite</code>'s
    * and added to this. Don't clutter this class with implementations. </p>
    *
    * <p> This class is based on <code>org.apache.commons.betwixt.TestAll</code> 
    * coded by James Strachan. </p>
    *
    * @author Robert Burrell Donkin
    * @version $Revision: 1.2 $
   */
  public class TestAll extends TestCase {
  
      public TestAll(String testName) {
          super(testName);
      }
      
      public static Test suite() {
          return new TestSuite(TestAll.class);
      }
      
      public void testServiceFinder1() {
          try {
              LogFactory factory =
                  (LogFactory)ServiceFinder.find(LogFactory.class,
                                                 LogFactoryImpl.class.getName());
              Log log = factory.getLog(TestAll.class);
              log.info("got log!");
          } finally {
              LogFactory.releaseAll();
              ServiceFinder.releaseAll();
          }
      }
      
      public void testServiceFinder2() {
          Properties props = new Properties();
          
          props.setProperty(LogFactory.class.getName(),
                            LogFactoryImpl.class.getName());
                            
          props.setProperty(Log.class.getName(), SimpleLog.class.getName());
          
          try {
              LogFactory factory =
                  (LogFactory)ServiceFinder.find(LogFactory.class, props);
              Log log = factory.getLog(TestAll.class);
              log.info("got log factory via service");
          } finally {
              LogFactory.releaseAll();
              ServiceFinder.releaseAll();
          }
      }
  
      /**
       * 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-sandbox/discovery/src/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@
  
  
  

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