Friday, October 26, 2012

Integrating Spring Framework, Jetty, and JBoss Narayana

Update 29-10-2012:
This does not work. I posted this only after testing rollback in a transaction, and it worked. However, I couldn't get it to work as Hibernate's transaction manager alongside Spring; e.g. update operations miss the transaction scope. I tried many setup variations. If someone manages to get this working, it'd be great if you shared. For the time being I'm falling back to CMT provided by JBoss AS.
Original post:
I had to browse through quite many websites and tested some adaptations to eventually get this to work. Shame on me, it's not all that complex how it ends up.
Oh, and my syntax highlighter does this XML tag uppercase thing that is so uncalled for.
My stack goes as following:
  • Spring Framework 3.1.2.RELEASE
  • JBoss Narayana 4.17.1.Final
  • Apache Derby (network) DB 10.9.1.0
  • Jetty 8.1.7.v20120910
The Spring Framework of this version doesn't even need persistence.xml to be present, so configuration, linking data source, persistence unit, and transaction manager, in a single Spring context XML is possible and makes more sense.  The JBoss Narayana JTA guide shows that to incorporate JDBC connections within itself:
  1. Use the com.arjuna.ats.jdbc.TransactionalDriver that comes with the Narayana library
  2. Wrap a javax.sql.XADataSource by creating an implementation class of com.arjuna.ats.internal.jdbc.DynamicClass and bind the data source to a JNDI (programmatically).
    The TransactionalDriver will use the DynamicClass as its data source provider.
I stumbled at binding.  Admittedly I'm not quite sure how it works on Jetty.  I managed to make it work by, firstly, bind the XADataSource to JNDI using Jetty's context configuration. Here's how it looks like in my jetty-env.xml.

 
 jdbc/dbxa
 
  
   mydb
   username
   password
  
 

Secondly, I let my implementation of DynamicClass, in its concrete getDataSource(dbName:String):XADataSource method to perform JNDI lookup, cast it to XADataSource, and return it. Simple as that. Why did I even bother struggling with Spring JNDI binding and JMX and whatever else. Here's how it looks like:
public XADataSource getDataSource(String dbName, boolean create)
  throws SQLException {
 try {
  InitialContext ic = new InitialContext();
  ClientXADataSource40 xa = (ClientXADataSource40) ic
    .lookup("jdbc/dbxa");
  return xa;
 } catch (NamingException e) {
  throw new SQLException(null, e);
 }
}
Afterwards, I bind things together in the Spring context XML.
Since I already defined the credentials in the Jetty context configuration, I don't need to repeat it here. The driver properties bean is just:

 
  
   my.implementation.of.DynamicClass
  
 

Next is the data source bean. I have to prepend the JNDI with jdbc:arjuna:, that's just how it works.

 
  com.arjuna.ats.jdbc.TransactionalDriver
 
 
 
  
 

And then the EntityManagerFactory bean, which also replaces persistence.xml. I happen to use Hibernate, so that's HibernateJpaVendorAdapter for me.

 
 
 
 
  
   
   
   
  
 
 
 
  
 

I also need to define the Narayana transaction manager and user transaction implementation beans as well as the Spring transaction manager bean itself.




 
  
 
 
  
 

And lastly if you like annotations:
As a bonus, you can also set where Narayana will store its objects, default timeout, etc by defining this factory bean.

 
 
 
  
   60
   .\arjuna
   .\arjuna
  
 

That's all. You can add a logger for com.arjuna.ats and set it to trace or fine to see whether it works. I don't suppose I need to show an example of how transactional annotation is used right. And there's that org.springframework.transaction.support.TransactionTemplate and org.springframework.transaction.interceptor.TransactionAspectSupport to allow manual, programmatic transaction control.

No comments:

Post a Comment