Sunday, May 20, 2007

Open Session In View

I was a part of a team that have developed several applications using Struts, Spring and Hibernate together, and one of the problems that have faced us while using Hibernate was the rendering of the view. The problem is that when you retrieve an object 'a' of persistence class 'A' that has an instance 'b' of persistence class 'B', and this relation is lazily loaded, the value of 'b' will be 'null'. This will cause a "LazyInitializationException" while rendering the view (if you need the value of 'b' in the view of course).

A quick and easy solution to that is to set the "lazy" attribute to "false" so that 'b' would be initialized while fetching 'a', but this is not always a good idea. In case of many-to-many relationships, using non-lazy relations might result in loading the entire database into the memory using a great number of "select" statements, which will result to very poor performance, and to massive memory consumption.

Another solution is to open another unit of work in the view, which is really bad for several reasons. First of all, as a design concept, the layers of your application should be loosely coupled, and by doing the previous practice you have coupled the presentation layer with you DB layer, which is bad. Another thing is that this destroys the separation of concerns concept.

The solution to this problem can be done by keeping the hibernate session alive until the view is rendered, and this is what Hibernate introduced as the Open Session In View Design Pattern. Since the Hibernate session will be opened, trying to retrieve 'b' in the view will cause Hibernate to go and fetch it from the DB. In a web application, this can be done through a filter/interceptor.

Spring framework comes with both a filter and an interceptor, so that you don't have to write your own. The problem that might face you, if you're using spring's HibernateTemplate,without doing your own session and transaction management, is that you will not be able to save, edit or delete anything, since both the filter and the interceptor provided by spring set the flush mode of the session to "NONE".

A solution to that, which I've learned from a friend of mine recently is to extend the filter provided by spring, override the getSession method to set a different flush mode, and override the closeSession method to flush the session before closing it. The sample code is shown below:



public class HibernateFilter extends OpenSessionInViewFilter {

@Override

protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {

Session session = SessionFactoryUtils.getSession(sessionFactory, true);

//set the FlushMode to auto in order to save objects.

session.setFlushMode(FlushMode.AUTO);

return session;

}


@Override

protected void closeSession(Session session, SessionFactory sessionFactory) {

try{

if (session != null && session.isOpen() && session.isConnected()) {

try {
session.flush();
}

catch (HibernateException e) {
throw new CleanupFailureDataAccessException("Failed to flush session before close: " + e.getMessage(), e);
}

catch(Exception e){
}
}
}

finally{
super.closeSession(session, sessionFactory);
}
}
}


By using this filter, you will be able to render the view easily, without having to set the "lazy" attribute to "false", or to open a hibernate session in the view, but you have to take care not to change any values of the persistence object in the view, because those changes will be saved to the DB at the end of the request. This is the main reason why the flush mode is set to "NONE" in the original filter and interceptor.

Why this blog?

Well, why do I set up a java blog? I'm not that super java guru who will write great articles that are going to help thousands of java developers. I'm a normal java web developer with only three years of experience. So why do I make a technical blog? Well, think of it as my personal notebook, where I write the technical stuff that I want to remember, and the tips and tricks I've learned, so that when I need them I would get back to them instead of searching the net for what I already know, but forgot.

So again, why a blog? I can do that on a document, or a real notebook. Well, The other reason is giving something back to the community. I've learned a lot through articles and blog entries by developers much more experienced than I am, so why don't I give something back? That's it.



One last thing to note is that I'm planning that most of my posts will not go into a lot details that are out of the scope of the article. To give an example, if I'm writing an article about a solution to a specific problem in struts with spring, I will not go into details of how to integrate struts with spring.



I hope that those entries are going to be useful to web developers, like other blogs were useful to me.