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.asm;
9   
10  import gnu.trove.TIntObjectHashMap;
11  import org.codehaus.aspectwerkz.reflect.ClassInfo;
12  import org.codehaus.aspectwerkz.exception.DefinitionException;
13  
14  import java.lang.ref.WeakReference;
15  import java.lang.ref.SoftReference;
16  import java.lang.ref.Reference;
17  import java.util.Properties;
18  import java.io.InputStream;
19  import java.io.IOException;
20  
21  /***
22   * A repository for the class info hierarchy. Is class loader aware.
23   *
24   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
25   */
26  public class AsmClassInfoRepository {
27      /***
28       * Map with all the class info repositories mapped to their class loader.
29       */
30      private static final TIntObjectHashMap s_repositories = new TIntObjectHashMap();
31  
32      /***
33       * Map with all the class info mapped to their class names.
34       */
35      private final TIntObjectHashMap m_repository = new TIntObjectHashMap();
36  
37      /***
38       * Class loader for the class repository.
39       */
40      private transient final WeakReference m_loaderRef;
41  
42      /***
43       * The annotation properties file.
44       */
45      private final Properties m_annotationProperties;
46  
47      /***
48       * Creates a new repository.
49       *
50       * @param loader
51       */
52      private AsmClassInfoRepository(final ClassLoader loader) {
53          m_loaderRef = new WeakReference(loader);
54          m_annotationProperties = new Properties();
55          if (loader != null) {
56              try {
57                  InputStream stream = loader.getResourceAsStream("annotation.properties");
58                  if (stream != null) {
59                      try {
60                          m_annotationProperties.load(stream);
61                      } finally {
62                          try {
63                              stream.close();
64                          } catch (Exception e) {
65                              ;
66                          }
67                      }
68                  }
69              } catch (IOException e) {
70                  throw new DefinitionException("could not find resource [annotation.properties] on classpath");
71              }
72          }
73      }
74  
75      /***
76       * Returns the class info repository for the specific class loader
77       *
78       * @param loader
79       * @return
80       */
81      public static synchronized AsmClassInfoRepository getRepository(final ClassLoader loader) {
82          int hash;
83          if (loader == null) { // boot cl
84              hash = 0;
85          } else {
86              hash = loader.hashCode();
87          }
88          Reference repositoryRef = (Reference) s_repositories.get(hash);
89          AsmClassInfoRepository repository = ((repositoryRef == null) ? null : (AsmClassInfoRepository) repositoryRef
90                  .get());
91          if (repository != null) {
92              return repository;
93          } else {
94              AsmClassInfoRepository repo = new AsmClassInfoRepository(loader);
95              s_repositories.put(hash, new SoftReference(repo));
96              return repo;
97          }
98      }
99  
100     /***
101      * Remove a class from the repository.
102      *
103      * @param className the name of the class
104      */
105     public static void removeClassInfoFromAllClassLoaders(final String className) {
106         //TODO - fix algorithm
107         throw new UnsupportedOperationException("fix algorithm");
108     }
109 
110     /***
111      * Returns the class info.
112      *
113      * @param className
114      * @return
115      */
116     public ClassInfo getClassInfo(final String className) {
117         Reference classInfoRef = ((Reference) m_repository.get(className.hashCode()));
118         ClassInfo info = (classInfoRef == null) ? null : (ClassInfo) (classInfoRef.get());
119         if (info == null) {
120             return checkParentClassRepository(className, (ClassLoader) m_loaderRef.get());
121         }
122         return info;
123     }
124 
125     /***
126      * Adds a new class info.
127      *
128      * @param classInfo
129      */
130     public void addClassInfo(final ClassInfo classInfo) {
131         // is the class loaded by a class loader higher up in the hierarchy?
132         if (checkParentClassRepository(classInfo.getName(), (ClassLoader) m_loaderRef.get()) == null) {
133             m_repository.put(classInfo.getName().hashCode(), new SoftReference(classInfo));
134         } else {
135             // TODO: remove class in child class repository and add it for the
136             // current (parent) CL
137         }
138     }
139 
140     /***
141      * Checks if the class info for a specific class exists.
142      *
143      * @param name
144      * @return
145      */
146     public boolean hasClassInfo(final String name) {
147         Reference classInfoRef = (Reference) m_repository.get(name.hashCode());
148         return (classInfoRef == null) ? false : (classInfoRef.get() != null);
149     }
150 
151     /***
152      * Removes the class from the repository (since it has been modified and needs to be rebuild).
153      *
154      * @param className
155      */
156     public void removeClassInfo(final String className) {
157         m_repository.remove(className.hashCode());
158     }
159 
160     /***
161      * Returns the annotation properties for the specific class loader.
162      *
163      * @return the annotation properties
164      */
165     public Properties getAnnotationProperties() {
166         return m_annotationProperties;
167     }
168 
169     /***
170      * Searches for a class info up in the class loader hierarchy.
171      *
172      * @param className
173      * @param loader
174      * @return the class info
175      * @TODO might clash for specific class loader lookup algorithms, user need to override this class and implement
176      * this method
177      */
178     public ClassInfo checkParentClassRepository(final String className, final ClassLoader loader) {
179         if (loader == null) {
180             return null;
181         }
182         ClassInfo info;
183         ClassLoader parent = loader.getParent();
184         if (parent == null) {
185             return null;
186         } else {
187             info = AsmClassInfoRepository.getRepository(parent).getClassInfo(className);
188             if (info != null) {
189                 return info;
190             } else {
191                 return checkParentClassRepository(className, parent);
192             }
193         }
194     }
195 }