Miles to go …

November 21, 2010

TOTD #151: Transactional Interceptors using CDI – Extensible Java EE 6

Filed under: General — arungupta @ 10:00 pm

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. Weld documentation certainly provide good details about how all the pieces fit together.

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

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • StumbleUpon
  • Technorati
  • Twitter
  • Slashdot
Related posts:
  1. TOTD #134: Interceptors 1.1 in Java EE 6 – What and How ?
  2. TOTD #129: Managed Beans 1.0 in Java EE 6 – What and How ?
  3. TOTD #145: CDI Events – a light-weight producer/consumer in Java EE 6
  4. TOTD #144: CDI @Produces for container-managed @Resource
  5. TOTD #132: Servlets 3.0 in Embedded GlassFish Reloaded – lightweight Java EE 6

9 Comments »

  1. I put together a similar library about a year ago — take a look at http://smokeandice.blogspot.com/2009/12/cdi-and-declarative-transactions.html

    M

    Comment by Matt Corey — November 22, 2010 @ 9:29 am

  2. Thanks Matt, funny I didn’t care to Google, your entry is indeed at the top :-)

    Comment by Arun Gupta — November 22, 2010 @ 9:44 am

  3. I’ve followed the instructions here, but once I place the binding annotation on my CDI component, injection stops working:

    @TxInterceptorBinding
    @Named
    public class ShoppingCart {
    @PersistenceUnit(unitName="em")
    private EntityManagerFactory emf;

    public void checkOut() {
    EntityManager em = emf.createEntityManager(); // NPE!
    System.out.println("Checking out");
    }
    }

    Have you run into that?

    Comment by Jason Lee — November 23, 2010 @ 11:45 am

  4. Jason,

    Did you try the sample included in the blog ? Did it work ?

    In your code sample, does it print "Checking out" on server.log if "EntityManager em = emf.createEntityManager()" line is removed along with other statements from the interceptor ?

    Comment by Arun Gupta — November 23, 2010 @ 1:01 pm

  5. This is also discussed at:

    http://seamframework.org/Community/InterceptorsBlockingInjection

    and

    http://twitter.com/#!/jasondlee/status/7203586014449664

    Comment by Arun Gupta — November 23, 2010 @ 3:10 pm

  6. Hello,

    You inject UserTransaction with @Resource. But CDI specification declares that you can inject Java EE user transaction via @Inject. Therefore injection may be done by

    @Inject @Resouce UserTransaction transaction;

    Comment by Gurkan Erdogdu — November 24, 2010 @ 7:41 am

  7. ​It appears the resource injection problem appears in even the most recent GlassFish build. It’s likely a Weld GlassFish integration problem. I followed up on the forum post on seamframework.org with an Arquillian test to demonstrate the failure.

    Comment by Dan Allen — November 24, 2010 @ 10:55 am

  8. Although both are correct, the preferred way of injecting the UserTransaction is to use @Inject.

    @Inject UserTransaction tx;

    The UserTransaction is a inject that CDI is required to support and thus maximized portability.

    Comment by Dan Allen — November 24, 2010 @ 10:57 am

  9. Arun,

    This is a great tip to help developers get started with CDI-style interceptor bindings.

    For developers that want to have transaction support on managed beans, I strongly recommend using one of the CDI extensions that are already out there that provide this feature. In fact, just about every CDI extension library is providing this very feature (a pretty good sign it should have been supported in the platform).

    Take a look at Seam Persistence (http://seamframework.org/Seam3/PersistenceModule), MyFaces CODI (https://cwiki.apache.org/confluence/display/EXTCDI/Index) or SoftwareMill CDI (https://github.com/softwaremill/softwaremill-common). The reason being, there’s a lot more to supporting transactions than just begin and commit.

    Comment by Dan Allen — November 24, 2010 @ 11:02 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.
Powered by WordPress