Bitronix configuration

After a first attempt to configure the JBoss transaction manager including  JMS, I finally decided to try the Bitronix transaction manager.

Here is the detail of the configuration.

First of all, you need to add the bitronix jars to your project, using Maven, it’s done very easily (unlike JBossTS, which needs a lot of different dependencies):

<dependency>
    <groupId>org.codehaus.btm</groupId>
    <artifactId>btm</artifactId>
    <version>2.1.3</version>
</dependency>

Now, the configuration, using Spring, as usual (you can retrieve some elements I used with the Narayana configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- enable transaction demarcation with annotations -->
    <tx:annotation-driven/>
    <tx:jta-transaction-manager/> 

    <!--  Bitronix Transaction Manager embedded configuration -->
    <bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
        <property name="serverId" value="spring-btm" />
        <property name="DefaultTransactionTimeout" value="300" />
    </bean>

    <!-- create BTM transaction manager -->
    <bean id="bitronixTransactionManager" factory-method="getTransactionManager"
        class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig" destroy-method="shutdown" />

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

<!-- Datasource config -->
    <bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close">
        <property name="className" value="com.informix.jdbcx.IfxXADataSource" />
        <property name="uniqueName" value="expElecCliCoredb" />
        <property name="maxPoolSize" value="5" />
        <property name="driverProperties">
            <props>
                <prop key="user">${user}</prop>
                <prop key="password">${pwd}</prop>
                <prop key="serverName">${serverName}</prop>
                <prop key="databaseName">${database}</prop>
                <prop key="portNumber">${port}</prop>
                <prop key="ifxIFXHOST">${host}</prop>
                <prop key="ifxIFX_LOCK_MODE_WAIT">5</prop>
                <prop key="ifxIFX_XASPEC">Y</prop>
                <prop key="ifxDB_LOCALE">en_us.819</prop>
            </props>
        </property>
    </bean>

    <!-- XA JMS Connection Factory, ensure that the jms server has been yet created (with depends-on or order definitions) 
    otherwise the factory is not available and you will receive an exception 
    (javax.jms.JMSException: error looking up wrapped XAConnectionFactory at /XAConnectionFactory)-->
    <bean id="xaJmsConnectionFactory" class="bitronix.tm.resource.jms.PoolingConnectionFactory"
        init-method="init" destroy-method="close">
        <property name="className" value="bitronix.tm.resource.jms.JndiXAConnectionFactory" />
                <property name="uniqueName" value="jmsConnectionFactory" />
        <property name="minPoolSize" value="10" />
        <property name="maxPoolSize" value="10" />
        <property name="driverProperties">
            <props>
                <prop key="name">/XAConnectionFactory</prop>
            </props>
        </property>
    </bean>

    <!--     The producer sends the messages to be processed on the queue -->
    <bean id="notificationsProducer" class="net.classnotfound.cli.core.service.component.NotificationsProducer">
        <property name="connectionFactory" ref="xaJmsConnectionFactory"/>
        <property name="notificationsQueue" ref="notificationsQueue"/>
    </bean>

    <bean id="notificationService" class="net.classnotfound.core.service.NotificationServiceImpl">
        <property name="authorMapper" ref="authorMapper"/>
        <property name="notificationsProducer" ref="notificationsProducer"/>
    </bean>
</beans>

Concerning this configuration, we can see that the way we configure the datasources is almost the same for database as for JMS. The tricky part comes from HornetQ which creates the JMS connection factory but we cannot access it as a standard Spring bean. It’s why we have to get it from JNDI, resulting in a different configuration using dedicated Bitronix component: bitronix.tm.resource.jms.JndiXAConnectionFactory.

This connection factory is now used by the JMS producer. When we send a JMS message, this call is proxied by Bironix to enlist this action in the transaction.

To start the transaction, we do it as usual using the well-known @Transactional annotation. Doing this, the transaction is automatically started, and when we send the JMS message, it is included in the transaction.

Here an example of its usage:

    public void sendNotification(final String message) throws Exception {
        notificationsQueueConnection = connectionFactory.createConnection();
        notificationsQueueSession = notificationsQueueConnection.createSession(true, 0);
        notificationsQueueProducer = notificationsQueueSession.createProducer(notificationsQueue);

        TextMessage textMessage = notificationsQueueSession.createTextMessage(message);
        notificationsQueueProducer.send(textMessage);
    }

It’s important to note that the session is created in the send method, because following the JMS specification, “Any call to the Connection.createSession method must take place within the transaction”. I tried to create the session in a @PostConstruct, there is no error, you can send your message but… Nothing happens 🙁

Done!

Improve server startup using Informix and MyBatis

Working on a project with an Informix database and using MyBatis as the persistence layer, I noted that the start-up of the server takes a long time (about 2 minutes). It is not really a problem if the performance of the application are good, as you don’t start your server all the day, but when you are in the implementation phase…
After step-by-step execution, I discovered that MyBatis gathers the metadata of the database to adapt its behavior, but this part was responsible of the delay (maybe Informix specific?).
I decided to replace this step, fortunately, using MyBatis with Spring, it’s not really a big deal 🙂
As the main purpose of this step is to identify the database provider, I defined a class which returns always the same information: Informix database.

  1. first, you need to define a new DatabaseIdProvider:
    public class IfxDatabaseIdProvider 
            implements org.apache.ibatis.mapping.DatabaseIdProvider {
      
      private static final Log log = LogFactory.getLog(IfxDatabaseIdProvider.class);
    
      private Properties properties;
      
      public String getDatabaseId(DataSource dataSource) {
        
        return "Informix Dynamic Server";
      }
    
      public void setProperties(Properties p) {
        this.properties = p;
      }
    
      public Properties getProperties() {
        return properties;
      }
    }
    
  2. now, you need to tell to MyBatis to use the new class, your Spring config file looks like:

        <bean id="ifxDatabaseIdProvider" 
            class="myPackage.IfxDatabaseIdProvider"/>
        
        <bean id="sqlSessionFactory" 
            class="org.mybatis.spring.SqlSessionFactoryBean">
          <property name="dataSource" ref="dataSource" />
          <property name="mapperLocations" value="classpath:mapper/*Mapper.xml"/>
          <property name="databaseIdProvider" ref="ifxDatabaseIdProvider"/>
        </bean>
    

Done!

Tomcat Datasource configuration

I describe here my favorite solution to define the datasource of my web applications.

To do that in Tomcat :

  1. Copy the JDBC driver jar into the Tomcat lib directory
  2. define the datasource in the file server.xml:
     <GlobalNamingResources>
    
        <Resource 
            auth="Container" 
            driverClassName="oracle.jdbc.OracleDriver" 
            maxActive="20" 
            maxIdle="10" 
            maxWait="-1" 
            name="jdbc/myGlobalDatasource" 
            password="password" 
            type="javax.sql.DataSource" 
            url="jdbc:oracle:thin:@[server]:[port]:[sid]" 
            username="user"/>
    
    </GlobalNamingResources>
  3. map this datasource to your application using its context.xml file:
    <ResourceLink 
        global="jdbc/globalDatasource" 
        name="jdbc/applicationDatasource" 
        type="javax.sql.DataSource"/>
  4. And now, when you want to use it (using Spring):
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="jdbc/applicationDatasource" />
        <property name="resourceRef" value="true" />
    </bean>

Done!

This example uses an Oracle connection but it can be easily adapted for another database.

JBoss transaction manager (Non XA)

This is my configuration for using the transaction manager implementation provided by JBoss outside of a JEE container. This configuration works for database transaction but not for JMS transaction;
The configuration is done with Spring which delegates the transaction management to the JBoss implementation. Even if I used all the stuff to be able to manage XA transactions, it is not working with JMS. It seems that the messages are not included in the transaction and with the lack of clear documentation to properly configure it, I finally gave up and decided to use an alternative provider.
I present here the configuration to use the JBoss transaction manager I used for database transaction management:

<!-- enable transaction demarcation with annotations -->
<tx:annotation-driven/>
<tx:jta-transaction-manager/> 

<!--     Transactionmanager Config  (uses CORBA??) -->
<!--     <bean class="com.arjuna.ats.jta.TransactionManager" factory-method="transactionManager" id="arjunaTransactionManager"></bean> -->
<!--     <bean class="com.arjuna.ats.jta.UserTransaction" factory-method="userTransaction" id="arjunaUserTransaction"></bean> -->

<!--     Transactionmanager Config  (local, without CORBA??-again...) -->
<bean class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple" id="arjunaTransactionManager"></bean>
<bean class="com.arjuna.ats.internal.jta.transaction.arjunacore.UserTransactionImple" id="arjunaUserTransaction"></bean>

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

<!-- Datasource config (use XA!)-->
<bean id="ifxXADataSource" class="com.informix.jdbcx.IfxXADataSource">
    <property name="user" value="${user}" />
    <property name="password" value="${pwd}" />
    <property name="serverName" value="${serverName}" /> 
    <property name="databaseName" value="${dbName}" /> 
    <property name="portNumber" value="${port}" />
    <property name="ifxIFXHOST" value="${host}" /> 
    <property name="ifxIFX_LOCK_MODE_WAIT" value="5" /> 
    <property name="ifxIFX_XASPEC" value="Y" />
    <property name="ifxDB_LOCALE" value="en_us.819" />        
</bean>

<bean id="dsXAConnectionFactory" class="org.apache.commons.dbcp.managed.DataSourceXAConnectionFactory">
    <constructor-arg><ref bean="arjunaTransactionManager"></ref></constructor-arg>
    <constructor-arg><ref bean="ifxXADataSource"></ref></constructor-arg>
</bean>

<bean id="pool" class="org.apache.commons.pool.impl.GenericObjectPool">
    <property name="maxActive" value="20"/>
    <property name="minIdle" value="5"/>
</bean>

<bean id="poolableConnectionFactory" class="org.apache.commons.dbcp.PoolableConnectionFactory">
    <constructor-arg name="connFactory" ref="dsXAConnectionFactory"/>
    <constructor-arg name="pool" ref="pool"/>
    <constructor-arg name="stmtPoolFactory"><null></null></constructor-arg>
    <constructor-arg name="validationQuery"><null></null></constructor-arg>
    <constructor-arg name="defaultReadOnly" value="false"/>
    <constructor-arg name="defaultAutoCommit" value="false"/>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.managed.ManagedDataSource" depends-on="poolableConnectionFactory">
    <constructor-arg name="pool" ref="pool"/>
    <constructor-arg name="transactionRegistry" value="#{dsXAConnectionFactory.getTransactionRegistry()}"/>
</bean>

Maven dependencies:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.framework.version>4.0.0.RELEASE</spring.framework.version>
    <apache.tomcat.version>7.0.50</apache.tomcat.version>
</properties>

<dependencies>
    <!-- Logging dependencies -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.6.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.6.1</version>
    </dependency>
    <dependency>
        <groupId>ant</groupId>
        <artifactId>ant-apache-log4j</artifactId>
        <version>1.6.5</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
    <dependency>
        <groupId>com.informix.jdbc</groupId>
        <artifactId>ifxjdbc</artifactId>
        <version>4.10</version>
    </dependency>
    <dependency>
        <groupId>com.informix.jdbc</groupId>
        <artifactId>ifxjdbcx</artifactId>
        <version>4.10</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.jbossts</groupId>
        <artifactId>narayana-all</artifactId>
        <version>4.17.16.Final</version>
        <type>pom</type>
    </dependency>
    <dependency>
        <groupId>org.jboss.spec.javax.transaction</groupId>
        <artifactId>jboss-transaction-api_1.1_spec</artifactId>
        <version>1.0.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.jbossts.jts</groupId>
        <artifactId>jbossjts-jacorb</artifactId>
        <version>4.17.13.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.logging</groupId>
        <artifactId>jboss-logging</artifactId>
        <version>3.1.0.GA</version>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
</dependencies>

Simple Spring configuration

Spring configuration for use of a simple transaction manager (non XA). The data source must be defined in a JNDI repository (Tomcat in my case).

application.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<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="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
                <property name="generateDdl" value="false" />
            </bean>
        </property>
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.connection.SetBigStringTryClob">true</prop> <!-- should be done via system properties -->
                <prop key="hibernate.jdbc.batch_size">0</prop>
                <prop key="hibernate.jdbc.use_streams_for_binary">true</prop>
            </props>
        </property>
    </bean>

	<!-- DBCP data source -->

	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName" value="jdbc/applicationDatasource" />
		<property name="resourceRef" value="true" />
	</bean>

	<!-- the transaction manager -->
	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<!-- exceptions translation -->
	<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

	<!-- persistance annotations -->
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

</beans>

Maven dependencies:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.framework.version>3.0.7.RELEASE</spring.framework.version>
    <hibernate.version>3.6.9.Final</hibernate.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.framework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.0-api</artifactId>
        <version>1.0.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
</dependencies>

To start automatically the Spring Ccontext, add in your web.xml:

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>