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

advertisement

AddThis Social Bookmark Button

Bean-Managed Transaction Suspension in J2EE

by Dmitri Maximovich
07/20/2005

Have you ever wondered why there are six types of Transaction demarcation attributes (NotSupported, Required, Supports, RequiresNew, Mandatory, and Never) supported in beans using container-managed transactions (CMT), but if you're using bean-managed transactions (BMT), the only functionality the EJB spec provides is to begin and commit/roll back transactions via the UserTransaction interface? Obviously the CMT model seems more capable--BMT lacks, for example, the ability to suspend and resume the current transaction, which means that you can't emulate the RequiresNew and NotSupported demarcations in BMT beans, at least not when you're using just the UserTransaction interface.

While the EJB specification doesn't explain why above-mentioned asymmetry exists, there is still a legitimate way to suspend and resume transactions in the BMT model. If you ever studied the contents of the javax.transaction package, you've probably noticed that along with the UserTransaction interface there is a TransactionManager interface that basically looks like an "extended" UserTransaction: the same methods--begin(), commit(), and rollback()--plus suspend() and resume().

If we can get a TransactionManager implementation from within our EJB, we will be able to achieve our goal of suspending and resuming transactions programmatically. Both the J2EE 1.3 and EJB 2.0 specifications are quiet about the availability of TransactionManager, but neither one of them explicitly prohibits using it. And since Container uses the Java Transaction API (JTA) internally for CMT transaction demarcation, we can be almost 100 percent sure that TransactionManager is present, and that it's just a matter of obtaining a reference to it in your code.

Related Reading

Head First EJB
Passing the Sun Certified Business Component Developer Exam
By Kathy Sierra, Bert Bates

In this article, we will see how to get a TransactionManager in several popular containers and show how to use it to extend functionality of bean-managed transactions, making them as powerful as container-managed transactions. We'll also outline some risks involved in using this advanced functionality, and at the end, explore how TransactionManager is used in the popular Spring framework.

Obtaining a Reference to TransactionManager in Various J2EE Servers

The J2EE and EJB specifications don't describe any standard means to obtain a reference to TransactionManager. Every J2EE container vendor is free to place it anywhere, or even to not provide any mechanism to access it from application code. In practice, though, all modern containers have mechanisms to obtain it. Below are examples how to get TransactionManagers from most popular J2EE containers.

Cast a UserTransaction (WebLogic, Orion, OC4J)

Any J2EE-compatible container must make the UserTransaction object available in JNDI under java:comp/UserTransaction. Since the UserTransaction interface is a subset of TransactionManager, some J2EE container vendors choose to provide a common implementation of both of them. WebLogic 8, Orion 2, and Oracle's OC4J EJB3 preview are examples of such an approach. In these containers, a reference to TransactionManager can be obtained just by getting a UserTransaction object from JNDI and casting it to TransactionManager. This is probably the simplest case.


private TransactionManager getFromUserTransaction() 
        throws Exception {
    InitialContext ctx = new InitialContext();
    UserTransaction ut = (UserTransaction)
        ctx.lookup("java:comp/UserTransaction");
    if (ut instanceof TransactionManager) {
        log("UserTransaction also TransactionManager");
        return (TransactionManager)ut;
    }
    return null;
}

Get TransactionManager Directly from JNDI (JBoss, WebLogic)

In JBoss 3 and WebLogic 8, TransactionManager is available in JNDI, albeit under different names, and therefore can be obtained by simple lookup:

private TransactionManager getFromJNDI() 
        throws Exception {
    InitialContext ctx = new InitialContext();
    try {
        // WebLogic
        return (TransactionManager)
            ctx.lookup("javax.transaction.TransactionManager");
     }
     catch (Exception e) {  }

    try {
        // JBoss
        return (TransactionManager)
            ctx.lookup("java:/TransactionManager");
    }
    catch (Exception e) { }
    return null;
}

Pages: 1, 2, 3, 4

Next Pagearrow