26 トリガーを使用したマップ操作の制御

マップ・トリガーを使用して、変更がマップ・エントリにコミットされる前に、マップ操作の検証、拒否または変更を行うことができます。

この章の構成は、次のとおりです。

マップ・トリガーの概要

マップ・トリガーは、Coherenceの標準機能を補助するもので、高度にカスタマイズされたキャッシュ管理システムを提供します。たとえば、マップ・トリガーを使用すると、無効なトランザクションを回避したり、複雑なセキュリティ認証または複雑なビジネス・ルールを施行することができます。また、透過的なイベント・ロギングや監査、データ変更の統計収集を行えます。トリガーのその他の用途には、キャッシュに対する操作を、アプリケーションの再デプロイメント時に発行されたものに制限することなどが挙げられます。

たとえば、NamedCacheの処理コードがあり、あるエントリの動作やコンテンツを、そのエントリがマップに挿入される前に変更するとします。マップ・トリガーを追加すると、既存のコードをすべて変更せずに、この変更を行うことができます。

マップ・トリガーは、アップグレード・プロセスの一環としても使用できます。マップ・トリガーを追加すると、挿入したエントリをキャッシュからキャッシュへ転用できます。

Coherenceキャッシュのマップ・トリガーは、データベースに適用されるトリガーに類似しています。これは、対応するマップ・エントリの保留中の変更(または削除)に応じて機能するMapTriggerインタフェースで表される機能エージェントです。保留中の変更は、MapTrigger.Entryインタフェースで表されます。このインタフェースは、InvocableMap.Entryインタフェースから継承され、基礎となるマップの値を取得、更新および削除するためのメソッドを提供します。

MapTriggerインタフェースには、マップ内の保留中の変更を検証、却下または変更する際に使用するprocessメソッドが備わっています。このメソッドは、基礎となるマップ・コンテンツの変更操作がコミットされる前にコールされます。このメソッドを実装すると、元の値と新しい値を分析することによって保留中の変更を評価し、次のいずれかの結果を得ることができます。

  • リクエストされた変更を別の値でオーバーライドします。

  • 元の値をリセットすることによって保留中の変更を元に戻します。

  • 基礎となるマップからエントリを削除します。

  • ランタイム例外をスローすることで保留中の変更を却下します。

  • 何もせずに、保留中の変更のコミットを許可します。

MapTrigger機能は通常、アプリケーション起動プロセスの一環として追加されます。MapTrigger APIで説明しているようにプログラムで追加できるほか、coherence-cache-config.xml構成ファイルでclass-factoryメカニズムを使用して構成することもできます。この場合、MapTriggerは、対応するキャッシュの最初のCacheFactory.getCache(...)コール時に登録されます。次の例は、createMapTriggerメソッドが新しいMapTriggerListener(new MyCustomTrigger());を返すことを前提としています。

<distributed-scheme>
   ...
   <listener>
      <class-scheme>
         <class-factory-name>package.MyFactory</class-factory-name>
         <method-name>createTriggerListener</method-name>
         <init-params>
            <init-param>
               <param-type>string</param-type>
               <param-value>{cache-name}</param-value>
            </init-param>
         </init-params>
      </class-scheme>
   </listener>
</distributed-scheme>

Coherenceには、MapTrigger.EntryインタフェースとMapTriggerインタフェースの他に、FilterTriggerクラスとMapTriggerListenerクラスが用意されています。FilterTriggerは、汎用のMapTrigger実装であり、関連付けられているFilterによって保留中の変更が却下された場合に、事前定義された処理を実行します。FilterTriggerは、保留中の操作を却下するか、変更を無視してエントリの元の値をリストアするか、またはエントリ自体を基礎となるマップから削除します。

MapTriggerListenerは、特別な目的に使用するMapListener実装であり、MapTriggerを対応するNamedCacheに登録する際に使用します。次の例では、PersonMapTriggerPeople名前付きキャッシュに登録します。

NamedCache person = CacheFactory.getCache("People");
MapTrigger trigger = new PersonMapTrigger();
person.addMapListener(new MapTriggerListener(trigger));

これらのAPIはcom.tangosol.utilパッケージ内にあります。

マップ・トリガーの例

基本的な例に従って、マップ・トリガーの使用方法を学習します。例26-1のコードは、マップ・トリガーとそのコール方法を示しています。

PersonMapTriggerクラスでは、processメソッドを実装して、マップに配置する前のエントリが変更されています。この場合、Personオブジェクトの姓の属性が大文字に変換されます。その後、オブジェクトはエントリに返されます。

例26-1 MapTriggerクラス

...

public class PersonMapTrigger implements MapTrigger 
    {
    public PersonMapTrigger()
        {
        }

    public void process(MapTrigger.Entry entry)
        {
        Person person  = (Person) entry.getValue();
        String sName   = person.getLastName();
        String sNameUC = sName.toUpperCase();
        
        if (!sNameUC.equals(sName))
           { 
           person.setLastName(sNameUC);
        
           System.out.println("Changed last name of [" + sName + "] to [" + person.getLastName() + "]");
        
           entry.setValue(person);
           }
        }

    // ---- hashCode() and equals() must be implemented

    public boolean equals(Object o)
        {
        return o != null && o.getClass() == this.getClass();
        }
    public int hashCode()
        {
        return getClass().getName().hashCode();
        }
    }

例26-2MapTriggerは、PersonMapTriggerをコールします。新しいMapTriggerListenerは、PersonMapTriggerPeople NamedCacheに渡します。

例26-2 MapTriggerコールと名前付きキャッシュへの引渡し

...

public class MyFactory
    {
    /**
    * Instantiate a MapTriggerListener for a given NamedCache
    */
    public static MapTriggerListener createTriggerListener(String sCacheName)
        {
        MapTrigger trigger;
        if ("People".equals(sCacheName))
            {
            trigger = new PersonMapTrigger();
            }
        else
            {
            throw IllegalArgumentException("Unknown cache name " + sCacheName);
            }

        System.out.println("Creating MapTrigger for cache " + sCacheName);

        return new MapTriggerListener(trigger);
        }

    public static void main(String[] args) 
        {
        NamedCache cache = CacheFactory.getCache("People");
        cache.addMapListener(createTriggerListener("People"));

        System.out.println("Installed MapTrigger into cache People");
        }
    }