Il est souvent utile pour l'application de réagir à certains événements qui surviennent dans Hibernate. Cela autorise l'implémentation de certaines sortes de fonctionnalités génériques, et d'extensions de fonctionnalités d'Hibernate.
L'interface Interceptor
fournit des "callbacks" de la session vers l'application et permettent à l'application de consulter et/ou de manipuler des
propriétés d'un objet persistant avant qu'il soit sauvegardé, mis à jour, supprimé ou chargé. Une utilisation possible de
cette fonctionnalité est de tracer l'accès à l'information. Par exemple, l'Interceptor
suivant positionne createTimestamp
quand un Auditable
est créé et met à jour la propriété lastUpdateTimestamp
quand un Auditable
est mis à jour.
Vous pouvez soit implémenter Interceptor
directement ou (mieux) étendre EmptyInterceptor
.
package org.hibernate.test; import java.io.Serializable; import java.util.Date; import java.util.Iterator; import org.hibernate.EmptyInterceptor; import org.hibernate.Transaction; import org.hibernate.type.Type; public class AuditInterceptor extends EmptyInterceptor { private int updates; private int creates; private int loads; public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { // do nothing } public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { updates++; for ( int i=0; i < propertyNames.length; i++ ) { if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) { currentState[i] = new Date(); return true; } } } return false; } public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { loads++; } return false; } public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { creates++; for ( int i=0; i<propertyNames.length; i++ ) { if ( "createTimestamp".equals( propertyNames[i] ) ) { state[i] = new Date(); return true; } } } return false; } public void afterTransactionCompletion(Transaction tx) { if ( tx.wasCommitted() ) { System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads); } updates=0; creates=0; loads=0; } }
Interceptors come in two flavors: Session
-scoped and SessionFactory
-scoped.
A Session
-scoped interceptor is specified when a session is opened using one of the overloaded SessionFactory.openSession() methods
accepting an Interceptor
.
Session session = sf.openSession( new AuditInterceptor() );
A SessionFactory
-scoped interceptor is registered with the Configuration
object prior to building the SessionFactory
. In this case, the supplied interceptor will be applied to all sessions opened from that SessionFactory
; this is true unless a session is opened explicitly specifying the interceptor to use. SessionFactory
-scoped interceptors must be thread safe, taking care to not store session-specific state since multiple sessions will use
this interceptor (potentially) concurrently.
new Configuration().setInterceptor( new AuditInterceptor() );