This is what the EJB 3.0 spec says about stateful bean instances (CMT-based, implementing SessionSynchronization) which are present in the "Transaction Method-Ready" state from their life cycle:
Session bean methods invoked by the client in this transaction can now be delegated to the
bean instance. An error occurs if a client attempts to invoke a method on the session object and
the bean’s metadata annotations and/or deployment descriptor for the method requires that the
container invoke the method in a different transaction context than the one with which the
instance is currently associated or in an unspecified transaction context.
I really cannot understand how this could happen! Stateful bean instances are dedicated to particular client, and EJB calls are synchronous, so the client code should look like:
0. acquire stateful bean instance - bean (no matter how exactly)
(n+1). bean.removeMethod(); or nothing (in which case the session will expire at some moment)
So, if method1() requires the beginning of a new CMT transaction - T1, it will be created by the JTA manager at the method beginning (and afterBegin() will be called on the bean instance). From now on, the bean instance is in "Transaction Method-Ready" state from its complete life cycle, associated with T1.
But before the 'bad' method2() could be executed from the client (that requires a new transactional context via, for instance, a REQUIRES_NEW attribute), method1() should be completed! This means that T1 should have been committed/rolled back. It should be a history! And i cannot see any way that the client could make so that new transactional context is required, while T1 is still active and associated with the bean instance . Stateful bean instances simply cannot be shared among different clients.
Any help would be appreciated! I am having my SCBCD 5 exam in 5 days ;)
The only option left to reproduce the scenario from the spec, is the one in which: after the method1() has started and the bean instance is associated with T1, inside the method1() source code, the bean itself invokes some other business method from the bean class (that requires new transactional context). But this is not relevant, since here there is no client interaction: the bean is doing this itself!
Can someone reproduce the scenario from the spec quote correctly ?
Let's have a servlet client (it could only use BMT transactions) and a CMT-based stateful session bean, implementing SessionSynchronization.
The bean has two business methods - A() which has the REQUIRED attribute, and B(), which has the REQUIRES_NEW attribute.
So here is the servlet:
@Resource UserTransaction tx;
bean = ... // look up the stateful bean;
While the A() invocation is processed, the bean uses the transaction context - T1 of the servlet, which is propagated to it. It makes the association with T1, and is called an afterBegin() callback by the container. The A() method is completed successfully, but the bean instance will remain in the "Transaction Method-Ready" state since the transaction, associated with it (T1), is still active and is not committed, neither rolled back.
However, when the client invokes B(), it will force the container to suspend T1 and start a new container transaction - T2, and this already violates the spec quote. So here we have an error.
Am i right ? Either i got it, or i am completely wrong....
The servlet usage isn't that crucial here, the same can happen with a stateless BMT bean client as well...