Overview

Suppose you have a Spring MVC application which has been running on Wildfly server.

This application uses following features/configurations:

  1. It uses Spring annotations.
  2. It uses JPA and thus has entity manager configured in its XML configuration.
  3. Application uses JNDI(Java Naming Directory Interface) to fetch datasource from server. This means that database details are provided in Wildfly’s standalone.xml file and JNDI name is also defined in spring’s configuration XML file.

Keeping above points in mind, spring configuration XML of the application should contain following

<jee:jndi-lookup id="dataSource" jndi-name="java:jboss/datasources/AppDataSource" />

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="persistenceUnitName" value="appUnit" />
   <property name="dataSource" ref="dataSource" />
   <property name="jpaVendorAdapter">
       <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
   </property>
   <property name="persistenceProvider">
       <bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
   </property>
   <property name="packagesToScan" value="com.codippa.entity" />
   <property name="jpaProperties">
      <props>
         <prop key="hibernate.id.new_generator_mappings">false</prop>
         <prop key="hibernate.max_fetch_depth">3</prop>
         <prop key="hibernate.jdbc.fetch_size">50</prop>
         <prop key="hibernate.jdbc.batch_size">150</prop>
         <prop key="hibernate.show_sql">false</prop>
         <prop key="hibernate.transaction.jta.platform">
               org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform
         </prop>
      </props>
   </property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>

Above configuration declares a bean which prepares entity manager for the application.
Data source for this entity manager is injected using jndi lookup and database details are provided inside Wildfly’s standalone.xml file.

Configuration also declares a transaction manager whose implementation class is provided by Spring.
All other properties depend upon specific application and are not mandatory.

Database details shall be provided as a datasource declared in Wildfly’s standalone.xml as below

<xa-datasource jndi-name="java:jboss/datasources/AppDataSource" pool-name="AppDataSource" 
enabled="true" use-ccm="true">
   <xa-datasource-property name="ServerName">localhost</xa-datasource-property>
   <xa-datasource-property name="DatabaseName">codippa</xa-datasource-property>
   <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
   <driver>mysql</driver>
   <security>
      <user-name>root</user-name>
      <password>root</password>
   </security>
</xa-datasource>

Above configuration file declares a data source which contains typical database connection parameters such as database server URL, database name, username, password and connection class.

Also, this datasource is exposed via a JNDI name.
Note that the name of this datasource and that defined in Spring application’s configuration file are same.
This when this application is deployed in Wildfly, it is able to look up the datasource and connect with the database defined in server’s configuration file.

Problem Statement
An application deployed in Wildfly server is working fine as per above configuration.

Now the same application needs to be deployed or migrated to Tomcat server. For this migration, following modifications are required.

1. Figure out jndi look up mechanism as supported by Tomcat.
This is because jndi name formats and resolution mechanism is different for every server.
Thus, we need to modify our application configuration to support this.

2. Determine the location where database details will be specified. Wildfly has a configuration file named standalone.xml file where database connection parameters are provided but there is no such file for Tomcat.

3. Configure a transaction manager for the application.
When the application is deployed in Wildfly, you might be using JtaTransactionManager as shown in the above configuration but this transaction manager might not be available for Tomcat since it is not an application server.

4. Find out a way to configure context path for your application.
Since the application is a web application, it would be deployed as a war.
Suppose the name of this war is mywebapp.war but while accessing the application, you want the URL as http://localhost:8080/codippa.
With Wildfly, you can create a file named jboss-web.xml and configure the context name but how should this be done with Tomcat.

Solution
For moving a web application running fine on Wildfly to Tomcat, above stated modifications need to be performed.

This section shall proceed step by step towards making such modifications.
First step is modifying Spring’s configuration so that it works fine with Tomcat. Updated configuration will look as below.

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/AppDataSource" 
expected-type="javax.sql.DataSource"/>

<bean id="entityManagerFactory"
   class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="persistenceUnitName" value="appUnit" />
   <property name="dataSource" ref="dataSource" />
   <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
   </property>
   <property name="persistenceProvider">
      <bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
   </property>
   <property name="packagesToScan" value="com.codippa.entity" />
   <property name="jpaProperties">
      <props>
         <prop key="hibernate.id.new_generator_mappings">false</prop>
         <prop key="hibernate.max_fetch_depth">3</prop>
         <prop key="hibernate.jdbc.fetch_size">50</prop>
         <prop key="hibernate.jdbc.batch_size">150</prop>
         <prop key="hibernate.show_sql">false</prop>
         <prop key="hibernate.transaction.jta.platform">
org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform
         </prop>
      </props>
   </property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory">
</bean>

Modified configuration is almost same as that working with Wildfly.
Only differences are

A. Format of jndi name is changed. This is because format of jndi name as supported by Tomcat starts with java:comp/env/jdbc.

B. Transaction manager implementation class is changed.
This is because Tomcat does not support JTA thus we need to provide it another transaction manager.
Although there are other options to implement transaction management using external transaction managers such as Atomikos but that requires some more configuration.
Configuration provided in the above example uses a transaction manager provided by Spring.

This configuration also covers step 3 outlined in the previous section, that is, configuring a transaction manager compatible with Tomcat web server.

Second configuration step involves providing database connection parameters.
This step will be performed in Tomcat’s configuration and does not required any modifications at the application level.

Open context.xml file inside conf folder of your Tomcat installation and add a Resource tag inside its Context tag.
This Resource tag shall contain all the database connection parameters as shown below.

<Context>
   <Resource name="jdbc/AppDataSource" auth="Container" type="javax.sql.DataSource"
      username="root" password="root"
      url="jdbc:mysql://localhost:3306/codippa"
      driverClassName="com.mysql.jdbc.Driver"
      initialSize="5" maxWait="5000"
      maxActive="120" maxIdle="5"
      validationQuery="select 1"
      poolPreparedStatements="true"/>
</Context>

Note that the jndi name is specified by the name attribute of the Resource and it matches with that specified in the Spring’s configuration file of the application.
Do not forget to put appropriate jdbc driver jar into Tomcat’s lib folder.

If your database configuration is fixed and need not be changed frequently, then it is recommended to place the Resource tag containing database connection information inside /META-INF/context.xml file inside your application and not inside Tomcat’s configuration files.

Last step is setting up the context path for your web application.
For this, open server.xml file inside conf folder of Tomcat installation. Inside this file, search for Host tag and place a Context tag inside it as shown below

<Host name="localhost" appBase="webapps" unpackWARs="true" 
      autoDeploy="false">
   <Context path="/codippa" docBase="codippa-appv1.2.war"></Context>
</Host>

docBase attribute of Context tag refers to the name of your application war and path attribute represents the context path by which the application will be accessed.
If Context tag is not provided, then default context path will be the same as the name of war with “.war” extension removed.
This step is not mandatory and is only required if you want the application to be accessed by a name that is different from the name of war.

Final Step
After following all the steps, place the application war into webapps folder of Tomcat installation.
Now start Tomcat server by navigating to bin folder and run command catalina.bat run.

If everything goes well and the server is started without any errors, then open any browser and open URL http://localhost:8080/context-path

Where 8080 is the default port of Tomcat, change it if Tomcat is running on another port and context-path is the path that you have configured.
If no path is configured, then use the name of application war.

Congratulations!!! you have successfully migrated your application from Wildfly to Tomcat.

If you face any issues or have performed any step other than those listed here, do add them in the comment section below.

Leave a Reply