第12章 インターセプタとイベント
アプリケーションが Hibernate の内部で発生するイベントに対応できると役に立つことがあります。ある種の一般的な機能を実装し、また Hibernate の機能を拡張することもできるようになります。
12.1. インターセプタ
Interceptor
インターフェースを使って、セッションからアプリケーションへコールバックをすることができます。これにより永続オブジェクトの保存、更新、削除、読み込みの前に、アプリケーションがプロパティを検査したり操作したりできるようになります。これは監査情報の追跡に利用できます。下の例で Interceptor
は Auditable
が作成されると自動的に createTimestamp
を設定し、Auditable
が更新されると自動的に lastUpdateTimestamp
プロパティを更新します。
Interceptor
を直接実装したり、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; } }
インターセプタには二種類あります:
Session
スコープとと SessionFactory
スコープ。
Session
スコープのインターセプタは、セッションをオープンするときに指定します。 Interceptor
を引数に取る SessionFactory.openSession() のオーバーロードメソッドの一つを使います。
Session session = sf.openSession( new AuditInterceptor() );
SessionFactory
スコープのインターセプタは SessionFactory
の構築の前に、Configuration
オブジェクトを使って登録します。この場合、提供されるインターセプタは SessionFactory
からオープンされたすべてのセッションに適用されます。これは使用するインターセプタを明示的に指定してセッションをオープンしない限り、そうなります。SessionFactory
スコープのインターセプタはスレッドセーフでなければなりません。複数のセッションがこのインターセプタを同時に使用する可能性があるため、セッション固有の状態を格納しないように気をつけてください。
new Configuration().setInterceptor( new AuditInterceptor() );