All the tests now pass when the advisors are generated
I only have a Domain for the instance advisors. I kind of had it running with Domains for the class advisors too, but removed this since I saw no immediate benefit and it was easier this way. To get this to work I had to make quite a few changes to the Domain class to override methods and check with parent manager/domain etc. Also there were some issues with whether each advisor should be registered with its Domain or the AspectManager. IIRC with the Domain as-is they would be added to the Domain, so when adding bindings dynamically to the AspectManager the list of advisors would be empty and none of the advisors would get their chains updated. I worked around this by overriding stuff in Domain to add them to AspectManager which made having separate Domains for class advisors seem pointless (or I just had the wrong idea :-)
We now have two ways of adding per instance advices:
1) Per instance API using Domain. Generated instance advisors have a domain to which we can add stuff. It works with adding bindings and we can now have dynamic additions of full-blown aspects per instance, sorted by precedence. I'm a bit unclear on if we need to be able to add metadata on a per instance basis via this API?
2) Old per instance API. The generated instance advisors implement InstanceAdvisor and delegate calls to the InstanceAdvisor methods to a GeneratedInstanceAdvisorMixin class. Functionally they should be exactly the same as before since it's the same code. I guess I could have simulated this using the underlying domain, but I think adding stuff before/after the main interceptor chains from the class advisors this way would be very difficult. Things added using 1) become part of the "main" interceptor chain, and things added using 2) are appended/inserted around that.
For the instance interceptor chains to get updated for a sub class instance where it does not implement an advised method from the super class, I had to add "invoke" methods to the instance advisor for all advised joinpoints from all superclasses, as in SubPOJOInstanceAdvisor.someMethod7774272070930259974().
I need to test the per instance stuff for caller pointcuts too.
I've made the mixin methods work more or less the same way as for normal methods (for generated advisors), i.e. a target method, a wrapper in class calling the mixin, and a wrapper method in the advisor creating an invocation. I left the invocation unoptimised
as in the old stuff. I still need to make this work with the new instance advisors.
This is more or less what we now have
package org.jboss.test.aop.dynamicgenadvisor;
public class POJO
implements Advised
{
private static final transient Advisor pojoadvisor$aop = new POJOAdvisor();
protected volatile transient Advisor currentAdvisor$aop;
protected transient InstanceAdvisor instanceAdvisor$aop;
public POJO()
{
super();
currentAdvisor$aop = _getAdvisor();
System.out.println("*** POJO ctor");
Object obj = null;
((POJOAdvisor)getCurrentAdvisor$aop()).aop(this);
}
public int org$jboss$test$aop$dynamicgenadvisor$POJO$someMethod$aop()
{
System.out.println("*** someMethod");
return 10;
}
public void notPrepared()
{
System.out.println("Not prepared");
}
public Advisor _getAdvisor()
{
return pojoadvisor$aop;
}
protected Advisor getCurrentAdvisor$aop()
{
//Access current advisor via this method in case class has been serialized
if(currentAdvisor$aop == null)
{
currentAdvisor$aop = _getAdvisor();
}
return currentAdvisor$aop;
}
public InstanceAdvisor _getInstanceAdvisor()
{
if(instanceAdvisor$aop == null)
{
synchronized(this)
{
if(instanceAdvisor$aop == null)
{
Advisor advisor = ((POJOAdvisor)pojoadvisor$aop).createInstanceAdvisor(this);
currentAdvisor$aop = advisor;
instanceAdvisor$aop = (InstanceAdvisor)advisor;
}
}
}
return instanceAdvisor$aop;
}
public int someMethod()
{
return ((POJOAdvisor)getCurrentAdvisor$aop()).someMethod7774272070930259974(this);
}
static class POJOAdvisor extends GeneratedClassAdvisor
implements Untransformable
{
int version;
protected static Class advisedClass = Thread.currentThread().getContextClassLoader().loadClass("org.jboss.test.aop.dynamicgenadvisor.POJO");
protected MethodInfo aop$MethodInfo_someMethod7774272070930259974;
protected AspectManager initialiseDomain()
{
//Class advisors use aspect manager
return AspectManager.instance();
}
protected void rebuildInterceptors()
{
version++;
super.rebuildInterceptors();
}
protected void internalRebuildInterceptors()
{
super.rebuildInterceptors();
}
protected void initialiseMethods()
{
aop$MethodInfo_someMethod7774272070930259974 = new MethodInfo(advisedClass, 0x6be3c3423709e006L, 0x8b506dc3bd620a28L, this);
addMethodInfo(aop$MethodInfo_someMethod7774272070930259974);
}
//Similar methods to initialise Constructors, Fields etc.
public Advisor createInstanceAdvisor(Object obj)
{
return new POJOInstanceAdvisor(obj, this);
}
protected int someMethod7774272070930259974(POJO pojo)
{
if(aop$MethodInfo_someMethod7774272070930259974.interceptors != null)
{
someMethod_7774272070930259974 somemethod_7774272070930259974 = new someMethod_7774272070930259974(aop$MethodInfo_someMethod7774272070930259974, aop$MethodInfo_someMethod7774272070930259974.interceptors);
somemethod_7774272070930259974.setTargetObject(pojo);
somemethod_7774272070930259974.typedTargetObject = pojo;
somemethod_7774272070930259974.setAdvisor(pojo.getCurrentAdvisor$aop());
return ((Integer)somemethod_7774272070930259974.invokeNext()).intValue();
} else
{
return pojo.org$jboss$test$aop$dynamicgenadvisor$POJO$someMethod$aop();
}
}
public POJOAdvisor()
{
super("org.jboss.test.aop.dynamicgenadvisor.POJO");
AspectManager.instance().setUsesGeneratedWeaving(true);
initialiseDomain();
initialiseMethods();
initialiseConstructors();
initialiseConstructions();
initialiseFieldReads();
initialiseFieldWrites();
super.initialise(advisedClass, initialiseDomain());
initialiseCallers();
}
protected POJOAdvisor(String s)
{
super("$1");
}
}
static class POJOInstanceAdvisor extends POJOAdvisor
implements Untransformable, InstanceAdvisor
{
POJOAdvisor classAdvisor;
protected Domain domain;
GeneratedInstanceAdvisorMixin instanceAdvisorMixin;
//To keep track of if instance interceptors added using old api should be readded
protected boolean aop$MethodInfo_someMethod7774272070930259974_updated;
public Domain getDomain()
{
return domain;
}
protected AspectManager initialiseDomain()
{
domain = new Domain(AspectManager.instance(), false);
((Domain)domain).setInheritsBindings(true);
return domain;
}
protected void advicesUpdated()
{
aop$MethodInfo_someMethod7774272070930259974_updated = true;
}
//Implement all InstanceAdvisor methods and delegate to mixin
public SimpleMetaData getMetaData()
{
return instanceAdvisorMixin.getMetaData();
}
public void insertInterceptor(Interceptor interceptor)
{
advicesUpdated();
instanceAdvisorMixin.insertInterceptor(interceptor);
}
public void removeInterceptor(String s)
{
advicesUpdated();
instanceAdvisorMixin.removeInterceptor(s);
}
...
protected void checkVersion()
{
if(classAdvisor.version != super.version)
{
super.version = classAdvisor.version;
internalRebuildInterceptors();
if(instanceAdvisorMixin.hasInterceptors())
{
advicesUpdated();
}
}
}
protected int someMethod7774272070930259974(POJO pojo)
{
checkVersion();
if(aop$MethodInfo_someMethod7774272070930259974_updated)
{
super.MethodInfo_someMethod7774272070930259974.interceptors = instanceAdvisorMixin.getInterceptors(super.MethodInfo_someMethod7774272070930259974.interceptors);
aop$MethodInfo_someMethod7774272070930259974_updated = false;
}
return super.someMethod7774272070930259974(pojo);
}
public POJOInstanceAdvisor(Object obj, POJOAdvisor pojoadvisor)
{
instanceAdvisorMixin = new GeneratedInstanceAdvisorMixin(obj, pojoadvisor);
classAdvisor = pojoadvisor;
super.version = classAdvisor.version;
}
}
static class someMethod_7774272070930259974 extends MethodInvocation
implements Untransformable{}
}
package org.jboss.test.aop.dynamicgenadvisor;
public class SubPOJO extends POJO
implements Advised
{
static class SubPOJOAdvisor extends POJO.POJOAdvisor
implements Untransformable
{
int version;
protected static Class advisedClass = Thread.currentThread().getContextClassLoader().loadClass("org.jboss.test.aop.dynamicgenadvisor.SubPOJO");
protected MethodInfo aop$MethodInfo_subMethod_N_3276343010251184758;
protected static ConstructorInfo aop$constructorInfo_0;
protected void initialiseMethods()
{
super.initialiseMethods();
aop$MethodInfo_subMethod_N_3276343010251184758 = new MethodInfo(advisedClass, 0xd288176417a4e58aL, 0xa49e7f9bfaceb963L, this);
addMethodInfo(aop$MethodInfo_subMethod_N_3276343010251184758);
}
protected void initialiseConstructors()
{
aop$constructorInfo_0 = new ConstructorInfo(advisedClass, 0, 0xa9840fe3aefd9b08L, 0xc974387c3e94e6bcL, this);
addConstructorInfo(aop$constructorInfo_0);
}
//Initialise the constructors, fields etc.
protected void initialiseConstructions()
{
}
public Advisor createInstanceAdvisor(Object obj)
{
return new SubPOJOInstanceAdvisor(obj, this);
}
protected void subMethod_N_3276343010251184758(SubPOJO subpojo)
{
if(aop$MethodInfo_subMethod_N_3276343010251184758.interceptors != null)
{
subMethod_N3276343010251184758 somemethod2_n3276343010251184758 = new subMethod_N3276343010251184758(aop$MethodInfo_subMethod_N_3276343010251184758, aop$MethodInfo_subMethod_N_3276343010251184758.interceptors);
somemethod2_n3276343010251184758.setTargetObject(subpojo);
somemethod2_n3276343010251184758.typedTargetObject = subpojo;
somemethod2_n3276343010251184758.setAdvisor(subpojo.getCurrentAdvisor$aop());
somemethod2_n3276343010251184758.invokeNext();
} else
{
subpojo.org$jboss$test$aop$dynamicgenadvisor$SubPOJO$subMethod$aop();
}
}
public SubPOJOAdvisor()
{
super("org.jboss.test.aop.dynamicgenadvisor.SubPOJO");
AspectManager.instance().setUsesGeneratedWeaving(true);
initialiseDomain();
initialiseMethods();
initialiseConstructors();
initialiseConstructions();
initialiseFieldReads();
initialiseFieldWrites();
super.initialise(advisedClass, initialiseDomain());
initialiseCallers();
}
protected SubPOJOAdvisor(String s)
{
super(s);
}
}
static class SubPOJOInstanceAdvisor extends SubPOJOAdvisor
implements Untransformable, InstanceAdvisor
{
SubPOJOAdvisor classAdvisor;
protected Domain domain;
GeneratedInstanceAdvisorMixin instanceAdvisorMixin;
protected boolean aop$MethodInfo_subMethod_N_3276343010251184758_updated;
protected boolean aop$MethodInfo_someMethod7774272070930259974_updated;
public Domain getDomain()
{
return domain;
}
protected AspectManager initialiseDomain()
{
domain = new Domain(AspectManager.instance(), false);
((Domain)domain).setInheritsBindings(true);
return domain;
}
protected void advicesUpdated()
{
aop$MethodInfo_subMethod_N_3276343010251184758_updated = true;
aop$MethodInfo_someMethod7774272070930259974_updated = true;
aop$FieldInfo_r_i_updated = true;
aop$FieldInfo_w_i_updated = true;
}
public SimpleMetaData getMetaData()
{
return instanceAdvisorMixin.getMetaData();
}
public Interceptor[] getInterceptors(Interceptor ainterceptor[])
{
return instanceAdvisorMixin.getInterceptors(ainterceptor);
}
public void insertInterceptor(Interceptor interceptor)
{
advicesUpdated();
instanceAdvisorMixin.insertInterceptor(interceptor);
}
//rest of instance advisor methods
...
protected void checkVersion()
{
if(classAdvisor.version != super.version)
{
super.version = classAdvisor.version;
internalRebuildInterceptors();
if(instanceAdvisorMixin.hasInterceptors())
{
advicesUpdated();
}
}
}
protected void subMethod_N_3276343010251184758(SubPOJO subpojo)
{
checkVersion();
if(aop$MethodInfo_subMethod_N_3276343010251184758_updated)
{
super.MethodInfo_subMethod_N_3276343010251184758.interceptors = instanceAdvisorMixin.getInterceptors(super.MethodInfo_subMethod_N_3276343010251184758.interceptors);
aop$MethodInfo_subMethod_N_3276343010251184758_updated = false;
}
super.subMethod_N_3276343010251184758(subpojo);
}
//Instance advisor for sub class must override this method from SUPER (i.e. POJO advisor)
//to check if per-instance interceptors have been added
protected int someMethod7774272070930259974(POJO pojo)
{
checkVersion();
if(aop$MethodInfo_someMethod7774272070930259974_updated)
{
super.aop$MethodInfo_someMethod7774272070930259974.interceptors = instanceAdvisorMixin.getInterceptors(super.aop$MethodInfo_someMethod7774272070930259974.interceptors);
aop$MethodInfo_someMethod7774272070930259974_updated = false;
}
return super.someMethod7774272070930259974(pojo);
}
public SubPOJOInstanceAdvisor(Object obj, SubPOJOAdvisor subpojoadvisor)
{
instanceAdvisorMixin = new GeneratedInstanceAdvisorMixin(obj, subpojoadvisor);
classAdvisor = subpojoadvisor;
super.version = classAdvisor.version;
}
}
static class subMethod_N3276343010251184758 extends MethodInvocation
implements Untransformable
{}
private static final transient Advisor subpojoadvisor$aop = new SubPOJOAdvisor();
public SubPOJO()
{
}
public void org$jboss$test$aop$dynamicgenadvisor$SubPOJO$subMethod$aop()
{
System.out.println("*** subMethod");
}
public Advisor _getAdvisor()
{
return subpojoadvisor$aop;
}
public InstanceAdvisor _getInstanceAdvisor()
{
if(super.instanceAdvisor$aop == null)
{
synchronized(this)
{
if(super.instanceAdvisor$aop == null)
{
Advisor advisor = ((SubPOJOAdvisor)subpojoadvisor$aop).createInstanceAdvisor(this);
super.currentAdvisor$aop = advisor;
super.instanceAdvisor$aop = (InstanceAdvisor)advisor;
}
}
}
return super.instanceAdvisor$aop;
}
public void subMethod()
{
((SubPOJOAdvisor)getCurrentAdvisor$aop()).subMethod_N_3276343010251184758(this);
}
}
Now for
* Should be able to define different advice chains for inherited methods.
http://jira.jboss.com/jira/browse/JBAOP-154
While I see how this would work once instrumented, I am struggling a bit to find out how to do this in the case of
public class Top
{
public void method();
}
public class Bottom
{
}
<bind pointcut="execution(* Bottom->method())">
</bind>
The problem is that the MethodExecutionTransformer will never pick out a matched pointcut (Bottom.method() does not exist), so neither Top or Bottom gets the hooks built in to match the pointcut. I tried out something by copying all CtMethods from Top into Bottom before doing the matching, and keeping those that match, but that seems like a pretty inefficient way to do it? I think you mentioned something that generated advisors would solve in this regard, but I'm not sure what?