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