Integration of a transaction manager in Tomcat for Spring and OpenJPA

Apache Tomcat is a lightweight alternative to a full fledged application server, if only the Servlet API, plus a few selected components of the Java EE specification will be used.

In this short tutorial I add a JTA transaction manager to Tomcat. I chose the open source version of the Atomikos transaction manager called Atomikos TransactionEssentials (Paid version: Atomikos ExtremeTransactions). Possible alternatives would be: JOTM or JBoss Transactions.
Subsequently the transaction manager is integrated in Spring and OpenJPA.

Constraint: The web application should be deployable on a full fledged application server without modification. This allows to use the extended Tomcat as the development platform, even if the application is operated on a JEE server in production.

Used versions

  • Tomcat 6.0.35
  • Atomikos TransactionsEssentials 3.7.0
  • OpenJPA 2.1.1
  • Spring 3.0.7


Tomcat configuration

Required libraries

Following libraries and resources have to be copied from the Atomikos distribution into the TOMCAT_HOME/lib directory:

  • AtomikosTransactionsEssentials-3.7.0/dist
    • atomikos-util.jar
    • transactions.jar
    • transactions-api.jar
    • transactions-jta.jar
    • transactions-jdbc.jar
  • AtomikosTransactionsEssentials-3.7.0/lib
    • geronimo-jta_1.0.1B_spec.jar
  • AtomikosTransactionsEssentials-3.7.0
    • transactions.properties


Tomcat lifecycle listener

A Tomcat lifecycle listener is used to start and stop the transaction manager.

package com.atomikos.tomcat;
 
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.icatch.system.Configuration;
 
public class AtomikosLifecycleListener implements LifecycleListener {
 
  private static Log log = LogFactory.getLog(AtomikosLifecycleListener.class);
 
  private UserTransactionManager utm;
 
  @Override
  public void lifecycleEvent(LifecycleEvent event) {
    try {
      if (Lifecycle.START_EVENT.equals(event.getType())) {
        if (utm == null) {
          log.info("Starting Atomikos Transaction Manager " + Configuration.getVersion());
          utm = new UserTransactionManager();
        }
        utm.init();
      } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) {
        if (utm != null) {
          log.info("Shutting down Atomikos Transaction Manager");
          utm.close();
        }
      }
    } catch (Exception e) {
      log.error("Exception", e);
    }
  }
}

Please compile this class, create a JAR and copy it to TOMCAT_HOME/lib.

The class uses following libraries:

  • transactions.jar
  • transactions-jta.jar
  • geronimo-jta_1.0.1B_spec.jar
  • commons-logging.jar (AtomikosTransactionsEssentials-3.7.0/examples/lib)
  • catalina.jar (TOMCAT_HOME/lib)


Register the lifecycle listener in the server.xml

The Tomcat lifecycle listener has to be added to the TOMCAT_HOME/conf/server.xml.

Find the following block:

<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

Add directly below these lines:

<!-- Transaction Manager Lifecycle Listener -->
<Listener className="com.atomikos.tomcat.AtomikosLifecycleListener" />


Register the user transaction factory in the context.xml

The user transaction factory has to be bind to the JNDI registry. This is done in the TOMCAT_HOME/conf/context.xml.

Find the following block:

<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>

Add directly below these lines:

<!-- User Transaction Factory -->
<Transaction factory="com.atomikos.icatch.jta.UserTransactionFactory" />


Spring configuration

The JTA transaction manager can be integrated in Spring with one instruction in the Spring configuration.

<!-- Automatically pick the appropriate JTA platform transaction manager -->
<tx:jta-transaction-manager />

Spring looks up the JTA UserTransaction and TransactionManager object via JNDI and provides it as a Spring bean named transactionManager. As we have only bind the UserTransaction object to JNDI, following constraint occurs: Spring can not suspend transactions and consequently does not support REQUIRES_NEW and NOT_SUPPORTED.
This reports Spring with the error message:

No JTA TransactionManager found: transaction suspension not available

If we can not live with this limitation, the transaction manager has to be configured as follows:

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.J2eeTransactionManager"/>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.J2eeUserTransaction"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
  <property name="transactionManager" ref="atomikosTransactionManager"/>
  <property name="userTransaction" ref="atomikosUserTransaction"/>
</bean>

This conflicts with our constraint. The Spring configuration has to be changed to be deployable on a full fledged application server. We have to separate the configuration in a Tomcat and JEE server part. Spring supports this with the PropertyPlaceholderConfigurer class and since Spring 3.1 with profiles.

OpenJPA configuration

First of all ensure that OpenJPA uses JTA. This is managed by the transaction-type in the persistence.xml:

<persistence-unit name="..." transaction-type="JTA">

Following system property teaches OpenJPA to use Atomikos:

-Dopenjpa.ManagedRuntime=invocation(TransactionManagerMethod=com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager)

Without the stated constraint, we could also do this in the persistence.xml:

<persistence-unit name="..." transaction-type="JTA">
  <properties>
    <property
        name="openjpa.ManagedRuntime"
        value="invocation(TransactionManagerMethod=com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager)" />
  • Facebook
  • Delicious
  • Digg
  • StumbleUpon
  • Reddit
  • Blogger
  • LinkedIn
Andreas Fritz

2 Responses to Integration of a transaction manager in Tomcat for Spring and OpenJPA

  1. Jürgen Kürsch says:

    Hallo,

    warum nicht gleich TomEE verwenden (http://openejb.apache.org/) ?

    Grüße
    Jürgen

    • Hallo Jürgen,

      TomEE ist eine interessante Alternative.
      Gegen TomEE sprachen unter anderem
      1. Es existiert noch keine finale Version. Für ein hausweites Ausrollen beim Kunden ist mir eine Beta 2 zu heikel – auch wenn es nur die Entwicklungsplattform ist.
      2. Der Kunde setzt WebSphere 7 ein. Daher ist Tomcat 6 die passende Wahl. TomEE / Tomcat 7 ist von den APIs zu aktuell 😉

      Viele Grüße
      Andreas

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>