001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.discovery.tools;
018
019 import java.util.HashMap;
020
021 import org.apache.commons.discovery.jdk.JDKHooks;
022
023
024 /**
025 * Cache by a 'key' unique to the environment:
026 *
027 * - ClassLoader::groupContext::Object Cache
028 * Cache : HashMap
029 * Key : Thread Context Class Loader (<code>ClassLoader</code>)
030 * Value : groupContext::SPI Cache (<code>HashMap</code>)
031 *
032 * //- groupContext::Object Cache
033 * // Cache : HashMap
034 * // Key : groupContext (<code>String</code>)
035 * // Value : <code>Object</code>
036 *
037 * When we 'release', it is expected that the caller of the 'release'
038 * have the same thread context class loader... as that will be used
039 * to identify cached entries to be released.
040 *
041 * @author Richard A. Sitze
042 */
043 public class EnvironmentCache {
044 /**
045 * Allows null key, important as default groupContext is null.
046 *
047 * We will manage synchronization directly, so all caches are implemented
048 * as HashMap (unsynchronized).
049 *
050 */
051 private static final HashMap root_cache = new HashMap();
052
053 /**
054 * Initial hash size for SPI's, default just seem TO big today..
055 */
056 public static final int smallHashSize = 13;
057
058 /**
059 * Get object keyed by classLoader.
060 */
061 public static synchronized Object get(ClassLoader classLoader)
062 {
063 /**
064 * 'null' (bootstrap/system class loader) thread context class loader
065 * is ok... Until we learn otherwise.
066 */
067 return root_cache.get(classLoader);
068 }
069
070 /**
071 * Put service keyed by spi & classLoader.
072 */
073 public static synchronized void put(ClassLoader classLoader, Object object)
074 {
075 /**
076 * 'null' (bootstrap/system class loader) thread context class loader
077 * is ok... Until we learn otherwise.
078 */
079 if (object != null) {
080 root_cache.put(classLoader, object);
081 }
082 }
083
084
085 /********************** CACHE-MANAGEMENT SUPPORT **********************/
086
087 /**
088 * Release all internal references to previously created service
089 * instances associated with the current thread context class loader.
090 * The <code>release()</code> method is called for service instances that
091 * implement the <code>Service</code> interface.
092 *
093 * This is useful in environments like servlet containers,
094 * which implement application reloading by throwing away a ClassLoader.
095 * Dangling references to objects in that class loader would prevent
096 * garbage collection.
097 */
098 public static synchronized void release() {
099 /**
100 * 'null' (bootstrap/system class loader) thread context class loader
101 * is ok... Until we learn otherwise.
102 */
103 root_cache.remove(JDKHooks.getJDKHooks().getThreadContextClassLoader());
104 }
105
106
107 /**
108 * Release any internal references to a previously created service
109 * instance associated with the current thread context class loader.
110 * If the SPI instance implements <code>Service</code>, then call
111 * <code>release()</code>.
112 */
113 public static synchronized void release(ClassLoader classLoader) {
114 /**
115 * 'null' (bootstrap/system class loader) thread context class loader
116 * is ok... Until we learn otherwise.
117 */
118 root_cache.remove(classLoader);
119 }
120 }