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 import java.util.Map; 021 022 import org.apache.commons.discovery.jdk.JDKHooks; 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 public class EnvironmentCache { 042 043 /** 044 * Allows null key, important as default groupContext is null. 045 * 046 * We will manage synchronization directly, so all caches are implemented 047 * as HashMap (unsynchronized). 048 */ 049 private static final Map<ClassLoader, Map<String, Object>> root_cache = 050 new HashMap<ClassLoader, Map<String, Object>>(); 051 052 /** 053 * Initial hash size for SPI's, default just seem TO big today.. 054 */ 055 public static final int smallHashSize = 13; 056 057 /** 058 * Get object keyed by classLoader. 059 * 060 * @param classLoader The class loader key 061 * @return The SPI name/instance cache 062 */ 063 public static synchronized Map<String, Object> get(ClassLoader classLoader) { 064 /* 065 * 'null' (bootstrap/system class loader) thread context class loader 066 * is ok... Until we learn otherwise. 067 */ 068 return root_cache.get(classLoader); 069 } 070 071 /** 072 * Put service keyed by spi & classLoader. 073 * 074 * @param classLoader The class loader key 075 * @param spis The SPI name/instance cache 076 */ 077 public static synchronized void put(ClassLoader classLoader, Map<String, Object> spis) { 078 /* 079 * 'null' (bootstrap/system class loader) thread context class loader 080 * is ok... Until we learn otherwise. 081 */ 082 if (spis != null) { 083 root_cache.put(classLoader, spis); 084 } 085 } 086 087 /********************** CACHE-MANAGEMENT SUPPORT **********************/ 088 089 /** 090 * Release all internal references to previously created service 091 * instances associated with the current thread context class loader. 092 * The <code>release()</code> method is called for service instances that 093 * implement the <code>Service</code> interface. 094 * 095 * This is useful in environments like servlet containers, 096 * which implement application reloading by throwing away a ClassLoader. 097 * Dangling references to objects in that class loader would prevent 098 * garbage collection. 099 */ 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 }