JRockit JVM Support For AOP, Part 2

Pages: 1, 2, 3, 4

Details on the API: The action Instance and the action Kind

As illustrated in the previous code samples, an action method can be either static or not. If the action method is not static, you must pass in an action instance on which the JVM invokes the action method.

This follows the syntax style with which a Java developer invokes a method reflectively using java.lang.reflect.Method.invoke(null/*static method*/, .../*args*/), although, unlike this example, with JVM AOP support, the underlying action invocation will not involve any reflection at all.

Giving the user control over the action instance opens up interesting use cases. For example, you could implement a simple delegation pattern to swap a whole action instance with a different implementation at runtime without involving the JVM internals.

Note that this will be useful to implement AOP aspect instantiation models (per clause) such as issingleton(), pertarget(), perthis(), percflow(), and so on, while not locking the JVM API to some predefined semantics.

Before registering the subscription to the weaver instance, it is given a kind that acts as the advice kind: before, instead-of, after-returning, or after-throwing.

To create a subscription, you can write something like the following:

 

// Get a Weaver instance that will act as a
// container for the subscription(s) we create
Weaver w = WeaverFactory.getWeaver();

// regular java.lang.reflect is used to refer
// to the action method "simpleStaticAction()"
Method staticActionMethod =
  SimpleAction.class.getDeclaredMethod(
      "simpleStaticAction",
      new Class[0]//no arguments
  );

MethodSubscription ms = new MethodSubscription(
    .../* where to match*/,
    InsertionType.BEFORE,
    staticActionMethod
);

w.addSubscription(ms);

This code sample assumes that you use a static action method implementation. Alternatively, you can code this using an instance method, in which case the MethodSubscription should be passed an instance of the containing class:

// Use of an action instance to refer to the
// non static action method "simpleAction()"
Method actionMethod =
  SimpleAction.class.getDeclaredMethod(
      "simpleAction",
      new Class[0]// no arguments
  );
// Instantiate the action instance
SimpleAction actionInstance = new SimpleAction();
MethodSubscription ms2 = new MethodSubscription(
    ...,// where to match, explained below
    InsertionType.BEFORE,
    actionMethod,
    actionInstance
);

w.addSubscription(ms2);

AOP semantics such as within() and withincode() type patterns are also implemented through variations around this API.

Details on the API: Subscriptions

As shown in the previous code sample, the subscription API relies on the java.lang.reflect.* object model and some simple abstraction, such as jrockit.ext.weaving.WMethod, to unify Method, Constructor, and the class's static initializer handling.

The first parameter of the new MethodSubscription(...) call must be a jrockit.ext.weaving.Filter instance, which has several concrete implementations to match on methods, fields, and so on.

A jrockit.ext.weaving.MethodFilter instance acts as the definition on which the JVM weaver implementation does the join point shadow matching. The jrockit.ext.weaving.MethodFilter allows filtering on (and also exposes extra structures to support within()/withincode() semantics):

  • The member modifiers (an int such as when using java.lang.reflect.Modifier)
  • A Class<? extends java.lang.annotation.Annotation> to match one (any of the) method runtime visible annotation(s)
  • A jrockit.ext.weaving.ClassFilter instance to match the declaring type
  • A jrockit.ext.weaving.StringFilter instance to match the method name
  • A jrockit.ext.weaving.ClassFilter instance to match the method return type
  • A jrockit.ext.weaving.UserDefinedFilter instance to implement a finer matching logic

The jrockit.ext.weaving.UserDefinedFilter callback mechanism is used to implement more advanced matching schemes (a concept similar to Spring AOP org.springframework.aop.MethodMatcher and org.springframework.aop.ClassFilter).

All of these structures are optional, and if null is encountered, it means "match any."

The jrockit.ext.weaving.ClassFilter exposes in a similar fashion:

  • A Class<? extends java.lang.annotation.Annotation> to match one (any) of the class runtime visible annotation(s)
  • A Class to match the class type
  • A boolean to express if subtypes are to be matched

The following therefore matches all method calls whose name starts with "bar." Note that we pass in several null values in this very simple case:

StringFilter sf =
  new StringFilter("bar", STARTSWITH);

MethodFilter mf =
  new MethodFilter(0, null, null, sf, null, null);

MethodSubscription ms = new MethodSubscription(
    mf,
    InsertionType.BEFORE,
    staticActionMethod
);

w.addSubscription(ms);

As a more realistic topic, the following matches all three EJB business methods:

// Prepare the pointcut to match
// @Stateless annotated classes business methods
MethodFilter ejbBizMethods = new MethodFilter(
    PUBLIC_NONSTATIC,
    // Method annotation does not matter
    null,
    new ClassFilter(
        // Declaring class, the java.lang.Class
        // for the EJB we are currently manipulating
        ejbClass,
        // no subtypes matching
        false,
        // class annotation
        Stateless.class
    ),
    // EJB methods matching is handled
    // in a UserDefinedFilter below instead
    null,
    // return type does not matter
    null,
    // custom Filter callback
    new UserDefinedFilter() {
        public boolean match(
                       MethodFilter methodFilter,
                       WMember member,
                       WMethod within) {
            return !isEjbLifeCycleMethod(member);
        }
    }
);

Pages: 1, 2, 3, 4

Next Page »