001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.reflect;
005:
006: import java.lang.ref.WeakReference;
007: import java.util.HashMap;
008: import java.util.Map;
009: import java.util.WeakHashMap;
010:
011: /**
012: * A repository for the class info hierarchy. Is class loader aware.
013: *
014: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
015: */
016: public class ClassInfoRepository {
017: /**
018: * Map with all the class info repositories mapped to their class loader.
019: */
020: private static final HashMap s_repositories = new HashMap();
021:
022: /**
023: * Map with all the class info mapped to their class names.
024: */
025: private final Map m_repository = new WeakHashMap();
026:
027: /**
028: * Class loader for the class repository.
029: */
030: private transient final WeakReference m_loaderRef;
031:
032: /**
033: * Creates a new repository.
034: *
035: * @param loader
036: */
037: private ClassInfoRepository(final ClassLoader loader) {
038: m_loaderRef = new WeakReference(loader);
039: }
040:
041: /**
042: * Returns the class info repository for the specific class loader
043: *
044: * @param loader
045: * @return
046: */
047: public static synchronized ClassInfoRepository getRepository(
048: final ClassLoader loader) {
049: Integer hash = new Integer(loader == null ? 0 : loader
050: .hashCode()); // boot cl
051: WeakReference repositoryRef = (WeakReference) s_repositories
052: .get(hash);
053: ClassInfoRepository repository = repositoryRef == null ? null
054: : (ClassInfoRepository) repositoryRef.get();
055: if (repository != null) {
056: return repository;
057: } else {
058: ClassInfoRepository repo = new ClassInfoRepository(loader);
059: s_repositories.put(hash, new WeakReference(repo));
060: return repo;
061: }
062: }
063:
064: /**
065: * Remove a class from the repository.
066: *
067: * @param className the name of the class
068: */
069: public static void removeClassInfoFromAllClassLoaders(
070: final String className) {
071: //TODO - fix algorithm
072: throw new UnsupportedOperationException("fix algorithm");
073: }
074:
075: /**
076: * Returns the class info.
077: *
078: * @param className
079: * @return
080: */
081: public ClassInfo getClassInfo(final String className) {
082: ClassInfo info = (ClassInfo) m_repository.get(className);
083: if (info == null) {
084: return checkParentClassRepository(className,
085: (ClassLoader) m_loaderRef.get());
086: }
087: return (ClassInfo) m_repository.get(className);
088: }
089:
090: /**
091: * Adds a new class info.
092: *
093: * @param classInfo
094: */
095: public void addClassInfo(final ClassInfo classInfo) {
096: // is the class loaded by a class loader higher up in the hierarchy?
097: if (checkParentClassRepository(classInfo.getName(),
098: (ClassLoader) m_loaderRef.get()) == null) {
099: // need to create new String instance to avoid using the original reference
100: m_repository
101: .put(new String(classInfo.getName()), classInfo);
102: } else {
103: // TODO: remove class in child class repository and add it for the current (parent) CL
104: }
105: }
106:
107: /**
108: * Checks if the class info for a specific class exists.
109: *
110: * @param name
111: * @return
112: */
113: public boolean hasClassInfo(final String name) {
114: return m_repository.containsKey(name);
115: }
116:
117: /**
118: * Searches for a class info up in the class loader hierarchy.
119: *
120: * @param className
121: * @param loader
122: * @return the class info
123: * @TODO might clash for specific class loader lookup algorithms, user need to override this class and implement
124: * this method
125: */
126: public ClassInfo checkParentClassRepository(final String className,
127: final ClassLoader loader) {
128: if (loader == null) {
129: return null;
130: }
131: ClassInfo info;
132: ClassLoader parent = loader.getParent();
133: if (parent == null) {
134: return null;
135: } else {
136: info = ClassInfoRepository.getRepository(parent)
137: .getClassInfo(className);
138: if (info != null) {
139: return info;
140: } else {
141: return checkParentClassRepository(className, parent);
142: }
143: }
144: }
145: }
|