How to use multiple persistence.xml in SOA

Couple of days back I was stuck into problem on how to use multiple persistance.xml in SOA (using Spring + JPA). It took me two long day to resolve the problem, hence thought it will be worth to share information. There may be better way to deal with this problem and comments\approaches are most welcome.

Scenario: We have two component SSO (Single Sign On including secirity feature) and Payment. Core component has responsiblity to provide core API, life cycle management, common utility etc. In production you can deploy SSO and Payment both component on single/different machine pointing to same DB or two database. Hence we need to have persistence.xml configured for each component.

I will explain problem is steps and we will come to solution working over different issue you can encounter.

Within Core: Define getEntityManager as abstract method to use component specific EntityManager via overriding this method.

public abstract class GenericJpaDAOImpl<T extends BaseEntity> implements GenericJpaDAO<T> {
              protected abstract EntityManager getEntityManager();
}

Component SSO:

public class UserDAOImpl extends GenericJpaDAOImpl<User> implements UserDAO {
            /* Any method specific to UserLogin */
           @PersistenceContext(unitName = “sso”, type = PersistenceContextType.TRANSACTION)
           protected EntityManager entityManager;

           @Override
           protected EntityManager getEntityManager() {
                   return this.entityManager;
           }
}

Persistence.xml

           <persistence-unit name=”sso” transaction-type=”RESOURCE_LOCAL”>

Application XML

 <tx:annotation-driven  transaction-manager=”transactionManager”/>
 <bean/>

    <bean id=”transactionManager”>
        <property name=”entityManagerFactory” ref=”entityManagerFactory”/>
    </bean>

 <bean id=”entityManagerFactory”>
        <property name=”dataSource” ref=”ssoDataSource” />
 <property  name=”persistenceUnitName” value=”sso”></property>
    </bean>
 
 <bean id=”ssoDataSource” destroy-method=”close”>
        <property name=”driverClass” value=”com.mysql.jdbc.Driver”/>
        <property name=”jdbcUrl” value=”<URL>”/>
        <property name=”user” value=”<USER>”/>
        <property name=”password” value=”<PASSWORD>”/>
    </bean>

Component Payment: Similar to above

public class PaymentDAOImpl extends GenericJpaDAOImpl<Payment> implements PaymentDAO {
              /* Any method specific to PaymentLogin */
             @PersistenceContext(unitName = “payment”, type = PersistenceContextType.TRANSACTION)
             protected EntityManager entityManager;

             @Override
             protected EntityManager getEntityManager() {
                       return this.entityManager;
             }
}

Persistence.xml

<persistence-unit name=”payment” transaction-type=”RESOURCE_LOCAL”>

Application XML

 <tx:annotation-driven  transaction-manager=”transactionManagerPayment”/>
  <bean/> 

    <bean id=”transactionManagerPayment”>
        <property name=”entityManagerFactory” ref=”entityManagerFactoryPayment”/>
    </bean>

<bean id=”entityManagerFactoryPayment” >
        <property name=”dataSource” ref=”paymentDataSource” />
 <property  name=”persistenceUnitName” value=”payment”></property>
    </bean>

<bean id=”paymentDataSource”  destroy-method=”close”>
        <property name=”driverClass” value=”com.mysql.jdbc.Driver”/>
        <property name=”jdbcUrl” value=”<URL>”/>
        <property name=”Payment” value=”<Payment>”/>
        <property name=”password” value=”<PASSWORD>”/>
    </bean>

Problem which you can encounter: If applicationContext xml for loads Payment component first DAO operations will work as expected for Payment component but SSO component does not work in case where you want to commit data (I.e. Save operation).

Reason: Problem is with defination/usage of multiple transaction manager.

To debug add getEntityManager().flush(); explicitly. Exception will be thrown for component loaded second while commiting/flushing data.

Exception: Details – no transaction is in progress.

How to resolve: If you do google lot of blog/article may confuse that it is not possible to use multiple JpaTransactionManager in cobination with annotation based Spring Transaction. They provide reference to JpaTransactionManager.

http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/orm/jpa/JpaTransactionManager.html

This transaction manager is appropriate for applications that use a single JPA EntityManagerFactory for transactional data access. JTA (usually through JtaTransactionManager) is necessary for accessing multiple transactional resources within the same transaction. Note that you need to configure your JPA provider accordingly in order to make it participate in JTA transactions.

To explain above JavaDoc comment – It suggest to use JTA Transaction manager where we want to manage Transaction across multiple resource/service which can be hosted on different machine. E.g. Order Management System – My application takes Order from client, validate local inventory for items, process payment (Via Third Party – maintaining there own transaction), update local inventory for items and dispatch item event (local)

You can have single JpaTransactionManager for transactional data access per component. Although it is good idea to use JTA (in cordination with application server to manage Transaction resource) at service layer.

I should not deviate from origional discussion. So solution to resolve this is using qualifier value for transaction manager.

1. Use <tx:annotation-driven/> without any attribute. I.e. Do not use transaction-manager within tag.
2. For Transaction Manager define unique qualifier name.

<bean id=”transactionManager”>
             <property name=”entityManagerFactory” ref=”entityManagerFactory”/>
             <qualifier value=”txManagerSSO”/>
</bean>

3. At method level where you are using declarative transaction define transaction with qualifier. E.g.
@Transactional(value=”txManagerSSO”,readOnly = false)

Note that it is better to use JTA to manage resource across component hosted on different machine.
Please comment for input/alternate approaches.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: