The aim of this article is to describe the use of Jencks (http://jencks.org). It is based on the version 1.1.1 of the project.
This project allows application to use the transaction and connector modules with the JCA support of Spring in order to use JCA in a managed mode outside a J2EE application server. It allows to develop more lightweight applications and to embed XA features into every applications even if they are not deployed in an application server.
The JCA support of Spring provides a dedicated FactoryBean implementation, LocalConnectionFactoryBean, to configure a JCA connector in a non managed mode. You can too use it to configure a connector in a managed mode if you specify an implementation of the JCA ConnectionManager interface in addition to the ManagedConnectionFactort as described in the following code.
<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean"> <property name="managedConnectionFactory"><ref local="managedConnectionFactory"/></property> <property name="connectionManager"><ref local="connectionManager"/></property> </bean>
Note that the LocalConnectionFactoryBean class can be used to expose different interfaces like the JMS ConnectionFactory, the JDBC DataSource, the Hibernate SessionFactory, of course the JCA ConnectionFactory...
When using this feature, you are now able to add your resources in the context of global transactions and use them with JTA.
Jencks is very close to the Geronimo and Spring projects. As a matter of fact, it provides dedicated FactoryBean to configure resources of the connector and transaction modules of Geronimo.
The first step to use Jencks is to configure the transaction module as following.
<bean id="connectionTracker"
class="org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTrackingCoordinator"/>
<bean id="transactionManagerImpl" class="org.jencks.factory.TransactionManagerFactoryBean">
<property name="defaultTransactionTimeoutSeconds" value="600"/>
<property name="transactionLog">
<bean class="org.apache.geronimo.transaction.log.UnrecoverableLog"/>
</property>
</bean>
<bean id="transactionContextManager" class="org.jencks.factory.TransactionContextManagerFactoryBean">
<property name="transactionManager" ref="transactionManagerImpl"/>
</bean>
<bean id="userTransaction" class="org.jencks.factory.UserTransactionFactoryBean">
<property name="transactionContextManager" ref="transactionContextManager"/>
<property name="connectionTrackingCoordinator" ref="connectionTracker"/>
</bean>
The connector module will use the entities in order to be able to use global transactions.
The next step is to configure the ConnectionManager implementation of Geronimo. It provides a pooling mechanism and a contract with the transaction manager. So you must configure a ConnectionManager for each factories (DataSource, SessionFactory, ConnectionManager...).
The configuration of the XA JMS ConnectionFactory of ActiveMQ is described in the following code. It is based on the ActiveMQ JCA connector. Firstly, you must configure the ConnectionManager and then the connector using it. Note that the configuration of ConnectionManager is similar for every connector.
<bean id="transactionSupport"
class="org.jencks.factory.XATransactionFactoryBean">
<property name="useTransactionCaching" value="true"/>
<property name="useThreadCaching" value="false"/>
</property>
</bean>
<bean id="poolingSupport" class="org.jencks.factory.SinglePoolFactoryBean">
<property name="maxSize" value="2"/>
<property name="minSize" value="1"/>
<property name="blockingTimeoutMilliseconds" value="60"/>
<property name="idleTimeoutMinutes" value="60"/>
<property name="matchOne" value="true"/>
<property name="matchAll" value="true"/>
<property name="selectOneAssumeMatch" value="true"/>
</bean>
<bean id="jmsConnectionManager" class="org.jencks.factory.ConnectionManagerFactoryBean">
<property name="transactionSupport" ref="transactionSupport"/>
<property name="poolingSupport" ref="poolingSupport"/>
<property name="transactionContextManager" ref="transactionContextManager"/>
<property name="connectionTracker" ref="connectionTracker"/>
</bean>
Then you need to configure the connector basing the ConnectionManager previously configured. Here is a sample with the connector of ActiveMQ. In this case, you can inject the JMS ConnectionFactory configured which is internally XA compliant. So it can participate in a 2PC transaction.
<bean id="jmsResourceAdapter" class="org.activemq.ra.ActiveMQResourceAdapter"> <property name="serverUrl" value="tcp://localhost:61616"/> </bean> <bean id="jmsManagedConnectionFactory" class="org.activemq.ra.ActiveMQManagedConnectionFactory"> <property name="resourceAdapter" ref="jmsResourceAdapter"/> </bean> <bean id="jmsConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean"> <property name="managedConnectionFactory" ref="jmsManagedConnectionFactory"/> <property name="connectionManager" ref="jmsConnectionManager"/> </bean>
With the use of Jencks, you can manage transactions in your application normally with the classic support of Spring. In this case, the implementation of the PlatformTransactionManager interface to use is JtaTransactionManager.
For more information, see the chapter Transaction management in the reference documentation of Spring. The following code shows how to configure the JtaTransactionManager with the previous configured beans.
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="userTransaction"/> <property name="transactionManager" ref="transactionManagerImpl"/> </bean>
In this howto, we have described the way to use Jencks, ActiveMQ and Spring to make global transactions with JCA and Geronimo outside the application server. The article is focused on the outbound communication of JCA. As the ActiveMQ connector is 1.5 compliant, you can use Jencks with inbound communication. I will describe this feature in a next howto.