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) {
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
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
132 if (checkParentClassRepository(classInfo.getName(), (ClassLoader) m_loaderRef.get()) == null) {
133 m_repository.put(classInfo.getName().hashCode(), new SoftReference(classInfo));
134 } else {
135
136
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 }