/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.aop;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.scopedpool.ScopedClassPool;
import javassist.scopedpool.ScopedClassPoolFactory;
import org.jboss.aop.advice.AdviceBinding;
import org.jboss.aop.advice.AdviceStack;
import org.jboss.aop.advice.AspectDefinition;
import org.jboss.aop.advice.AspectFactoryWithClassLoader;
import org.jboss.aop.advice.ClassifiedBindingCollection;
import org.jboss.aop.advice.DynamicCFlowDefinition;
import org.jboss.aop.advice.InterceptorFactory;
import org.jboss.aop.advice.PrecedenceDef;
import org.jboss.aop.advice.PrecedenceDefEntry;
import org.jboss.aop.advice.PrecedenceSorter;
import org.jboss.aop.advice.Scope;
import org.jboss.aop.array.ArrayAdvisor;
import org.jboss.aop.array.ArrayBinding;
import org.jboss.aop.array.ArrayReplacement;
import org.jboss.aop.classpool.AOPClassLoaderScopingPolicy;
import org.jboss.aop.classpool.AOPClassPoolRepository;
import org.jboss.aop.instrument.GeneratedAdvisorInstrumentor;
import org.jboss.aop.instrument.Instrumentor;
import org.jboss.aop.instrument.InstrumentorFactory;
import org.jboss.aop.instrument.TransformerCommon;
import org.jboss.aop.introduction.AnnotationIntroduction;
import org.jboss.aop.introduction.InterfaceIntroduction;
import org.jboss.aop.metadata.ClassMetaDataBinding;
import org.jboss.aop.metadata.ClassMetaDataLoader;
import org.jboss.aop.metadata.SimpleClassMetaDataLoader;
import org.jboss.aop.microcontainer.lifecycle.LifecycleCallbackBinding;
import org.jboss.aop.microcontainer.lifecycle.LifecycleManager;
import org.jboss.aop.pointcut.CFlowStack;
import org.jboss.aop.pointcut.DeclareDef;
import org.jboss.aop.pointcut.DynamicCFlow;
import org.jboss.aop.pointcut.Pointcut;
import org.jboss.aop.pointcut.PointcutExpression;
import org.jboss.aop.pointcut.PointcutInfo;
import org.jboss.aop.pointcut.PointcutStats;
import org.jboss.aop.pointcut.Typedef;
import org.jboss.aop.pointcut.ast.ClassExpression;
import org.jboss.aop.util.UnmodifiableEmptyCollections;
import org.jboss.aop.util.logging.AOPLogger;
import org.jboss.logging.Logger;
import org.jboss.util.collection.WeakValueHashMap;
import org.jboss.util.loading.Translatable;
import org.jboss.util.loading.Translator;
/**
* This singleton class manages all pointcuts and metadata.
* Coders can access it via the AspectManager.instance() method.
* <p/>
* It is also the middle man between the ClassLoader and
* the actual class instrumentation as well.
* <p/>
* App Developers that want to create and apply, interceptors,
* pointcuts, or metadata at runtime can also use this object
* to do that.
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @author adrian@jboss.org
* @version $Revision: 75065 $
*/
public class AspectManager
implements Translator
{
private static final Logger logger = AOPLogger.getLogger(AspectManager.class);
/** Indicates that a call to the factory has been made, but it returned null. */
private static final Object NULL_ASPECT = new Object();
/** Lock to be used when lazy creating the collections */
Object lazyCollectionLock = new Object();
/** Advisors registered with this manager/domain */
protected final WeakHashMap<Class<?>, WeakReference<Advisor>> advisors = new WeakHashMap<Class<?>, WeakReference<Advisor>>();
/** A map of domains by class, maintaned by the top level AspectManager */
protected volatile WeakHashMap<Class<?>, WeakReference<Domain>> subDomainsPerClass = UnmodifiableEmptyCollections.EMPTY_WEAK_HASHMAP;
/** A map of domains by name */
protected volatile WeakValueHashMap<String, Domain> subDomainsByName = UnmodifiableEmptyCollections.EMPTY_WEAK_VALUE_HASHMAP;
/** Each domain may have sub domains interested in changes happening in this manager/domain */
protected volatile WeakHashMap<Domain, Object> subscribedSubDomains = UnmodifiableEmptyCollections.EMPTY_WEAK_HASHMAP;
/** A queue for adding new subscribed subdomains to */
protected volatile WeakHashMap<Domain, Object> subscribedSubDomainsQueue = UnmodifiableEmptyCollections.EMPTY_WEAK_HASHMAP;
protected int subscribedDomainQueueRef;
protected volatile LinkedHashMap<String, InterfaceIntroduction> interfaceIntroductions = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
protected volatile LinkedHashMap<String, ArrayReplacement> arrayReplacements = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
protected volatile LinkedHashMap<String, ArrayBinding> arrayBindings = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
protected volatile LinkedHashMap<String, AnnotationIntroduction> annotationIntroductions =UnmodifiableEmptyCollections. EMPTY_LINKED_HASHMAP;
protected volatile LinkedHashMap<String, AnnotationIntroduction> annotationOverrides = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
@Deprecated
protected volatile LinkedHashMap<String, AdviceBinding> bindings = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
volatile ClassifiedBindingCollection bindingCollection;
protected volatile LinkedHashMap<String, Typedef> typedefs = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
protected volatile HashMap<String, InterceptorFactory> interceptorFactories = UnmodifiableEmptyCollections.EMPTY_HASHMAP;
protected volatile HashMap<String,ClassMetaDataLoader> classMetaDataLoaders = UnmodifiableEmptyCollections.EMPTY_HASHMAP;
protected volatile HashMap<String, AdviceStack> interceptorStacks = UnmodifiableEmptyCollections.EMPTY_HASHMAP;
protected volatile HashMap<String, DeclareDef> declares = UnmodifiableEmptyCollections.EMPTY_HASHMAP;
protected volatile ConcurrentHashMap<String, CFlowStack> cflowStacks = UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP;
protected volatile ConcurrentHashMap<String, DynamicCFlowDefinition> dynamicCFlows = UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP;
protected volatile ConcurrentHashMap<String, AspectDefinition> aspectDefinitions = UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP;
protected volatile ConcurrentHashMap<String, Object> perVMAspects = UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP;
/** class name prefixes to explicitly exclude unless contained in include. Maintained by top-level AspectManager */
protected volatile ArrayList<String> exclude = UnmodifiableEmptyCollections.EMPTY_ARRAYLIST;
/** class name prefixes to explicitly include, this overrides whatever was set in exclude. Maintained by top-level AspectManager */
protected volatile ArrayList<String> include = UnmodifiableEmptyCollections.EMPTY_ARRAYLIST;
/** A set of wildcard enabled classnames that will be ignored no matter if they have been included. Maintained by top-level AspectManager */
protected volatile ArrayList<String> ignore = UnmodifiableEmptyCollections.EMPTY_ARRAYLIST;
/** A set of annotation names that will be included even though they are invisible. */
protected List<String> includeInvisibleAnnotations = Collections .emptyList();
/** ClassExpressions built from ignore. Maintained by top-level AspectManager */
protected ClassExpression[] ignoreExpressions = new ClassExpression[0];
protected volatile LinkedHashMap<String, Pointcut> pointcuts = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
// contains pointcuts-binding association info
protected volatile LinkedHashMap<String, PointcutInfo> pointcutInfos = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
// these fields represent whether there are certain pointcut types.
// for performance reasons the transformers and binders can make a lot of us of this.
protected boolean execution = false;
protected boolean construction = false;
protected boolean call = false;
protected boolean within = false;
protected boolean get = false;
protected boolean set = false;
protected boolean withincode = false;
public static boolean classicOrder = false;
protected volatile LinkedHashMap<String, ClassMetaDataBinding> classMetaData = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
protected volatile HashMap<String, DomainDefinition> containers = UnmodifiableEmptyCollections.EMPTY_HASHMAP;
protected volatile LinkedHashMap<String, PrecedenceDef> precedenceDefs = UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP;
protected PrecedenceDefEntry[] sortedPrecedenceDefEntries;
protected WeavingStrategy weavingStrategy;
protected DynamicAOPStrategy dynamicStrategy = new LoadInterceptedClassesStrategy();
// indicates that the transformation process has begun
protected boolean transformationStarted = false;
/** The classloader scoping policy */
// This shouldn't really be static (artifact of singleton and self-bootstrap design)
private static AOPClassLoaderScopingPolicy classLoaderScopingPolicy;
//Keeps track of if we need to convert references etc for a given class. Domains for scoped classloaders will have their own version of this
protected static InterceptionMarkers interceptionMarkers = new InterceptionMarkers();
// Static -------------------------------------------------------
protected static AspectManager manager;
public static boolean optimize = true;
public static boolean debugClasses;//If true, the generated advisor instrumentor will output the generated classes
public static ClassLoaderValidation classLoaderValidator;
//Keep track of the microcontainer lifecycle callbacks
public LifecycleManager lifecycleManager = new LifecycleManager(this);
/**
* logging switch. We don't use log4j to avoid another heavy library
*/
public static boolean verbose = false;
/**
* Whether or not we should maintain the deprecated Advisor.methodInterceptors field
* This is required in jboss 4.x for backwards compatibility with EJB 3
* See JBAOP-517
*/
public static boolean maintainAdvisorMethodInterceptors;
/**
* Get the top level aspect manager
*
* @return the top level aspect manager
*/
public static synchronized AspectManager getTopLevelAspectManager()
{
if (classLoaderScopingPolicy == null)
{
//We are not running in jboss
return instance();
}
AspectManager result = initManager();
Domain scopedDomain = classLoaderScopingPolicy.getTopLevelDomain(result);
if (scopedDomain != null)
result = scopedDomain;
return result;
}
public static synchronized AspectManager instance()
{
return instance(SecurityActions.getContextClassLoader());
}
/**
* Get the aspect manager for a classloader
*
* @param loadingClassLoader the classloader
* @return the aspect manager
*/
public static synchronized AspectManager instance(ClassLoader loadingClassLoader)
{
AspectManager result = initManager();
if (classLoaderScopingPolicy != null)
{
Domain scopedDomain = classLoaderScopingPolicy.getDomain(loadingClassLoader, result);
if (scopedDomain != null)
result = scopedDomain;
}
return result;
}
/**
* Initialise the manager if not already dones so<p>
*
* This method should be invoked in a synchronized block
*
* @return the manager
*/
private static AspectManager initManager()
{
if (manager == null)
{
AccessController.doPrivileged(new PrivilegedAction<AspectManager>()
{
public AspectManager run()
{
String optimized = System.getProperty("jboss.aop.optimized", null);
if (optimized != null)
{
optimize = (new Boolean(optimized)).booleanValue();
}
String pruneit = System.getProperty("jboss.aop.prune", null);
if (pruneit != null)
{
AOPClassPoolRepository.getInstance().setPrune((new Boolean(pruneit)).booleanValue());
}
manager = new AspectManager();
//Initialise frequently used fields needed by the top-level manager
manager.subDomainsPerClass = new WeakHashMap<Class<?>, WeakReference<Domain>>();
manager.exclude = new ArrayList<String>();
manager.include = new ArrayList<String>();
manager.ignore = new ArrayList<String>();
manager.includeInvisibleAnnotations = new ArrayList<String>();
AOPClassPoolRepository.getInstance().setAspectManager(manager);
if (!verbose)
{
verbose = (new Boolean(System.getProperty("jboss.aop.verbose", "false"))).booleanValue();
}
String exclude = System.getProperty("jboss.aop.exclude", null);
if (exclude != null)
{
ArrayList<String> list = splitString(exclude, ",");
manager.setExclude(list);
}
String include = System.getProperty("jboss.aop.include", null);
if (include != null)
{
ArrayList<String> list = splitString(include, ",");
manager.setInclude(list);
}
String ignore = System.getProperty("jboss.aop.ignore", null);
if (ignore != null)
{
ArrayList<String> list = splitString(ignore, ",");
manager.setIgnore(list);
}
String invisibleAnnotations = System.getProperty("jboss.aop.invisible.annotations", null);
if(invisibleAnnotations != null)
{
ArrayList<String> list = splitString(invisibleAnnotations, ",");
manager.setIncludedInvisibleAnnotations(list);
}
String instrument = System.getProperty("jboss.aop.instrumentor", null);
InstrumentorFactory.initialise(instrument);
String advisorName = System.getProperty("jboss.aop.advisor", null);
AdvisorFactory.initialise(advisorName);
String debugClass = System.getProperty("jboss.aop.debug.classes", null);
if (debugClass != null)
{
debugClasses = (new Boolean(debugClass)).booleanValue();
}
String classic = System.getProperty("jboss.aop.classicorder", null);
if (classic != null)
{
classicOrder = (new Boolean(classic)).booleanValue();
}
String methodInterceptors = System.getProperty("jboss.aop.advisor.methodInterceptors", null);
if (methodInterceptors != null)
{
maintainAdvisorMethodInterceptors = (new Boolean(methodInterceptors)).booleanValue();
}
Deployment.deploy();
return null;
}
});
}
return manager;
}
private static ArrayList<String> splitString(String string, String delim)
{
if (string != null)
{
ArrayList<String> list = new ArrayList<String>();
for(String token : string.split(delim))
{
list.add(token.trim());
}
return list;
}
return null;
}
/**
* Get the classLoaderScopingPolicy.
*
* @return the classLoaderScopingPolicy.
*/
public static AOPClassLoaderScopingPolicy getClassLoaderScopingPolicy()
{
return classLoaderScopingPolicy;
}
/**
* Set the classLoaderScopingPolicy.
*
* TODO does it make sense for this to be modified once it has been set?
* @param classLoaderScopingPolicy the classLoaderScopingPolicy.
*/
public static void setClassLoaderScopingPolicy(AOPClassLoaderScopingPolicy classLoaderScopingPolicy)
{
AspectManager.classLoaderScopingPolicy = classLoaderScopingPolicy;
}
public InterceptionMarkers getInterceptionMarkers()
{
return interceptionMarkers;
}
public LinkedHashMap<String, Pointcut> getPointcuts()
{
return pointcuts;
}
public LinkedHashMap<String, PointcutInfo> getPointcutInfos()
{
return pointcutInfos;
}
public CFlowStack getCFlowStack(String name)
{
return cflowStacks.get(name);
}
public void addCFlowStack(CFlowStack stack)
{
initCflowStacksMap();
cflowStacks.put(stack.getName(), stack);
}
public void removeCFlowStack(String name)
{
cflowStacks.remove(name);
}
public DynamicCFlow getDynamicCFlow(String name)
{
DynamicCFlowDefinition def = dynamicCFlows.get(name);
if (def != null)
{
return def.create();
}
return null;
}
/* (non-Javadoc)
* @see org.jboss.aop.Manager#addDynamicCFlow(java.lang.String, org.jboss.aop.advice.DynamicCFlowDefinition)
*/
public void addDynamicCFlow(String name, DynamicCFlowDefinition cflow)
{
initDynamicCflowsMap();
dynamicCFlows.put(name, cflow);
}
public void removeDynamicCFlow(String name)
{
dynamicCFlows.remove(name);
}
/**
* This is a callback object that receives events about
* new pointcuts, interceptors and metadata.
* The Aspect Management console hooks into this listener
*/
public static AspectNotificationHandler notificationHandler = null;
public static boolean suppressTransformationErrors = false;
/**
* Suppress when a class cannot be found that a class references
* This may happen if code in a class references something and the
* class is not in the classpath.
*/
public static boolean suppressReferenceErrors = true;
// Constructors -------------------------------------------------
/**
* Called by subclasses
*/
public AspectManager()
{
this.bindingCollection = new ClassifiedBindingCollection();
}
/**
* Every <class-metadata> tag corresponds to
* a ClassMetaDataLoader. The ClassMetaDataLoader knows how to take
* arbitrary XML and apply it to SimpleMetaData.
* <p/>
* Given a group, return the loader for that group
*/
public ClassMetaDataLoader findClassMetaDataLoader(String group)
{
ClassMetaDataLoader loader = classMetaDataLoaders.get(group);
if (loader == null) loader = SimpleClassMetaDataLoader.singleton;
return loader;
}
/**
* Every <class-metadata> tag corresponds to
* a ClassMetaDataLoader. The ClassMetaDataLoader knows how to take
* arbitrary XML and apply it to SimpleMetaData.
* <p/>
* Add a loader for a given group
*/
public void addClassMetaDataLoader(String group, ClassMetaDataLoader loader)
{
initClassMetaDataLoadersMap();
classMetaDataLoaders.put(group, loader);
}
/**
* Remove a loader for a given group
*/
public void removeClassMetaDataLoader(String group)
{
classMetaDataLoaders.remove(group);
}
public Map<Class<?>, WeakReference<Advisor>> getAdvisors()
{
return advisors;
}
public Advisor getAdvisor(String name)
{
/*
synchronized (advisors)
{
return (Advisor) advisors.get(name);
}
*/
throw new RuntimeException("OPERATION NOT SUPPORTED ANYMORE");
}
/**
* Returns the binding map.
* <p>
* The returned map must be used for read purposes only. To edit the
* binding collection, call {@link #addBinding(AdviceBinding)} and
* {@link #removeBinding(String)} instead.
*
* @return the map containing all advice bindings indexed by their names
*/
public LinkedHashMap<String, AdviceBinding> getBindings()
{
return bindingCollection.getBindings();
}
/**
* Returns the classified binding collection.
* <p>
* <b>Attention:</b> this collection is not supposed to be edited. Hence, only
* get methods can be called by clients.
*
* @return the classified binding collection
*/
ClassifiedBindingCollection getBindingCollection()
{
return bindingCollection;
}
protected Map<Class<?>, WeakReference<Domain>> getSubDomainsPerClass()
{
return subDomainsPerClass;
}
public Advisor findAdvisor(Class<?> clazz)
{
if (getSubDomainsPerClass().size() > 0)
{
//For generated advisors each advisor has its own domain
//This is primarily needed for the reflection aspect
Domain subDomain = null;
synchronized (getSubDomainsPerClass())
{
WeakReference<Domain> ref = getSubDomainsPerClass().get(clazz);
if (ref != null)
{
subDomain = ref.get();
}
}
if (subDomain != null && subDomain != this)
{
Advisor advisor = subDomain.findAdvisor(clazz);
if (advisor != null)
{
return advisor;
}
}
}
synchronized (advisors)
{
WeakReference<Advisor> ref = advisors.get(clazz);
if (ref == null) return null;
return ref.get();
}
}
/**
* Takes a string of the form /sub1/sub2/sub3 of subdomains by name, where the leading "/" is the main AspectManager.
* The main user of the naming of domains is (un)serialization of advisors/containers
*
* @param The FQN of the domain
* @return the domain referenced by the FQN or null if it does not exist
*/
public AspectManager findManagerByName(String fqn)
{
String[] nameparts = fqn.split("/");
return findManagerByName(nameparts);
}
private AspectManager findManagerByName(String[] nameparts)
{
AspectManager found = this;
for (int i = 0 ; i < nameparts.length ; i++)
{
if (nameparts[i].trim().length() == 0)
{
continue;
}
found = found.findManagerByNameInternal(nameparts[i]);
if (found == null)
{
break;
}
}
return found;
}
private AspectManager findManagerByNameInternal(String name)
{
return subDomainsByName.get(name);
}
protected void addSubDomainByName(Domain domain)
{
initSubDomainsByNameMap();
subDomainsByName.put(domain.getDomainName(), domain);
}
public String getManagerFQN()
{
return "/";
}
public ClassAdvisor getAdvisorIfAdvised(Class<?> clazz)
{
return (ClassAdvisor)getAnyAdvisorIfAdvised(clazz);
}
/**
* Take into account that an advisor may be a container
*/
public Advisor getAnyAdvisorIfAdvised(Class<?> clazz)
{
try
{
Advisor advisor;
advisor = findAdvisor(clazz);
if (advisor == null)
{
return null;
}
if (advisor.getClazz() == null && advisor instanceof ClassAdvisor)
{
((ClassAdvisor)advisor).attachClass(clazz);
if (notificationHandler != null)
{
notificationHandler.attachClass(clazz.getName());
}
}
return advisor;
}
catch (RuntimeException ex)
{
ex.printStackTrace();
throw ex;
}
}
/**
* This method is called by the aspectized class when it is loaded
* This causes all initialization of interceptors for ClassAdvisor
*
* @param clazz
* @return
*/
public synchronized ClassAdvisor getAdvisor(Class<?> clazz)
{
ClassAdvisor advisor = null;
// See if one already exists
advisor = (ClassAdvisor)findAdvisor(clazz);
// if one does not
if (advisor == null)
{
advisor = AdvisorFactory.getClassAdvisor(clazz, this);
initialiseClassAdvisor(clazz, advisor);
}
return advisor;
}
public synchronized void initialiseClassAdvisor(Class<?> clazz, ClassAdvisor advisor)
{
synchronized (advisors)
{
advisors.put(clazz, new WeakReference<Advisor>(advisor));
}
registerClass(clazz);
advisor.attachClass(clazz);
InterceptorChainObserver observer = dynamicStrategy.getInterceptorChainObserver(clazz);
advisor.setInterceptorChainObserver(observer);
if (notificationHandler != null)
{
notificationHandler.attachClass(clazz.getName());
}
}
// Public -------------------------------------------------------
public static Map<ClassLoader, ClassPool> getRegisteredCLs()
{
return AOPClassPoolRepository.getInstance().getRegisteredCLs();
}
/**
* This method will check to see if a register classloader has been undeployed (as in JBoss)
*/
public static void clearUnregisteredClassLoaders()
{
AOPClassPoolRepository.getInstance().clearUnregisteredClassLoaders();
}
/**
* Checks to see if an Advisor represents a class that should have been undeployed.
*
* @param advisor
* @return
*/
public boolean isAdvisorRegistered(Advisor advisor)
{
synchronized (getRegisteredCLs())
{
if (!advisors.containsKey(advisor.getClazz())) return false;
if (classLoaderValidator != null)
{
if (classLoaderValidator.isValidClassLoader(advisor.getClazz().getClassLoader()))
{
return true;
}
else
{
unregisterClassLoader(advisor.getClazz().getClassLoader());
return false;
}
}
else
{
ScopedClassPool pool = (ScopedClassPool) getRegisteredClassPool(advisor.getClazz().getClassLoader());
if (pool == null) return false;
if (pool.isUnloadedClassLoader())
{
unregisterClassLoader(advisor.getClazz().getClassLoader());
return false;
}
else
{
return true;
}
}
}
}
public ClassPool findClassPool(ClassLoader cl)
{
if (!(cl instanceof Translatable))
{
// findClassPool has problems with boot and system classes.
return registerClassLoader(SecurityActions.getContextClassLoader());
}
return registerClassLoader(cl);
}
protected ClassPool getRegisteredClassPool(ClassLoader cl)
{
return getRegisteredCLs().get(cl);
}
public ClassPool registerClassLoader(ClassLoader ucl)
{
return AOPClassPoolRepository.getInstance().registerClassLoader(ucl);
}
protected void registerClass(Class<?> clazz)
{
AOPClassPoolRepository.getInstance().registerClass(clazz);
}
public void unregisterClassLoader(ClassLoader cl)
{
AOPClassPoolRepository.getInstance().unregisterClassLoader(cl);
}
public ArrayList<String> getExclude()
{
return exclude;
}
public void setExclude(ArrayList<String> exclude)
{
this.exclude.clear();
this.exclude.addAll(exclude);
}
public ArrayList<String> getInclude()
{
return include;
}
public void setInclude(ArrayList<String> include)
{
this.include.clear();
this.include.addAll(include);
}
public ArrayList<String> getIgnore()
{
return ignore;
}
public List<String> getIncludedInvisibleAnnotations()
{
return includeInvisibleAnnotations;
}
public void setIncludedInvisibleAnnotations(List<String> ia)
{
includeInvisibleAnnotations.clear();
includeInvisibleAnnotations.addAll(ia);
}
public ClassExpression[] getIgnoreExpressions()
{
return ignoreExpressions;
}
public void setIgnore(ArrayList<String> ignore)
{
this.ignore.clear();
this.ignore.addAll(ignore);
ignoreExpressions = new ClassExpression[ignore.size()];
for (int i = 0 ; i < ignore.size() ; i++)
{
String ex = ignore.get(i);
ignoreExpressions[i] = new ClassExpression(ex);
}
}
public boolean ignoreClass(String classname)
{
ArrayList<String> ignore = getIgnore();
if (ignore == null) return false;
ClassExpression[] ignoreExprs = getIgnoreExpressions();
for (int i = 0; i < ignoreExprs.length; i++)
{
if(ignoreExprs[i].matches(classname)) return true;
}
return false;
}
public boolean includeClass(String classname)
{
ArrayList<String> include = getInclude();
if (include == null) return false;
for (int i = 0; i < include.size(); i++)
{
String str = include.get(i);
if (classname.startsWith(str)) return true;
}
return false;
}
public boolean excludeClass(String classname)
{
ArrayList<String> exclude = getExclude();
if (exclude == null) return false;
for (int i = 0; i < exclude.size(); i++)
{
String str = exclude.get(i);
if (str.equals("*")) return true;
if (classname.startsWith(str)) return true;
}
return false;
}
public static boolean getPrune()
{
return AOPClassPoolRepository.getInstance().isPrune();
}
public static void setPrune(boolean prune)
{
AOPClassPoolRepository.getInstance().setPrune(prune);
}
public static void setClassPoolFactory(ScopedClassPoolFactory factory)
{
AOPClassPoolRepository.getInstance().setClassPoolFactory(factory);
}
public static ScopedClassPoolFactory getClassPoolFactory()
{
return AOPClassPoolRepository.getInstance().getClassPoolFactory();
}
public boolean isNonAdvisableClassName(String classname)
{
if (ignoreClass(classname)) return true;
if (includeClass(classname)) return false;
if (excludeClass(classname)) return true;
return (classname.startsWith("org.jboss.aop.") ||
classname.endsWith("$aop") ||
classname.startsWith("javassist") ||
classname.startsWith("org.jboss.util.") ||
classname.startsWith("gnu.trove.") ||
classname.startsWith("EDU.oswego.cs.dl.util.concurrent.") ||
// System classes
classname.startsWith("org.apache.tools.ant") ||
classname.startsWith("org.apache.crimson") ||
classname.startsWith("org.apache.xalan") ||
classname.startsWith("org.apache.xml") ||
classname.startsWith("org.apache.xpath") ||
classname.startsWith("org.ietf.") ||
classname.startsWith("org.omg.") ||
classname.startsWith("org.w3c.") ||
classname.startsWith("org.xml.sax.") ||
classname.startsWith("sunw.") ||
classname.startsWith("sun.") ||
classname.startsWith("java.") ||
classname.startsWith("javax.") ||
classname.startsWith("com.sun.") ||
classname.startsWith("junit") ||
classname.startsWith("jrockit.") ||
classname.startsWith("com.bea.vm.") ||
classname.startsWith("$Proxy")
);
}
/**
* This is the hook for ClassLoaders that want to instrument their classes with AOP
* <p/>
* This would be called during a findClass or loadClass call. The return value
* is used by defineClass to create the class from bytecode
*/
public byte[] transform(ClassLoader loader,
String className,
@SuppressWarnings(value= {"all"}) Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws Exception
{
byte[] b = translate(className, loader, classfileBuffer);
return b;
}
/**
* This is to be backward compatible with JBoss 3.2.3 Translator interface
*
* @param className
* @param loader
* @return
* @throws Exception
*/
public byte[] translate(String className, ClassLoader loader) throws Exception
{
return translate(className, loader, null);
}
/**
* This is to be backward compatible with JBoss 3.2.3 Translator interface
* TODO: stalep, added a synchronized block for the entire method to prevent
* a deadlock. its not optimal and should be further reviewed.
* (commented out sync block inside the method)
*
* @param className
* @param loader
* @return
* @throws Exception
*/
public synchronized byte[] translate(String className, ClassLoader loader, byte[] classfileBuffer) throws Exception
{
try
{
if (isNonAdvisableClassName(className))
{
return null;
}
if (weavingStrategy == null)
{
if (TransformerCommon.isCompileTime() || classicOrder)
{
weavingStrategy = new ClassicWeavingStrategy();
}
else if(InstrumentorFactory.getInstrumentor(this,dynamicStrategy.getJoinpointClassifier())
instanceof GeneratedAdvisorInstrumentor)
{
weavingStrategy = new SuperClassesFirstWeavingStrategy();
}
else
{
weavingStrategy = new ClassicWeavingStrategy();
}
}
return weavingStrategy.translate(this, className, loader, classfileBuffer);
}
catch (Exception e)
{
// AutoGenerated
throw new RuntimeException(e);
}
}
/**
* Add an interceptor factory that can be referenced by name.
*/
public void addInterceptorFactory(String name, InterceptorFactory factory)
{
initInterceptorFactoriesMap();
synchronized (interceptorFactories)
{
interceptorFactories.put(name, factory);
}
}
/**
* Remove an interceptor factory that can be referenced by name.
*/
public void removeInterceptorFactory(String name)
{
synchronized (interceptorFactories)
{
interceptorFactories.remove(name);
}
}
public Map<String, InterceptorFactory> getInterceptorFactories()
{
return interceptorFactories;
}
/**
* Find the interceptor factory that can be referenced by name.
*/
public InterceptorFactory getInterceptorFactory(String name)
{
synchronized (interceptorFactories)
{
return interceptorFactories.get(name);
}
}
public void addPrecedence(PrecedenceDef precedenceDef)
{
initPrecedenceDefsMap();
synchronized (precedenceDefs)
{
precedenceDefs.put(precedenceDef.getName(), precedenceDef);
}
forceResortPrecedenceDefs();
}
public void removePrecedence(String name)
{
synchronized (precedenceDefs)
{
precedenceDefs.remove(name);
}
forceResortPrecedenceDefs();
}
protected void forceResortPrecedenceDefs()
{
synchronized (precedenceDefs)
{
sortedPrecedenceDefEntries = null;
}
synchronized (subscribedSubDomains)
{
copySubDomainsFromQueue(true);
boolean newSubscribers = true;
while (newSubscribers)
{
for (Domain domain : subscribedSubDomains.keySet())
{
domain.forceResortPrecedenceDefs();
}
newSubscribers = copySubDomainsFromQueue(false);
}
}
}
public LinkedHashMap<String, PrecedenceDef> getPrecedenceDefs()
{
return precedenceDefs;
}
public PrecedenceDefEntry[] getSortedPrecedenceDefEntries()
{
if (sortedPrecedenceDefEntries == null)
{
synchronized (precedenceDefs)
{
if (sortedPrecedenceDefEntries == null)
{
sortedPrecedenceDefEntries = PrecedenceSorter.createOverallPrecedence(this);
}
}
}
return sortedPrecedenceDefEntries;
}
/**
* Add a referencable InterceptorStack( <stack> )
*/
public void addAdviceStack(AdviceStack stack)
{
initInerceptorStacksMap();
synchronized (interceptorStacks)
{
interceptorStacks.put(stack.getName(), stack);
}
}
/**
* Remove a referencable InterceptorStack( <stack> )
*/
public void removeInterceptorStack(String name)
{
synchronized (interceptorStacks)
{
interceptorStacks.remove(name);
}
}
/**
* Find an interceptor stack referenced by name ( <stack> )
*/
public AdviceStack getAdviceStack(String name)
{
synchronized (interceptorStacks)
{
return interceptorStacks.get(name);
}
}
protected boolean attachMetaData(ClassAdvisor advisor, CtClass clazz, boolean addAdvisor) throws Exception
{
boolean attached = false;
synchronized (classMetaData)
{
for (ClassMetaDataBinding data : classMetaData.values())
{
if (data.matches(advisor, clazz))
{
attached = true;
if (addAdvisor) data.addAdvisor(advisor);
ClassMetaDataLoader loader = data.getLoader();
loader.bind(advisor, data, clazz.getDeclaredMethods(), clazz.getDeclaredFields(), clazz.getDeclaredConstructors());
}
}
}
return attached;
}
protected void attachMetaData(Advisor advisor, Class<?> clazz)
{
synchronized (classMetaData)
{
for (ClassMetaDataBinding data : classMetaData.values())
{
addAdvisorToClassMetaDataBinding(data, clazz, advisor, clazz);
}
}
}
public ClassAdvisor getTempClassAdvisor(CtClass clazz) throws Exception
{
ClassAdvisor advisor = AdvisorFactory.getClassAdvisor(clazz, this);
attachMetaData(advisor, clazz, false);
applyInterfaceIntroductions(advisor, clazz);
return advisor;
}
public Advisor getTempClassAdvisorIfNotExist(Class<?> clazz)
{
Advisor advisor = findAdvisor(clazz);
if (advisor != null) return advisor;
if (Advised.class.isAssignableFrom(clazz))
{
Class<?> superClass = clazz;
try
{
while (superClass != null)
{
try
{
Field field = superClass.getDeclaredField(Instrumentor.HELPER_FIELD_NAME);
SecurityActions.setAccessible(field);
advisor = (ClassAdvisor) field.get(null);
if (advisor != null)
{
return advisor;
}
else
{
break;
}
}
catch (NoSuchFieldException e)
{
superClass = clazz.getSuperclass();
}
}
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
advisor = AdvisorFactory.getClassAdvisor(clazz, this);
advisor.setClazz(clazz);
return advisor;
}
public DomainDefinition getContainer(String name)
{
return containers.get(name);
}
public void addContainer(DomainDefinition def)
{
initContainersMap();
containers.put(def.getName(), def);
}
public void removeContainer(String name)
{
containers.remove(name);
}
/**
* Find a pointcut of with a given name
*/
public Pointcut getPointcut(String name)
{
synchronized (pointcuts)
{
return pointcuts.get(name);
}
}
/**
* Remove an interceptor pointcut with a given name
*/
public void removePointcut(String name)
{
synchronized (pointcuts)
{
pointcuts.remove(name);
pointcutInfos.remove(name);
}
}
/**
* Add an interceptor pointcut with a given name
*/
public synchronized void addPointcut(Pointcut pointcut)
{
removePointcut(pointcut.getName());
initPointcutsMap();
initPointcutInfosMap();
synchronized (pointcuts)
{
pointcuts.put(pointcut.getName(), pointcut);
pointcutInfos.put(pointcut.getName(), new PointcutInfo(pointcut, this.transformationStarted));
}
updatePointcutStats(pointcut);
}
/**
* THis method is used for performance reasons.
*
* @param pointcut
*/
protected void updatePointcutStats(Pointcut pointcut)
{
// the following is for performance reasons.
if (pointcut instanceof PointcutExpression)
{
PointcutExpression expr = (PointcutExpression) pointcut;
expr.setManager(this);
PointcutStats stats = expr.getStats();
updateStats(stats);
}
else
{
// can't be sure so set all
execution = true;
construction = true;
call = true;
within = true;
get = true;
set = true;
withincode = true;
}
}
protected void updateStats(PointcutStats stats)
{
if (stats != null)
{
construction |= stats.isConstruction();
execution |= stats.isExecution();
call |= stats.isCall();
within |= stats.isWithin();
get |= stats.isGet();
set |= stats.isSet();
withincode |= stats.isWithincode();
}
else
{
if (verbose && logger.isDebugEnabled()) logger.debug("Setting all pointcut stats to true");
// can't be sure so set all
execution = true;
construction = true;
call = true;
within = true;
get = true;
set = true;
withincode = true;
}
}
public boolean isExecution()
{
return execution;
}
public boolean isConstruction()
{
return construction;
}
public boolean isCall()
{
return call;
}
public boolean isWithin()
{
return within;
}
public boolean isWithincode()
{
return withincode;
}
public boolean isGet()
{
return get;
}
public boolean isSet()
{
return set;
}
/**
* Remove an interceptor pointcut with a given name
*/
public void removeBinding(String name)
{
AdviceBinding binding = internalRemoveBinding(name);
if (binding != null)
{
binding.clearAdvisors();
dynamicStrategy.interceptorChainsUpdated();
}
}
public synchronized void removeBindings(ArrayList<String> binds)
{
clearUnregisteredClassLoaders();
HashSet<Advisor> bindingAdvisors = new HashSet<Advisor>();
ArrayList<AdviceBinding> removedBindings = null;
synchronized (bindingCollection)
{
removedBindings = this.bindingCollection.remove(binds);
for (AdviceBinding removedBinding: removedBindings)
{
ArrayList<Advisor> ads = removedBinding.getAdvisors();
bindingAdvisors.addAll(ads);
Pointcut pointcut = removedBinding.getPointcut();
this.removePointcut(pointcut.getName());
}
}
Iterator<Advisor> it = bindingAdvisors.iterator();
while (it.hasNext())
{
Advisor advisor = it.next();
if (!isAdvisorRegistered(advisor))
{
//Check sub domains in case of generated advisors
WeakReference<Domain> ref = getSubDomainsPerClass().get(advisor.getClazz());
Domain domain = null;
if (ref != null) domain = ref.get();
if (domain != null)
{
if (subscribedSubDomains.containsKey(domain) || subscribedSubDomainsQueue.containsKey(domain))
{
if (!domain.isAdvisorRegistered(advisor))continue;
}
else
{
continue;//If advisor does not belong to a subscribed subdomain, we should not rebuild
}
}
}
advisor.removeAdviceBindings(removedBindings);
}
dynamicStrategy.interceptorChainsUpdated();
}
/**
* Add an interceptor pointcut with a given name
*/
public void addBinding(AdviceBinding binding)
{
Set<Advisor> affectedAdvisors = null;
AdviceBinding removedBinding = null;
synchronized(this)
{
removedBinding = internalRemoveBinding(binding.getName());
affectedAdvisors = removedBinding == null ? null : new HashSet<Advisor>(removedBinding.getAdvisors());
initPointcutsMap();
initPointcutInfosMap();
synchronized (pointcuts)
{
Pointcut pointcut = binding.getPointcut();
pointcuts.put(pointcut.getName(), pointcut);
pointcutInfos.put(pointcut.getName(), new PointcutInfo(pointcut, binding, this.transformationStarted));
updatePointcutStats(pointcut);
}
initBindingsMap();
synchronized (bindingCollection)
{
bindingCollection.add(binding);
}
}
synchronized (advisors)
{
Set<Advisor> handledAdvisors = new HashSet<Advisor>();
updateAdvisorsForAddedBinding(binding, handledAdvisors);
if (affectedAdvisors != null && affectedAdvisors.size() > 0)
{
for (Advisor advisor : affectedAdvisors)
{
if (isAdvisorRegistered(advisor))
advisor.removeAdviceBinding(removedBinding);
}
}
}
this.dynamicStrategy.interceptorChainsUpdated();
}
protected void updateAdvisorsForAddedBinding(AdviceBinding binding, Set<Advisor> handledAdvisors)
{
synchronized (advisors)
{
Collection<Class<?>> keys = advisors.keySet();
if (keys.size() > 0)
{
Iterator<Class<?>> it = keys.iterator();
while (it.hasNext())
{
Advisor advisor = getAdvisorFromAdvisorsKeySetIterator(it);
if (advisor == null) continue;
if (handledAdvisors.contains(advisor)) continue;
handledAdvisors.add(advisor);
if (binding.getPointcut().softMatch(advisor))
{
if (AspectManager.verbose && logger.isDebugEnabled())
logger.debug("softmatch succeeded for : " + advisor.getName() + " " + binding + " " + binding.getPointcut().getExpr());
advisor.newBindingAdded(binding);
//affectedAdvisors.remove(advisor);
}
else
{
if (AspectManager.verbose && logger.isDebugEnabled())
logger.debug("softmatch failed for : " + advisor.getName() + " " + binding + " " + binding.getPointcut().getExpr());
}
}
}
}
synchronized (subscribedSubDomains)
{
copySubDomainsFromQueue(true);
boolean newSubscribers = true;
while (newSubscribers)
{
Collection<Domain> domains = subscribedSubDomains.keySet();
if (domains.size() > 0)
{
//When interceptors are installed as beans in the microcontainer, creating the interceptor instances
for (Domain domain : domains)
{
domain.updateAdvisorsForAddedBinding(binding, handledAdvisors);
}
}
newSubscribers = copySubDomainsFromQueue(false);
}
}
}
public void removeClassMetaData(String name)
{
internalRemoveClassMetaData(name);
}
public void internalRemoveClassMetaData(String name)
{
synchronized (classMetaData)
{
ClassMetaDataBinding meta = classMetaData.remove(name);
if (meta == null) return;
meta.clearAdvisors();
}
}
public void addClassMetaData(ClassMetaDataBinding meta)
{
internalRemoveClassMetaData(meta.getName());
//Add the metadata before we update the advisors. Important for the generated instance advisors
initClassMetaDataMap();
synchronized (classMetaData)
{
classMetaData.put(meta.getName(), meta);
}
updateAdvisorsForAddedClassMetaData(meta);
}
protected void updateAdvisorsForAddedClassMetaData(ClassMetaDataBinding meta)
{
synchronized (advisors)
{
Iterator<Class<?>> it = advisors.keySet().iterator();
while (it.hasNext())
{
Advisor advisor = getAdvisorFromAdvisorsKeySetIterator(it);
if (advisor == null) continue;
Class<?> clazz = advisor.getClazz();
addAdvisorToClassMetaDataBinding(meta, clazz, advisor, clazz);
}
}
synchronized (subscribedSubDomains)
{
copySubDomainsFromQueue(true);
boolean newSubscribers = true;
while (newSubscribers)
{
if (subscribedSubDomains.size() > 0)
{
for (Domain domain : subscribedSubDomains.keySet())
{
domain.updateAdvisorsForAddedClassMetaData(meta);
}
}
newSubscribers = copySubDomainsFromQueue(false);
}
}
}
protected void addAdvisorToClassMetaDataBinding(ClassMetaDataBinding meta, Class<?> clazz, Advisor advisor, Class<?> advisedClass)
{
if (meta.matches(advisor, clazz))
{
meta.addAdvisor(advisor);
}
else if (advisor.chainOverridingForInheritedMethods())
{
//If advisor class does not match class metadata directly, try the superclasses so that methods can inherit
//old skool weaving doesn't support metadata overriding for inherited methods, so only do this extra work for generated advisors
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && superClass != Object.class)
{
addAdvisorToClassMetaDataBinding(meta, superClass, advisor, advisedClass);
}
}
}
//--- Introductions
/**
* Retrieve an introduction pointcut of a certain name
*/
public InterfaceIntroduction getInterfaceIntroduction(String name)
{
synchronized (interfaceIntroductions)
{
return interfaceIntroductions.get(name);
}
}
/**
* Register an introduction pointcut
*/
public synchronized void addInterfaceIntroduction(InterfaceIntroduction pointcut)
{
removeInterfaceIntroduction(pointcut.getName());
initInterfaceIntroductionsMap();
synchronized (interfaceIntroductions)
{
interfaceIntroductions.put(pointcut.getName(), pointcut);
}
}
/**
* remove an introduction pointcut of a certain name
*/
public void removeInterfaceIntroduction(String name)
{
synchronized (interfaceIntroductions)
{
InterfaceIntroduction pointcut = interfaceIntroductions.remove(name);
if (pointcut == null) return;
pointcut.clearAdvisors();
}
}
/**
* Retrieve an introduction pointcut of a certain name
*/
public ArrayReplacement getArrayReplacement(String name)
{
synchronized (arrayReplacements)
{
return arrayReplacements.get(name);
}
}
/**
* Register an introduction pointcut
*/
public synchronized void addArrayReplacement(ArrayReplacement pointcut)
{
removeArrayReplacement(pointcut.getName());
initArrayReplacementMap();
synchronized (arrayReplacements)
{
arrayReplacements.put(pointcut.getName(), pointcut);
}
}
/**
* remove an introduction pointcut of a certain name
*/
public void removeArrayReplacement(String name)
{
synchronized (arrayReplacements)
{
arrayReplacements.remove(name);
}
}
/**
* Retrieve an introduction pointcut of a certain name
*/
public ArrayBinding getArrayBinding(String name)
{
synchronized (arrayBindings)
{
return arrayBindings.get(name);
}
}
/**
* Register an introduction pointcut
*/
public synchronized void addArrayBinding(ArrayBinding binding)
{
removeArrayBinding(binding.getName());
initArrayBindingMap();
synchronized (arrayBindings)
{
arrayBindings.put(binding.getName(), binding);
ArrayAdvisor.addBinding(binding);
}
}
/**
* remove an introduction pointcut of a certain name
*/
public void removeArrayBinding(String name)
{
synchronized (arrayBindings)
{
ArrayBinding pointcut = arrayBindings.remove(name);
if (pointcut == null) return;
ArrayAdvisor.removeBinding(pointcut);
}
}
/**
* Register an annotation introduction
*/
public synchronized void addAnnotationIntroduction(AnnotationIntroduction pointcut)
{
String name = pointcut.getOriginalAnnotationExpr() + pointcut.getOriginalExpression();
removeAnnotationIntroduction(pointcut);
initAnnotationIntroductionsMap();
synchronized (annotationIntroductions)
{
annotationIntroductions.put(name, pointcut);
}
}
/**
* remove an annotation pointcut
*/
public void removeAnnotationIntroduction(AnnotationIntroduction pointcut)
{
String name = pointcut.getOriginalAnnotationExpr() + pointcut.getOriginalExpression();
synchronized (annotationIntroductions)
{
annotationIntroductions.remove(name);
}
}
public List<AnnotationIntroduction> getAnnotationIntroductions()
{
synchronized (annotationIntroductions)
{
return new ArrayList<AnnotationIntroduction>(annotationIntroductions.values());
}
}
public synchronized void addDeclare(DeclareDef declare)
{
removeDeclare(declare.getName());
initDeclaresMap();
synchronized (declares)
{
declares.put(declare.getName(), declare);
}
if (declare.isPointcut())
{
PointcutStats stats;
stats = new PointcutStats(declare.getAst(), manager);
stats.matches();
updateStats(stats);
}
}
public void removeDeclare(String name)
{
synchronized (declares)
{
declares.remove(name);
}
}
public Iterator<DeclareDef> getDeclares()
{
return declares.values().iterator();
}
protected void applyInterfaceIntroductions(Advisor advisor, Class<?> clazz)
{
Map<String, InterfaceIntroduction> interfaceIntroductions = getInterfaceIntroductions();
if (interfaceIntroductions != null && interfaceIntroductions.size() > 0)
{
for (InterfaceIntroduction pointcut : interfaceIntroductions.values())
{
if (pointcut.matches(advisor, clazz))
{
pointcut.addAdvisor(advisor);
}
}
}
}
protected void applyInterfaceIntroductions(ClassAdvisor advisor, CtClass clazz) throws Exception
{
Map<String, InterfaceIntroduction> interfaceIntroductions = getInterfaceIntroductions();
if (interfaceIntroductions != null && interfaceIntroductions.size() > 0)
{
for (InterfaceIntroduction pointcut : interfaceIntroductions.values())
{
if (pointcut.matches(advisor, clazz))
{
pointcut.addAdvisor(advisor);
}
}
}
}
/**
* Register an annotation introduction
*/
public synchronized void addAnnotationOverride(AnnotationIntroduction pointcut)
{
String name = pointcut.getOriginalAnnotationExpr() + pointcut.getOriginalExpression();
initAnnotationOverridesMap();
synchronized (annotationOverrides)
{
annotationOverrides.put(name, pointcut);
}
updateAdvisorsForAddedAnnotationOverride(pointcut);
}
public void updateAdvisorsForAddedAnnotationOverride(AnnotationIntroduction introduction)
{
synchronized (advisors)
{
Iterator<Class<?>> it = advisors.keySet().iterator();
while (it.hasNext())
{
Advisor advisor = getAdvisorFromAdvisorsKeySetIterator(it);
if (advisor == null) continue;
advisor.deployAnnotationOverride(introduction);
}
}
synchronized (subscribedSubDomains)
{
copySubDomainsFromQueue(true);
boolean newSubscribers = true;
while (newSubscribers)
{
for (Domain domain : subscribedSubDomains.keySet())
{
domain.updateAdvisorsForAddedAnnotationOverride(introduction);
}
newSubscribers = copySubDomainsFromQueue(false);
}
}
}
/**
* remove an annotation pointcut
*/
public void removeAnnotationOverride(AnnotationIntroduction pointcut)
{
String name = pointcut.getOriginalAnnotationExpr() + pointcut.getOriginalExpression();
synchronized (annotationOverrides)
{
annotationOverrides.remove(name);
}
}
public List<AnnotationIntroduction> getAnnotationOverrides()
{
synchronized (annotationOverrides)
{
return new ArrayList<AnnotationIntroduction>(annotationOverrides.values());
}
}
public Object getPerVMAspect(AspectDefinition def)
{
return getPerVMAspect(def.getName());
}
public Object getPerVMAspect(String def)
{
Object aspect = perVMAspects.get(def);
if (aspect == null)
{
AspectDefinition adef = aspectDefinitions.get(def);
if (adef != null && adef.getScope() == Scope.PER_VM)
{
synchronized (adef)
{
aspect = createPerVmAspect(def, adef, null);
}
}
}
if (aspect == NULL_ASPECT)
{
return null;
}
return aspect;
}
protected Object createPerVmAspect(String def, AspectDefinition adef, ClassLoader scopedClassLoader)
{
Object instance = null;
synchronized (adef)
{
try
{
if (scopedClassLoader != null && adef.getFactory() instanceof AspectFactoryWithClassLoader)
{
//If a scoped classloader with no parent delegation redefines the class, we need to make sure that that class is pushed on the stack
((AspectFactoryWithClassLoader)adef.getFactory()).pushScopedClassLoader(scopedClassLoader);
}
instance = adef.getFactory().createPerVM();
initPerVMAspectsMap();
if (instance == null)
{
// indicates that the factory must not be called again
// the factory has already been called and returned null
perVMAspects.put(def, NULL_ASPECT);
}
else
{
perVMAspects.put(def, instance);
}
}
finally
{
if (scopedClassLoader != null && adef.getFactory() instanceof AspectFactoryWithClassLoader)
{
((AspectFactoryWithClassLoader)adef.getFactory()).popScopedClassLoader();
}
}
}
return instance;
}
public void addAspectDefinition(AspectDefinition def)
{
removeAspectDefinition(def.getName());
initAspectDefintitionsMap();
aspectDefinitions.put(def.getName(), def);
}
public void removeAspectDefinition(String name)
{
internalRemoveAspectDefintion(name);
}
protected AspectDefinition internalRemoveAspectDefintion(String name)
{
AspectDefinition def = aspectDefinitions.remove(name);
if (def != null)
{
def.undeploy();
if (def.getScope() == Scope.PER_VM) perVMAspects.remove(def.getName());
}
return def;
}
public Map<String, AspectDefinition> getAspectDefinitions()
{
return aspectDefinitions;
}
public AspectDefinition getAspectDefinition(String name)
{
return aspectDefinitions.get(name);
}
public synchronized void addTypedef(Typedef def) throws Exception
{
removeTypedef(def.getName());
initTypedefsMap();
synchronized (typedefs)
{
typedefs.put(def.getName(), def);
}
}
public void removeTypedef(String name)
{
synchronized (typedefs)
{
typedefs.remove(name);
}
}
public Typedef getTypedef(String name)
{
synchronized (typedefs)
{
return typedefs.get(name);
}
}
public Map<String, InterfaceIntroduction> getInterfaceIntroductions()
{
return interfaceIntroductions;
}
public Map<String, ArrayReplacement> getArrayReplacements()
{
return arrayReplacements;
}
public Map<String, Typedef> getTypedefs()
{
return typedefs;
}
public Map<String, AdviceStack> getInterceptorStacks()
{
return interceptorStacks;
}
public Map<String, ClassMetaDataLoader> getClassMetaDataLoaders()
{
return classMetaDataLoaders;
}
public Map<String, CFlowStack> getCflowStacks()
{
return cflowStacks;
}
public Map<String, DynamicCFlowDefinition> getDynamicCFlows()
{
return dynamicCFlows;
}
public Map<String, Object> getPerVMAspects()
{
return perVMAspects;
}
public Map<String, ClassMetaDataBinding> getClassMetaData()
{
return classMetaData;
}
/**
* Returns the dynamic aop strategy to be used.
*/
public DynamicAOPStrategy getDynamicAOPStrategy()
{
return this.dynamicStrategy;
}
/**
* Sets the dynamic aop strategy to be used.
* Should be called only before any class is transformed.
* @param strategy the new dynamic aop strategy.
*/
public void setDynamicAOPStrategy(DynamicAOPStrategy strategy)
{
// avoid users calling this method in run time
if (this.transformationStarted)
{
throw new RuntimeException("Dynamic AOP Strategy Update not allowed in run time");
}
this.dynamicStrategy = strategy;
}
/**
* Removes an AdviceBinding without notifying dynamic aop strategy.
* @param name the binding to be removed.
*/
private synchronized AdviceBinding internalRemoveBinding(String name)
{
synchronized (bindingCollection)
{
AdviceBinding binding = bindingCollection.remove(name);
if (binding == null)
{
return null;
}
Pointcut pointcut = binding.getPointcut();
this.removePointcut(pointcut.getName());
return binding;
}
}
// public void setBindings(LinkedHashMap bindings)
// {
// initBindingsMap();
// this.bindings.clear();
// this.bindings.putAll(bindings);
// }
public void addSubDomainPerClass(Class<?> clazz, Domain domain)
{
synchronized (getSubDomainsPerClass())
{
getSubDomainsPerClass().put(clazz, new WeakReference<Domain>(domain));
}
}
/**
* Add subscriber to queue
* @see AspectManager#copySubDomainsFromQueue(boolean)
*/
public void subscribeSubDomain(Domain domain)
{
initSubscribedSubDomainsMap();
initSubscribedSubDomainsQueueMap();
synchronized (subscribedSubDomains)
{
subscribedSubDomainsQueue.put(domain, "Contents do not matter");
}
}
public void unsubscribeSubDomain(Domain domain)
{
synchronized (subscribedSubDomains)
{
subscribedSubDomains.remove(domain);
}
}
public Map<Domain, Object> getSubscribedSubDomains()
{
return subscribedSubDomains;
}
private Advisor getAdvisorFromAdvisorsKeySetIterator(Iterator<Class<?>> it)
{
Class<?> clazz = it.next();
if (classLoaderValidator != null && !classLoaderValidator.isValidClassLoader(clazz.getClassLoader()))
{
it.remove();
return null;
}
WeakReference<Advisor> ref = advisors.get(clazz);
if (ref == null) return null;
Advisor advisor = ref.get();
if (advisor == null)
{
it.remove();
return null;
}
return advisor;
}
/**
* When running in the microcontainer with aspects installed as beans, a ClassProxyContainer will be created per bean
* to check if this bean needs interceptors, each container creates a sunscribed domain for matching. This subscribed
* domain is added to a queue, which is checked when we need to iterate over the subscribed domains.
*/
private boolean copySubDomainsFromQueue(boolean increment)
{
boolean copied = false;
initSubscribedSubDomainsMap();
synchronized (subscribedSubDomains)
{
if (!increment && subscribedDomainQueueRef > 0) subscribedDomainQueueRef--;
if (subscribedDomainQueueRef == 0 && subscribedSubDomainsQueue.size() > 0){
subscribedSubDomains.putAll(subscribedSubDomainsQueue);
subscribedSubDomainsQueue.clear();
copied = true;
}
if (increment) subscribedDomainQueueRef++;
}
return copied;
}
public void addLifecycleDefinition(AspectDefinition def)
{
lifecycleManager.addLifecycleDefinition(def);
}
public void removeLifecycleDefinition(String name)
{
lifecycleManager.removeLifecycleDefinition(name);
}
public void addLifecycleBinding(LifecycleCallbackBinding lifecycleBinding)
{
lifecycleManager.addLifecycleBinding(lifecycleBinding);
}
public Map<String, LifecycleCallbackBinding> getLifecycleBindings()
{
return lifecycleManager.getLifecycleBindings();
}
public void removeLifecycleBinding(String name)
{
lifecycleManager.removeLifecycleBinding(name);
}
// public void dumpSubDomainsAndAdvisors(int indent)
// {
// indent(indent);
// System.out.println("Manager: " + this);
// indent++;
// indent(indent);
// System.out.println("<Advisors>");
// //indent(indent);
//
// for (Iterator it = advisors.keySet().iterator() ; it.hasNext() ; )
// {
// Class clazz = (Class) it.next();
// Advisor advisor = null;
// WeakReference ref = (WeakReference) advisors.get(clazz);
// if (ref != null) advisor = (Advisor) ref.get();
// indent(indent);
// System.out.println(System.identityHashCode(advisor) + " " + advisor);
// indent(indent);
// }
// indent--;
// indent(indent);
// System.out.println("</Advisors>");
//
// indent(indent);
// System.out.println("<Sub domains>");
// indent++;
// for (Iterator it = subscribedSubDomains.keySet().iterator(); it.hasNext() ; )
// {
// AspectManager manager = (AspectManager)it.next();
// manager.dumpSubDomainsAndAdvisors(indent);
// }
// indent--;
// indent(indent);
// System.out.println("</Sub domains>");
// indent--;
//
// }
//
// private void indent(int indent)
// {
// for (int i = 0 ; i < indent ; i++) System.out.print(" ");
// }
protected void initSubDomainsByNameMap()
{
if (subDomainsByName == UnmodifiableEmptyCollections.EMPTY_WEAK_VALUE_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (subDomainsByName == UnmodifiableEmptyCollections.EMPTY_WEAK_VALUE_HASHMAP)
{
subDomainsByName = new WeakValueHashMap<String, Domain>();
}
}
}
}
protected void initSubscribedSubDomainsMap()
{
if (subscribedSubDomains == UnmodifiableEmptyCollections.EMPTY_WEAK_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (subscribedSubDomains == UnmodifiableEmptyCollections.EMPTY_WEAK_HASHMAP)
{
subscribedSubDomains = new WeakHashMap<Domain, Object>();
}
}
}
}
protected void initSubscribedSubDomainsQueueMap()
{
if (subscribedSubDomainsQueue == UnmodifiableEmptyCollections.EMPTY_WEAK_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (subscribedSubDomainsQueue == UnmodifiableEmptyCollections.EMPTY_WEAK_HASHMAP)
{
subscribedSubDomainsQueue = new WeakHashMap<Domain, Object>();
}
}
}
}
protected void initInterfaceIntroductionsMap()
{
if (interfaceIntroductions == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (interfaceIntroductions == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
interfaceIntroductions = new LinkedHashMap<String, InterfaceIntroduction>();
}
}
}
}
protected void initArrayReplacementMap()
{
if (arrayReplacements == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (arrayReplacements == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
arrayReplacements = new LinkedHashMap<String, ArrayReplacement>();
}
}
}
}
protected void initArrayBindingMap()
{
if (arrayBindings == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (arrayBindings == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
arrayBindings = new LinkedHashMap<String, ArrayBinding>();
}
}
}
}
protected void initAnnotationIntroductionsMap()
{
if (annotationIntroductions == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (annotationIntroductions == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
annotationIntroductions = new LinkedHashMap<String, AnnotationIntroduction>();
}
}
}
}
protected void initAnnotationOverridesMap()
{
if (annotationOverrides == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (annotationOverrides == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
annotationOverrides = new LinkedHashMap<String, AnnotationIntroduction>();
}
}
}
}
protected void initBindingsMap()
{
if (!bindingCollection.isInitialized())
{
synchronized(lazyCollectionLock)
{
if (!bindingCollection.isInitialized())
{
bindingCollection.initialize();
bindings = bindingCollection.getBindings();
}
}
}
}
protected void initTypedefsMap()
{
if (typedefs == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (typedefs == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
typedefs = new LinkedHashMap<String, Typedef>();
}
}
}
}
protected void initInterceptorFactoriesMap()
{
if (interceptorFactories == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (interceptorFactories == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
interceptorFactories = new HashMap<String, InterceptorFactory>();
}
}
}
}
protected void initClassMetaDataLoadersMap()
{
if (classMetaDataLoaders == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (classMetaDataLoaders == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
classMetaDataLoaders = new HashMap<String, ClassMetaDataLoader>();
}
}
}
}
protected void initInerceptorStacksMap()
{
if (interceptorStacks == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (interceptorStacks == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
interceptorStacks = new HashMap<String, AdviceStack>();
}
}
}
}
protected void initDeclaresMap()
{
if (declares == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (declares == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
declares = new HashMap<String, DeclareDef>();
}
}
}
}
protected void initCflowStacksMap()
{
if (cflowStacks == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (cflowStacks == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
cflowStacks = new ConcurrentHashMap<String, CFlowStack>();
}
}
}
}
protected void initDynamicCflowsMap()
{
if (dynamicCFlows == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (dynamicCFlows == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
dynamicCFlows = new ConcurrentHashMap<String, DynamicCFlowDefinition>();
}
}
}
}
protected void initAspectDefintitionsMap()
{
if (aspectDefinitions == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (aspectDefinitions == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
aspectDefinitions = new ConcurrentHashMap<String, AspectDefinition>();
}
}
}
}
protected void initPerVMAspectsMap()
{
if (perVMAspects == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (perVMAspects == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
perVMAspects = new ConcurrentHashMap<String, Object>();
}
}
}
}
protected void initPointcutsMap()
{
if (pointcuts == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (pointcuts == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
pointcuts = new LinkedHashMap<String, Pointcut>();
}
}
}
}
protected void initPointcutInfosMap()
{
if (pointcutInfos == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (pointcutInfos == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
pointcutInfos = new LinkedHashMap<String, PointcutInfo>();
}
}
}
}
protected void initClassMetaDataMap()
{
if (classMetaData == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (classMetaData == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
classMetaData = new LinkedHashMap<String, ClassMetaDataBinding>();
}
}
}
}
protected void initContainersMap()
{
if (containers == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (containers == UnmodifiableEmptyCollections.EMPTY_HASHMAP)
{
containers = new HashMap<String, DomainDefinition>();
}
}
}
}
protected void initPrecedenceDefsMap()
{
if (precedenceDefs == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (precedenceDefs == UnmodifiableEmptyCollections.EMPTY_LINKED_HASHMAP)
{
precedenceDefs = new LinkedHashMap<String, PrecedenceDef>();
}
}
}
}
}