Wednesday, August 10, 2011

Hibernate Interceptors

Are you using hibernate and thinking of using Database Triggers? Then wait....

If most of your database operations are done via stored procedures then having triggers in place is the only choice to intercept any DML calls.

But since we are using hibernate we need a more object oriented way of handling things.
Hibernate interceptors is similar to triggers in database. Monitoring DML operations via triggers is the most efficient way, but it won't be easy to maintain, understand and manipulate business logic when all database operations are done via hibernate.

Coming straight to the point, hibernate provides "org.hibernate.Interceptor" interface to have the business logic to perform pre or post operations around DML hibernate calls. Following methods are required to be implemented against "org.hibernate.Interceptor".

public interface Interceptor {

public void afterTransactionBegin(Transaction arg0) {

}

public void afterTransactionCompletion(Transaction arg0) {

}

public void beforeTransactionCompletion(Transaction arg0) {

}

public int[] findDirty(Object arg0, Serializable arg1, Object[] arg2,
Object[] arg3, String[] arg4, Type[] arg5) {
return null;
}

public Object getEntity(String arg0, Serializable arg1)
throws CallbackException {
return null;
}

public String getEntityName(Object arg0) throws CallbackException {
return null;
}

public Object instantiate(String arg0, EntityMode arg1, Serializable arg2)
throws CallbackException {
return null;
}

public Boolean isTransient(Object arg0) {
return null;
}

public void onDelete(Object arg0, Serializable arg1, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
}

public boolean onFlushDirty(Object arg0, Serializable arg1, Object[] arg2,
Object[] arg3, String[] arg4, Type[] arg5) throws CallbackException {
return false;
}

public boolean onLoad(Object arg0, Serializable arg1, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
return false;
}

public boolean onSave(Object arg0, Serializable arg1, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
return false;
}

public void postFlush(Iterator arg0) throws CallbackException {

}

public void preFlush(Iterator arg0) throws CallbackException {

}
}
Since you won't be interested in implementing all of the methods, hibernate provides "org.hibernate.EmptyInterceptor" class which has empty implementation of the Interceptor interface. Now, as per your need you can override any of the desired method. Below is the sample class which I plugged in hibernate configuration to print out the primary key of any object which is getting saved.

package com.test.interceptor;

import java.io.Serializable;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;

public class InsertMonitorInterceptor extends EmptyInterceptor{

@Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
System.out.println("Saving..." + id + ": " entity);
return super.onSave(entity, id, state, propertyNames, types);
}
}
Once you have your Interceptor class implementation ready it can be very easily plugged with any existing hibernate configuration as shown below.


new Configuration().configure(DBUtil.class.getResource("hibernate.cfg.xml"))
.setInterceptor(new InsertMonitorInterceptor())
.buildSessionFactory();
That's it. You can have different interceptor implementation plug it in to start using them.
Hope this article will be helpful. happy Intercepting.

Thanks.

No comments: