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.Iterator;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.velocity.runtime.log.Log;
29  
30  /**
31   * This is the internal introspector cache implementation.
32   *
33   * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
34   * @version $Id: IntrospectorCacheImpl.java 685685 2008-08-13 21:43:27Z nbubna $
35   * @since 1.5
36   */
37  public final class IntrospectorCacheImpl implements IntrospectorCache
38  {
39      /**
40       * define a public string so that it can be looked for if interested
41       */
42      public final static String CACHEDUMP_MSG =
43          "IntrospectorCache detected classloader change. Dumping cache.";
44  
45      /** Class logger */
46      private final Log log;
47      
48      /**
49       * Holds the method maps for the classes we know about. Map: Class --&gt; ClassMap object.
50       */
51      private final Map classMapCache = new HashMap();
52  
53      /**
54       * Keep the names of the classes in another map. This is needed for a multi-classloader environment where it is possible
55       * to have Class 'Foo' loaded by a classloader and then get asked to introspect on 'Foo' from another class loader. While these
56       * two Class objects have the same name, a <code>classMethodMaps.get(Foo.class)</code> will return null. For that case, we
57       * keep a set of class names to recognize this case.  
58       */
59      private final Set classNameCache = new HashSet();
60  
61      /**
62       * C'tor
63       */
64      public IntrospectorCacheImpl(final Log log)
65      {
66  	    this.log = log;
67      }
68  
69      /**
70       * Clears the internal cache.
71       */
72      public void clear()
73      {
74          synchronized (classMapCache)
75          {
76              classMapCache.clear();
77              classNameCache.clear();
78              log.debug(CACHEDUMP_MSG);
79          }
80      }
81  
82      /**
83       * Lookup a given Class object in the cache. If it does not exist, 
84       * check whether this is due to a class change and purge the caches
85       * eventually.
86       *
87       * @param c The class to look up.
88       * @return A ClassMap object or null if it does not exist in the cache.
89       */
90      public ClassMap get(final Class c)
91      {
92          if (c == null)
93          {
94              throw new IllegalArgumentException("class is null!");
95          }
96  
97          ClassMap classMap = (ClassMap)classMapCache.get(c);
98          if (classMap == null)
99          {
100             /*
101              * check to see if we have it by name.
102              * if so, then we have an object with the same
103              * name but loaded through a different class loader.
104              * In that case, we will just dump the cache to be sure.
105              */
106             synchronized (classMapCache)
107             {
108                 if (classNameCache.contains(c.getName()))
109                 {
110                     clear();
111                 }
112             }
113         }
114         return classMap;
115     }
116 
117     /**
118      * Creates a class map for specific class and registers it in the
119      * cache.  Also adds the qualified name to the name-&gt;class map
120      * for later Classloader change detection.
121      *
122      * @param c The class for which the class map gets generated.
123      * @return A ClassMap object.
124      */
125     public ClassMap put(final Class c)
126     {
127         final ClassMap classMap = new ClassMap(c, log);
128         synchronized (classMapCache)
129         {
130             classMapCache.put(c, classMap);
131             classNameCache.add(c.getName());
132         }
133         return classMap;
134     }
135 
136 }