/*
* 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 gnu.trove.TLongObjectHashMap;
import java.lang.annotation.Annotation;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import org.jboss.aop.advice.AdviceBinding;
import org.jboss.aop.advice.AspectDefinition;
import org.jboss.aop.advice.CFlowInterceptor;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.advice.InterceptorFactory;
import org.jboss.aop.advice.PrecedenceSorter;
import org.jboss.aop.advice.Scope;
import org.jboss.aop.annotation.AnnotationElement;
import org.jboss.aop.annotation.AnnotationRepository;
import org.jboss.aop.instrument.ConstructionTransformer;
import org.jboss.aop.instrument.ConstructorExecutionTransformer;
import org.jboss.aop.introduction.AnnotationIntroduction;
import org.jboss.aop.introduction.InterfaceIntroduction;
import org.jboss.aop.joinpoint.ConstructorJoinpoint;
import org.jboss.aop.joinpoint.Invocation;
import org.jboss.aop.joinpoint.InvocationResponse;
import org.jboss.aop.joinpoint.Joinpoint;
import org.jboss.aop.joinpoint.MethodInvocation;
import org.jboss.aop.metadata.ClassMetaDataBinding;
import org.jboss.aop.metadata.ConstructorMetaData;
import org.jboss.aop.metadata.FieldMetaData;
import org.jboss.aop.metadata.MethodMetaData;
import org.jboss.aop.metadata.SimpleMetaData;
import org.jboss.aop.pointcut.PointcutMethodMatch;
import org.jboss.aop.util.JoinPointComparator;
import org.jboss.aop.util.UnmodifiableEmptyCollections;
import org.jboss.metadata.spi.MetaData;
import org.jboss.metadata.spi.signature.ConstructorSignature;
import org.jboss.metadata.spi.signature.FieldSignature;
import org.jboss.metadata.spi.signature.MethodSignature;
import org.jboss.util.NestedRuntimeException;
import org.jboss.util.NotImplementedException;
/**
* Manages the interceptor chains of an aspect context (usually, this context is
* composed by either all joinpoints of a class, or the joinponts of an instance).
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @author adrian@jboss.org
* @version $Revision: 74555 $
*/
public abstract class Advisor
{
/**
* Returns the {@code MethodInfo} that represents the execution of the method
* identified by {@code hash}.
*
* @param hash a hash code that identifies uniquely a method inside the context.
* @return a {@code MethodInfo} representing the queried method execution
* joinpoint.
*/
public MethodInfo getMethodInfo(long hash)
{
return methodInfos.getMethodInfo(hash);
}
/**
* Identifies an advice.
*/
private class AdviceInterceptorKey
{
private String adviceName;
private Joinpoint joinpoint;
private int hash;
public AdviceInterceptorKey(String adviceName, Joinpoint joinpoint)
{
this.adviceName = adviceName;
this.joinpoint = joinpoint;
hash = adviceName.hashCode();
hash = 29 * hash + (joinpoint != null ? joinpoint.hashCode() : 0);
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (!(o instanceof AdviceInterceptorKey)) return false;
final AdviceInterceptorKey adviceInterceptorKey = (AdviceInterceptorKey) o;
if (!adviceName.equals(adviceInterceptorKey.adviceName)) return false;
if (joinpoint != null ? !joinpoint.equals(adviceInterceptorKey.joinpoint) : adviceInterceptorKey.joinpoint != null) return false;
return true;
}
@Override
public int hashCode()
{
return hash;
}
}
/** Read/Write lock to be used when lazy creating the collections */
protected Object lazyCollectionLock = new Object();
/** The collection of bindings that are applied to one or more joinpoints in the advised context. */
protected Set<AdviceBinding> adviceBindings = new HashSet<AdviceBinding>();
/** The collection of interface introductions that affect the advised context. */
protected volatile ArrayList<InterfaceIntroduction> interfaceIntroductions = UnmodifiableEmptyCollections.EMPTY_ARRAYLIST;
/** The collection of class metadata bindings that are applied to the advised context. */
protected volatile ArrayList<ClassMetaDataBinding> classMetaDataBindings = UnmodifiableEmptyCollections.EMPTY_ARRAYLIST;
/** Meta data that apply to all advised joinpoints. */
protected SimpleMetaData defaultMetaData = new SimpleMetaData();
/** Method execution joinpoints meta data.*/
protected MethodMetaData methodMetaData = new MethodMetaData();
/** Field read/write joinpoints meta data. */
protected FieldMetaData fieldMetaData = new FieldMetaData();
/** The target class meta data.*/
protected SimpleMetaData classMetaData = new SimpleMetaData();
/** Constructor execution joinpoints meta data. */
protected ConstructorMetaData constructorMetaData = new ConstructorMetaData();
//Does not seem to be used
//protected HashMap classAnnotations = UnmodifiableEmptyCollections.EMPTY_HASHMAP;
/** Repository that contains all annotations applied to the context of this advisor */
protected AnnotationRepository annotations = new AnnotationRepository();
/** Indicates whether there is one or more aspects applied to this context. */
protected boolean doesHaveAspects = false;
/** Name that identifies this advisor. */
protected String name;
/** Contains all the aspect instances applied to this context. */
protected ConcurrentHashMap<String, Object> aspects = new ConcurrentHashMap<String, Object>();
/** Contains all the interceptor instances applied to this context. */
protected HashMap<AspectDefinition, Map<String, Interceptor>> adviceInterceptors = new HashMap<AspectDefinition, Map<String, Interceptor>>();
/** Contains all definitions of PER_INSTANCE aspects applied to this context. */
protected volatile CopyOnWriteArraySet<AspectDefinition> perInstanceAspectDefinitions = UnmodifiableEmptyCollections.EMPTY_COPYONWRITE_ARRAYSET;
/** Contains all definitions of PER_JOINPOINT scoped aspects applied to this sccontext*/
protected volatile ConcurrentHashMap<AspectDefinition, Set<Joinpoint>> perInstanceJoinpointAspectDefinitions = UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP;
/** The {@code java.lang.String} class */
static Class<?> cl = java.lang.String.class;
/** Maps all advised methods to their interceptor chains. */
protected volatile TLongObjectHashMap advisedMethods = UnmodifiableEmptyCollections.EMPTY_TLONG_OBJECT_HASHMAP;
// The method signatures are sorted at transformation and load time to
// make sure the tables line up.
//Common sense suggests that this should be lazily initialised for generated advisors, profiling shows that is a major performance hit...
/** @deprecated use methodInfos instead. These remain here for compatibility with EJB 3 in JBoss 4.x. See JBAOP-517
* @see AspectManager#maintainAdvisorMethodInterceptors
*/
protected TLongObjectHashMap methodInterceptors = new TLongObjectHashMap();
/** Collection of method execution joinpoints. */
protected MethodInterceptors methodInfos = new MethodInterceptors(this);;
/** Domain to which this advisor belongs. */
protected AspectManager manager;
/** Target class of the advised joinpoint. */
protected Class<?> clazz = null;
/** Target class loader of the advised joinpoint. */
protected WeakReference<ClassLoader> loader = null;
/** Contains the constructors that belong to the advised context. */
protected Constructor<?>[] constructors;
/** @deprecated Use constructorInfos instead */
protected Interceptor[][] constructorInterceptors;
protected ConstructorInfo[] constructorInfos; //This should replace constructorInterceptors
/** @deprecated Use constructorInfos instead */
protected Interceptor[][] constructionInterceptors;
protected ConstructionInfo[] constructionInfos;
/** The advisor meta data. */
private MetaData metadata;
/**
* Indicates that a call to factory create has already been made, but the factory
* returned {@code null}.
*/
protected static Object NULL_ASPECT = new Object();
/**
* Constructor.
* <p>
* Do not use this method to create {@code Advisor} instances. Instead, use the
* {@code create} methods of {@linke AdvisorFactory}.
*
* @param name identifies the advisor to be created.
* @param manager the domain to which this advisor belongs.
*/
public Advisor(String name, AspectManager manager)
{
this.name = name;
this.manager = manager;
}
/**
* Returns the list of constructors that belong to the advised context.
*
* @return an array of constructors
*/
public Constructor<?>[] getConstructors()
{
return constructors;
}
/** @deprecated Use getConstructorInfos instead*/
public Interceptor[][] getConstructorInterceptors()
{
return constructorInterceptors;
}
/**
* Returns the list of advised constructor execution joinpoints.
*
* @return an array of {@code ConstructorInfo} objects
*/
public ConstructorInfo[] getConstructorInfos()
{
return constructorInfos;
}
/** @deprecated Use getConstructionInfos instead*/
public Interceptor[][] getConstructionInterceptors()
{
return constructionInterceptors;
}
/**
* Returns the list of advised construction joinpoints.
*
* @return an array of {@code ConstructionInfo} objects
*/
public ConstructionInfo[] getConstructionInfos()
{
return constructionInfos;
}
/**
* @deprecated Need a better mechanism to override the
* methods seen by pointcuts, e.g. those provided
* by a "proxy advisor"
*/
public Method[] getAllMethods()
{
return null;
}
/**
* Returns the aspect manager that represents the domain to which this
* {@code Advisor} belongs.
*
* @return an {@link AspectManager} instance.
*/
public AspectManager getManager()
{
return manager;
}
/**
* For use by generated advisors. They will explicitly set the manager.
*
* @param manager the domain to which this {@code Advisor} belongs.
*/
protected void setManager(AspectManager manager)
{
this.manager = manager;
}
/**
* Returns the collection of class meta data bindings that are applied to the
* advised context.
*
* @return a list of {@code ClassMetaDataBinding}. This list is not a copy, and,
* hence, must not be edited.
*/
public List<ClassMetaDataBinding> getClassMetadataBindings()
{
return classMetaDataBindings;
}
/**
* Returns the target class meta data.
*
* @return the target class meta data. This object is not a copy, and, hence, must
* not be edited.
*/
public SimpleMetaData getClassMetaData()
{
return classMetaData;
}
/**
* Returns the meta data that is applied to all joinpoints and to the target
* class.
*
* @return the meta data that apply to all joinpoints and to the target class.
* This object is not a copy, and, hence, must not be edited.
*/
public SimpleMetaData getDefaultMetaData()
{
return defaultMetaData;
}
/**
* Returns the method joinpoints meta data
*
* @return the method joinpoints meta data. This object is not a copy, and, hence,
* must not be edited.
*/
public MethodMetaData getMethodMetaData()
{
return methodMetaData;
}
/**
* Returns the field joinpoints meta data
*
* @return the field joinpoints meta data. This object is not a copy, and, hence,
* must not be edited.
*/
public FieldMetaData getFieldMetaData()
{
return fieldMetaData;
}
/**
* Returns the constructor joinpoints meta data
*
* @return the constructor joinpoints meta data. This object is not a copy, and,
* hence, must not be edited.
*/
public ConstructorMetaData getConstructorMetaData()
{
return constructorMetaData;
}
/**
* Deploys to the advised context all {@code AnnotationIntroduction} that should
* override current annotions, in case they are present.
* <br>
* The annotation introductions to be deployed are extracted from this advisor
* domain ({@link AspectManager#getAnnotationOverrides()}).
*/
public void deployAnnotationOverrides()
{
List<AnnotationIntroduction> annotationOverrides = getManager().getAnnotationOverrides();
if (annotationOverrides != null)
{
for (int i = 0; i < annotationOverrides.size(); ++i)
{
AnnotationIntroduction introduction = annotationOverrides.get(i);
deployAnnotationOverride(introduction);
}
}
}
/**
* Deploys {@code introduction} to the advised context, overriding current
* annotions with the same name, in case they are present.
*
* @param introduction an annotation introduction that must be applied to the
* advised context.
*/
public void deployAnnotationOverride(AnnotationIntroduction introduction)
{
if (System.getSecurityManager() == null)
{
DeployAnnotationOverrideAction.NON_PRIVILEGED.deploy(this, introduction);
}
else
{
DeployAnnotationOverrideAction.PRIVILEGED.deploy(this, introduction);
}
}
/**
* Deploys {@code introduction} to the advised context, overriding current
* annotions with the same name, in case they are present.
* <br>
* <b>This method must not be called externally</b>, since it will perform
* deployment from outside a privileged environment. Use
* {@link #deployAnnotationOverride(AnnotationIntroduction)} instead.
*
* @param introduction an annotation introduction that must be applied to the
* advised context.
*
* @param introduction
*/
public void doDeployAnnotationOverride(AnnotationIntroduction introduction)
{
if (introduction.matches(this, clazz))
{
annotations.addClassAnnotation(introduction.getAnnotation().getIdentifier(), introduction.getOriginalAnnotationExpr());
}
Class<?> theClass = clazz;
deployMethodAnnotationOverrides(theClass, introduction);
Field[] fields = theClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
if (introduction.matches(this, fields[i]))
{
annotations.addAnnotation(fields[i], introduction.getAnnotation().getIdentifier(), introduction.getOriginalAnnotationExpr());
}
}
Constructor<?>[] cons = theClass.getDeclaredConstructors();
for (int i = 0; i < cons.length; i++)
{
if (introduction.matches(this, cons[i]))
{
annotations.addAnnotation(cons[i], introduction.getAnnotation().getIdentifier(), introduction.getOriginalAnnotationExpr());
}
}
}
/**
* Deploys to the advised context all {@code InterfaceIntroduction} whose pointcut
* matches one or more advised joinpoints.
* <br>
* The interface introductions to be deployed are extracted from this advisor
* domain ({@link AspectManager#getInterfaceIntroductions()}).
*/
protected void initializeInterfaceIntroductions(Class<?> theClass)
{
manager.applyInterfaceIntroductions(this, theClass);
}
/**
* Recursively deploys all method annotation introductions, overriding annotations
* with the same name.
* <p><i>For internal use only.</i>
*
* @param theClass the class that contains the affected methods. Must be
* equal to {@link #getClazz()} or to one of its super
* classes.
* @param introduction the introduction to be deployed.
*/
protected void deployMethodAnnotationOverrides(Class<?> theClass, AnnotationIntroduction introduction)
{
if (theClass.getSuperclass() != null)
{
deployMethodAnnotationOverrides(theClass.getSuperclass(), introduction);
}
Method[] methods = theClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++)
{
if (introduction.matches(this, methods[i]))
{
annotations.addAnnotation(methods[i], introduction.getAnnotation().getIdentifier(), introduction.getOriginalAnnotationExpr());
}
}
}
/**
* Returns the annotation repository used by this advisor to keep all annotations
* that are applied to the advised joinpoints.
* <p><i>For internal use only.</i>
*
* @return the annotation repository.
*/
public AnnotationRepository getAnnotations()
{
return annotations;
}
/**
* Returns an object representing the meta data of type {@code annotation}, if
* present.
*
* @param annotation the type of meta data/annotation queried
* @return the meta data/annotation of type {@code annotation}
*/
public Object resolveAnnotation(Class<? extends Annotation> annotation)
{
return resolveTypedAnnotation(annotation);
}
/**
* Returns an object representing the meta data of type {@code annotation}, if
* present.
*
* @param annotation the type of meta data/annotation queried
* @return the meta data/annotation of type {@code annotation}
*/
public <T extends Annotation> T resolveTypedAnnotation(Class<T> annotation)
{
if (metadata != null)
{
T value = metadata.getAnnotation(annotation);
if (value != null) return value;
}
//Need to use the untyped version since that is used by EJB3
if (annotations.isDisabled(annotation))
return null;
//MUST call this instead of AR.resolveTypedClassAnnotation since EJB3 overrides AR.resolveClassAnnotation
T value = (T)annotations.resolveClassAnnotation(annotation);
if (value == null && clazz != null && metadata == null)
{
value = AnnotationElement.getVisibleAnnotation(clazz, annotation);
}
return value;
}
/**
* Indicates whether the advised class has an annotation/meta data whose name is
* {@code annotation}.
*
* @param annotation the name of an annotation
* @return {@code true} if there is an annotation/meta data whose name is {@code
* annotation}
*/
public boolean hasAnnotation(String annotation)
{
return hasAnnotation(clazz, annotation);
}
/**
* Indicates whether {@code tgt} has an annotation/meta data whose name is {@code
* annotation}.
*
* @param tgt the target class whose annotations/meta data will be examined.
* @param annotation the name of an annotation
* @return {@code true} if there is an annotation/meta data whose name is {@code
* annotation}
*/
public boolean hasAnnotation(Class<?> tgt, String annotation)
{
return hasAnnotation(tgt, annotation, null);
}
/**
* Indicates whether {@code tgt} has an annotation/meta data whose type is {@code
* annotation}.
*
* @param tgt the target class whose annotations/meta data will be examined.
* @param annotation the type of an annotation
* @return {@code true} if {@code tgt} has an annotation/meta data whose type is
* {@code annotation}
*/
public boolean hasAnnotation(Class<?> tgt, Class<? extends Annotation> annotation)
{
return hasAnnotation(tgt, null, annotation);
}
private boolean hasAnnotation(Class<?> tgt, String annotation, Class<? extends Annotation> annotationClass)
{
if (annotation == null && annotationClass == null)
{
throw new RuntimeException("annotation or annotationClass must be passed in");
}
if (annotation == null)
{
annotation = annotationClass.getName();
}
if (metadata != null)
{
if (metadata.isMetaDataPresent(annotation)) return true;
}
if (annotations.hasClassAnnotation(annotation)) return true;
if (tgt == null) return false;
try
{
if (metadata == null)
{
return AnnotationElement.isAnyAnnotationPresent(tgt, annotation);
}
}
catch (Exception e)
{
throw new RuntimeException(e); //To change body of catch statement use Options | File Templates.
}
return false;
}
public Object resolveAnnotation(Method m, Class<? extends Annotation> annotation)
{
return resolveTypedAnnotation(0, m, annotation);
}
public <T extends Annotation> T resolveTypedAnnotation(Method m, Class<T> annotation)
{
return resolveTypedAnnotation(0, m, annotation);
}
public Object resolveAnnotation(long hash, Method m, Class<? extends Annotation> annotation)
{
return resolveTypedAnnotation(hash, m, annotation);
}
public <T extends Annotation> T resolveTypedAnnotation(long hash, Method m, Class<T> annotation)
{
if (metadata != null)
{
MethodSignature signature = new MethodSignature(m.getName(), m.getParameterTypes());
MetaData methodMD = metadata.getComponentMetaData(signature);
if (methodMD != null)
{
T val = methodMD.getAnnotation(annotation);
if (val != null) return val;
}
}
if (annotations.isDisabled(m,annotation))
return null;
//MUST call this instead of AR.resolveTypedClassAnnotation since EJB3 overrides AR.resolveClassAnnotation
T value = (T)annotations.resolveAnnotation(m, annotation);
if (value == null && metadata == null)
{
value = AnnotationElement.getVisibleAnnotation(m, annotation);
}
return value;
}
public Object resolveAnnotation(Method m, Class<?>[] annotationChoices)
{
for (Class<?> ann : annotationChoices)
{
Object val = resolveTypedAnnotation(m, (Class<? extends Annotation>)ann);
if (val != null) return val;
}
return null;
}
public <T extends Annotation> T resolveTypedAnnotation(Method m, Class<T>[] annotationChoices)
{
for (Class<T> ann : annotationChoices)
{
T val = resolveTypedAnnotation(m, ann);
if (val != null) return val;
}
return null;
}
public Object resolveAnnotation(Field f, Class<? extends Annotation> annotation)
{
return resolveTypedAnnotation(f, annotation);
}
public <T extends Annotation> T resolveTypedAnnotation(Field f, Class<T> annotation)
{
T value = null;
if (metadata != null)
{
FieldSignature signature = new FieldSignature(f);
MetaData fieldMD = metadata.getComponentMetaData(signature);
if (fieldMD != null)
{
value = fieldMD.getAnnotation(annotation);
if (value != null) return value;
}
}
//MUST call this instead of AR.resolveTypedClassAnnotation since EJB3 overrides AR.resolveClassAnnotation
value = (T)annotations.resolveAnnotation(f, annotation);
if (value == null && metadata == null)
{
value = AnnotationElement.getVisibleAnnotation(f, annotation);
}
return value;
}
public Object resolveAnnotation(Constructor<?> c, Class<? extends Annotation> annotation)
{
return resolveTypedAnnotation(c, annotation);
}
public <T extends Annotation> T resolveTypedAnnotation(Constructor<?> c, Class<T> annotation)
{
T value = null;
if (metadata != null)
{
ConstructorSignature signature = new ConstructorSignature(c);
MetaData conMD = metadata.getComponentMetaData(signature);
if (conMD != null)
{
value = conMD.getAnnotation(annotation);
if (value != null) return value;
}
}
//MUST call this instead of AR.resolveTypedClassAnnotation since EJB3 overrides AR.resolveClassAnnotation
value = (T)annotations.resolveAnnotation(c, annotation);
if (value == null && metadata == null)
{
value = AnnotationElement.getVisibleAnnotation(c, annotation);
}
return value;
}
public boolean hasAnnotation(Method m, String annotation)
{
return hasAnnotation(0, m, annotation, null);
}
public boolean hasAnnotation(Method m, Class<? extends Annotation> annotation)
{
return hasAnnotation(0, m, null, annotation);
}
private boolean hasAnnotation(long hash, Method m, String annotation, Class<? extends Annotation> annotationClass)
{
if (annotation == null && annotationClass == null)
{
throw new RuntimeException("annotation or annotationClass must be passed in");
}
if (annotation == null)
{
annotation = annotationClass.getName();
}
if (metadata != null)
{
if (hasJoinPointAnnotation(m.getDeclaringClass(), new MethodSignature(m), annotation))
{
return true;
}
}
if (annotations.hasAnnotation(m, annotation)) return true;
try
{
if (metadata == null)
{
return AnnotationElement.isAnyAnnotationPresent(m, annotation);
}
}
catch (Exception e)
{
throw new RuntimeException(e); //To change body of catch statement use Options | File Templates.
}
return false;
}
public boolean hasAnnotation(Field m, Class<? extends Annotation> annotation)
{
return hasAnnotation(m, annotation.getName());
}
public boolean hasAnnotation(Field m, String annotation)
{
if (metadata != null)
{
if (hasJoinPointAnnotation(m.getDeclaringClass(), new FieldSignature(m), annotation))
{
return true;
}
}
if (annotations.hasAnnotation(m, annotation)) return true;
try
{
if (metadata == null)
{
return AnnotationElement.isAnyAnnotationPresent(m, annotation);
}
}
catch (Exception e)
{
throw new RuntimeException(e); //To change body of catch statement use Options | File Templates.
}
return false;
}
public boolean hasAnnotation(Constructor<?> m, String annotation)
{
if (metadata != null)
{
if (hasJoinPointAnnotation(m.getDeclaringClass(), new ConstructorSignature(m), annotation))
{
return true;
}
}
if (annotations.hasAnnotation(m, annotation)) return true;
try
{
if (metadata == null)
{
return AnnotationElement.isAnyAnnotationPresent(m, annotation);
}
}
catch (Exception e)
{
throw new RuntimeException(e); //To change body of catch statement use Options | File Templates.
}
return false;
}
private boolean hasJoinPointAnnotation(Class<?> declaringClass, org.jboss.metadata.spi.signature.Signature sig, String annotation)
{
if (metadata != null)
{
if (annotation != null)
{
MetaData md = metadata.getComponentMetaData(sig);
if (md != null)
{
if (md.isMetaDataPresent(annotation))
return true;
}
}
}
return false;
}
public boolean hasAnnotation(CtClass clazz, String annotation)
{
if (annotations.hasClassAnnotation(annotation)) return true;
try
{
return AnnotationElement.isAnyAnnotationPresent(clazz, annotation);
}
catch (Exception e)
{
throw new RuntimeException(e); //To change body of catch statement use Options | File Templates.
}
}
public boolean hasAnnotation(CtMethod member, String annotation)
{
// todo these are here so that we can chain configuration domains
if (annotations.hasAnnotation(member, annotation)) return true;
return AnnotationElement.isAnyAnnotationPresent(member, annotation);
}
public boolean hasAnnotation(CtField member, String annotation)
{
// todo these are here so that we can chain configuration domains
if (annotations.hasAnnotation(member, annotation)) return true;
return AnnotationElement.isAnyAnnotationPresent(member, annotation);
}
public boolean hasAnnotation(CtConstructor member, String annotation)
{
// todo these are here so that we can chain configuration domains
if (annotations.hasAnnotation(member, annotation)) return true;
return AnnotationElement.isAnyAnnotationPresent(member, annotation);
}
/**
* Get the metadata
*
* @return the metadata
*/
public MetaData getMetadata()
{
return metadata;
}
/**
* Set the metadata
*
* FIXME why does this have java.lang.Object signature?
* @param metadata the metadata
*/
public void setMetadata(MetaData metadata)
{
this.metadata = metadata;
}
public String getName()
{
return name;
}
public final boolean hasAspects()
{
return doesHaveAspects;
}
public synchronized void removeAdviceBinding(AdviceBinding binding)
{
adviceBindings.remove(binding);
rebuildInterceptorsForRemovedBinding(binding);
doesHaveAspects = adviceBindings.size() > 0;
}
public synchronized void removeAdviceBindings(ArrayList<AdviceBinding> bindings)
{
adviceBindings.removeAll(bindings);
rebuildInterceptors();
doesHaveAspects = adviceBindings.size() > 0;
}
/**
* a new binding has been added to the AspectManager, recalculate interceptors
*/
public synchronized void newBindingAdded()
{
rebuildInterceptors();
doesHaveAspects = adviceBindings.size() > 0;
}
public synchronized void newBindingAdded(AdviceBinding binding)
{
rebuildInterceptorsForAddedBinding(binding);
doesHaveAspects = adviceBindings.size() > 0;
}
public ArrayList<InterfaceIntroduction> getInterfaceIntroductions()
{
return interfaceIntroductions;
}
public synchronized void addInterfaceIntroduction(InterfaceIntroduction pointcut)
{
initInterfaceIntroductionsList();
interfaceIntroductions.add(pointcut);
}
public synchronized void removeInterfaceIntroduction(InterfaceIntroduction pointcut)
{
interfaceIntroductions.remove(pointcut);
}
protected abstract void rebuildInterceptors();
protected abstract void rebuildInterceptorsForAddedBinding(AdviceBinding binding);
protected abstract void rebuildInterceptorsForRemovedBinding(AdviceBinding removedBinding);
/**
* If the info was updated in response to a rebuildInterceptorsForAddedBinding call it will have the
* original interceptors in the interceptors array, and the appended interceptors in the interceptorChain
* List. We need to merge the two so that all the interceptors appear in the interceptorChain List before finalizing
* the chain
*/
protected final void adjustInfoForAddedBinding(JoinPointInfo info)
{
Interceptor[] icptrs = info.getInterceptors();
if (icptrs != null && icptrs.length > 0)
{
List<Interceptor> chain = info.getInterceptorChain();
List<Interceptor> buf = new ArrayList<Interceptor>(chain.size() + icptrs.length);
buf.addAll(Arrays.asList(icptrs));
buf.addAll(chain);
chain.clear();
chain.addAll(buf);
}
}
////////////////////////////////
// Metadata. Metadata will be used for things like Transaction attributes (Required, RequiresNew, etc...)
//
public abstract void addClassMetaData(ClassMetaDataBinding data);
public abstract void removeClassMetaData(ClassMetaDataBinding data);
// This is aspect stuff. Aspect again, is a class that encapsulates advices
public Object getPerVMAspect(AspectDefinition def)
{
return getManager().getPerVMAspect(def);
}
public void addPerInstanceAspect(AspectDefinition def)
{
initPerInstanceAspectDefinitionsSet();
perInstanceAspectDefinitions.add(def);
def.registerAdvisor(this);
}
public void removePerInstanceAspect(AspectDefinition def)
{
perInstanceAspectDefinitions.remove(def);
}
public Set<AspectDefinition> getPerInstanceAspectDefinitions()
{
return perInstanceAspectDefinitions;
}
// This is aspect stuff. Aspect again, is a class that encapsulates advices
public void addPerInstanceJoinpointAspect(Joinpoint joinpoint, AspectDefinition def)
{
Set<Joinpoint> joinpoints = perInstanceJoinpointAspectDefinitions.get(def);
if (joinpoints == null)
{
joinpoints = new CopyOnWriteArraySet<Joinpoint>();
initPerInstanceJoinpointAspectDefinitionsMap();
perInstanceJoinpointAspectDefinitions.put(def, joinpoints);
def.registerAdvisor(this);
}
joinpoints.add(joinpoint);
}
void addPerInstanceJoinpointAspect(Set<Joinpoint> joinpoints, AspectDefinition def)
{
initPerInstanceJoinpointAspectDefinitionsMap();
Set<Joinpoint> setJoinpoints = perInstanceJoinpointAspectDefinitions.get(def);
if (setJoinpoints == null)
{
setJoinpoints = new CopyOnWriteArraySet<Joinpoint>();
perInstanceJoinpointAspectDefinitions.put(def, setJoinpoints);
def.registerAdvisor(this);
}
setJoinpoints.addAll(joinpoints);
}
public void removePerInstanceJoinpointAspect(AspectDefinition def)
{
perInstanceJoinpointAspectDefinitions.remove(def);
}
public Map<AspectDefinition, Set<Joinpoint>> getPerInstanceJoinpointAspectDefinitions()
{
return perInstanceJoinpointAspectDefinitions;
}
public Object getPerClassAspect(AspectDefinition def)
{
Object aspect = aspects.get(def.getName());
if (aspect == NULL_ASPECT)
{
return null;
}
return aspect;
}
public Object getPerClassAspect(String def)
{
Object aspect = aspects.get(def);
if (aspect == NULL_ASPECT)
{
return null;
}
return aspect;
}
public void addPerClassAspect(AspectDefinition def)
{
if (aspects.containsKey(def.getName())) return;
Object aspect = def.getFactory().createPerClass(this);
if (aspect == null)
{
aspect = NULL_ASPECT;
}
aspects.put(def.getName(), aspect);
def.registerAdvisor(this);
}
public void removePerClassAspect(AspectDefinition def)
{
aspects.remove(def.getName());
adviceInterceptors.remove(def);
}
public Interceptor getAdviceInterceptor(AspectDefinition def, String adviceName, Joinpoint joinpoint)
{
AdviceInterceptorKey key = new AdviceInterceptorKey(adviceName, joinpoint);
synchronized (adviceInterceptors)
{
Map<String, Interceptor> map = adviceInterceptors.get(def);
if (map != null)
{
return map.get(key);
}
}
return null;
}
public void addAdviceInterceptor(AspectDefinition def, String adviceName, Interceptor interceptor, Joinpoint joinpoint)
{
synchronized (adviceInterceptors)
{
Map<String, Interceptor> map = adviceInterceptors.get(def);
if (map == null)
{
map = new HashMap<String, Interceptor>();
adviceInterceptors.put(def, map);
}
map.put(adviceName, interceptor);
}
}
protected void createInterceptorChain(InterceptorFactory[] factories, ArrayList<Interceptor> newinterceptors, Joinpoint joinpoint)
{
for (int i = 0; i < factories.length; i++)
{
if (factories[i].getType().isGeneratedOnly())
{
throw new RuntimeException("Before/After/Throwing is only supported for Generated Advisors");
}
if (factories[i].isDeployed())
{
Interceptor interceptor = factories[i].create(this, joinpoint);
if (interceptor != null)
{
newinterceptors.add(interceptor);
}
}
}
}
protected void resolveMethodPointcut(AdviceBinding binding)
{
long[] keys = methodInfos.keys();
for (int i = 0; i < keys.length; i++)
{
Method method = (Method) advisedMethods.get(keys[i]);
PointcutMethodMatch match = binding.getPointcut().matchesExecution(this, method);
if (match != null && match.isMatch())
{
adviceBindings.add(binding);
if (AspectManager.verbose)
{
/*
RepositoryClassLoader loader = (RepositoryClassLoader)clazz.getClassLoader();
try
{
System.err.println("method matched binding " + binding.getPointcut().getExpr() + " " + method.toString() + " " + loader.getObjectName());
}
catch (MalformedObjectNameException e)
{
throw new RuntimeException(e);
}
*/
System.err.println("[debug] method matched binding: " + method.toString());
}
binding.addAdvisor(this);
MethodMatchInfo info = methodInfos.getMatchInfo(keys[i]);
info.addMatchedBinding(binding, match);
}
}
}
protected void updateMethodPointcutAfterRemove(AdviceBinding binding)
{
long[] keys = methodInfos.keys();
for(int i =0; i < keys.length; i++)
{
Method method = (Method) advisedMethods.get(keys[i]);
PointcutMethodMatch match = binding.getPointcut().matchesExecution(this, method);
if (match != null && match.isMatch())
{
if (AspectManager.verbose)
{
System.err.println("[debug] removing matched binding: "+method.toString());
}
MethodMatchInfo info = methodInfos.getMatchInfo(keys[i]);
info.removeMatchedBinding(binding, match);
info.getInfo().clear();
}
}
}
protected void lockWriteChain(MethodInterceptors methodInterceptors)
{
Object[] methodMatchInfos = methodInterceptors.infos.getValues();
for (int i = 0; i < methodMatchInfos.length; i++)
{
MethodMatchInfo methodMatchInfo = (MethodMatchInfo) methodMatchInfos[i];
methodMatchInfo.getInfo().getInterceptorChainReadWriteLock().writeLock().lock();
}
}
protected void unlockWriteChain(MethodInterceptors methodInterceptors)
{
Object[] methodMatchInfos = methodInterceptors.infos.getValues();
for (int i = 0; i < methodMatchInfos.length; i++)
{
MethodMatchInfo methodMatchInfo = (MethodMatchInfo) methodMatchInfos[i];
methodMatchInfo.getInfo().getInterceptorChainReadWriteLock().writeLock().unlock();
}
}
protected void resetChain(MethodInterceptors methodInterceptors)
{
Object[] methodMatchInfos = methodInterceptors.infos.getValues();
for (int i = 0; i < methodMatchInfos.length; i++)
{
MethodMatchInfo methodMatchInfo = (MethodMatchInfo) methodMatchInfos[i];
if (methodMatchInfo.bindings != null)
{
methodMatchInfo.bindings.clear();
}
if (methodMatchInfo.pointcutMethodMatches != null)
{
methodMatchInfo.pointcutMethodMatches.clear();
}
methodMatchInfo.getInfo().clear();
}
}
protected void resetChainKeepInterceptors(MethodInterceptors methodInterceptors)
{
Object[] methodMatchInfos = methodInterceptors.infos.getValues();
for (int i = 0; i < methodMatchInfos.length; i++)
{
MethodMatchInfo methodMatchInfo = (MethodMatchInfo) methodMatchInfos[i];
JoinPointInfo info = methodMatchInfo.getInfo();
info.clear();
}
}
protected void finalizeMethodChain()
{
boolean maintain = AspectManager.maintainAdvisorMethodInterceptors;
TLongObjectHashMap newMethodInfos = (maintain) ? new TLongObjectHashMap() : null;
long[] keys = methodInfos.keys();
for (int i = 0; i < keys.length; i++)
{
MethodMatchInfo matchInfo = methodInfos.getMatchInfo(keys[i]);
matchInfo.populateBindings();
MethodInfo info = matchInfo.getInfo();
adjustInfoForAddedBinding(info);
ArrayList<Interceptor> list = info.getInterceptorChain();
Interceptor[] interceptors = null;
if (list.size() > 0)
{
interceptors = applyPrecedence(list.toArray(new Interceptor[list.size()]));
}
info.setInterceptors(interceptors);
if (maintain)
{
newMethodInfos.put(keys[i], info);
}
}
methodInterceptors = newMethodInfos;
}
public InvocationResponse dynamicInvoke(Object target, Invocation invocation)
throws Throwable
{
// Only need to set Method because fields will already have been set.
if (invocation instanceof MethodInvocation)
{
Interceptor[] aspects = null;
MethodInvocation methodInvocation = (MethodInvocation) invocation;
long hash = methodInvocation.getMethodHash();
MethodInfo info = methodInfos.getMethodInfo(hash);
aspects = info.getInterceptors();
if (aspects == null) aspects = new Interceptor[0];
if (target != null && target instanceof Advised)
{
InstanceAdvised advised = (InstanceAdvised) target;
aspects = advised._getInstanceAdvisor().getInterceptors(aspects);
}
MethodInvocation nextInvocation = new MethodInvocation(info, aspects);
nextInvocation.setMetaData(invocation.getMetaData());
nextInvocation.setTargetObject(target);
nextInvocation.setArguments(methodInvocation.getArguments());
nextInvocation.setAdvisor(this);
InvocationResponse response = new InvocationResponse(nextInvocation.invokeNext());
response.setContextInfo(nextInvocation.getResponseContextInfo());
return response;
}
throw new RuntimeException("dynamic field invocations not supported yet!");
}
/**
* EJB3 counts on this being unchecked
*/
@SuppressWarnings("unchecked")
public Class getClazz()
{
return clazz;
}
void setClazz(Class<?> clazz)
{
this.clazz = clazz;
}
/**
* Defines the class loader associated with the advised context.
*
* @param loader the class loader that loaded all joinpoints contained in the
* advised context.
* @throws IllegalStateException when there is already a class associated with
* this advisor ({@link #getClazz()}), and {@link loader} is non-null and
* different from the class loader that loaded the advised class.
*/
void setClassLoader(ClassLoader loader) throws IllegalStateException
{
if (this.clazz != null && loader != null &&
loader != this.clazz.getClassLoader())
{
throw new IllegalStateException("Cannot have both loader and class");
}
if (loader == null)
{
this.loader = null;
}
else
{
this.loader = new WeakReference<ClassLoader>(loader);
}
}
/**
* Returns the class loader associated with this advisor.
*
* @return the class loader that loaded all joinpoints contained in the advised
* context.
*/
public ClassLoader getClassLoader()
{
if (this.loader != null)
{
ClassLoader cl = loader.get();
if (cl != null)
{
return cl;
}
}
if (clazz != null)
{
ClassLoader cl = SecurityActions.getClassLoader(clazz);
if (cl != null)
{
return cl;
}
}
return null;
}
/**
* @deprecated Use Class.getSimpleName() instead
*/
public static String getSimpleName(Class<?> clazz)
{
String name = clazz.getName();
int lastIndex = name.lastIndexOf('.');
if (lastIndex < 0)
{
return name;
}
return name.substring(lastIndex + 1);
}
protected void initializeConstructorChain()
{
if (clazz != null && constructors == null)
{
constructors = clazz.getDeclaredConstructors();
}
this.constructorInfos = new ConstructorInfo[constructors.length];
for (int i = 0; i < constructors.length; i++)
{
final ConstructorInfo info = new ConstructorInfo();
info.setConstructor(constructors[i]);
info.setIndex(i);
try
{
final String name = ConstructorExecutionTransformer.constructorFactory(clazz.getSimpleName());
final Class<?>[] types = constructors[i].getParameterTypes();
Method method = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>()
{
public Method run() throws Exception
{
return clazz.getDeclaredMethod(name, types);
}
});
info.setWrapper(method);
}
catch (PrivilegedActionException e1)
{
Exception e = e1.getException();
if (e instanceof NoSuchMethodException == false)
throw new NestedRuntimeException(e);
}
info.setAdvisor(this);
constructorInfos[i] = info;
try
{
final String name = ConstructorExecutionTransformer.getConstructorInfoFieldName(getSimpleName(clazz), i);
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
{
public Object run() throws Exception
{
Field infoField = clazz.getDeclaredField(name);
infoField.setAccessible(true);
infoField.set(null, new WeakReference<ConstructorInfo>(info));
return null;
}
});
}
catch (PrivilegedActionException e1)
{
Exception e = e1.getException();
if (e instanceof NoSuchFieldException == false)
throw new NestedRuntimeException(e);
}
}
}
protected void initializeConstructionChain()
{
this.constructionInfos = new ConstructionInfo[constructors.length];
for (int i = 0; i < constructors.length; i++)
{
ConstructionInfo info = new ConstructionInfo();
info.setConstructor(constructors[i]);
info.setIndex(i);
info.setAdvisor(this);
constructionInfos[i] = info;
try
{
Field infoField = clazz.getDeclaredField(ConstructionTransformer.getConstructionInfoFieldName(clazz.getSimpleName(), i));
infoField.setAccessible(true);
infoField.set(null, new WeakReference<ConstructionInfo>(info));
}
catch (NoSuchFieldException e)
{
// ignore, method may not be advised.
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
}
protected void finalizeChain(JoinPointInfo[] infos)
{
if (infos == null)
{
return;
}
for (int i = 0; i < infos.length; i++)
{
JoinPointInfo info = infos[i];
adjustInfoForAddedBinding(info);
ArrayList<Interceptor> list = info.getInterceptorChain();
Interceptor[] interceptors = null;
if (list.size() > 0)
{
interceptors = applyPrecedence(list.toArray(new Interceptor[list.size()]));
}
info.setInterceptors(interceptors);
}
}
protected void lockWriteChain(JoinPointInfo[] infos)
{
if (infos == null)
{
return;
}
for (int i = 0; i < infos.length; i++)
{
infos[i].getInterceptorChainReadWriteLock().writeLock().lock();
}
}
protected void unlockWriteChain(JoinPointInfo[] infos)
{
if (infos == null)
{
return;
}
for (int i = 0; i < infos.length; i++)
{
infos[i].getInterceptorChainReadWriteLock().writeLock().unlock();
}
}
protected void resetChain(JoinPointInfo[] infos)
{
if (infos == null)
{
return;
}
for (int i = 0; i < infos.length; i++)
{
infos[i].clear();
}
}
protected void resetChainKeepInterceptors(JoinPointInfo[] infos)
{
if (infos == null)
{
return;
}
for (int i = 0; i < infos.length; i++)
{
infos[i].resetChainKeepInterceptors();
}
}
// protected void finalizeConstructionChain(ArrayList newConstructionInfos)
// {
// for (int i = 0; i < newConstructionInfos.size(); i++)
// {
// ConstructionInfo info = (ConstructionInfo) newConstructionInfos.get(i);
// ArrayList list = info.getInterceptorChain();
// Interceptor[] interceptors = null;
// if (list.size() > 0)
// {
// interceptors = applyPrecedence((Interceptor[]) list.toArray(new Interceptor[list.size()]));
// }
// info.setInterceptors(interceptors);
// }
// }
protected void resolveConstructorPointcut(AdviceBinding binding)
{
for (int i = 0; i < constructors.length; i++)
{
Constructor<?> constructor = constructors[i];
if (binding.getPointcut().matchesExecution(this, constructor))
{
if (AspectManager.verbose) System.err.println("[debug] constructor matched binding: " + constructor);
adviceBindings.add(binding);
binding.addAdvisor(this);
pointcutResolved(constructorInfos[i], binding, new ConstructorJoinpoint(constructor));
}
}
}
protected void resolveConstructionPointcut(AdviceBinding binding)
{
if (constructionInfos.length > 0)
{
for (int i = 0; i < constructionInfos.length ;i++)
{
ConstructionInfo info = constructionInfos[i];
Constructor<?> constructor = info.getConstructor();
if (binding.getPointcut().matchesConstruction(this, constructor))
{
if (AspectManager.verbose) System.err.println("[debug] construction matched binding: " + constructor);
adviceBindings.add(binding);
binding.addAdvisor(this);
pointcutResolved(info, binding, new ConstructorJoinpoint(constructor));
}
}
}
}
/** @deprecated We should just be using xxxxInfos */
protected void populateInterceptorsFromInfos()
{
if (constructorInfos == null)
{
constructorInterceptors = new Interceptor[0][];
}
else
{
constructorInterceptors = new Interceptor[constructorInfos.length][];
for (int i = 0 ; i < constructorInfos.length ; i++)
{
constructorInterceptors[i] = constructorInfos[i].getInterceptors();
}
}
}
/**
* Default implementation adds interceptorChain directly to the info.
* GeneratedClassAdvisor overrides this
*/
protected void pointcutResolved(JoinPointInfo info, AdviceBinding binding, Joinpoint joinpoint)
{
ArrayList<Interceptor> curr = info.getInterceptorChain();
if (binding.getCFlow() != null)
{
ArrayList<Interceptor> cflowChain = new ArrayList<Interceptor>();
createInterceptorChain(binding.getInterceptorFactories(), cflowChain, joinpoint);
Interceptor[] cflowInterceptors = cflowChain.toArray(new Interceptor[cflowChain.size()]);
curr.add(new CFlowInterceptor(binding.getCFlowString(), binding.getCFlow(), cflowInterceptors));
}
else
{
createInterceptorChain(binding.getInterceptorFactories(), curr, joinpoint);
}
}
Interceptor[] applyPrecedence(Interceptor[] interceptors)
{
return PrecedenceSorter.applyPrecedence(interceptors, manager);
}
/**
* Whether the type of advisor supports matching on pointcut expression, where the method is defined in a superclass only,
* while the pointcut expression class matches the subclass. This is currently only supported for generated advisors, due to
* the new weaving model. So (with generated advisors) if we have<BR/>
* <code><BR/>
* public class Super {<BR/>
* void method(){}<BR/>
* }<BR/>
* <BR/>
* public class Sub etxends Super {<BR/>
* }<BR/>
* </code>
* and<BR/>
* <code>
* <bind pointcut="execution(* Super->method())"><BR/>
* <interceptor class="A"/><BR/>
* </bind><BR/>
* <bind pointcut="execution(* sub->method())"><BR/>
* <interceptor class="B"/><BR/>
* </bind><BR/>
* </code><BR/>
* Super.method() will be intercepted by A only<BR/>
* Sub.method() will be intercepted by A and B
*
*/
public boolean chainOverridingForInheritedMethods()
{
return false;
}
/**
* @param overriding the new value of chainOverridingForInheritedMethods
* @see Advisor#chainOverridingForInheritedMethods()
*/
protected void setChainOverridingForInheritedMethods(boolean overriding)
{
//Implemented by base-classes
throw new NotImplementedException("Not a legal operation for Advisor");
}
interface DeployAnnotationOverrideAction
{
void deploy(Advisor advisor, AnnotationIntroduction introduction);
DeployAnnotationOverrideAction PRIVILEGED = new DeployAnnotationOverrideAction()
{
public void deploy(final Advisor advisor, final AnnotationIntroduction introduction)
{
try
{
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
{
public Object run()
{
advisor.doDeployAnnotationOverride(introduction);
return null;
}
});
}
catch (PrivilegedActionException e)
{
Exception ex = e.getException();
if (ex instanceof RuntimeException)
{
throw (RuntimeException)ex;
}
throw new RuntimeException(ex);
}
}
};
DeployAnnotationOverrideAction NON_PRIVILEGED = new DeployAnnotationOverrideAction()
{
public void deploy(Advisor advisor, AnnotationIntroduction introduction)
{
advisor.doDeployAnnotationOverride(introduction);
}
};
}
public void cleanup()
{
//AspectDefinitions have strong links back to us
for(AspectDefinition def : perInstanceAspectDefinitions)
{
removePerInstanceAspect(def);
def.unregisterAdvisor(this);
}
for(AspectDefinition def : perInstanceJoinpointAspectDefinitions.keySet())
{
removePerInstanceJoinpointAspect(def);
def.unregisterAdvisor(this);
}
AspectDefinition[] defs = adviceInterceptors.keySet().toArray(new AspectDefinition[adviceInterceptors.size()]);
for(int i = 0 ; i < defs.length ; i++)
{
if (defs[i].getScope() == Scope.PER_CLASS)
{
removePerClassAspect(defs[i]);
defs[i].unregisterAdvisor(this);
}
}
if (methodInfos != null)
{
methodInfos. clear();
}
}
protected void initInterfaceIntroductionsList()
{
if (interfaceIntroductions == UnmodifiableEmptyCollections.EMPTY_ARRAYLIST)
{
synchronized(lazyCollectionLock)
{
if (interfaceIntroductions == UnmodifiableEmptyCollections.EMPTY_ARRAYLIST)
{
interfaceIntroductions = new ArrayList<InterfaceIntroduction>();
}
}
}
}
protected void initClassMetaDataBindingsList()
{
if (classMetaDataBindings == UnmodifiableEmptyCollections.EMPTY_ARRAYLIST)
{
synchronized(lazyCollectionLock)
{
if (classMetaDataBindings == UnmodifiableEmptyCollections.EMPTY_ARRAYLIST)
{
classMetaDataBindings = new ArrayList<ClassMetaDataBinding>();
}
}
}
}
protected void initPerInstanceAspectDefinitionsSet()
{
if (perInstanceAspectDefinitions == UnmodifiableEmptyCollections.EMPTY_COPYONWRITE_ARRAYSET)
{
synchronized(lazyCollectionLock)
{
if (perInstanceAspectDefinitions == UnmodifiableEmptyCollections.EMPTY_COPYONWRITE_ARRAYSET)
{
perInstanceAspectDefinitions = new CopyOnWriteArraySet<AspectDefinition>();
}
}
}
}
protected void initPerInstanceJoinpointAspectDefinitionsMap()
{
if (perInstanceJoinpointAspectDefinitions == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (perInstanceJoinpointAspectDefinitions == UnmodifiableEmptyCollections.EMPTY_CONCURRENT_HASHMAP)
{
perInstanceJoinpointAspectDefinitions = new ConcurrentHashMap<AspectDefinition, Set<Joinpoint>>();
}
}
}
}
protected void initAdvisedMethodsMap()
{
if (advisedMethods == UnmodifiableEmptyCollections.EMPTY_TLONG_OBJECT_HASHMAP)
{
synchronized(lazyCollectionLock)
{
if (advisedMethods == UnmodifiableEmptyCollections.EMPTY_TLONG_OBJECT_HASHMAP)
{
advisedMethods = new TLongObjectHashMap();
}
}
}
}
public boolean hasSameMethodAspectLength(Advisor other)
{
if (this.getClazz() != other.getClazz())
{
throw new IllegalArgumentException("The advisors must be of the same type. Mine: " +
this.getClazz().getName() + "; other: " + other.getClazz().getName());
}
long[] myKeys = this.methodInfos.infos.keys();
long[] otherKeys = other.methodInfos.keys();
return JoinPointComparator.hasSameMethodAspectLength(myKeys, otherKeys, this, other);
}
public boolean hasSameConstructorAspectLength(Advisor other)
{
if (this.getClazz() != other.getClazz())
{
throw new IllegalArgumentException("The advisors must be of the same type. Mine: " +
this.getClazz().getName() + "; other: " + other.getClazz().getName());
}
ConstructorInfo[] myInfos = this.getConstructorInfos();
ConstructorInfo[] otherInfos = other.getConstructorInfos();
return JoinPointComparator.hasSameConstructorAspectLength(myInfos, otherInfos);
}
}