Distributed transaction is piece of cake when the application runs in the container. Datasources can be configured in the application server and be bound to JNDI tree. UserTransaction is also available in the JNDI tree. Application code just uses the JTA interface, UserTransaction, for transaction demarcation.
Lets have a quick look at how this is done in the application code. Then we will see how to unit test this code layer, that participate in distributed transaction, outside the container.
- Configure XA datasources in application server with JNDI name say ds1 & ds2. You can either use admin console provided by the application server or update server specific datasource configuration file.
- Configure two hibernate session factory, one for each datasource.
one_hibernate.cfg.xml for datasource:ds1 two_hibernate.cfg.xml for datasource:ds2
Code in my Hibernate Util class:
SessionFactory sessionFactory = new Configuration().configure("/one_hibernate.cfg.xml").buildSessionFactory();
static_sessionFactory_Map.put("DS_ONE", sessionFactory);sessionFactory = new Configuration().configure("/two_hibernate.cfg.xml").buildSessionFactory();static_sessionFactory_Map.put("DS_TWO", sessionFactory);
- Add transactional properties to hibernate.cfg.xml. I am using JBoss Application Server.
<property name="hibernate.current_session_context_class">jta</property><property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property><property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
- Add transaction demarcation at business layer. Code in the business component typically would look like below
InitialContext ic = new InitialContext();UserTransaction ut = (javax.transaction.UserTransaction) ic.lookup("UserTransaction");try{ut.begin();//invoke dao that uses ds1//send xa jms messages//run some other business logic//invoke dao that uses ds2//etc etcut.commit();}catch(SomeException ex){ut.rollback();}
So we are all set. Code will nicely handle distributed transactions! Now challenge here is: how to write junit tests to test this application outside the server container. How do we make JNDI datasources, UserTransaction, Transaction context available to the code? We need a standalone Transaction Manager. Junit tests need setup code to bind datasources and UserTransaction object. Lets go step by step.
- Configure hibernate to use Bitronix Transaction Manager
<property name="hibernate.current_session_context_class">jta</property><property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property><property name="hibernate.transaction.manager_lookup_class">custom.lookup.manager.see.bitronix.doc</property>
- Use Apache Naming in-memory JNDI service provider to bind the resources
Setup code in junit tests:
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");InitialContext ic = new InitialContext();//create and bind datasources. We are using Oracle database serverOracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();ds.setURL("jdbc:oracle:thin:@host:port:sid1");ds.setUser("username");ds.setPassword("password");ic.rebind("ds1", ds);ds = new OracleConnectionPoolDataSource();ds.setURL("jdbc:oracle:thin:@host:port:sid2");ds.setUser("username");ds.setPassword("password");ic.rebind("ds2", ds);
//we are using bitronix.tm.TransactionManagerServicesUserTransaction userTransaction = TransactionManagerServices.getTransactionManager();ic.rebind("UserTransaction", userTransaction);
- All set! Just write junit tests to test business methods
public void testBuzApi(){MyBizClass bizObj = new MyBizClass();SomeObject retObj = bizObj.myMethodOne();//some assertXXX(.....);}
Looks like its not a challenging task to unit test java EE code, right. We just need to provide all the resources application code expect while running in a server container.
2 comments:
Would you zip your project for us to try?
Hi There,
Thanks for leaving the first comment on my blog! I will try to put together test codes as a small project whenever I get some free time. Meanwhile, please let me know if you have any specific questions.
Thanks
Post a Comment