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