ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Bean-Managed Transaction Suspension in J2EE
Pages: 1, 2, 3, 4

As you can see, with the help of the TransactionManager interface, you can extend the standard functionality provided by UserTransaction and achieve in BMT code the same level of flexibility available for CMT beans.



One non-obvious thing to remember is that when a transaction is suspended, it doesn't mean that the transactional timer is stopped. In other words, if the transaction timeout was set to 30 seconds and then transaction was suspended for 20 seconds and resumed, the transaction would have only ten seconds left to run before timeout. Transaction suspension simply disassociates a transaction with the running thread, and the resume() call associates it back without affecting the transactional timeout timer.

Known Issues

Because the J2EE specification doesn't require the availability and functionality of TransactionManager in J2EE containers (although we know that it should be there because of underlying JTA infrastructure), there are a few issues that exist in some application servers. For example, one particularly strange anomaly exists in WebLogic versions 7, 8, and 9 (beta): if a transaction was marked for rollback (by calling UserTransaction.setRollbackOnly()) and then suspended, attempting to resume the suspended transaction will fail with:

javax.transaction.InvalidTransactionException: Attempt to resume an inactive transaction

The following code illustrates this behavior.


...
// obtain UserTransaction object and start transaction
InitialContext ctx = new InitialContext();
UserTransaction userTransaction = (UserTransaction)
    ctx.lookup("java:comp/UserTransaction");
userTransaction.begin();

// mark for rollback
userTransaction.setRollbackOnly();
            
TransactionManager tm = getTransactionManager();

// suspend transaction
Transaction transaction = tm.suspend();
                
// resume suspended transaction
// this call will fail with InvalidTransactionException
//  in WebLogic
tm.resume(transaction);
...

Fortunately, there is a workaround for this particular problem. WebLogic's implementation of TransactionManager, along with the standard resume(Transaction transaction) method, has a forceResume(Transaction transaction) method that can be used instead. The code below demonstrates the pattern that should be used when your code is running in WebLogic. Note that in this case, the reference to TransactionManager should be cast to WebLogic's custom implementation interfaces ( weblogic.transaction.TransactionManager in WebLogic 7 or weblogic.transaction.ClientTransactionManager in WebLogic 8 and above).


...
// obtain UserTransaction object and start transaction
InitialContext ctx = new InitialContext();
UserTransaction userTransaction = (UserTransaction)
    ctx.lookup("java:comp/UserTransaction");
userTransaction.begin();

// mark for rollback
userTransaction.setRollbackOnly();
            
TransactionManager tm = getTransactionManager();

// suspend transaction
Transaction transaction = tm.suspend();
                
// resume suspended transaction
try {
    // first try standard JTA call
    tm.resume(transaction);
}
catch (InvalidTransactionException e) {
    // standard method failed, try forceResume()
    if (tm instanceof 
        weblogic.transaction.ClientTransactionManager) {
        // WebLogic 8 and above
        ((weblogic.transaction.ClientTransactionManager)tm)
            .forceResume(transaction);
    }    
    else if (tm instanceof 
        weblogic.transaction.TransactionManager) {
        // WebLogic 7
        ((weblogic.transaction.TransactionManager)tm)
            .forceResume(transaction)
    }
    else {
        // cannot resume
        throw e;
    }
}
...

Pages: 1, 2, 3, 4

Next Pagearrow