Saturday, January 17, 2009

Interceptors in Hibernate ORM Framework - An Introduction

1) Introduction

This article deals with Hibernate Interceptors. Hibernate is an open-source project that provides ORM solution. For more information about Hibernate, novice readers are encouraged to read the article An Introduction to Hibernate on javabeat before reading this article.

Situations may demand to perform some set of pre-requisite/post-requisite operations before/after the core functional logic. In such a case, an interceptor can be used to intercept the existing business functionality to provide extensible or add-on features. They provide pluggable architecture and are generally callback methods that will be called by the framework in response to a particular set of events/actions if properly registered and configured. They follow the standard Interceptor pattern and they have various advantages in an application design. They can be used to monitor the various parts of the input that are passed to an application to validate them. They even have the capability to overwrite the core functional logic of the module.

For example, consider an online shopping system that ships goods to the customer's shipping address upon placing a request. Suppose, there is an enhancement to this application telling that the request has to be validated because of the increasing number of spams and the customer should be notified through e-mail (or mobile) upon successful delivery of the goods. These two enhancements have to be projected into the application's core logic.

Having a general overview of the core logic will look something like the following,

Validate the User Request
Ship the Goods to the customer
Notify the customer about its successful delivery
As we can see above, the two enhancements have to be projected within the application's core logic which requires code changes. But, if the application has to be properly designed with the notion of Interceptors, then the code change can be eliminated to the maximum.

2) Interceptors in Hibernate

Hibernate provides an ORM solution for persisting and querying data in the database. A Hibernate application can be structured in a way such that certain methods can be make to be invoked when a particular life-cycle event occurs. Not always the API in a software/product will completely satisfy the application needs and requirements. Hibernate is no more away from this. Therefore, Hibernate API is designed in such a way to provide pluggable framework through the notion of Interceptors.

In a multi-tiered application, the situation for the inclusion of Interceptors can happen at any level. It can happen at the Client level, Server level and even at the persistence level. Imagine an application is saving employee records in a database and now the application mandates to display to the Database admin about the history of inserts and updates.

A simple general overview of the logic looks like the following,

Insert/Update the records in the Database
During Insert/Update, maintain the log information in a file
As we can see, the maintenance of this logging information should happen whenever when an insert/update goes to the Database. Such a logger interceptor can be easily plugged into the application with minimal code change because of the flexible design of Hibernate.

2.1) Types of Interceptors

Based on their scope, Interceptors in Hibernate can fall under two categories. They are,

Application-scoped Interceptors
Session-scoped Interceptors
2.1.1) Application-scoped Interceptor

An application can contain one or more database sessions represented by the Session interface. If an application is configured to use Global Interceptors, then it will affect the persistent objects in all the sessions. The following code configures a global interceptor,

Configuration configuration = new Configuration();
configuration.setInterceptor(new MyInterceptor());

SessionFactory sessionFactory = configuration.buildSessionFactory();

Session session1 = sessionFactory.openSession();
Employee e1, e2 = null;
// Assume e1 and e2 objects are associated with session1.

Session session2 = sessionFactory.openSession();
User u1, u2 = null
//Assume u1 and u2 objects are associated with session1.
A global-scoped interceptor can be set to an application by calling the Configuration.setInterceptor(Interceptor) method. In the above code, we have two different session objects 'session1' and 'session2'. Let us assume that e1 and e2 Employee objects are associated with session 'session1' and u1 and u2 User objects are associated with session 'session2'. The applied application-scoped interceptor would have affected all the objects (e1, e2, u1 and u2), even though they are in different sessions.

2.1.2) Session-scoped Interceptor

A session-scoped interceptor will affect all the persistent objects that are associated with that particular session only. The following code shows how to configure a session-scoped interceptor,

Configuration configuration = new Configuration();

SessionFactory sessionFactory = configuration.buildSessionFactory();

MyInterceptor myInterceptor = new MyInterceptor();
Session session1 = sessionFactory.openSession(myInterceptor);
Employee e1, e2 = null;
// Assume e1 and e2 objects are associated with session 'session1'.

MyAnotherInterceptor myAnotherInterceptor = new MyAnotherInterceptor ();
Session session2 = sessionFactory.openSession(myAnotherInterceptor);
User u1, u2 = null;
// Assume u1 and u2 objects are associated with session 'session2'.
From the above code, we can infer that a session-scoped interceptor can be set by calling the method SessionFactory.openSession(Interceptor). In the above code, we have two different session objects 'session1' and 'session2' being configured with interceptors MyInterceptor and MyAnotherInterceptor respectively. So, e1 and e2 objects will be affected by MyInterceptor, whereas u1 and u2 objects will be affected by MyAnotherInterceptor.

No comments: