Chained InterceptorThe Interceptor interface allows the registration of a custom object that gets called by Hibernate at some specific point when the application is running. While this allows some flexibility, we can go one step further by allowing several interceptor instances to be chained together, forming what can be called a Chained Interceptor. Each interceptor can deal with a specific problem (eg auditing, logging, security, ...), and the chain transparently propagates the different callbacks to each instance. The main problem with this approach is that while some callbacks are well suited for such an approach (basically, the ones returning a boolean / null (such as onLoad(), on Save(), preFlush(), postFlush()...)), there are other methods such as instantiate() or findDirty() which would be more difficult to integrate. A simple solution to these problematic cases is to simply have the first interceptor who returns something valid (that is, something not null) win. The following code is an example of such a ChainedInterceptor. Note that this ChainedInterceptor implements the Interceptor interface so that it can be registered by the Hibernate framework. The interceptor to be chained are passed as an array in the constructor or using a setter. Updated 06/12/2003 : added CallbackException Updated 06/19/2003 : fixed typo in onDelete: changed onSave() to onDelete()
import java.io.Serializable;
import java.util.Iterator;
import net.sf.hibernate.Interceptor;
import net.sf.hibernate.type.Type;
/**
* Implementation of the Hibernate <code>Interceptor</code>
* interface that allows the chaining of several different
* instances of the same interface.
*
* @author Laurent RIEU
* @see Interceptor
*/
public class ChainedInterceptor implements Interceptor {
// Interceptors to be chained
private Interceptor[] interceptors;
/**
* Constructor
*/
public ChainedInterceptor() {
super();
}
/**
* Constructor
* @param An array of interceptors
*/
public ChainedInterceptor(Interceptor[] interceptors) {
super();
this.interceptors = interceptors;
}
/**
* @see net.sf.hibernate.Interceptor#onLoad(java.lang.Object,
* java.io.Serializable, java.lang.Object[], java.lang.String[],
* net.sf.hibernate.type.Type[])
*/
public boolean onLoad(
Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) throws CallbackException {
boolean result = false;
for (int i = 0; i < interceptors.length; i++) {
if (interceptors[i]
.onLoad(entity, id, state, propertyNames, types)) {
/* Returns true if one interceptor in the chain has
* modified the object state result = true;
*/
}
}
return result;
}
/**
* @see net.sf.hibernate.Interceptor#onFlushDirty(java.lang.Object,
* java.io.Serializable, java.lang.Object[], java.lang.Object[],
* java.lang.String[], net.sf.hibernate.type.Type[])
*/
public boolean onFlushDirty(
Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) throws CallbackException {
boolean result = false;
for (int i = 0; i < interceptors.length; i++) {
if (interceptors[i]
.onFlushDirty(
entity,
id,
currentState,
previousState,
propertyNames,
types)) {
/* Returns true if one interceptor in the chain has modified
* the object current state result = true;
*/
}
}
return result;
}
/**
* @see net.sf.hibernate.Interceptor#onSave(java.lang.Object,
* java.io.Serializable, java.lang.Object[], java.lang.String[],
* net.sf.hibernate.type.Type[])
*/
public boolean onSave(
Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) throws CallbackException {
boolean result = false;
for (int i = 0; i < interceptors.length; i++) {
if (interceptors[i]
.onSave(entity, id, state, propertyNames, types)) {
/* Returns true if one interceptor in the chain has
* modified the object state result = true;
*/
}
}
return result;
}
/**
* @see net.sf.hibernate.Interceptor#onDelete(java.lang.Object,
* java.io.Serializable, java.lang.Object[], java.lang.String[],
* net.sf.hibernate.type.Type[])
*/
public void onDelete(
Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) throws CallbackException {
for (int i = 0; i < interceptors.length; i++) {
interceptors[i].onDelete(entity, id, state, propertyNames, types);
}
}
/**
* @see net.sf.hibernate.Interceptor#preFlush(java.util.Iterator)
*/
public void preFlush(Iterator entities) throws CallbackException {
for (int i = 0; i < interceptors.length; i++) {
interceptors[i].preFlush(entities);
}
}
/**
* @see net.sf.hibernate.Interceptor#postFlush(java.util.Iterator)
*/
public void postFlush(Iterator entities) throws CallbackException {
for (int i = 0; i < interceptors.length; i++) {
interceptors[i].postFlush(entities);
}
}
/**
* @see net.sf.hibernate.Interceptor#isUnsaved(java.lang.Object)
*/
public Boolean isUnsaved(Object entity) {
Boolean result = null;
for (int i = 0; i < interceptors.length; i++) {
result = interceptors[i].isUnsaved(entity);
if (result != null) {
// If any interceptor has returned either true or false, stop the chain
break;
}
}
return result;
}
/**
* @see net.sf.hibernate.Interceptor#findDirty(java.lang.Object,
* java.io.Serializable, java.lang.Object[], java.lang.Object[],
* java.lang.String[], net.sf.hibernate.type.Type[])
*/
public int[] findDirty(
Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
int[] result = null;
for (int i = 0; i < interceptors.length; i++) {
result =
interceptors[i].findDirty(
entity,
id,
currentState,
previousState,
propertyNames,
types);
if (result != null) {
/* If any interceptor has returned something not null,
* stop the chain
*/
break;
}
}
return result;
}
/**
* @see net.sf.hibernate.Interceptor#instantiate(java.lang.Class,
* java.io.Serializable)
*/
public Object instantiate(Class clazz, Serializable id) throws CallbackException {
Object result = null;
for (int i = 0; i < interceptors.length; i++) {
result = interceptors[i].instantiate(clazz, id);
if (result != null) {
/* If any interceptor has returned something not null,
* stop the chain
*/
break;
}
}
return result;
}
/**
* Returns an array containing the instances of the <code>Interceptor</code>
* interface that are chained within this interceptor.
* @return An array of interceptor
*/
public Interceptor[] getInterceptors() {
return interceptors;
}
/**
* Sets the instances of the <code>Interceptor</code> interface
* that are chained within this interceptor.
* @param interceptors
*/
public void setInterceptors(Interceptor[] interceptors) {
this.interceptors = interceptors;
}
}
|