2009/05/13

EJB3: Conscious Session Bean

Last week, I wanted to demonstrate @TransactionAttribute in a session bean using JBoss AS 5.1.0 GA and EJB3. Everything seemed pretty simple...

@Stateless
public class OmnipotentBean implements Omnipotent {
    @TransactionAttribute(REQUIRED)
    public String transactionRequired() throws SystemException {
        try {
            transactionNever();
            System.err.println("No exception occured - ERROR");
        } catch (EJBException e) {
            System.out.println("Expected exception - OK");
        }
    }

   @TransactionAttribute(NEVER)
    public String transactionNever() throws SystemException {
        ...
    }
}

As you can see, I wanted to show that calling a method with a transaction attribute set to NEVER from a method that already runs in a transaction throws an exception. But the exception was not thrown. How come?

Let's start from the client. What kind of object do we get from JNDI when we looked up OmnipotentBean/remote? It was neither OmnipotentBean or its interface. It was a dynamically generated class based on java.lang.reflect.Proxy, which handles all method calls and passes them to the server. You can call its method because it implements Omnipotent interface. Moreover, the call passes through a set of interceptors, which can perform additional work and setup the environment, inlcuding security and transactional interceptors.

The same applies at the server side. What is this inside transactionRequired() method? It is just a OmnipotentBean class instance, thus a simple POJO. We must lookup the EJB through JNDI to get a proxy object for transactional attributes to start working.

Another uncomfortable thing is that we cannot use dependency injection in our session bean to inject its proxy. Not having the bean initialized at the time of its initialization when dependencies are being injected, this is the cause.

So, are all the problems just JBoss AS's whims? What does the specification say? EJB3 - JSR-220 (file EJB Core, page 343):

The following subsections define the responsibilities of the container for managing the invocation of an enterprise bean business method when the method is invoked via the enterprise bean’s business interface (and/or home or component interface), or web service endpoint. The container’s responsibilities depend on the value of the transaction attribute.

Everything is all right. EJB container (i.e., the application server) must manage the invocations of bean's methods only when they are called via the business interface, which is the proxy object.

Maybe this is not suprising to you and you are right. It is very logical. Just bear in mind that a session bean must be conscious of its own business interface when invoking methods of its own.

. .