Sunday, May 18, 2008

HIBERNATE - Relational Persistence for Idiomatic Java - 12

HIBERNATE - Relational Persistence for Idiomatic Java
Hibernate Reference Documentation
Hibernateレファレンスドキュメンテーション
3.2.2

Table of Contents(コンテンツテーブル)
Preface(序文)
1. Introduction to Hibernate(Hibernateの紹介)
2. Architecture(アーキテクチャ)
3. Configuration(設定)
4. Persistent Classes(永続クラス)
5. Basic O/R Mapping(基本的なO/Rマッピング)
6. Collection Mapping(コレクションのマッピング)
7. Association Mappings(関連マッピング)
8. Component Mapping(コンポーネントのマッピング)
9. Inheritance Mapping(継承マッピング)
10. Working with objects(オブジェクトを扱う)
11. Transactions And Concurrency(トランザクションと並行性)
12. Interceptors and events(インターセプタとイベント)
12.1. Interceptors(インターセプタ)
12.2. Event system(イベントシステム)
12.3. Hibernate declarative security(Hibernateの宣言的なセキュリティ)

Chapter 12. Interceptors and events(12章:インターセプタイベント)
It is often useful for the application to react to certain events that occur inside Hibernate. This allows implementation of certain kinds of generic functionality, and extension of Hibernate functionality.
アプリケーションがHibernateの内部で発生するイベントに対応できると役に立つことがあります。ある種の一般的な機能を実装できるようになり、またHibernateの機能を拡張することもできるようになります。
12.1. Interceptors(インターセプタ)
The Interceptor interface provides callbacks from the session to the application allowing the application to inspect and/or manipulate properties of a persistent object before it is saved, updated, deleted or loaded. One possible use for this is to track auditing information. For example, the following Interceptor automatically sets thecreateTimestamp when an Auditable is created and updates the lastUpdateTimestampproperty when an Auditable is updated.
Interceptorインターフェイスを使って、セッションからアプリケーションへコールバックをすることができます。これにより永続オブジェクトの保存、更新、削除、読み込みの前に、アプリケーションがプロパティを検査したり操作したりできるようになります。これは監査情報の追跡に利用できます。下の例で Interceptor Auditableが作成されると自動的に createTimestampを設定し、Auditableが更新されると自動的にlastUpdateTimestampプロパティを更新します。
You may either implement Interceptor directly or (better) extend EmptyInterceptor.
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;
    }

}
Interceptors come in two flavors: Session-scoped and SessionFactory-scoped.
インターセプタには二種類あります:Sessionスコープのものと SessionFactoryスコープのものです。
Session-scoped interceptor is specified when a session is opened using one of the overloaded SessionFactory.openSession() methods accepting an Interceptor.
Sessionスコープのインターセプタは、セッションをオープンするときに指定します。Interceptorを引数に取るSessionFactory.openSession()のオーバーロードメソッドの一つを使います。
Session session = sf.openSession( new AuditInterceptor() );
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.
SessionFactoryスコープのインターセプタは Configurationオブジェクトを使って登録します。これは SessionFactoryの構築よりも優先されます。この場合、提供されるインターセプタは SessionFactoryからオープンされたすべてのセッションに適用されます。これは使用するインターセプタを明示的に指定してセッションをオープンしない限り、そうなります。SessionFactoryスコープのインターセプタはスレッドセーフでなければなりません。複数のセッションが(潜在的に)このインターセプタを同時並行で使用することになるため、セッション固有の状態を格納しないように気をつけてください。
new Configuration().setInterceptor( new AuditInterceptor() );
12.2. Event system(エベントシステム)
If you have to react to particular events in your persistence layer, you may also use the Hibernate3 event architecture. The event system can be used in addition or as a replacement for interceptors.
永続化層で特定のイベントに対応しなければならない場合、Hibernate3のイベントアーキテクチャを使うこともできます。イベントシステムはインターセプタと一緒に使うか、またはインターセプタの代わりとして使うことができます。
Essentially all of the methods of the Session interface correlate to an event. You have aLoadEvent, a FlushEvent, etc (consult the XML configuration-file DTD or theorg.hibernate.event package for the full list of defined event types). When a request is made of one of these methods, the Hibernate Session generates an appropriate event and passes it to the configured event listeners for that type. Out-of-the-box, these listeners implement the same processing in which those methods always resulted. However, you are free to implement a customization of one of the listener interfaces (i.e., the LoadEvent is processed by the registered implemenation of theLoadEventListener interface), in which case their implementation would be responsible for processing any load() requests made of the Session.
本質的に Sessionインターフェイスのすべてのメソッドは、1個のイベントと相互に関連します。例えば LoadEventFlushEventなどがあります(定義済みのイベント型の一覧については、XML設定ファイルのDTD org.hibernate.eventパッケージを調べてください)。リクエストがこれらのメソッドの1つから作られるとき、Hibernate Sessionは適切なイベントを生成し、そのイベント型に設定されたイベントリスナに渡します。すばらしいことに、これらのリスナはそのメソッドと同じ処理を実装します。とはいえ、リスナインターフェイスの一つを自由にカスタム実装できます(つまり、LoadEventは登録されたLoadEventListenerインターフェイスの実装により処理されます)。その場合、その実装には Sessionから作られたどのような load()リクエストをも処理する責任があります。
The listeners should be considered effectively singletons; meaning, they are shared between requests, and thus should not save any state as instance variables.
リスナは事実上シングルトンであると見なせます。つまりリスナはリクエスト間で共有されるため、インスタンス変数として状態を保持するべきではないということです。
A custom listener should implement the appropriate interface for the event it wants to process and/or extend one of the convenience base classes (or even the default event listeners used by Hibernate out-of-the-box as these are declared non-final for this purpose). Custom listeners can either be registered programmatically through theConfiguration object, or specified in the Hibernate configuration XML (declarative configuration through the properties file is not supported). Here's an example of a custom load event listener:
カスタムリスナは処理したいイベントについて適切なインターフェイスを実装するべきです。便利な基底クラスのうちの一つを継承してもよいです(またはHibernateがデフォルトで使用するイベントリスナを継承してもよいです。すばらしいことに、この目的のために非finalとして宣言されています)。カスタムリスナは Configurationオブジェクトを使ってプログラムから登録するか、HibernateXML設定ファイルで指定できます(プロパティファイルで宣言的に設定する方法はサポートされていません)。カスタムロードイベントリスナの例を示します。
public class MyLoadListener implements LoadEventListener {
    // this is the single method defined by the LoadEventListener interface
    public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
            throws HibernateException {
        if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
            throw MySecurityException("Unauthorized access");
        }
    }
}
You also need a configuration entry telling Hibernate to use the listener in addition to the default listener:
デフォルトリスナ以外のリスナを使うには、Hibernateへの設定も必要です:
<hibernate-configuration>
    <session-factory>
        ...
        <event type="load">
            <listener class="com.eg.MyLoadListener"/>
            <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
        </event>
    </session-factory>
</hibernate-configuration>
Instead, you may register it programmatically:
またその他に、プログラムで登録する方法もあります:
Configuration cfg = new Configuration();
LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
cfg.EventListeners().setLoadEventListeners(stack);
Listeners registered declaratively cannot share instances. If the same class name is used in multiple <listener/> elements, each reference will result in a separate instance of that class. If you need the capability to share listener instances between listener types you must use the programmatic registration approach.
リスナを宣言的に登録すると、そのリスナのインスタンスを共有できません。複数の要素で同じクラス名が使われると、それぞれの参照はそのクラスの別々のインスタンスを指すことになります。リスナ型の間でリスナインスタンスを共有する必要があれば、プログラムで登録する方法を採らなければなりません。
Why implement an interface and define the specific type during configuration? Well, a listener implementation could implement multiple event listener interfaces. Having the type additionally defined during registration makes it easier to turn custom listeners on or off during configuration.
なぜインターフェイスを実装して、特化した型を設定時に指定するのでしょうか?リスナの実装クラスに、複数のイベントリスナインターフェイスを実装できるからです。登録時に追加で型を指定することで、カスタムリスナのon/offを設定時に簡単に切り替えられます。
12.3. Hibernate declarative security(Hibernateの宣言的なセキュリティ)
Usually, declarative security in Hibernate applications is managed in a session facade layer. Now, Hibernate3 allows certain actions to be permissioned via JACC, and authorized via JAAS. This is optional functionality built on top of the event architecture.
一般的にHibernateアプリケーションの宣言的なセキュリティは、セッションファサード層で管理します。現在、Hiberenate3JACCで許可しかつ、JAASで認証したアクションを許しています。これはイベントアーキテクチャの最上位に組み込まれているオプションの機能です。
First, you must configure the appropriate event listeners, to enable the use of JAAS authorization.
まず最初に、適切なイベントリスナを設定してJAAS認証を使えるようにしなければなりません。
<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>
Note that <listener type="..." class="..."/> is just a shorthand for <event type="..."><listener class="..."/></event> when there is exactly one listener for a particular event type.
特定のイベント型に対してちょうど一つのリスナがあるとき、<listener type="..." class="..."/> <event type="..."><listener class="..."/></event>の簡略形に過ぎないことに注意してください。
Next, still in hibernate.cfg.xml, bind the permissions to roles:
次に、同じく hibernate.cfg.xmlでロールにパーミッションを与えてください:
<grant role="admin" entity-name="User" actions="insert,update,read"/>
<grant role="su" entity-name="User" actions="*"/>
The role names are the roles understood by your JACC provider.
このロール名は使用するJACCプロバイダに理解されるロールです。

No comments:

Post a Comment