You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by tr...@apache.org on 2006/01/20 14:48:55 UTC

svn commit: r370807 [4/22] - in /directory/sandbox/trustin/mina-spi: ./ core/src/main/java/org/apache/mina/common/ core/src/main/java/org/apache/mina/common/support/ core/src/main/java/org/apache/mina/common/support/discovery/ core/src/main/java/org/ap...

Added: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/DiscoverSingleton.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/DiscoverSingleton.java?rev=370807&view=auto
==============================================================================
--- directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/DiscoverSingleton.java (added)
+++ directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/DiscoverSingleton.java Fri Jan 20 05:47:50 2006
@@ -0,0 +1,531 @@
+/*
+ * $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.mina.common.support.discovery.tools;
+
+import java.util.HashMap;
+import java.util.Properties;
+
+import org.apache.mina.common.support.discovery.DiscoveryException;
+import org.apache.mina.common.support.discovery.jdk.JDKHooks;
+import org.apache.mina.common.support.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() {
+        EnvironmentCache.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)EnvironmentCache.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.
+     */
+    // FIXME: Why is this here? All the methods used are static.
+    //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)EnvironmentCache.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)EnvironmentCache.get(classLoader);
+            
+            if (spis == null) {
+                spis = new HashMap(EnvironmentCache.smallHashSize);
+                EnvironmentCache.put(classLoader, spis);
+            }
+            
+            spis.put(spiName, service);
+        }
+    }
+}

Propchange: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/DiscoverSingleton.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/EnvironmentCache.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/EnvironmentCache.java?rev=370807&view=auto
==============================================================================
--- directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/EnvironmentCache.java (added)
+++ directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/EnvironmentCache.java Fri Jan 20 05:47:50 2006
@@ -0,0 +1,165 @@
+/*
+ * $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.mina.common.support.discovery.tools;
+
+import java.util.HashMap;
+
+import org.apache.mina.common.support.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);
+    }
+}

Propchange: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/EnvironmentCache.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ManagedProperties.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ManagedProperties.java?rev=370807&view=auto
==============================================================================
--- directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ManagedProperties.java (added)
+++ directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ManagedProperties.java Fri Jan 20 05:47:50 2006
@@ -0,0 +1,376 @@
+/*
+ * 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.mina.common.support.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.mina.common.support.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();
+                    }
+                });
+    }
+}

Propchange: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ManagedProperties.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/PropertiesHolder.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/PropertiesHolder.java?rev=370807&view=auto
==============================================================================
--- directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/PropertiesHolder.java (added)
+++ directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/PropertiesHolder.java Fri Jan 20 05:47:50 2006
@@ -0,0 +1,110 @@
+/*
+ * $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.mina.common.support.discovery.tools;
+
+import java.util.Properties;
+
+import org.apache.mina.common.support.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;
+    }
+}

Propchange: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/PropertiesHolder.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ResourceUtils.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ResourceUtils.java?rev=370807&view=auto
==============================================================================
--- directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ResourceUtils.java (added)
+++ directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ResourceUtils.java Fri Jan 20 05:47:50 2006
@@ -0,0 +1,197 @@
+/*
+ * $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.mina.common.support.discovery.tools;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.mina.common.support.discovery.DiscoveryException;
+import org.apache.mina.common.support.discovery.Resource;
+import org.apache.mina.common.support.discovery.ResourceIterator;
+import org.apache.mina.common.support.discovery.resource.ClassLoaders;
+import org.apache.mina.common.support.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
+    {
+        DiscoverResources explorer = new DiscoverResources(loaders);
+        ResourceIterator resources = explorer.findResources(resourceName);
+        
+        if (spi != null  &&
+            !resources.hasNext()  &&
+            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.
+             */
+            resourceName = getPackageName(spi).replace('.','/') + "/" + resourceName;
+            resources = explorer.findResources(resourceName);
+        }
+        
+        return resources.hasNext()
+               ? resources.nextResource()
+               : null;
+    }
+    
+    /**
+     * 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;
+    }
+}

Propchange: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/ResourceUtils.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/SPInterface.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/SPInterface.java?rev=370807&view=auto
==============================================================================
--- directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/SPInterface.java (added)
+++ directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/SPInterface.java Fri Jan 20 05:47:50 2006
@@ -0,0 +1,203 @@
+/*
+ * $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.mina.common.support.discovery.tools;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.mina.common.support.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
+    {
+        verifyAncestory(impl);
+        
+        return ClassUtils.newInstance(impl, paramClasses, params);
+    }
+    
+    public void verifyAncestory(Class impl) {
+        ClassUtils.verifyAncestory(spi, impl);
+    }
+}

Propchange: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/SPInterface.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/Service.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/Service.java?rev=370807&view=auto
==============================================================================
--- directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/Service.java (added)
+++ directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/Service.java Fri Jan 20 05:47:50 2006
@@ -0,0 +1,162 @@
+/*
+ * ====================================================================
+ *
+ * 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.mina.common.support.discovery.tools;
+
+import java.util.Enumeration;
+
+import org.apache.mina.common.support.discovery.ResourceClass;
+import org.apache.mina.common.support.discovery.ResourceClassIterator;
+import org.apache.mina.common.support.discovery.ResourceNameIterator;
+import org.apache.mina.common.support.discovery.resource.ClassLoaders;
+import org.apache.mina.common.support.discovery.resource.classes.DiscoverClasses;
+import org.apache.mina.common.support.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);
+        }
+        
+        ResourceNameIterator servicesIter =
+            (new DiscoverServiceNames(loaders)).findResourceNames(spi.getSPName());
+
+        final ResourceClassIterator services =
+            (new DiscoverClasses(loaders)).findResourceClasses(servicesIter);
+        
+        return new Enumeration() {
+            private Object object = null;
+            
+            public boolean hasMoreElements() {
+                if (object == null) {
+                    object = getNextClassInstance();
+                }
+                return object != null;
+            }
+            
+            public Object nextElement() {
+                Object obj = object;
+                object = null;
+                return obj;
+            }
+
+            private Object getNextClassInstance() {
+                while (services.hasNext()) {
+                    ResourceClass info = services.nextResourceClass();
+                    try {
+                        return spi.newInstance(info.loadClass());
+                    } catch (Exception e) {
+                        // ignore
+                    }
+                }
+                return null;
+            }
+        };
+    }
+}

Propchange: directory/sandbox/trustin/mina-spi/core/src/main/java/org/apache/mina/common/support/discovery/tools/Service.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision