AspectWerkz tutorial: Plain Java AOP, Java 5 Annotations, and EJB 3 Transactions.

Abstract

In this article, Alexandre Vasseur explains how to make use of the rich semantics of the new AspectWerkz 2.x AOP framework and its annotation driven approach to implement a subset of the EJB 3 specification with Java 5: annotation driven Container Managed Transaction (CMT).

There has been a lot of hype around using AOP to implement declarative transaction management "à la" EJB 3, based on annotations, but there are still interesting things to explain and for those familiar with it but not with AspectWerkz, this is a good background to have.

This tutorial first explains the way that is most intuitive for users familiar with proxy based frameworks and explains why this approach is not sufficient from an AOP design perspective. It then goes step by step into more AOP semantics details with AspectWerkz Java 5 annotation defined aspects, aspect abstraction and annotation driven AOP. The end result is a completely reusable implementation for the EJB 3 Container Managed Transaction specification with support for the @javax.ejb.TransactionAttribute to define transaction boundaries and @javax.ejb.Inject instance variable injection that simplifies JNDI based lookups. The implementation is not tied to any EJB container and will run without extra compilation phase than just a JVM option introduced by Java 5.

Tutorial objectives and requirements

Our objective in this tutorial is to guide you in AspectWerkz Java 5 support to:

The tutorial is based on Java 5 and Java 5 annotations (JSR-175). The complete source code and third parties libraries are part of the project. An Ant based build script is provided. For it to run you will thus need:

Since the goal is not to deal with JTA related details, we will use the ObjectWeb JOTM JTA javax.transaction.TransactionManager implementation but we will ensure that our design is not in any way tied to this implementation.

EJB 3 and CMT with Annotations

To fully understand the concepts implemented in this tutorial it is worth explaining what is in the EJB 3 specification and what we aim at implementing using AOP.

EJB 3 includes Container Managed Transaction (CMT) just as EJB 2.x but enables us to declare transaction boundaries using annotations directly into the EJB business methods through the @javax.ejb.TransactionAttribute that will define which transaction level is required when running the business method. The well known EJB 2.x transaction levels are unchanged and the concepts of CMT as defined in EJB 2.x specification still apply.

EJB 3 provide a way to avoid using JNDI lookup and use various annotation driven dependency injection mechanism to access EJB environment such as javax.transaction.UserTransaction as regular instance variables for example.

EJB 3 source code for transaction management will thus looks like this (some parts are omitted).

// EJB bean annotations omitted
public class BusinessBean {
    // the EJB container will handle this field
    @Inject private UserTransaction m_userTransaction;

    // the EJB container has to handle the transaction level we define
    @TransactionAttribute(REQUIRED)
    public void methodRequiredTX() throws BusinessException {
        // do something
        // may throw a runtime exception (unchecked)
        // may throw a business exception (checked)
    }
}

The transaction levels are among the enum javax.ejb.TransactionAttributeType: MANDATORY, REQUIRED (defaults), REQUIRESNEW, SUPPORTS, NOTSUPPORTED and NEVER. A correct implementation should for example reuse the transaction context in the executing thread if a method is defined with a REQUIRED level and is in the flow of a REQUIRESNEW defined method.

Further on, if the business method fails with an exception, proper transaction handling must happen. In this tutorial, we will assume that the container has to rollback upon unchecked exceptions (subclass of java.lang.RuntimeException) and not rollback upon checked exception.

Tutorial materials

Download the tutorial zip here.

When you extract it you will get the following structure:

[tutorial root]
    build.xml                   Ant script
    lib                         dependencies
    src
        main
            aspectwerkz         Aspects implementation in the aspectwerkz.* package
            javax               javax.ejb.* EJB 3 annotations (an incomplete subset suitable for this tutorial only)
        samples
            aspectwerkz         Sample standalone application
            META-INF/aop.xml    AspectWerkz AOP deployment descriptor

The dependencies are AspectWerkz 2.0.RC1 with Java 5 support, JTA javax.transaction APIs and ObjectWeb JOTM TransactionManager.

In this tutorial we also include source code for a limited subset of the EJB 3 annotations (package names are subject to change since the specification is not final):

The complete source code can also be checked out from our CVS anonymously from the tutorials-AW2 module:

cvs -d :pserver:anonymous@cvs.aspectwerkz.codehaus.org:/home/projects/aspectwerkz/scm login
cvs -z3 -d :pserver:anonymous@cvs.aspectwerkz.codehaus.org:/home/projects/aspectwerkz/scm co tutorials-AW2

Writing the TransactionAttributeAwareTransactionProtocol aspect

In this section, you will learn how to write the aspect using AspectWerkz annotation based AOP. Our goal is to advise the methods annotated with the @javax.ejb.TransactionAttribute so that we handle the transaction management.

The dependency injection driven by @javax.ejb.Inject will be explained in a separate section.

Aspect: the unit of modularity

In AspectWerkz an aspect is a regular class with optional class level annotations. The aspect is the unit of modularity, so we will write one aspect to contain the full CMT logic.

In this tutorial, the aspect aims at being generic, so it will only be dependant upon JTA interface APIs. We will subclass the aspect to provide a JOTM based implementation later. Our aspect will thus be an abstract class, that you can then easily extend to provide an alternative implementation for the application server you are using.

The concrete subclass aspect will be further on instantiated by the AspectWerkz runtime. We decide to have a singleton aspect (one per JVM) and leave the thread safety management (attach a transaction to a thread, get the current transaction context for the executing thread etc) to the actual JTA implementation. Though perJVM deployment model is the default in AspectWerkz (and we thus don't have to specify it) we can also write it explicitly.

// this annotation could be remove since we are using the default deployment-model
@Aspect("perJVM")
public abstract class TransactionAttributeAwareTransactionProtocol {
    ...
}

Pointcuts: Where to apply the aspect behaviour ?

We aim at applying transaction management on methods annotated with EJB 3 @javax.ejb.TransactionAttribute annotation. For such, we will make use of AspectWerkz capabilities to match on Java 5 annotations. The following pointcut will match any method in any class that is annotated with the @javax.ejb.TransactionAttribute annotation. Note that we don't narrow the pointcut to a specific class since we aim at using our transaction protocol without any EJB.

execution(@javax.ejb.TransactionAttribute * *.*(..))

The execution(...) syntax means that we want to advise on the callee side of the method invocation (and not on the caller side, which would be different for example if we had some remote calls).The generic syntax for a method pointcut is as follows:

[<annotation>]* <returnedType> <classPattern>.<methodPattern>(<signature pattern>)
You can refer to the AspectWerkz documentation for more details on the wildcards.

The pointcut construct in AspectWerkz is defined as an annotated field in the aspect class. The field type is org.codehaus.aspectwerkz.definition.Pointcut, and the field name will be used when we will bind advice to it.

@Aspect(“perJVM”)
public abstract class TransactionAttributeAwareTransactionProtocol {

    /**
     * The pointcut that picks out all transacted methods.
     */
    @Expression("execution(@javax.ejb.TransactionAttribute * *.*(..))")
    Pointcut transactedMethods;

    ...
}

Note: EJB 3 specification also defines a class level annotation that will be the default for business methods without annotation. The pointcut for such a more correct implementation would thus require to match on class annotation as well by using the within(...) syntax that will match on types:

         execution(@javax.ejb.TransactionAttribute * *.*(..))
         ||
         (execution(* *.*(..)) && within(@javax.ejb.TransactionAttribute *))

Advice: How to implement behaviour and bind it to pointcuts

For each well defined point in the target application (join point) that will match the previously defined pointcut, we need to add transaction management behaviour. This will be realized through the concept of advice.

Using an Around advice
A first approach that has been somehow implemented in several proxy based frameworks would be to use an Around advice that will intercept the annotated methods execution. Such an advice body would look like this (pseudo code):

Intercept @javax.ejb.TransactionAttribute annotated methods (Method interceptedMethod) {
    txLevel = get the interceptedMethod TransactionAttribute annotation value (f.e. REQUIRED)
    try {
        1 - do transaction management [open / reuse / suspend / go on]

        2 - proceed with the actual method execution

    } catch ( RuntimeException ) {

        3 – mark as rollback only

    } finally {

        4 – end transaction management [commit / rollback / go on / resume]
    }
}

If simple, such an approach as a drawback. Indeed, the transaction management logic is cleanly isolated in the aspect, but unfortunately resumed within one single advice with a try / catch / finally block that interferes on the transaction semantics. It does not make it clear that an unchecked exception will enforce a rollback. This design requirement is lost in one single line of code in the middle of this method.

Using Before and After throwing / finally advice
By making use of richer semantics that have been first introduced by AspectJ, we will write it slightly differently using:

AspectWerkz advice in Java 5 can be defined using annotations. Here are the method level annotations that we will use for such an aspect (in the org.codehaus.aspectwerkz.annotation package):

@Aspect("perJVM")
public abstract class TransactionAttributeAwareTransactionProtocol {

    @Expression("execution(@javax.ejb.TransactionAttribute * *.*(..))")
    Pointcut transactedMethods;

    /**
     * Before advice that will initiate transaction management is bounded to the transactedMethods pointcut
     */
    @Before("transactedMethods")
    public void enterTransactedMethod(...) throws Throwable {
        ...
    }
}

Accessing static information about the join point

In the advice body we will have to get the annotation on the advised method. This information is static, and thus we will make use of AspectWerkz StaticJoinPoint instead of JoinPoint. The StaticJoinPoint provides better performance since it does not expose runtime information (method arguments values etc.). To make use of it, all we have to do is to declare it in our advice signature.

    @Before(<pointcut>)
    public void enterTransactedMethod(final StaticJoinPoint jp) throws Throwable {
        ...
    }

Implementing RequiresNew and transaction suspending

To support the REQUIRESNEW transaction level, we need to suspend the current transaction – if a transaction already exists –, create the new transaction, and after the method invocation has ended, resume the suspended transaction. When using an around advice approach, this would be straightforward. We would just store the suspended transaction in a local variable and then proceed to the next invocation, and restore it in the finally block.

Using the before and after advice approach brings one drawback to solve this issue. It may seem that we need to add an aspect instance variable so that we can share context between the before and the after finally advice. But since we have decided to use a perJVM aspect, this field would not be thread safe. We will thus use a ThreadLocal field to ensure thread safety. This is a pay as you go model. The ThreadLocal field will only be used on a specific condition on the transaction boundary, while changing the aspect deployment model to a hypothetical perThread or better a perCflow would affect every single transaction.

@Aspect("perJVM")
public abstract class TransactionAttributeAwareTransactionProtocol {

    private ThreadLocal suspendedTxTL;

    @Before(...)
    public beforeAdvice(StaticJoinPoint jp) {
        ...
        // if we have to suspend the current transaction to build a new one for requiresNew support
        getTransactionManager().suspend(currentTx);
        storeInThreadLocal(currentTx);
        ...
    }

    @AfterFinally(...)
    public afterFinallyAdvice(StaticJoinPoint jp) {
        ...
        // if we had to suspend a current transaction to build a new one for requiresNew support
        // we need to resume it
        Transaction suspendedTx  = (Transaction) fetchFromThreadLocal();
        getTransactionManager().resume(suspendedTx);
        ...
    }
}

The reusable TransactionAttributeAwareTransactionProtocol aspect

The complete skeleton of our aspect is thus:

@Aspect("perJVM")
abstract class TransactionAttributeAwareTransactionProtocol {

    @Expression("execution(@javax.ejb.TransactionAttribute * *.*(..))")
    Pointcut transactedMethods;

    private ThreadLocal suspendedTxTL;

    /**
     * Before advice to start a TX if needed
     * Makes use of StaticJoinPoint
     */
    @Before("transactedMethods")
    public void enterTransactedMethod(final StaticJoinPoint jp) throws Throwable {
        // get the transaction annotation value from the method or the class as per EJB 3 specification
        MethodSignature sig = (MethodSignature)jp.getSignature();
        Class declaringType = sig.getDeclaringType();
        Method method = sig.getMethod();
        TransactionAttributeType txType = getTransactionAttributeTypeFor(declaringType, method);

        // the getTransactionManager() is abstract
        final TransactionManager tm = getTransactionManager();

        // handles transaction management depending on the current transaction context
        // and the wished transaction level for the method we advise
        ...
    }

    /**
     * Invoked when an unchecked exception is thrown out of a transacted method.
     * Marks the current transaction as ROLLBACK_ONLY.
     */
    @AfterThrowing(
        type = "java.lang.RuntimeException",
        pointcut = "transactedMethods"
    )
    public void exitTransactedMethodWithException() throws Throwable {
        final TransactionManager tm = getTransactionManager();
        if (isExistingTransaction(tm)) {
            logInfo("Setting TX to ROLLBACK_ONLY");
            tm.setRollbackOnly();
        }
    }

    /**
     * Invoked when exiting a transacted method. Performs the actual commit or rollback depending on the
     * status of the transaction. Resumes suspended transactions.
     */
    @AfterFinally("transactedMethods")
    public void exitTransactedMethod(final StaticJoinPoint jp) throws Throwable {
        final TransactionManager tm = getTransactionManager();
        // handle transaction logic
        ...
    }
}

Implementing a concrete implementation with JOTM

So far, our abstract class is not tied to any JTA Transaction Manager and relies on the JTA APIs only. Two abstract methods are left to be implemented in a subclass for a specific implementation:


	// returns the transaction manager
	protected abstract TransactionManager getTransactionManager()

	// returns the transaction associated with the current thread
	protected abstract UserTransaction getUserTransaction()

In this tutorial we have decided to use ObjectWeb JOTM so that we can easily run a sample outside of a container. The concrete implementation is quite straightforward. We are using a public no-argument constructor that will be called once by the underlying runtime upon singleton aspect instantiation. To implement a BEA WebLogic specific implementation you would have to do a JNDI lookup or use WebLogic specific APIs instead of instantiating the Jotm class.

@Aspect("perJVM")
public class JOTMTransactionProtocol extends TransactionAttributeAwareTransactionProtocol { 

    private final TransactionManager m_transactionManager;
    private final Jotm m_jotm;

    public JOTMTransactionProtocol() {
        try {
            m_jotm = new Jotm(true, false);
            m_transactionManager = m_jotm.getTransactionManager();
        } catch (NamingException e) {
            throw new TransactionException("Could not create a new JOTM Transaction Manager", e);
        }
    }

    protected TransactionManager getTransactionManager() {
        return m_transactionManager;
    }

    protected UserTransaction getUserTransaction() {
        return m_jotm.getUserTransaction();
    }
}

Running the project with Java 5

A simple standalone application annotated with @javax.ejb.TransactionAttribute is part of the project.

Compiling the application

Since we are using Java 5, no extra compilation step is needed. Regular javac compilation will take care of the annotations and our plain java aspects.

You can simply run the following in the root folder of the tutorial:

java –version
// make sure you are running with Java 5

ant compile

Before running it we need to weave our target application so that the transaction management is inserted at all the methods with the TransactionAttribute annotation. AspectWerkz provides an easy way to go through this step with Java 5 JVMTI (JSR-163) support. We will simply compile and run the application as usual with just a single JVM option (-javaagent) and a specific XML file in our path to declare which aspects to use.

Writing the aop.xml deployment descriptor

To declare to the runtime system which aspect to use, we write a simple aop.xml file that we will put in a META-INF/aop.xml entry in the classpath. Some more advanced deployment unit to be deployed in an application server could be constituted using one or more aop.xml but that is out of the scope of this tutorial.

This file simply list the aspect(s) we want to use by their class name:

<!DOCTYPE aspectwerkz PUBLIC "-//AspectWerkz//DTD//EN" "http://aspectwerkz.codehaus.org/dtd/aspectwerkz2.dtd">
<aop>
    <system id="aop.ejb3.cmt">
        <aspect class="aspectwerkz.tutorial.tx.JOTMTransactionProtocol"/>
    </system>
</aop>
For more detail and advanced usage of the XML deployment descriptor in AspectWerkz, refer to the documentation.

Running with Java 5

To run the application, we will use the new Java 5 JVMTI (JSR-163) –javaagent option that will transparently hook in AspectWerkz in the JVM. Running it through command line would look like the following:

java –javaagent:lib/aspectwerkz-jdk5-2.0.RC1.jar –classpath ... MyMain
Here we have the classpath containing the current tutorial root folder "." so that the META-INF/aop.xml can be found in the classpath, and containing all required jars and build path.

For convenience, we can run the sample with the Ant script

    ant samples:tx

Some information should appear on the standard output. The last part of the output comes from a sample where a method with the REQUIRED transaction semantic calls another method with the REQUIRED semantic as well. Only one transaction should cover the two methods. Since we added some simple log to our transaction protocol we can see the expected behaviour.

[TransactionProtocol:INFO] Starts TX with attribute REQUIRED at [aspectwerkz.tutorial.tx.Main.startTxRequired_InvokeTxRequired(..)]
[TransactionProtocol:INFO]   TX begin
[Main:INFO]     startTxRequired_InvokeTxRequired
[TransactionProtocol:INFO] Starts TX with attribute REQUIRED at [aspectwerkz.tutorial.tx.Main.txRequired(..)]
[Main:INFO]         txRequired
[Main:INFO]         noOp
[Main:INFO] TX status: STATUS_ACTIVE
[TransactionProtocol:INFO] Committing TX

Note on IDE integration

If you want to compile and run the project from within your IDE and without using the Ant script, you have to make sure that the aspectwerkz-jdk5-<version>.jar file is first in the project classpath. This file contains the AspectWerkz Java 5 annotations implementation and is overriding defaults Java 1.4 version that are in the aspectwerkz-<version>.jar file.

Adding support for EJB 3 instance variable dependency injection

Our objective in this last section is to add support for instance variable dependency injection as described in the EJB 3 specification. Our business bean instance will then be able to access the javax.transaction.UserTransaction instance of the current thread by simply using an instance variable annotated with @javax.ejb.Inject without any JNDI lookup.

public class BusinessBean {

     // the EJB container will handle this field
     @Inject private UserTransaction m_userTransaction;

     void someMethod() {
           // direct access to container injected dependencies
           System.out.println(m_userTransaction.getStatus())
     }
}

To implement this field value injection we will use a get(...) pointcut that will match read access on any field annotated with @javax.ejb.Inject and whose type is javax.transaction.UserTransaction. The pointcut is thus :

get(@javax.ejb.Inject javax.transaction.UserTransaction *)

Note that the EJB 3 specification is wider than this and specifies setter injection and some more advanced scenarios. Moreover it would make sense to narrow down this pointcut to the EJB 3 annotated classes only using a within(...) pointcut for a specific EJB 3 implementation.

To inject the value when the field is accessed, we will use an Around advice that returns the UserTransaction instance for the current thread. The resulting code is thus:

@Aspect("perJVM")
abstract class TransactionAttributeAwareTransactionProtocol {

    @Expression("get(@javax.ejb.Inject javax.transaction.UserTransaction *)")
    Pointcut injectedUserTransaction;

    @Around("injectedUserTransaction")
    public Object resolveUserTransactionInjection() throws Throwable {
        return getUserTransaction();
    }

    ...
}

The provided sample makes use of this instance variable injection mechanism driven by annotation. It is interesting to note that this field access pointcut is not a feature available in any of the proxy based framework like Spring AOP, DynAOP etc but is available in AOP frameworks like AspectWerkz, AspectJ and JBoss AOP which are using bytecode instrumentation.

Conclusion

In this tutorial, we went through a reusable implementation of the EJB 3 CMT specification. Using rich semantics of AOP like before, after throwing and after finally advice enables us to clearly implement the logic for the transaction boundaries.

AspectWerkz supports matching on Java 5 annotations which enables us to add behaviour to the static metadata contained in the Annotation driven nature of the EJB 3 components.

Plain Java AOP, where aspects are annotated Java classes and advanced integration with latest Java 5 innovations reduce the complexity of AOP integration without narrowing its scope like proxy based implementations do.

By using one standardized JVM option introduced by Java 5 we are able to run an ObjectWeb JOTM based EJB 3 transaction implementation without any actual EJBs or J2EE container.

Step by step design decision regarding access to join point information and aspect inheritance as well as some performance considerations brings a modular component that supports EJB 3 container managed transaction and transaction resource injection driven by annotation, while keeping it generic and open for any underlying JTA implementation.

AOP enables us to implement a small but interesting subset of the upcoming EJB 3 specification in just a few hours, while not using any source processing techniques.

Appendices: What about Java 1.4 ?

AspectWerkz is compatible with Java 1.4 as well, and provides a doclet based (JavaDoc) strongly typed annotation mechanism. A similar aspect could be used to match on whether EJB 3 like JavaDoc styled annotations or some custom ones that would be implemented with regular interfaces and JavaDoc doclets. Most of the changes would be implied by the enum use and the reflective access to annotations using Java 5 reflection API. Moreover, an extra step to compile the JavaDoc based annotations would be necessary, and the JVM integration would be a bit more effort than just a JVM option unless you are using the BEA JRockit JVM which provides a single JVM option integration feature just as it has been standardized in Java 5.

A Java 1.4 annotation would thus be defined like this:

package javax14.ejb3;

// notice that we are using a regular interface
// instead of the Java 5 "@interface" keyword to define Annotations
public interface Java14TransactionAttribute {
    Java14TransactionAttributeType value() ;
}

public class Java14TransactionAttributeType {
    // emulates an enum
    public static final REQUIRED = new Java14TransactionAttributeType(“REQUIRED”);
    ...
}

And Java 1.4 annotated source code will looks like this

public class Java 14Main {

    /**
     * @javax14.ejb3.Java14TransactionAttribute(javax14.ejb3.Java14TransactionAttributeType.REQUIRED)
     */
    public void businessMethodTxRequired() {
        ...
    }

    ...
}

Thanks to the annotation interface class, the annotation is strongly typed and we can access it reflectively using the AspectWerkz Annotations API (that can read Java 5 annotation as well)

String annotationName = "javax14.ejb3.Java14TransactionAttribute";
Method businessMethod = ...;
Java14TransactionAttribute txLevel = (Java14TransactionAttribute )
        org.codehaus.aspectwerkz.Annotations.getAnnotation(annotationName, businessMethod);

For more information about Annotation implementation for Java 1.3/1.4 in AspectWerkz, refer to the online documentation.

Links

AspectWerkz
JTA specification
ObjectWeb JOTM
EJB 3 JSR 220 specification
Java 5 Annotations JSR 175 specification
Java 5 JVMTI specification

Biography

Alexandre Vasseur is Software Engineer at the Java Runtime Products Group, BEA Systems. He is the co-founder of the AspectWerkz AOP framework.