View Javadoc

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 }