Thursday, March 11, 2010

Hibernate Session and Transaction Management

It seems, there are several approaches to manage Hibernate sessions and transactions:
  • explicitly by the application
  • explicitly by the application with ThreadLocal pattern (example)
  • via Hibernate transaction demarcation with JTA
  • via Hibernate transaction demarcation with plain JDBC
  • using Spring Framework
  • using EJB / CMT (container-managed transactions)
For a good explanation of all options, other than ThreadLocal, see Hibernate document. Note that EJB, as well as JTA, are available even outside the J2EE container as a module. Also, supposedly, the Spring Framework can be easily used just for the functionality you decide to use from it and it doesn't require the application to use all parts of this framework.

Basic Approach: Managed by Application
Here's a code sample from hibernate document:
Session session = factory.openSession();
Transaction tx = null;
try {
    tx = session.beginTransaction();

    // Do some work
    session.load(...);
    session.persist(...);

    tx.commit(); // Flush happens automatically
}
catch (RuntimeException e) {
    tx.rollback();
    throw e; // or display error message
}
finally {
    session.close();
}
You choose the approach.

Monday, March 8, 2010

Android Testing - Tips

  • What is Android Context class? It's "an interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system."
  • The native Android OS support for testing is based on jUnit 3. Don't try to use jUnit 4. The results are not predictable. I had the first test run fine, but no more tests would finish.
  • Testing support:

    • Use ActivityInstrumentationTestCase2 for functional testing of a single Activity. The selected activity will be created and managed by the system as specified by the regular activity lifecycle. Tests can interact with the UI widgets to imitate user actions.
    • Use ActivityUnitTestCase to run unit tests of an isolated activity. Activity under test will not be subject to regular activity lifecycle.
  • If you see a problem of type error: device not found and shutdown the adb.exe process. It will restart automatically and try to reconnect to the device. Sometimes, starting the intended Instrumentation on emulator (an option in Dev Tools application) does it all for you.
  • If adb does not connect after restarting it (shows "DeviceMonitor]Connection attempts: 11..." and LogCat nic nie pokazuje), restart PC.

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?

J2EE - Tips and Tricks

  • Sun/Oracle's J2EE 5 SDK is installed in small pieces. Unlike previous versions of J2EE, there is no j2ee.jar. And so, pieces of it are installed in glassfish\modules folder, as separate jars. For example, the JTA stuff is installed as jta.jar (the implmementation stuff, com.sun....* classes) and javax.transactions.jar, which holds the core of the JTA API.