View Javadoc

1   package org.apache.velocity.util.introspection;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.apache.velocity.runtime.log.Log;
28  
29  /**
30   * This is the internal introspector cache implementation.
31   *
32   * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
33   * @version $Id: IntrospectorCacheImpl.java 898032 2010-01-11 19:51:03Z nbubna $
34   * @since 1.5
35   */
36  public final class IntrospectorCacheImpl implements IntrospectorCache
37  {
38      /**
39       * define a public string so that it can be looked for if interested
40       */
41      public final static String CACHEDUMP_MSG =
42          "IntrospectorCache detected classloader change. Dumping cache.";
43  
44      /** Class logger */
45      private final Log log;
46      
47      /**
48       * Holds the method maps for the classes we know about. Map: Class --&gt; ClassMap object.
49       */
50      private final Map classMapCache = new HashMap();
51  
52      /**
53       * Keep the names of the classes in another map. This is needed for a multi-classloader environment where it is possible
54       * to have Class 'Foo' loaded by a classloader and then get asked to introspect on 'Foo' from another class loader. While these
55       * two Class objects have the same name, a <code>classMethodMaps.get(Foo.class)</code> will return null. For that case, we
56       * keep a set of class names to recognize this case.  
57       */
58      private final Set classNameCache = new HashSet();
59  
60      /**
61       * C'tor
62       */
63      public IntrospectorCacheImpl(final Log log)
64      {
65  	    this.log = log;
66      }
67  
68      /**
69       * Clears the internal cache.
70       */
71      public void clear()
72      {
73          synchronized (classMapCache)
74          {
75              classMapCache.clear();
76              classNameCache.clear();
77              log.debug(CACHEDUMP_MSG);
78          }
79      }
80  
81      /**
82       * Lookup a given Class object in the cache. If it does not exist, 
83       * check whether this is due to a class change and purge the caches
84       * eventually.
85       *
86       * @param c The class to look up.
87       * @return A ClassMap object or null if it does not exist in the cache.
88       */
89      public ClassMap get(final Class c)
90      {
91          if (c == null)
92          {
93              throw new IllegalArgumentException("class is null!");
94          }
95  
96          ClassMap classMap = (ClassMap)classMapCache.get(c);
97          if (classMap == null)
98          {
99              /*
100              * check to see if we have it by name.
101              * if so, then we have an object with the same
102              * name but loaded through a different class loader.
103              * In that case, we will just dump the cache to be sure.
104              */
105             synchronized (classMapCache)
106             {
107                 if (classNameCache.contains(c.getName()))
108                 {
109                     clear();
110                 }
111             }
112         }
113         return classMap;
114     }
115 
116     /**
117      * Creates a class map for specific class and registers it in the
118      * cache.  Also adds the qualified name to the name-&gt;class map
119      * for later Classloader change detection.
120      *
121      * @param c The class for which the class map gets generated.
122      * @return A ClassMap object.
123      */
124     public ClassMap put(final Class c)
125     {
126         final ClassMap classMap = new ClassMap(c, log);
127         synchronized (classMapCache)
128         {
129             classMapCache.put(c, classMap);
130             classNameCache.add(c.getName());
131         }
132         return classMap;
133     }
134 
135 }