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) {
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
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
124 if (checkParentClassRepository(classInfo.getName(), (ClassLoader) m_loaderRef.get()) == null) {
125 m_repository.put(classInfo.getName().hashCode(), new SoftReference(classInfo));
126 } else {
127
128
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 }