javaosgiaopaspectjload-time-weaving

OSGi WeavingHook Examples


Does anybody have any examples of using the OSGi 4.3+ Weaving Hook Service? What about with AspectJ, ASM, JavaAssist? Is anybody actually using OSGi WeavingHooks?

The example in OSGi Core 5.0.0 section 56.2 simply leaves out the actual weaving and says "the final weaving is left as an exercise to the reader".

My goal is to:

  1. create an annotation (@MyAnnotation) that I can place on fields (primitives or objects).
  2. create an org.osgi.framework.hooks.weaving.WeavingHook to weave classes with that annotation
  3. use load-time weaving to pointcut at any modification of fields with that annotation
  4. fire EventAdmin events that the field was modified.
  5. dynamically update the bundle wiring from the WeavingHook to wire to the EventAdmin bundle.

My problem is mostly with #3.

I'm currently trying to use the AspectJ WeavingAdaptor to do the weaving, but I'm having problems getting my aspect library in to it, since its expecting the java.net.URL[] aspectURLs in the constructor to be either jars or directories it can find on the filesystem, and not bundles. Also, i'm not sure how to handle any new classes generated by the weaver through callbacks to the acceptClass(String name, bytes[]) method of GeneratedClassHandler.

Maybe WeavingAdaptor is not the right place to start my weaving? Or maybe I shouldn't use AspectJ?

MyAnnotation.java

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}

MyWeavingHook.java

public class MyWeavingHook implements WeavingHook {

    public class MyWeavingClassloader implements WeavingClassLoader {

        private Bundle b;

        public MyWeavingClassLoader(Bundle b) {
            this.b = b;
        }

        void acceptClass(java.lang.String name, byte[] bytes) {
            //no way to get this back into the woven classes bundle classloader?
        } 

        URL[] getAspectURLs() {
            //how do I get a handle to my aspect library that AspectJ can understand?
        }
    }

    public void weave(WovenClass myclass) {
        Bundle b = Framework.getBundle(MyWeavingHook.class);
        WeavingClassLoader wc = new WeavingClassLoader(b);
        WeavingAdaptor w = new WeavingAdaptor(wc);
        if (shouldWeave(myclass))
          myclass.setBytes(w.weave(myClass.getBytes()));
        //should catch exceptions
    }

    private boolean shouldWeave(WovenClass myclass) {
        //not sure of the best logic to pick which classes to weave yet
    }
}

MyAspect.aj

privileged aspect MyAspect {
    after() : set(* *) && @annotation(MyAnnotation) {
      //send EventAdmin event
    }
}

MyTestClass.java

public class MyTestClass {
    @MyAnnotation
    private int myField;

    public void doSomething() {
      //do stuff with myField
    }
}

I could use Spring AOP, but I want this to work for any bundle, not just beans instantiated through Spring or Blueprint. Also, Equinox Weaving doesn't seem to be using the OSGi weaving hook spec yet and I don't want to be tied to Equinox. I have no problem scrapping AspectJ if something else works better.

Reference to a similar question: Is it possible to do bytecode manipulation when using OSGi?

UPDATE:

End result is I just used Equinox Aspects and installed it into Karaf. Was 3 bundles, one library, and a system property. I'll use it until they either update it to us OSGi weaving or I write my own OSGi weaving hooks to use the AspectJ code similar to Equinox Aspects. I don't like the weaving indicators required to get Equinox Aspects to work because it introduces a require-bundle/reexport or an import-package on the AspectJ RT in the bundle to be woven. This dependency should be dynamically added and advised outside of the bundle.


Solution

  • Have a look at ProxyWeavingHook from Proxy module of Apache Aries. It uses the ASM library directly to modify the bytecode so more low level.