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;
9   
10  import gnu.trove.TIntObjectHashMap;
11  
12  import java.lang.ref.WeakReference;
13  import java.util.Map;
14  import java.util.WeakHashMap;
15  
16  /***
17   * A repository for the class info hierarchy. Is class loader aware.
18   * 
19   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
20   */
21  public class ClassInfoRepository {
22      /***
23       * Map with all the class info repositories mapped to their class loader.
24       */
25      private static final TIntObjectHashMap s_repositories = new TIntObjectHashMap();
26  
27      /***
28       * Map with all the class info mapped to their class names.
29       */
30      private final Map m_repository = new WeakHashMap();
31  
32      /***
33       * Class loader for the class repository.
34       */
35      private transient final WeakReference m_loaderRef;
36  
37      /***
38       * Creates a new repository.
39       * 
40       * @param loader
41       */
42      private ClassInfoRepository(final ClassLoader loader) {
43          m_loaderRef = new WeakReference(loader);
44      }
45  
46      /***
47       * Returns the class info repository for the specific class loader
48       * 
49       * @param loader
50       * @return
51       */
52      public static synchronized ClassInfoRepository getRepository(final ClassLoader loader) {
53          int hash;
54          if (loader == null) { // boot cl
55              hash = 0;
56          } else {
57              hash = loader.hashCode();
58          }
59          WeakReference repositoryRef = (WeakReference) s_repositories.get(hash);
60          ClassInfoRepository repository = ((repositoryRef == null) ? null : (ClassInfoRepository) repositoryRef.get());
61          if (repository != null) {
62              return repository;
63          } else {
64              ClassInfoRepository repo = new ClassInfoRepository(loader);
65              s_repositories.put(hash, new WeakReference(repo));
66              return repo;
67          }
68      }
69  
70      /***
71       * Remove a class from the repository.
72       * 
73       * @param className the name of the class
74       */
75      public static void removeClassInfoFromAllClassLoaders(final String className) {
76          //TODO - fix algorithm
77          throw new UnsupportedOperationException("fix algorithm");
78      }
79  
80      /***
81       * Returns the class info.
82       * 
83       * @param className
84       * @return
85       */
86      public ClassInfo getClassInfo(final String className) {
87          ClassInfo info = (ClassInfo) m_repository.get(className);
88          if (info == null) {
89              return checkParentClassRepository(className, (ClassLoader) m_loaderRef.get());
90          }
91          return (ClassInfo) m_repository.get(className);
92      }
93  
94      /***
95       * Adds a new class info.
96       * 
97       * @param classInfo
98       */
99      public void addClassInfo(final ClassInfo classInfo) {
100         // is the class loaded by a class loader higher up in the hierarchy?
101         if (checkParentClassRepository(classInfo.getName(), (ClassLoader) m_loaderRef.get()) == null) {
102             // need to create new String instance to avoid using the original reference
103             m_repository.put(new String(classInfo.getName()), classInfo);
104         } else {
105             // TODO: remove class in child class repository and add it for the current (parent) CL
106         }
107     }
108 
109     /***
110      * Checks if the class info for a specific class exists.
111      * 
112      * @param name
113      * @return
114      */
115     public boolean hasClassInfo(final String name) {
116         return m_repository.containsKey(name);
117     }
118 
119     /***
120      * Searches for a class info up in the class loader hierarchy.
121      * 
122      * @param className
123      * @param loader
124      * @return the class info
125      * @TODO might clash for specific class loader lookup algorithms, user need to override this class and implement
126      *       this method
127      */
128     public ClassInfo checkParentClassRepository(final String className, final ClassLoader loader) {
129         if (loader == null) {
130             return null;
131         }
132         ClassInfo info;
133         ClassLoader parent = loader.getParent();
134         if (parent == null) {
135             return null;
136         } else {
137             info = ClassInfoRepository.getRepository(parent).getClassInfo(className);
138             if (info != null) {
139                 return info;
140             } else {
141                 return checkParentClassRepository(className, parent);
142             }
143         }
144     }
145 }