Reimplementing AspectManager/Domains to understand jboss-cl
kabirkhan Feb 17, 2009 2:12 PMI have almost completed the reimplementation of the classpools
http://www.jboss.org/index.html?module=bb&op=viewtopic&t=143639
To understand the classloading rules used in JBoss AOP, all that is outstanding is a bit of work in AS 5 which will be possible following the upgrade to jboss-cl 2.0.3.GA. The next part is to reimplement the AspectManagers and Domains that are used in AOP to understand the classloading rules.
Before I start, here is how the classloader scoping currently works. It works by classloader domain, and the deployment containing AOP information determines where the AOP information is deployed. For woven classes, the classloader domain of its loading class determines which AOP information is applied to that class.
Currently, if a deployment is not scoped (i.e. the classloader belongs to the default domain) the AOP information is deployed to the main AspectManager. The AOP information used is shared among all classes loaded by classloaders belonging to the default domain. If a deployment is scoped (i.e. the classloader belongs to a child of the default domain) the AOP information is deployed to an AOP Domain, which is mapped onto the classloader Domain. Again, all the information deployed into that AOP Domain is applied to all classes loaded by classloaders belonging to the corresponding classloader Domain. Domains are hierarchical with a parent link that takes you to the parent Domain, with the "root" the main AspectManager. A child domain will inherit AOP information from its parents in this scenario with parent-first/-last ordering controlled by the behaviour of the classloader Domain.
In a nutshell, everything is visible to everything else that belongs to that classloader domain, which is fine at the moment since to my knowledge nobody is really using the more advanced features of the classloaders in AS 5 yet.
With the new classloaders there can be some visibility constraints between classloaders deployed within a domain, making us need some way to define what AOP information is visble between different loaders.
There are a few main use-cases and scenarios in which jboss aop is deployed, I will try to outline some problems I can see at the moment wrt how these are deployed, assuming that there are two classloaders deployed to a classloader domain, where:
ClassLoader A: Imports: pkg.b Private packages: pkg.a
ClassLoader B: Exports: pkg.b ImportAll: false
The main problem I can see is with AOP "introducing" new classes to the woven POJOs. In the examples given the new classes are from added interceptors, but the same holds true for interface introductions, mixins, annotation-introductions, metadata-loaders etc.
1) AOP deployed as part of a standalone jboss-aop.xml
=====================================================
Assuming that the classes have been prepared, an -aop.xml file is deployed containing binding information that is used to apply bindings to the classes. What happens is
a) New class is visible from the affected classes classloader
<bind pointcut="all(pkg.a.PojoA) OR all(pkg.b.PojoB)"> <interceptor name="pkg.b.MyInterceptor"/> </bind>
This should work out of the box since CL B has the pkg.b.MyInterceptor class , and it can be seen from both PojoA's loader (CL A) and PojoB's loader (CL B).
b) New class is not visible from the affected classes classloader
<bind pointcut="all(pkg.a.PojoA) OR all(pkg.b.PojoB)"> <interceptor name="pkg.a.MyInterceptor"/> </bind>
Here PojoA would get the extra interceptor, PojoB's would currently cause an error since pkg.a.MyInterceptor cannot be loaded from CL B.
2) AOP deployed as part of a deployment
=======================================
An .aop file is deployed containing a META-INF/jboss-aop.xml file that is used to apply bindings to the classes. Normally, this should contain the interceptor classes (discussed below) , but could also refer to external classes (which is discussed in point 1 above)
a) New class is visible from the affected classes classloader
Deployment against CL B contains a .aop file containing the following
<bind pointcut="all(pkg.a.PojoA) OR all(pkg.b.PojoB)"> <interceptor name="pkg.b.MyInterceptor"/> </bind>
This will work since pkg.b.MyInterceptor is visible from both CL A and CL B.
b) New class is not visible from the affected classes classloader
Deployment against CL B contains a .aop file containing the following
<bind pointcut="all(pkg.a.PojoA) OR all(pkg.b.PojoB)"> <interceptor name="pkg.a.MyInterceptor"/> </bind>
Here PojoA would get the extra interceptor, PojoB's would currently cause an error since pkg.a.MyInterceptor cannot be loaded from CL B.
c) New standalone class is not visible from the affected classes classloader
If I deploy a c.aop on its own that gets the classloader CL C deployed against the same domain as A and B, containing
<bind pointcut"all(pkg.a.PojoA) OR all(pkg.b.PojoA)"> <!-- loaded by classloader C, part of c.aop --> <interceptor name="pkg.c.MyInterceptor"/> </bind>
As far as I can tell, neither CL A nor CL B will be able to load pkg.c.MyInterceptor?
I am slightly unsure what happens when the classes are woven in the examples given. When weaving PojoA, that gets additional interfaces such as the the org.jboss.aop.Advised interface, references to org.jboss.aop.Advisor etc., which I am not sure off the top of my head are visible from CL A?
In the examples I gave, JBoss AOP will currently throw an error if a required interceptor class cannot be found. A few ideas to fix this is
I) Swallow Exceptions
If an interceptor class or introduced interface cannot be found, just log the error and continue. I don't think that is a good thing though, but included it for completeness.
II) Use a special classloader for interceptors etc.
A special aop classloader could be used for the aspects at runtime, but that would require changes to the woven code to set the correct classloader, which we don't really want to do when weaving/running outside of the AS. Also, as in the cases of interface introductions the interface/mixin must be visible when the class is loaded.
III) Somehow make new classes from AOP globally visible
How?
IV) Set up delegating AOP domains for each class(loader)
Instead of giving a reference to the whole AOP Domain when getting the domain for a classloader, it should return a AOPClassLoaderManager that is unique to that classloader, and contains the things from the underlying AOP Domain that are visible from the classloader. For example in 2b) above the AOPClassLoaderManager for CL A would contain the binding, while the AOPClassLoaderManager for CL B would not contain that particular binding. I am unsure how that would work for 2c) if pkg.c.MyInterceptor is not visible from CL A or B? While this might be another flavour of "Swallow Exceptions", at least we could include some management capability to see what exists in the classloading domain vs what is visible from the classloader. As to how to use these rules in the domains, we were able to delegate a lot of work for the classloading rules to jboss-cl. Maybe the easiest is to do the same here as well? When adding a binding or something else that needs to load a class make sure that the AOPClassLoaderManager is able to load up that class using its classloader, and if not blacklist that binding? When a classloader joins the classloader Domain later, recheck all the AOP Domain's blacklisted bindings etc. and unblacklist the newly found ones?