1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.discovery.tools; 18 19 import java.util.HashMap; 20 import java.util.Map; 21 22 import org.apache.commons.discovery.jdk.JDKHooks; 23 24 /** 25 * Cache by a 'key' unique to the environment: 26 * 27 * - ClassLoader::groupContext::Object Cache 28 * Cache : HashMap 29 * Key : Thread Context Class Loader (<code>ClassLoader</code>) 30 * Value : groupContext::SPI Cache (<code>HashMap</code>) 31 * 32 * //- groupContext::Object Cache 33 * // Cache : HashMap 34 * // Key : groupContext (<code>String</code>) 35 * // Value : <code>Object</code> 36 * 37 * When we 'release', it is expected that the caller of the 'release' 38 * have the same thread context class loader... as that will be used 39 * to identify cached entries to be released. 40 */ 41 public class EnvironmentCache { 42 43 /** 44 * Allows null key, important as default groupContext is null. 45 * 46 * We will manage synchronization directly, so all caches are implemented 47 * as HashMap (unsynchronized). 48 */ 49 private static final Map<ClassLoader, Map<String, Object>> root_cache = 50 new HashMap<ClassLoader, Map<String, Object>>(); 51 52 /** 53 * Initial hash size for SPI's, default just seem TO big today.. 54 */ 55 public static final int smallHashSize = 13; 56 57 /** 58 * Get object keyed by classLoader. 59 * 60 * @param classLoader The class loader key 61 * @return The SPI name/instance cache 62 */ 63 public static synchronized Map<String, Object> get(ClassLoader classLoader) { 64 /* 65 * 'null' (bootstrap/system class loader) thread context class loader 66 * is ok... Until we learn otherwise. 67 */ 68 return root_cache.get(classLoader); 69 } 70 71 /** 72 * Put service keyed by spi & classLoader. 73 * 74 * @param classLoader The class loader key 75 * @param spis The SPI name/instance cache 76 */ 77 public static synchronized void put(ClassLoader classLoader, Map<String, Object> spis) { 78 /* 79 * 'null' (bootstrap/system class loader) thread context class loader 80 * is ok... Until we learn otherwise. 81 */ 82 if (spis != null) { 83 root_cache.put(classLoader, spis); 84 } 85 } 86 87 /********************** CACHE-MANAGEMENT SUPPORT **********************/ 88 89 /** 90 * Release all internal references to previously created service 91 * instances associated with the current thread context class loader. 92 * The <code>release()</code> method is called for service instances that 93 * implement the <code>Service</code> interface. 94 * 95 * This is useful in environments like servlet containers, 96 * which implement application reloading by throwing away a ClassLoader. 97 * Dangling references to objects in that class loader would prevent 98 * garbage collection. 99 */ 100 public static synchronized void release() { 101 /* 102 * 'null' (bootstrap/system class loader) thread context class loader 103 * is ok... Until we learn otherwise. 104 */ 105 root_cache.remove(JDKHooks.getJDKHooks().getThreadContextClassLoader()); 106 } 107 108 /** 109 * Release any internal references to a previously created service 110 * instance associated with the current thread context class loader. 111 * If the SPI instance implements <code>Service</code>, then call 112 * <code>release()</code>. 113 * 114 * @param classLoader The class loader key 115 */ 116 public static synchronized void release(ClassLoader classLoader) { 117 /* 118 * 'null' (bootstrap/system class loader) thread context class loader 119 * is ok... Until we learn otherwise. 120 */ 121 root_cache.remove(classLoader); 122 } 123 124 }