Download (direct link):
followed by method call
(8) Rollback beforeCompletion() afterCompletion(false)
(9) Commit beforeCompletion() afterCompletion(true)
Transaction aware method calls Figure 50.1 Stateful session EJB lifecycle.
When Transactions Go Awry, or Consistent State in Stateful Session EJBs 435
Examining how a bean moves through its various states during its lifecycle will help us understand how transactions affect bean state and how we can solve the transaction state problem.
1. Initially, an EJB is in the does not exist state. In the does not exist state, a stateful bean has not been called for (often referred to as pooled) but is potentially ready for quick creation and use. Various application servers handle this state in different ways. Many, including BEA WebLogic Server, precreate beans so that they are ready for immediate use.
2. A bean moves into the callable state when a client calls the home interface create() method. In the callable (outside a transaction) state, a bean has been created and is ready for use. Beans in the callable state are method ready and stay in the method state until they are destroyed, or passivated.
3. Beans move to the passivated state because they have been inactive for a long period of time. Passivated beans are normally stored in some sort of highspeed backing store outside RAM to conserve system memory.
4. A bean can move from the passivated state back to callable as a result of a client calling a method on the bean. Under normal circumstances, passivated beans are restored without any developer work or interaction. However, the EJB specification provides methods for notifying a bean that it has been passivated and then restored.
5. If a bean is inactive long enough, it may be destroyed by the bean container. Further method calls on such a bean will result in a client exception. Many application servers will reset the state of such an object and return it to a ready-for-use object pool.
6. A bean moves to the callable (inside a transaction) state the first time a method is called after a transaction is started. The session synchronization interface method afterBegin() is called at this point, but before the method call is evoked, to signal the bean that a transaction has been started. We will use afterBegin() to signal we should store our state for reset later.
7. After a transaction has been started, all bean method calls become part of that transaction until either a commit or a rollback occurs. As long as the transaction is active, we remain in this state.
8. If a transaction is rolled back, the bean moves to the callable (outside a transaction) state. The beforeCompletion() method is called, followed by afterCompletion(false) being called. The bean could then revert its state to a known point before the transaction began.
9. When a transaction is committed, the bean moves from back to the callable (outside a transaction) state. However, unlike item 8 above, the transaction was committed and the afterCompletion(true) method is called. Since the session state is consistent with the transaction state, no action need be taken.
We can solve the transaction/bean state problem by a combination of the Session-Synchronization interface and careful store and reset logic within our application. The SessionSynchronization interface requires that we implement three specific methods:
436 Item 50
¦¦ public void afterBegin(). Represented by transition 6 in the EJB lifecycle diagram. Here is where we would implement any logic to store current state. In the EJB lifecyle, afterBegin() is called after a transaction has begun but before any methods that would be part of the transaction. Transaction context can be obtained and manipulated within the afterBegin() method.
¦¦ public void beforeCompletion(). Represented by transitions 8 and 9 in the EJB lifecycle diagram. beforeCompletion() is called when a transaction is committed but before the actual commit operation takes place. Any work done within beforeCompletion() is within the context of the transaction.
¦¦ public void afterCompletion(boolean committed). Represented by transaction 8 (failed) and 9 (committed) in the EJB lifecycle diagram. afterCompletion!) is called after the transaction has been committed or rolled back. The committed flag can be used to determine if the transaction was successfully committed. Here is where we would implement any required logic to store or update bean state. An important note: afterCompletion() is not called inside the context of a transaction.
A complete description of Stateless Session EJB is beyond the scope of this text. Only the implementation of stateless session EJBs is presented in this section. For complete coverage of EJB development, see Mastering Enterprise JavaBeans, Second Edition by Ed Roman (Wiley, 2002) or Developing Java Enterprise Applications by Stephen Asbury and Scott R. Weiner (Wiley, 2001).
In Listing 50.1 we can take advantage of transaction boundaries by specifying the session synchronization interface, as shown on line 7, and implementing the required methods. To solve our problem, we must save our current state, have all methods operate within transaction boundaries, and then be able to determine if our transaction succeeded or failed and restore state appropriately.