| Summary: | [Aspects] Can't weave fragments | ||
|---|---|---|---|
| Product: | [Eclipse Project] Equinox | Reporter: | Matthew Webster <matthew_webster> |
| Component: | Incubator | Assignee: | equinox.incubator-inbox <equinox.incubator-inbox> |
| Status: | RESOLVED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | jeffmcaffer |
| Version: | 3.2 | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows XP | ||
| Whiteboard: | |||
The javadoc is not clear, but the intention was that the initializedClassLoader would only be called for the host's BaseData object. Can you give more details why you would need this called for fragment BaseData objects. The calls to ClassLoadingHook.processClass pass the BundleEntry (which may come from a fragment) and the ClasspathManager. You should be able to get the host BaseData and the BaseClassLoader from the ClasspathManager. In AspectJ LTW we have ClassLoader <-> WeavingAdaptor -> Weaver -> World. Under OSGi things are more complex. We still need to use a class loader but things revolve around bundles and services: Bundle <-> BundleData <-> BundleFile -> AspectJAdaptor(ClassLoader) -> WeavingService(ClassLoader) -> WeavingAdaptor ... The lifecycle of the AspectJAdaptor highly asynchronous: 1. AspectJAdaptor(BaseData) [BundleFileWrapperFactoryHook.wrapBundleFile()] 2. setBaseLoader(BaseClassLoader) [ClassLoadingHook.initializedClassLoader()] 3. initialize() [ClassLoadingHook.initializedClassLoader()] We initialize the adaptor on first reference i.e. when we try to weave the first class in a particular bundle. By that time we should have all the information we need to instantiate a weaving service in particular the bundle class loader. It is at this point we fail for fragments. I have only just discovered this problem when trying to weave some SWT classes that happen to reside in the win32 fragment. I think this my problem because a fragment shares a class loader with its host so it should share a WeavingAdaptor and therefore probably a weaving service. When I create an AspectJAdaptor it should probably figure out that it's a fragment and get hold or the right weaving service. perhaps speaking out of turn here but can the weaving focus on classloaders and use the rest of the context for scoping? That is, you hook a weaver into a classloader and then it can use the location of the class at hand (from a bundle, a fragment, etc) to determine higher level ideas of how, if, when an aspect should be applied? For example, I want to apply an aspect but only to a particular fragment of a particular host or just the host and not the fragments, or... Not at all. I could probably, by using a separate weaver and world though a separate weaving service, scope an aspect to a fragment of the host but I'm not sure that it would be desirable. One example is that fragments are an extremely useful way of introducing an aspect into an existing bundle, so I definitely want the scope of an aspect to exceed the fragment that defines it. In which case I want to weave everything in that bundle including other fragments. My understanding is that the contents of a fragment logically become part of the host: the manifests are merged and the classpath appended. At runtime a class can "see" every other class in the bundle including those in fragments and it can't tell where they came from: the PackageAdmin service will say it is the host (because it must use the defining class loader). I want aspects to behave like classes so they should "see" and therefore weave everything that is logically part of the bundle. An interesting question. Right. I was thinking that at the classloader level you can tell where a class is coming from because the classloader is in effect scanning the classpath (bundle itself, fragments etc) to find the .class file. You are absolutely right though that once a class is loaded you can't really tell where it came from (though that functionality could likely be implemented by replaying the class file lookup...) While it would be possible to scope aspects along bundle-fragment and fragment-fragment boundaries I don't believe it would be useful. In my view fragments are an implementation detail that should not affect aspect scoping and would in fact prevent the application of some of the patterns I have been developing. The aspect writer already has the pointcut while the bundle writer has the aop.xml include/exclude elements to control scope. Change AspectJAdaptor.initialize() to determine whether a bundle is in fact a fragment and if so obtain the weaving service for the host. Should probably use a separate caching service when implementing Bug 161023 "[Aspects] Phase III - Byte-code Caching". Should I add weaving/not weaving messages for fragments and can't weave for org.aspectj bundles? Fix available |
Bundle fragments are not woven because ClassLoadingHook.initializedClassLoader() is never called for the BundleData instance: > AspectJAdaptor.initialize() bundle=update@plugins/org.eclipse.swt.win32.win32.x86_3.2.0.v3232m.jar, baseLoader=null W AspectJAdaptor.initialize() symbolicName=update@plugins/org.eclipse.swt.win32.win32.x86_3.2.0.v3232m.jar, baseLoader=null < AspectJAdaptor.initialize() weavingService=false, cachingService=false Is this a Hooks bug or do I need to set the loader myself from the host bundle?