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