Tomcat 7 with full JTA

Everytime I clean my home directory I purge something important.

Just like a week week ago when I  realized my Tomcat 7 installation was gone and with it all the things I had to do to get JOTM running in there.

Once again I spent a while to get everything back together.
But THIS time I am writing it down.

Tomcat Setup

So I want to have Tomcat 7 with full JTA (should also work on older Tomcat versions).
I will be using JOTM as it provides everything I need.

After downloading the JOTM-distribution copy the following jars to <tomcat-home>/lib.

  • commons-logging-api.jar
  • jotm-core.jar
  • log4j.jar
  • ow2-connector-1.5-spec.jar
  • ow2-jta-1.1-spec.jar
I will also add the tomcat connection pool to show a full example later on.
Download the distribution and add the following jars to <tomcat-home>/lib.
  • tomcat-jdbc.jar
  • tomcat-juli.jar

JNDI

Now we need to tell Tomcat how to create the required JNDI-resources.

Note:
Everything created using the Resource-tag will end up in java:comp/env/. Tomcat doesn’t provide functionality to put it somewhere else (or I was simply too blind to find it).

To make resources available we need to edit <tomcat-home>/conf/context.xml.
The first thing we need to add is a connection pool to showcase the useage of JTA later on.

<ResourceLink global="jdbc/myDB" name="jdbc/myDB" type="javax.sql.DataSource"/>
<Resource
	driverClassName="org.h2.Driver"
	factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
	name="jdbc/myDB"
	password=""
	type="javax.sql.DataSource"
	url="jdbc:h2:tcp://localhost/~/test"
	username="sa"/>

Now we need to add the actual JTA-related resources, starting with the the TransactionSynchronizationRegistry.
Remembering what I wrote above we have to be aware that the TransactionSynchronizationRegistryFactory will end up at java:comp/env/TransactionSynchronizationRegistry and not at java:comp/TransactionSynchronizationRegistry as the JEE-spec requires.
More on that later.

<Resource
	name="TransactionSynchronizationRegistry"
	auth="Container"
	type="javax.transaction.TransactionSynchronizationRegistry"
	factory="org.objectweb.jotm.TransactionSynchronizationRegistryFactory"/>

The final step is to add the actual transaction manager. In older versions of Tomcat one had to register the JTA-factory as a resource.
Today we got a specialized tag for that.

<Transaction
	factory="org.objectweb.jotm.UserTransactionFactory"
	jotm.timeout="60"/>

The main difference between the Transaction-tag and the Resource-Tag is that the transaction manager will end up at java:comp/UserTransaction, which is the name required by JEE.
That’s it for installing the JOTM as JTA-provider in Tomcat.

To make things available in the web application we need to add a couple of lines to web.xml in our webapplication.

<resource-env-ref>
	<description>DB Connection </description>
	<resource-env-ref-name>jdbc/myDB</resource-env-ref-name>
	<resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
</resource-env-ref>

<resource-env-ref>
	<description>JTA transaction manager</description>
	<resource-env-ref-name>jta/UserTransaction</resource-env-ref-name>
	<resource-env-ref-type>javax.transaction.UserTransaction</resource-env-ref-type>
</resource-env-ref>

<resource-env-ref>
	<description>JTA Transaction Synchronization Registry</description>
	<resource-env-ref-name>TransactionSynchronizationRegistry</resource-env-ref-name>
	<resource-env-ref-type>javax.transaction.TransactionSynchronizationRegistry</resource-env-ref-type>
</resource-env-ref>

Putting it all together

A little example on how to use JTA in your webapplication via spring:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="dataSource" ref="dataSource"/>
	<property name="jpaVendorAdapter">
		<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
			<property name="showSql" value="false"/>
		</bean>
	</property>
	<propertyname="jpaProperties">
		<props>
			<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
		</props>
	</property>
</bean>

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/myDB" resource-ref="true"/>

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
	<property name="transactionSynchronizationRegistryName" value="java:comp/env/TransactionSynchronizationRegistry"/>
	<property name="transactionManagerName" value="java:comp/UserTransaction"/>
</bean>

The only thing I don’t really like about this configuration is this line:

<property name="transactionSynchronizationRegistryName" value="java:comp/env/TransactionSynchronizationRegistry"/>

This is no problem, as long as your only deployment target is Tomcat.

If Tomcat  is only used for local deployments for development and the production system is some sort of JEE-server you will have to change the JNDI-location to the JEE-default.

This is easily achieved using maven-profiles.

Advertisements