One of the questions often asked in recently, and I’ve been wondering too, is how to enable transactions using CDI Interceptors. This Tip Of The Day (TOTD) will share some basic piece of code on how to author a CDI interceptor that enable transactions. TOTD #134 provide more details about interceptors.
Lets jump to the code straight away. Lets look at the transaction interceptor binding code:
package org.glassfish.samples;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;
@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface TxInterceptorBinding {
}
And the actual interceptor:
package org.glassfish.samples;
import javax.annotation.Resource;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.transaction.UserTransaction;
@TxInterceptorBinding @Interceptor
public class TxInterceptor {
@Resource UserTransaction tx;
@AroundInvoke
public Object manageTransaction(InvocationContext context) throws Exception {
tx.begin();
System.out.println("Starting transaction");
Object result = context.proceed();
tx.commit();
System.out.println("Committing transaction");
return result;
}
}
This interceptor is injecting a "UserTransaction" and sandwiching the business method invocation between start and end of trnasaction. This interceptor is not dealing with any rollback scenarios or exception handling and so will need to be modified for a real-life scenario.
"beans.xml" looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>org.glassfish.samples.TxInterceptor</class>
</interceptors>
</beans>
This basically enables the interceptor.
With all the plumbing code now ready, lets use this interceptor on our application code as:
package org.glassfish.samples;
@TxInterceptorBinding
public class ShoppingCart {
public void checkOut() {
System.out.println("Checking out");
}
}
The important part is "@TxInterceptorBinding" as a class-level annotation. Now this ShoppingCart can be injected in any Java EE resource such as:
@Inject ShoppingCart shoppingCart;
such as in a Servlet. Now invoking the servlet shows the following sequence of code in the server log:
INFO: Starting transaction
INFO: Checking out
INFO: Committing transaction
That’s it folks!
The code for this sample application can be downloaded from here. Just download and unzip the code, open the project in NetBeans (tried with 7.0 beta) and run it on GlassFish or any other Java EE 6-compliant container.
If you are using EJBs in a WAR, which is now allowed per Java EE 6, then you can certainly leverage all the annotation-driven transactions within your web application instead of maintaining your own interceptor-driven transactions. A similar approach can be used for security as well.
How are you dealing with transactions in your web application – using CDI-based interceptors or let the container manage it all for you ?
Technorati: totd cdi javaee6 glassfish interceptors transactions