/************************************************************************************** * Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved. * * http://aspectwerkz.codehaus.org * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the LGPL license * * a copy of which has been included with this distribution in the license.txt file. * **************************************************************************************/ package org.codehaus.aspectwerkz.reflect.impl.asm; import gnu.trove.TIntObjectHashMap; import org.codehaus.aspectwerkz.reflect.ClassInfo; import org.codehaus.aspectwerkz.exception.DefinitionException; import java.lang.ref.WeakReference; import java.lang.ref.SoftReference; import java.lang.ref.Reference; import java.util.Properties; import java.io.InputStream; import java.io.IOException; /** * A repository for the class info hierarchy. Is class loader aware. * * @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a> */ public class AsmClassInfoRepository { /** * Map with all the class info repositories mapped to their class loader. */ private static final TIntObjectHashMap s_repositories = new TIntObjectHashMap(); /** * Map with all the class info mapped to their class names. */ private final TIntObjectHashMap m_repository = new TIntObjectHashMap(); /** * Class loader for the class repository. */ private transient final WeakReference m_loaderRef; /** * The annotation properties file. */ private final Properties m_annotationProperties; /** * Creates a new repository. * * @param loader */ private AsmClassInfoRepository(final ClassLoader loader) { m_loaderRef = new WeakReference(loader); m_annotationProperties = new Properties(); if (loader != null) { try { InputStream stream = loader.getResourceAsStream("annotation.properties"); if (stream != null) { try { m_annotationProperties.load(stream); } finally { try { stream.close(); } catch (Exception e) { ; } } } } catch (IOException e) { throw new DefinitionException("could not find resource [annotation.properties] on classpath"); } } } /** * Returns the class info repository for the specific class loader * * @param loader * @return */ public static synchronized AsmClassInfoRepository getRepository(final ClassLoader loader) { int hash; if (loader == null) { // boot cl hash = 0; } else { hash = loader.hashCode(); } Reference repositoryRef = (Reference) s_repositories.get(hash); AsmClassInfoRepository repository = ((repositoryRef == null) ? null : (AsmClassInfoRepository) repositoryRef .get()); if (repository != null) { return repository; } else { AsmClassInfoRepository repo = new AsmClassInfoRepository(loader); s_repositories.put(hash, new SoftReference(repo)); return repo; } } /** * Remove a class from the repository. * * @param className the name of the class */ public static void removeClassInfoFromAllClassLoaders(final String className) { //TODO - fix algorithm throw new UnsupportedOperationException("fix algorithm"); } /** * Returns the class info. * * @param className * @return */ public ClassInfo getClassInfo(final String className) { Reference classInfoRef = ((Reference) m_repository.get(className.hashCode())); ClassInfo info = (classInfoRef == null) ? null : (ClassInfo) (classInfoRef.get()); if (info == null) { return checkParentClassRepository(className, (ClassLoader) m_loaderRef.get()); } return info; } /** * Adds a new class info. * * @param classInfo */ public void addClassInfo(final ClassInfo classInfo) { // is the class loaded by a class loader higher up in the hierarchy? if (checkParentClassRepository(classInfo.getName(), (ClassLoader) m_loaderRef.get()) == null) { m_repository.put(classInfo.getName().hashCode(), new SoftReference(classInfo)); } else { // TODO: remove class in child class repository and add it for the // current (parent) CL } } /** * Checks if the class info for a specific class exists. * * @param name * @return */ public boolean hasClassInfo(final String name) { Reference classInfoRef = (Reference) m_repository.get(name.hashCode()); return (classInfoRef == null) ? false : (classInfoRef.get() != null); } /** * Removes the class from the repository (since it has been modified and needs to be rebuild). * * @param className */ public void removeClassInfo(final String className) { m_repository.remove(className.hashCode()); } /** * Returns the annotation properties for the specific class loader. * * @return the annotation properties */ public Properties getAnnotationProperties() { return m_annotationProperties; } /** * Searches for a class info up in the class loader hierarchy. * * @param className * @param loader * @return the class info * @TODO might clash for specific class loader lookup algorithms, user need to override this class and implement * this method */ public ClassInfo checkParentClassRepository(final String className, final ClassLoader loader) { if (loader == null) { return null; } ClassInfo info; ClassLoader parent = loader.getParent(); if (parent == null) { return null; } else { info = AsmClassInfoRepository.getRepository(parent).getClassInfo(className); if (info != null) { return info; } else { return checkParentClassRepository(className, parent); } } } }