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/08/15 21:33:25 UTC

cvs commit: jakarta-commons/discovery/src/java/org/apache/commons/discovery DiscoverSingleton.java

rsitze      2002/08/15 12:33:25

  Modified:    discovery/src/java/org/apache/commons/discovery
                        DiscoverSingleton.java
  Added:       discovery/src/java/org/apache/commons/discovery/tools
                        EnvironmentCache.java
  Log:
  Factored portions of caching out to tools package.
  
  Revision  Changes    Path
  1.1                  jakarta-commons/discovery/src/java/org/apache/commons/discovery/tools/EnvironmentCache.java
  
  Index: EnvironmentCache.java
  ===================================================================
  /*
   * $Header$
   * $Revision$
   * $Date$
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.discovery.tools;
  
  import java.lang.reflect.InvocationTargetException;
  import java.util.Map;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Properties;
  
  import org.apache.commons.discovery.base.Environment;
  import org.apache.commons.discovery.base.ImplClass;
  import org.apache.commons.discovery.base.SPInterface;
  import org.apache.commons.discovery.load.ClassLoaderUtils;
  
  
  /**
   * 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.
   * 
   */
  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(Environment env)
      {
          /**
           * 'null' (bootstrap/system class loader) thread context class loader
           * is ok...  Until we learn otherwise.
           */
          HashMap groups =
              (HashMap)root_cache.get(env.getThreadContextClassLoader());
  
          return (groups != null)
                 ? (HashMap)groups.get(env.getGroupContext())
                 : null;
      }
      
      /**
       * Put service keyed by spi & classLoader.
       */
      public static synchronized void put(Environment env, Object object)
      {
          /**
           * 'null' (bootstrap/system class loader) thread context class loader
           * is ok...  Until we learn otherwise.
           */
          if (object != null)
          {
              HashMap groups =
                  (HashMap)root_cache.get(env.getThreadContextClassLoader());
                  
              if (groups == null) {
                  groups = new HashMap(smallHashSize);
                  root_cache.put(env.getThreadContextClassLoader(), groups);
              }
  
              groups.put(env.getGroupContext(), 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.
           */
          ClassLoader threadContextClassLoader =
              ClassLoaderUtils.getThreadContextClassLoader();
  
          HashMap groups = (HashMap)root_cache.get(threadContextClassLoader);
  
          if (groups != null) {
              Iterator groupIter = groups.values().iterator();
  
              while (groupIter.hasNext()) {
                  Object object = groupIter.next();
              }
              groups.clear();
          }
          root_cache.remove(threadContextClassLoader);
      }
      
      
      /**
       * 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(Environment env) {
          /**
           * 'null' (bootstrap/system class loader) thread context class loader
           * is ok...  Until we learn otherwise.
           */
          HashMap groups =
              (HashMap)root_cache.get(env.getThreadContextClassLoader());
  
          if (groups != null) {
              groups.remove(env.getGroupContext());
          }
      }
  }
  
  
  
  1.5       +40 -134   jakarta-commons/discovery/src/java/org/apache/commons/discovery/DiscoverSingleton.java
  
  Index: DiscoverSingleton.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/discovery/src/java/org/apache/commons/discovery/DiscoverSingleton.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- DiscoverSingleton.java	15 Aug 2002 17:45:46 -0000	1.4
  +++ DiscoverSingleton.java	15 Aug 2002 19:33:25 -0000	1.5
  @@ -70,6 +70,7 @@
   import org.apache.commons.discovery.base.ImplClass;
   import org.apache.commons.discovery.base.SPInterface;
   import org.apache.commons.discovery.load.ClassLoaderUtils;
  +import org.apache.commons.discovery.tools.EnvironmentCache;
   
   
   /**
  @@ -498,9 +499,7 @@
            * Return previously registered service object (not class)
            * for this spi, bound only to current thread context class loader.
            */
  -        Object service = get(env.getThreadContextClassLoader(),
  -                             env.getGroupContext(),
  -                             spi.getSPName());
  +        Object service = get(env, spi.getSPName());
   
           if (service == null) {
               try {
  @@ -508,10 +507,7 @@
                       DiscoverClass.newInstance(env, spi, properties, defaultImpl);
       
                   if (service != null) {
  -                    put(env.getThreadContextClassLoader(),
  -                        env.getGroupContext(),
  -                        spi.getSPName(),
  -                        service);
  +                    put(env, spi.getSPName(), service);
                   }
               } catch (DiscoveryException de) {
                   throw de;
  @@ -557,9 +553,7 @@
            * Return previously registered service object (not class)
            * for this spi, bound only to current thread context class loader.
            */
  -        Object service = get(env.getThreadContextClassLoader(),
  -                             env.getGroupContext(),
  -                             spi.getSPName());
  +        Object service = get(env, spi.getSPName());
   
           if (service == null) {
               try {
  @@ -569,10 +563,7 @@
                                                       defaultImpl);
       
                   if (service != null) {
  -                    put(env.getThreadContextClassLoader(),
  -                        env.getGroupContext(),
  -                        spi.getSPName(),
  -                        service);
  +                    put(env, spi.getSPName(), service);
                   }
               } catch (DiscoveryException de) {
                   throw de;
  @@ -598,31 +589,8 @@
        * Dangling references to objects in that class loader would prevent
        * garbage collection.
        */
  -    public static void release() {
  -        ClassLoader threadContextClassLoader =
  -            ClassLoaderUtils.getThreadContextClassLoader();
  -
  -        /**
  -         * 'null' (bootstrap/system class loader) thread context class loader
  -         * is ok...  Until we learn otherwise.
  -         */
  -        synchronized (root_cache) {
  -            HashMap groups = (HashMap)root_cache.get(threadContextClassLoader);
  -
  -            if (groups != null) {
  -                Iterator groupIter = groups.values().iterator();
  -
  -                while (groupIter.hasNext()) {
  -                    HashMap spis = (HashMap)groupIter.next();
  -                    
  -                    if (spis != null) {
  -                        spis.clear();
  -                    }
  -                }
  -                groups.clear();
  -            }
  -            root_cache.remove(threadContextClassLoader);
  -        }
  +    public static synchronized void release() {
  +        root_cache.release();
       }
       
       
  @@ -632,27 +600,14 @@
        * If the SPI instance implements <code>Service</code>, then call
        * <code>release()</code>.
        */
  -    public static void release(String groupContext) {
  -        ClassLoader threadContextClassLoader =
  -            ClassLoaderUtils.getThreadContextClassLoader();
  -
  -        /**
  -         * 'null' (bootstrap/system class loader) thread context class loader
  -         * is ok...  Until we learn otherwise.
  -         */
  -        synchronized (root_cache) {
  -            HashMap groups = (HashMap)root_cache.get(threadContextClassLoader);
  -
  -            if (groups != null) {
  -                HashMap spis = (HashMap)groups.get(groupContext);
  -                
  -                if (spis != null) {
  -                    spis.clear();
  -                }
  -                groups.remove(groupContext);
  -            }
  -            root_cache.remove(threadContextClassLoader);
  +    public static synchronized void release(String groupContext) {
  +        HashMap spis = (HashMap)root_cache.get(new Environment(groupContext));
  +        
  +        if (spis != null) {
  +            spis.clear();
           }
  +        
  +        root_cache.release(new Environment(groupContext));
       }
   
       /**
  @@ -661,26 +616,11 @@
        * If the SPI instance implements <code>Service</code>, then call
        * <code>release()</code>.
        */
  -    public static void release(String groupContext, Class spiClass) {
  -        ClassLoader threadContextClassLoader =
  -            ClassLoaderUtils.getThreadContextClassLoader();
  -
  -        /**
  -         * 'null' (bootstrap/system class loader) thread context class loader
  -         * is ok...  Until we learn otherwise.
  -         */
  -        if (spiClass != null) {
  -            synchronized (root_cache) {
  -                HashMap groups = (HashMap)root_cache.get(threadContextClassLoader);
  -
  -                if (groups != null) {
  -                    HashMap spis = (HashMap)groups.get(groupContext);
  -
  -                    if (spis != null) {
  -                        spis.remove(spiClass.getName());
  -                    }
  -                }
  -            }
  +    public static synchronized void release(String groupContext, Class spiClass) {
  +        HashMap spis = (HashMap)root_cache.get(new Environment(groupContext));
  +        
  +        if (spis != null) {
  +            spis.remove(spiClass.getName());
           }
       }
   
  @@ -690,7 +630,7 @@
        * If the SPI instance implements <code>Service</code>, then call
        * <code>release()</code>.
        */
  -    public static void release(Class spiClass) {
  +    public static synchronized void release(Class spiClass) {
           release(Environment.defaultGroupContext, spiClass);
       }
       
  @@ -723,75 +663,41 @@
        */
   
       /**
  -     * Allows null key, important as default groupContext is null.
  +     * Implements first two levels of the cache (loader & groupContext).
  +     * Allows null keys, important as default groupContext is null.
        */
  -    private static final HashMap root_cache = new HashMap();
  +    private static final EnvironmentCache root_cache = new EnvironmentCache();
   
       /**
  -     * Initial hash size for SPI's, default just seem TO big today..
  -     */
  -    private static final int smallHashSize = 13;
  -    
  -    /**
        * Get service keyed by spi & classLoader.
        */
  -    static Object get(ClassLoader loader, String groupContext, String spiName)
  +    private static synchronized Object get(Environment env,
  +                                           String spiName)
       {
  -        Object service = null;
  -
  -        /**
  -         * 'null' (bootstrap/system class loader) thread context class loader
  -         * is ok...  Until we learn otherwise.
  -         */
  -        synchronized (root_cache) {
  -            HashMap groups =
  -                (HashMap)root_cache.get(loader);
  -
  -            if (groups != null) {
  -                HashMap spis =
  -                    (HashMap)groups.get(groupContext);
  -
  -                if (spis != null) {
  -                    
  -                    service = (Object)spis.get(spiName);
  -                }
  -            }
  -        }
  -
  -        return service;
  +        HashMap spis = (HashMap)root_cache.get(env);
  +        
  +        return (spis != null)
  +               ? spis.get(spiName)
  +               : null;
       }
       
       /**
        * Put service keyed by spi & classLoader.
        */
  -    static void put(ClassLoader loader, String groupContext, String spiName,
  -                    Object service)
  +    private static synchronized void put(Environment env,
  +                                         String spiName,
  +                                         Object service)
       {
  -        /**
  -         * 'null' (bootstrap/system class loader) thread context class loader
  -         * is ok...  Until we learn otherwise.
  -         */
           if (service != null)
           {
  -            synchronized (root_cache) {
  -                HashMap groups =
  -                    (HashMap)root_cache.get(loader);
  -                    
  -                if (groups == null) {
  -                    groups = new HashMap(smallHashSize);
  -                    root_cache.put(loader, groups);
  -                }
  -
  -                HashMap spis =
  -                    (HashMap)groups.get(groupContext);
  -
  -                if (spis == null) {
  -                    spis = new HashMap(smallHashSize);
  -                    groups.put(groupContext, spis);
  -                }
  -
  -                spis.put(spiName, service);
  +            HashMap spis = (HashMap)root_cache.get(env);
  +            
  +            if (spis == null) {
  +                spis = new HashMap(root_cache.smallHashSize);
  +                root_cache.put(env, spis);
               }
  +            
  +            spis.put(spiName, service);
           }
       }
   }
  
  
  

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