View Javadoc

1   /***************************************************************************************
2    * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved.                 *
3    * http://aspectwerkz.codehaus.org                                                    *
4    * ---------------------------------------------------------------------------------- *
5    * The software in this package is published under the terms of the LGPL license      *
6    * a copy of which has been included with this distribution in the license.txt file.  *
7    **************************************************************************************/
8   package org.codehaus.aspectwerkz.reflect.impl.javassist;
9   
10  import gnu.trove.TIntObjectHashMap;
11  import org.codehaus.aspectwerkz.reflect.ClassInfo;
12  
13  import java.lang.ref.WeakReference;
14  import java.util.Map;
15  import java.util.WeakHashMap;
16  
17  import javassist.CtClass;
18  
19  /***
20   * A repository for the class info hierarchy. Is class loader aware. <p/>TODO refactor some with JavaClassInfoRepository
21   * but keep em separate for system runtime sake in AOPC (WLS)
22   * 
23   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
24   */
25  public class JavassistClassInfoRepository {
26      /***
27       * Map with all the class info repositories mapped to their class loader.
28       */
29      private static final TIntObjectHashMap REPOSITORIES = new TIntObjectHashMap();
30  
31      /***
32       * Map with all the class info mapped to their class names.
33       */
34      private final Map m_repository = new WeakHashMap();
35  
36      /***
37       * Class loader for the class repository.
38       */
39      private transient final WeakReference m_loaderRef;
40  
41      /***
42       * Creates a new repository.
43       * 
44       * @param loader
45       */
46      private JavassistClassInfoRepository(final ClassLoader loader) {
47          m_loaderRef = new WeakReference(loader);
48      }
49  
50      /***
51       * Returns the class info repository for the specific class loader
52       * 
53       * @param loader
54       * @return
55       */
56      public static synchronized JavassistClassInfoRepository getRepository(final ClassLoader loader) {
57          int hash;
58          if (loader == null) { // boot cl
59              hash = 0;
60          } else {
61              hash = loader.hashCode();
62          }
63          WeakReference repositoryRef = (WeakReference) REPOSITORIES.get(hash);
64          JavassistClassInfoRepository repository = ((repositoryRef == null)
65              ? null
66              : (JavassistClassInfoRepository) repositoryRef.get());
67          if (repository != null) {
68              return repository;
69          } else {
70              JavassistClassInfoRepository repo = new JavassistClassInfoRepository(loader);
71              REPOSITORIES.put(hash, new WeakReference(repo));
72              return repo;
73          }
74      }
75  
76      /***
77       * Remove a class from the repository.
78       * 
79       * @param className the name of the class
80       */
81      public static void removeClassInfoFromAllClassLoaders(final String className) {
82          //FIXME - fix algorithm
83          throw new UnsupportedOperationException("fix algorithm");
84      }
85  
86      /***
87       * Returns the class info.
88       * 
89       * @param className
90       * @return
91       */
92      public ClassInfo getClassInfo(final String className) {
93          ClassInfo info = (ClassInfo) m_repository.get(className);
94          if (info == null) {
95              return checkParentClassRepository(className, (ClassLoader) m_loaderRef.get());
96          }
97          return (ClassInfo) m_repository.get(className);
98      }
99  
100     /***
101      * Adds a new class info.
102      * 
103      * @param classInfo
104      */
105     public void addClassInfo(final ClassInfo classInfo) {
106         // is the class loaded by a class loader higher up in the hierarchy?
107         if (checkParentClassRepository(classInfo.getName(), (ClassLoader) m_loaderRef.get()) == null) {
108             m_repository.put(new String(classInfo.getName()), classInfo);
109         } else {
110             // FIXME remove class in child class repository and add it for the current (parent) CL
111         }
112     }
113 
114     /***
115      * Checks if the class info for a specific class exists.
116      * 
117      * @param name
118      * @return
119      */
120     public boolean hasClassInfo(final String name) {
121         return m_repository.containsKey(name);
122     }
123 
124     /***
125      * Searches for a class info up in the class loader hierarchy.
126      * 
127      * @param className
128      * @param loader
129      * @return the class info
130      * @TODO might clash for specific class loader lookup algorithms, user need to override this class and implement
131      *       this method
132      */
133     public ClassInfo checkParentClassRepository(final String className, final ClassLoader loader) {
134         if (loader == null) {
135             return null;
136         }
137         ClassInfo info;
138         ClassLoader parent = loader.getParent();
139         if (parent == null) {
140             return null;
141         } else {
142             info = JavassistClassInfoRepository.getRepository(parent).getClassInfo(className);
143             if (info != null) {
144                 return info;
145             } else {
146                 return checkParentClassRepository(className, parent);
147             }
148         }
149     }
150 
151     /***
152      * Removes the class from the repository (since it has been modified and needs to be rebuild).
153      * 
154      * @param clazz
155      */
156     public void removeClassInfo(final CtClass clazz) {
157         m_repository.remove(clazz.getName());
158     }
159 }