views:

17455

answers:

4

I have a web application using JPA and JTA with Spring. I would like to support both JBoss and Tomcat. When running on JBoss, I'd like to use JBoss' own TransactionManager, and when running on Tomcat, I'd like to use JOTM.

I have both scenarios working, but I now find that I seem to need two separate Spring configurations for the two cases. With JOTM, I need to use Spring's JotmFactoryBean:

<bean id="transactionManager" 
 class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="userTransaction">
        <bean class="org.springframework.transaction.jta.JotmFactoryBean"/>
    </property>
</bean>

In JBoss, though, I just need to fetch "TransactionManager" from JNDI:

<bean id="transactionManager" 
 class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager">
        <bean class="org.springframework.jndi.JndiObjectFactoryBean">
             <property name="resourceRef" value="true" />
             <property name="jndiName" value="TransactionManager" />
             <property name="expectedType" 
               value="javax.transaction.TransactionManager" />
        </bean>
    </property>
</bean>

Is there a way to configure this so that the appropriate TransactionManager - JBoss or JOTM - is used, without the need for two different configuration files?

+4  A: 

You can use PropertyConfigurerPlaceholder to inject bean references as well as simple values.

For example if you call your beans 'jotm' and 'jboss' then you could inject your TM like:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE">
    <property name="location" value="classpath:/path/to/application.properties"/>
</bean>
<bean id="jotm">...</bean>
<bean id="jboss">...</bean>
<bean id="bean-requiring-transaction-manager">
    <property name="transactionManager" ref="${transaction.strategy}"/>
</bean>

Then you can swap transaction managers using

  • transaction.strategy=jotm in a properties file
  • -Dtransaction.strategy=jotm as a system property

This is one possible approach. See my blog for a more complete example.

Hope this helps.

toolkit
+2  A: 

If you are using Spring 2.5 you can use <tx:jta-transaction-manager/>. I have not used it with JBoss but it should work for you according to section 9.8 Application server-specific integration from the Spring reference manual.

bmatthews68
A: 

The <tx:jta-transaction-manager/> approach will look for a transaction manager in several default locations listed here. If your JBoss transaction manager is not in one of those locations, I suggest you move it, if possible, or move it in Tomcat so that both containers have their TM in the same JNDI location.

Chochos
+5  A: 

I think you have missed the point of JNDI. JNDI was pretty much written to solve the problem you have!

I think you can take it up a level, so instead of using the "userTransaction" or "transactionManager from JNDI" depending on your situation. Why not add the "JtaTransactionManager" to JNDI. That way you push the configuration to the JNDI where it is supposed to be instead of creating even more configuration files [ like there aren't enough already ;) ].

David Newcomb