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                      m_annotationProperties.load(stream);
60                  }
61              } catch (IOException e) {
62                  throw new DefinitionException("could not find resource [annotation.properties] on classpath");
63              }
64          }
65      }
66  
67      /***
68       * Returns the class info repository for the specific class loader
69       * 
70       * @param loader
71       * @return
72       */
73      public static synchronized AsmClassInfoRepository getRepository(final ClassLoader loader) {
74          int hash;
75          if (loader == null) { // boot cl
76              hash = 0;
77          } else {
78              hash = loader.hashCode();
79          }
80          Reference repositoryRef = (Reference) s_repositories.get(hash);
81          AsmClassInfoRepository repository = ((repositoryRef == null) ? null : (AsmClassInfoRepository) repositoryRef
82                  .get());
83          if (repository != null) {
84              return repository;
85          } else {
86              AsmClassInfoRepository repo = new AsmClassInfoRepository(loader);
87              s_repositories.put(hash, new SoftReference(repo));
88              return repo;
89          }
90      }
91  
92      /***
93       * Remove a class from the repository.
94       * 
95       * @param className the name of the class
96       */
97      public static void removeClassInfoFromAllClassLoaders(final String className) {
98          //TODO - fix algorithm
99          throw new UnsupportedOperationException("fix algorithm");
100     }
101 
102     /***
103      * Returns the class info.
104      * 
105      * @param className
106      * @return
107      */
108     public ClassInfo getClassInfo(final String className) {
109         Reference classInfoRef = ((Reference)m_repository.get(className.hashCode()));
110         ClassInfo info = (classInfoRef==null)?null:(ClassInfo)(classInfoRef.get());
111         if (info == null) {
112             return checkParentClassRepository(className, (ClassLoader) m_loaderRef.get());
113         }
114         return info;
115     }
116 
117     /***
118      * Adds a new class info.
119      * 
120      * @param classInfo
121      */
122     public void addClassInfo(final ClassInfo classInfo) {
123         // is the class loaded by a class loader higher up in the hierarchy?
124         if (checkParentClassRepository(classInfo.getName(), (ClassLoader) m_loaderRef.get()) == null) {
125             m_repository.put(classInfo.getName().hashCode(), new SoftReference(classInfo));
126         } else {
127             // TODO: remove class in child class repository and add it for the
128             // current (parent) CL
129         }
130     }
131 
132     /***
133      * Checks if the class info for a specific class exists.
134      * 
135      * @param name
136      * @return
137      */
138     public boolean hasClassInfo(final String name) {
139         Reference classInfoRef = (Reference)m_repository.get(name.hashCode());
140         return (classInfoRef==null)?false:(classInfoRef.get()!=null);
141     }
142 
143     /***
144      * Removes the class from the repository (since it has been modified and needs to be rebuild).
145      * 
146      * @param className
147      */
148     public void removeClassInfo(final String className) {
149         m_repository.remove(className.hashCode());
150     }
151 
152     /***
153      * Returns the annotation properties for the specific class loader.
154      *
155      * @return the annotation properties
156      */
157     public Properties getAnnotationProperties() {
158         return m_annotationProperties;
159     }
160 
161     /***
162      * Searches for a class info up in the class loader hierarchy.
163      * 
164      * @param className
165      * @param loader
166      * @return the class info
167      * @TODO might clash for specific class loader lookup algorithms, user need to override this class and implement
168      *       this method
169      */
170     public ClassInfo checkParentClassRepository(final String className, final ClassLoader loader) {
171         if (loader == null) {
172             return null;
173         }
174         ClassInfo info;
175         ClassLoader parent = loader.getParent();
176         if (parent == null) {
177             return null;
178         } else {
179             info = AsmClassInfoRepository.getRepository(parent).getClassInfo(className);
180             if (info != null) {
181                 return info;
182             } else {
183                 return checkParentClassRepository(className, parent);
184             }
185         }
186     }
187 }