001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005:
006: package com.tc.aspectwerkz.reflect.impl.asm;
007:
008: import com.tc.aspectwerkz.exception.DefinitionException;
009: import com.tc.aspectwerkz.reflect.ClassInfo;
010:
011: import java.io.IOException;
012: import java.io.InputStream;
013: import java.lang.ref.Reference;
014: import java.lang.ref.SoftReference;
015: import java.lang.ref.WeakReference;
016: import java.util.HashMap;
017: import java.util.Properties;
018:
019: /**
020: * A repository for the class info hierarchy. Is class loader aware.
021: *
022: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
023: */
024: public class AsmClassInfoRepository {
025: /**
026: * Map with all the class info repositories mapped to their class loader.
027: */
028: private static final HashMap s_repositories = new HashMap();
029:
030: /**
031: * Map with all the class info mapped to their class names.
032: */
033: private final HashMap m_repository = new HashMap();
034:
035: /**
036: * Class loader for the class repository.
037: */
038: private transient final WeakReference m_loaderRef;
039:
040: /**
041: * The annotation properties file.
042: */
043: private final Properties m_annotationProperties;
044:
045: /**
046: * Creates a new repository.
047: *
048: * @param loader
049: */
050: private AsmClassInfoRepository(final ClassLoader loader) {
051: m_loaderRef = new WeakReference(loader);
052: m_annotationProperties = new Properties();
053: if (loader != null) {
054: try {
055: InputStream stream = loader
056: .getResourceAsStream("annotation.properties");
057: if (stream != null) {
058: try {
059: m_annotationProperties.load(stream);
060: } finally {
061: try {
062: stream.close();
063: } catch (Exception e) {
064: //
065: }
066: }
067: }
068: } catch (IOException e) {
069: throw new DefinitionException(
070: "could not find resource [annotation.properties] on classpath");
071: }
072: }
073: }
074:
075: /**
076: * Returns the class info repository for the specific class loader
077: *
078: * @param loader
079: * @return
080: */
081: public static AsmClassInfoRepository getRepository(
082: final ClassLoader loader) {
083: Integer hash = new Integer(loader == null ? 0 : loader
084: .hashCode()); // boot cl
085:
086: synchronized (s_repositories) {
087: AsmClassInfoRepository repository = lookup(hash);
088:
089: // normal return case for existing repositories
090: if (repository != null) {
091: return repository;
092: }
093: }
094:
095: // Construct the repo outside of the lock (see CDV-116)
096: AsmClassInfoRepository repo = new AsmClassInfoRepository(loader);
097:
098: // check again
099: synchronized (s_repositories) {
100: AsmClassInfoRepository repository = lookup(hash);
101:
102: // another thread won, don't replace the mapping
103: if (repository != null) {
104: return repository;
105: }
106:
107: s_repositories.put(hash, new SoftReference(repo));
108: }
109:
110: return repo;
111:
112: }
113:
114: private static AsmClassInfoRepository lookup(Integer hash) {
115: Reference repositoryRef = (Reference) s_repositories.get(hash);
116: return ((repositoryRef == null) ? null
117: : (AsmClassInfoRepository) repositoryRef.get());
118: }
119:
120: /**
121: * Remove a class from the repository.
122: *
123: * @param className the name of the class
124: */
125: public static void removeClassInfoFromAllClassLoaders(
126: final String className) {
127: // TODO - fix algorithm
128: throw new UnsupportedOperationException("fix algorithm");
129: }
130:
131: /**
132: * Returns the class info.
133: *
134: * @param className
135: * @return
136: */
137: public ClassInfo getClassInfo(final String className) {
138: Reference classInfoRef = ((Reference) m_repository
139: .get(new Integer(className.hashCode())));
140: ClassInfo info = classInfoRef == null ? null
141: : (ClassInfo) classInfoRef.get();
142: if (info == null) {
143: return checkParentClassRepository(className,
144: (ClassLoader) m_loaderRef.get());
145: }
146: return info;
147: }
148:
149: /**
150: * Adds a new class info.
151: *
152: * @param classInfo
153: */
154: public void addClassInfo(final ClassInfo classInfo) {
155: // is the class loaded by a class loader higher up in the hierarchy?
156: if (checkParentClassRepository(classInfo.getName(),
157: (ClassLoader) m_loaderRef.get()) == null) {
158: m_repository.put(
159: new Integer(classInfo.getName().hashCode()),
160: new SoftReference(classInfo));
161: } else {
162: // TODO: remove class in child class repository and add it for the
163: // current (parent) CL
164: }
165: }
166:
167: /**
168: * Checks if the class info for a specific class exists.
169: *
170: * @param name
171: * @return
172: */
173: public boolean hasClassInfo(final String name) {
174: Reference classInfoRef = (Reference) m_repository
175: .get(new Integer(name.hashCode()));
176: return (classInfoRef == null) ? false
177: : (classInfoRef.get() != null);
178: }
179:
180: /**
181: * Removes the class from the repository (since it has been modified and needs to be rebuild).
182: *
183: * @param className
184: */
185: public void removeClassInfo(final String className) {
186: m_repository.remove(new Integer(className.hashCode()));
187: }
188:
189: /**
190: * Returns the annotation properties for the specific class loader.
191: *
192: * @return the annotation properties
193: */
194: public Properties getAnnotationProperties() {
195: return m_annotationProperties;
196: }
197:
198: /**
199: * Searches for a class info up in the class loader hierarchy.
200: *
201: * @param className
202: * @param loader
203: * @return the class info
204: * @TODO might clash for specific class loader lookup algorithms, user need to override this class and implement this
205: * method
206: */
207: public ClassInfo checkParentClassRepository(final String className,
208: final ClassLoader loader) {
209: if (loader == null) {
210: return null;
211: }
212: ClassLoader parent = loader.getParent();
213: if (parent == null) {
214: return null;
215: } else {
216: AsmClassInfoRepository parentRep = AsmClassInfoRepository
217: .getRepository(parent);
218:
219: Reference classInfoRef = ((Reference) parentRep.m_repository
220: .get(new Integer(className.hashCode())));
221: ClassInfo info = classInfoRef == null ? null
222: : (ClassInfo) classInfoRef.get();
223: if (info != null) {
224: return info;
225: } else {
226: return checkParentClassRepository(className, parent);
227: }
228: }
229: }
230:
231: /*
232: * public ClassInfo checkParentClassRepository(final String className, final ClassLoader loader) { if (loader == null) {
233: * return null; } ClassLoader parent = loader.getParent(); if (parent == null) { return null; } else { ClassInfo info =
234: * AsmClassInfoRepository.getRepository(parent).getClassInfo(className); if (info != null) { return info; } else {
235: * return checkParentClassRepository(className, parent); } } }
236: */
237:
238: }
|