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 }