Tuesday, March 2, 2010

JSON RESTfull Service Using Jersey with Hibernate Persistence on Glassfish - Part 2

This is continuation of my blog on this topic. I'm adding the solution to the questions/issues left out in that first blog as delineated in the last part of the blog. Actually, this effort wasn't successful. I wasn't able to make it work. Although made a good progress, I had to go back to the approach presented in my previous blog. This post is just to document what I was able to achieve.

JTA
Switch to use JTA, instead of native JDBC transactions. All new application servers support JTA natively. With JTA, the session is bound to the transaction. If you call sessionFactory.getCurrentSession(), anytime between userTransaction.begin() and userTransaction.commit(), a session bound to this transaction is returned. User transaction is usually obtained via JNDI. So, an example of code:
UserTransaction tx = (UserTransaction)new InitialContext()
 .lookup("java:comp/UserTransaction");

SessionFactory factory = HibernateUtil.getSessionFactory();
PersonDao dao = new PersonDao(factory);

try{
 tx.begin();
 
 dao.saveOrUpdate(person);
 
    tx.commit();

} catch( Exception ex) {
 tx.rollback();
}
while the only thing that the Dao needs to do is to request the session via: factory.getCurrentSession().

The required Hibernate configuration file hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory name="hibernate/sessionFactory">
     <property name="transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</property>
     <property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
        <property name="connection.datasource">jdbc/xaderby</property>
        <property name="dialect">org.hibernate.dialect.DerbyDialect</property>
        <property name="current_session_context_class">jta</property>
        <property name="hbm2ddl.auto">create</property>
    
     <mapping resource="olcc/entity/Person.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
where jdbc/xaderby is a data source defined on Glassfish, of type javax.sql.XADataSource.

Configuration
Glassfish 3
Hibernate 3.5
JDK 6 (Derby included)

Result
This configuration results in the following error message:

FINEST: saving transient instance
FINE: surrounding JTA transaction suspended [JavaEETransactionImpl: txId=1 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[org.hibernate.transaction.CacheSynchronization, org.hibernate.context.JTASessionContext$CleanupSynch@1d069e4]]
FINE: opening JDBC connection
INFO: JTS5014: Recoverable JTS instance, serverId = [100]

FINE: select next_hi from hibernate_unique_key for read only with rs
FINE: update hibernate_unique_key set next_hi = ? where next_hi = ?
FINE: closing JDBC connection (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)
SEVERE: org.hibernate.HibernateException: unable to resume previously suspended transaction
    at org.hibernate.engine.transaction.Isolater$JtaDelegate.delegateWork(Isolater.java:179)
    at org.hibernate.engine.transaction.Isolater.doIsolatedWork(Isolater.java:64)
    at org.hibernate.engine.TransactionHelper.doWorkInNewTransaction(TransactionHelper.java:74)
    at org.hibernate.id.TableGenerator.generate(TableGenerator.java:118)
    at org.hibernate.id.TableHiLoGenerator.generate(TableHiLoGenerator.java:84)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122)
When I tried using a plain javax.sql.DataSource instead of XADataSource, I was getting XAResource.start error.

Remaining Questions:
  • findAllByProperty(), findByCriteria() and/or findByExample() methods. Commonly used. What is the right way to implement them?

No comments: