IBM Connections Event SPI 概要

IBM Connections のバージョン 3.0 から新たに登場した、データ変更のイベントをトラッキングするための Java SPI である「Event SPI」について

IBM Connections (旧 IBM Lotus Connections) は 2007年の登場以来、企業向けソーシャル・ソフトウェアとして数々の機能拡張がなされてきました。その中でも"企業向け"という観点から特に重要となる機能の 1つが、監査やコンプライアンス対応のための機能です。この監査やコンプライアンスの要求に柔軟に対応するために、「Event SPI」と呼ばれるコンテンツの作成、更新、削除といったデータ変更のイベントをトラッキングするための Java SPI (System Programming Interface) がバージョン 3.0 から登場しました。本稿ではこの Event SPI の概要と、実際に Event SPI を使ってイベント・ハンドラーを開発、デプロイする手順について具体例を交えながら紹介します。

小野 充志, Lotus テクノロジー開発, IM & Lotus 開発/ソフトウェア開発研究所, IBM

小野 充志は、日本アイ・ビー・エム ソフトウェア開発研究所の Lotus テクノロジー開発に所属するソフトウェア・エンジニアです。



2012年 1月 13日

はじめに

IBM Connections (旧 IBM Lotus Connections) は、企業向けソーシャル・ソフトウェアとして 2007年に登場しました。当初提供していたコンポーネントは「プロフィール」「ブログ」「ブックマーク (旧ドッグイア)」「コミュニティー」「アクティビティー」の 5つでしたが、その後バージョンアップごとに新たなコンポーネントが追加され、現在では「ホームページ」「ファイル」「Wiki」「フォーラム」を加えた 9つのコンポーネントから構成されています。さらに各コンポーネントについても数々の拡張がなされており、プロフィール内でステータスを投稿したり各ユーザーのボード上でメッセージをやり取りしたりする「マイクロ・ブロギング」機能、「ソーシャル・アナリティクス」によるおすすめ機能、コミュニティー内で画像や動画などのメディアを共有する「メディア・ギャラリー」機能、アイデアを共有し投票や意見交換する「アイデア・ブログ」機能など、バージョンを重ねるごとに便利な新機能が追加され、進化し続けています (図 1)。各機能の詳細については製品紹介のページを参照してください。

図 1. IBM Connections の機能の変遷
IBM Connections の機能の変遷

このような機能の充実によりユーザーの利用が促進され、さらに多くの重要なコンテンツがやり取りされるようになると、監査やコンプライアンス対応のための機能が企業にとってますます重要となってきます。IBM Connections のバージョン 3.0 では、こうしたコンプライアンスの要求に対応するために以下のような機能強化がなされています。

  • イベント・トラッキング: コンプライアンス対応を考える上で、ユーザーが行った操作に関するログ収集の機能は欠かすことができません。ログ収集を柔軟に行えるようにするためにバージョン 3.0 から登場したのが、「Event SPI」と呼ばれるコンテンツの作成、更新、削除といったデータ変更のイベントをトラッキングするための Java SPI (System Programming Interface) です。この Event SPI を使うことで、各企業の要求に合わせて自由にログ収集のモジュールを開発できるようになりました。
  • アクセス制御 (ACL): コンテンツへのアクセス制御を適切に行うことは、コンプライアンスの観点からみても非常に重要です。アクセス制御の機能自体は従来から提供されており、コミュニティー、アクティビティー、ファイルなどの各コンポーネント内で設定可能でしたが、バージョン 3.0 ではプロフィールのタイプによるアクセス権の設定や、コミュニティーを新規作成できる作成者権限などの設定が可能になり、より柔軟にアクセス権を設定することができるようになりました。
  • モデレーション: モデレーション機能により、ブログなどに投稿されたコンテンツを管理者がチェックして健全な状態に保つことも、コンプライアンス対応につながります。ブログのモデレーション機能は以前のバージョンから提供されていましたが、バージョン 3.0 で UI が刷新され多くの機能が追加されました。さらに、新しくモデレーションのための REST API も提供され、ブログだけでなくフォーラムやファイルについても API を使ってモデレーションすることが可能になりました。

本稿では 1つ目にあげたイベント・トラッキングの機能である Event SPI にフォーカスし、実際に Event SPI を使ってモジュールを開発、デプロイする手順について具体例を交えながら紹介していきます。


Event SPI 概要

Event SPI は IBM Connections のバージョン 3.0 から登場したイベント・トラッキングのための Java SPI です。Event SPI を使ってイベント・ハンドラーを実装することにより、IBM Connections 上で発生する様々なイベントをトラッキングすることが可能です。コンプライアンス対応を主な目的として登場した機能で、イベントのログをデータベースなどに記録し、監査レポートの作成などを行うというのが典型的な利用例です。これ以外にも、イベントのログからソーシャル分析を行ったり、イベント発生時に他のシステムにイベント情報を送信して連携を行ったりといったさまざまな用途に利用可能です。

トラッキング可能なイベント

IBM Connections 上で行われる処理には、イベントが発生する処理と発生しない処理があります (表 1)。コンプライアンス対応の要求に応えるため、データの変更を伴う処理についてはすべてのコンポーネントにおいて必ずイベントが発生するようになっています。これには、コンテンツの作成、更新、削除、プリファレンスの変更といったユーザーによる操作だけでなく、ユーザーのライフサイクル管理などの管理者による操作、モデレーターによるモデレーションの処理、さらにはアクティビティーの自動完了処理などのシステムによる自動処理もすべて含まれます。また、IBM Connections が提供している Web UI からの操作だけでなく、REST API を使った変更操作についてもイベントが発生します。これらのイベントはすべて Event SPI によってトラッキング可能です。

逆に、データの変更を伴わない閲覧だけの操作についてはイベントが発生しません。これには、コンテンツの閲覧操作だけでなく、検索処理やファイルのダウンロード処理、REST API による GET 処理なども含まれます。また、IBM Connections の構成ファイルの変更や、WebSphere Application Server (以下 WAS) や OS などのプラットフォーム・レベルでのシステム設定変更についてもイベントは発生しません。このようなイベントの発生しない処理については Event SPI でトラッキングすることはできません。

表 1. IBM Connections 上でイベントが発生する処理と発生しない処理
イベントが発生する処理
  • ユーザーによるコンテンツの作成、更新、削除操作すべて (API による更新操作も含む)
  • ユーザーによるプリファレンスやパーソナライズの設定
  • 管理者による変更処理 (例:アカウント無効化などのユーザーライフサイクル管理)
  • コンテンツのモデレーション処理
  • データ変更を伴うようなシステムによる自動処理 (例:アクティビティーの自動完了処理)
イベントが発生しない処理
  • コンテンツの閲覧操作すべて (検索、ファイルのダウンロード、API による閲覧操作も含む)
  • IBM Connections の構成ファイルの設定変更 (例: LotusConnections-config.xml の変更)
  • WAS や OS のシステム設定変更

アーキテクチャー

Event SPI のアーキテクチャーは図 2 のようになっています。データ変更処理によって発生したイベントはすべて IBM Connections が内部的に持っているキュー (図の「WAS JMS キュー」) に入るようになっており、それらを Java SPI を介してトラッキングできるようになっています。この Event SPI は、コンプライアンス対応のためのログ管理モジュールや監査レポート作成ツールなどを作成できるように開発者向けに提供されているものですが、実は IBM Connections の内部でも利用されています。例えば、図 2 にもあるように「River of News」と呼ばれるホームページ上の更新通知機能がこの Event SPI を利用して実装されています。また、モデレーション機能の実装にもこの Event SPI が利用されています。

図 2. Event SPI のアーキテクチャー
Event SPI のアーキテクチャー

イベントとイベント・ハンドラー

イベント・ハンドラーのタイプ

イベントをトラッキングするには、発生したイベントのデータを受け取るイベント・ハンドラーを Event SPI を使って実装する必要があります。このイベント・ハンドラーには以下の 2つのタイプがあります (図 3、表 2)。

  • プレイベント・ハンドラー (Pre-event hander) : イベント処理が実際に実行される前に呼び出されるイベント・ハンドラーです。イベント処理が実行される前に呼び出されるため、受け取ったイベントのデータの一部を変更したりすることが可能です。ただし、このプレイベント・ハンドラーはすべてのイベントで利用できるわけではなく、ブログなどのモデレーションに関するイベントのみに利用が限定されています。プレイベント・ハンドラーの呼び出しは同期呼び出しであるため、イベント・ハンドラー内の処理の速度がユーザーへのレスポンス・タイムに直接影響します。そのため、同期呼び出しのイベント・ハンドラーでは重い処理を行わないようにする必要があります。
  • ポストイベント・ハンドラー (Post-event handler) : イベント処理が実際に実行され、データがコミットされた後に呼び出されるイベント・ハンドラーです。処理が完了した後であるため、イベントのデータは読み取り専用で、変更することはできません。呼び出しはデプロイ時の構成ファイルの設定により、同期呼び出しか非同期呼び出しかを選択することができます。非同期呼び出しはすべてのイベントに対して有効ですが、同期呼び出しはプレイベント・ハンドラーと同様、ブログなどのモデレーションに関するイベントのみに利用が限定されています。そのため、コンプライアンス対応などですべてのイベントのトラッキングを行いたい場合は、非同期呼び出しのポストイベント・ハンドラーを使用します。
図 3. プレイベント・ハンドラーとポストイベント・ハンドラー
プレイベント・ハンドラーとポストイベント・ハンドラー
表 2. イベント・ハンドラーのタイプとその特徴
 プレイベント・ハンドラー (Pre-event hander)ポストイベント・ハンドラー (Post-event hander)
呼び出されるタイミング処理が実際に実行される前処理が実際に実行され、データがコミットされた後
イベントのデータ一部を変更可能読み取り専用。変更不可。
利用可能なイベントブログなどのモデレーションに関するイベントでのみ利用可能すべてのイベントで利用可能
同期/非同期同期のみ同期、非同期を選択可能
実装するインターフェースcom.ibm.connections.spi.events.
PreEventHandler
com.ibm.connections.spi.events.
EventHandler
継承する抽象クラス (オプション)com.ibm.connections.spi.events.
AbstractPreEventHandler
com.ibm.connections.spi.events.
AbstractEventHandler
handleEvent メソッドで受け取る
イベント・オブジェクトのクラス
com.ibm.connections.spi.events.
object.mutable.MutableEvent
com.ibm.connections.spi.events.
object.Event

この 2つのタイプのイベント・ハンドラーでは実装する Java インターフェースがそれぞれ異なります。まず、プレイベント・ハンドラーの場合は com.ibm.connections.spi.events.PreEventHandler インターフェースを実装します。このインターフェースの実装クラスは以下の 3つのメソッドを実装する必要があります。

  • public void init() throws com.ibm.connections.spi.events.EventHandlerInitException
    初期化処理を行うメソッド。インスタンスの初期化の際に 1回だけ呼び出されます (ただし、複数インスタンス作成される可能性があるため、その場合はインスタンスごとに 1回ずつ呼び出されます)。初期化が失敗した際には EventHandlerInitException をスローするようにします。
  • public void destroy()
    終了処理を行うメソッド。インスタンスの破棄の際に 1回だけ呼び出されます (ただし、複数インスタンスが作成された場合は、インスタンスごとに 1回ずつ呼び出されます)。
  • public void handleEvent(com.ibm.connections.spi.events.object.mutable.MutableEvent event) throws com.ibm.connections.spi.events.EventHandlerException
    イベントが発生する際に呼び出されるメソッド。このメソッドはイベントが発生する度に呼び出されるので、複数回呼び出されます。マルチ・スレッドで呼び出される可能性もあるので、イベント・ハンドラーのクラスはスレッド・セーフである必要があります。引数で受け取るのは、イベントのデータが格納された MutableEvent オブジェクトです。”Mutable”という言葉からも分かるように、このオブジェクトが持つイベントのデータは一部変更が可能です。エラーが発生した場合は、 EventHandlerException をスローするようにします。

一方、ポストイベント・ハンドラーの場合は com.ibm.connections.spi.events.EventHandler インターフェースを実装します。このインターフェースの実装クラスでも invoke、destroy、handleEvent の 3つのメソッドを実装する必要がありますが、handleEvent の引数がプレイベント・ハンドラーの場合と異なります。

  • public void handleEvent(com.ibm.connections.spi.events.object.Event event) throws com.ibm.connections.spi.events.EventHandlerException
    基本的にプレイベント・ハンドラーの handleEvent と同様ですが、引数で受け取るオブジェクトが MutableEvent オブジェクトではなく、Event オブジェクトになっています。この Event オブジェクトのデータはすべて読み取り専用で、変更することができません。

もし初期化処理と終了処理が不要な場合には、init メソッドと destroy メソッドのデフォルト実装が提供されている抽象クラスをアダプターとして用いることもできます。プレイベント・ハンドラーの場合は com.ibm.connections.spi.events.AbstractPreEventHandler 抽象クラス、ポストイベント・ハンドラーの場合は com.ibm.connections.spi.events.AbstractEventHandler 抽象クラスを継承することで、handleEvent メソッドのみを実装することでイベント・ハンドラーを作成することができます。

イベントのデータ

イベント・ハンドラーの handleEvent メソッドで受け取ることができる MutableEvent オブジェクトおよび Event オブジェクトには、表 3 に挙げたようなデータが格納されています。それぞれ getter メソッドでデータのオブジェクトを取得することが可能です。詳細は Event SPI の JavaDoc を参照してください。

表 3. イベント・オブジェクト内に格納されているデータの詳細
コア・データ (すべてのイベントに共通)
データ名詳細
IDイベント ID
Nameイベント名
(例: blog.created、blog.entry.created など)
Scopeイベントのスコープ
(例: PUBLIC、PRIVATE、COMMUNITY など)
Sourceイベントの発生元となるコンポーネント
(例: ACTIVITIES、BLOGS、BOOKMARKS など)
Timestampイベント発生時刻
Typeイベントのタイプ
(例: CREATE、UPDATE、DELETE など)
その他のデータ (イベントによって取得できるものとできないものがある)
データ名詳細
Actorこのイベントの元となる処理を実行したユーザーの情報
(表示名、メールアドレスなど)
AttachmentData添付ファイルの情報
Containerイベントが関連しているコンテナーの情報
(例:ブログのエントリーやコメントを投稿した場合は、それらのコンテナーとなっているブログの情報)
ContentDataコンテンツの情報
* MutableEvent の場合はコンテンツの中身の変更やタグの追加、削除などの変更処理が可能
CorrelationDataイベントの関連情報
(例:ブログのコメントを投稿した場合は、そのコメントが投稿されたブログ・エントリーの情報)
FlaggedContentDataフラグがつけられたコンテンツの情報
(例:ブログのエントリーなどが問題のあるアイテムとしてフラグがつけられた場合に、そのフラグの数やカテゴリーの情報)
ItemDataこのイベントに関するアイテムの情報
(例:ブログのエントリーを投稿した場合は、そのブログ・エントリー自身の ID、タイトル、URL、Atom URL などの情報)
* MutableEvent の場合はタイトルを変更可能
MembershipData変更があったメンバーやグループの情報
ModerationDataモデレーションの情報
(例:モデレーションのステートやコメントなどの情報)
* MutableEvent の場合はステートやコメントを変更可能
ScopeDataスコープの情報
(例:スコープが PRIVATE だった場合、設定されているユーザーやグループの ACL の情報)
TargettingDataこのイベントの元となる処理のターゲットとなっているユーザーもしくはグループの情報
(例:ブログのコメントが投稿された際は、そのブログのエントリーを投稿したユーザー)

各コンポーネントから発生するイベントにおいて具体的にどのようなイベントのデータが取得できるかについては、イベントの種類が約 400 にも及ぶためここでは説明を省略しますが、IBM Connections Wiki のイベント・リファレンスのページにコンポーネント毎に詳細がまとめられていますのでそちらを参照してください。


Event SPI を使ったイベント・ハンドラーの開発手順

ここからは実際に Event SPI を使ってイベント・ハンドラーを開発する手順を紹介します。ここではプリイベント・ハンドラーとポストイベント・ハンドラーをそれぞれ実装してみます。なお、IBM Connections Wiki にも Programming an event handler というイベント・ハンドラー開発手順の紹介記事が掲載されていますのでそちらも合わせて参照してください。

開発環境

Event SPI のモジュール開発環境は Java のライブラリー開発ができる環境であれば特に指定はありません。本稿では Eclipse 3.7.1 を使用して開発手順を紹介します。開発に使用する JRE (Java Runtime Environment) のバージョンについては、IBM Connections の前提環境である WAS 7 で JRE1.6 が使用されているため、これに合わせて JRE1.6 を使用します。

Event SPI のライブラリーのインポート

Event SPI のモジュールを開発するには、Event SPI のライブラリーである「lc.events.spi.jar」という JAR ファイルを開発環境にインポートする必要があります。この lc.events.spi.jar は、すでにデプロイ済みの IBM Connections の各コンポーネントのデプロイ先のフォルダに含まれています。どのコンポーネントにも同じ JAR ファイルが含まれているため、どのコンポーネントからコピーしてきても構いません。例えばブログの場合には、<WAS の profiles フォルダ>\<アプリケーションサーバー名>\installedApps\<セル名>\Blogs.earフォルダの中に lc.events.spi.jar が含まれているので、これを開発環境にコピーします (図 4)。

図 4. ブログのデプロイ先フォルダから lc.events.spi.jar をコピー
ブログのデプロイ先フォルダから lc.events.spi.jar をコピー

続いて、Eclipse のワークスペースで新規 Java プロジェクトを作成し、開発環境にコピーした lc.events.spi.jar ファイルをインポートします。ここでは図 5 のように lib というフォルダを作成して、その中にインポートします。

図 5. lc.events.spi.jar を Java プロジェクトにインポート
lc.events.spi.jar を Java プロジェクトにインポート

インポートした lc.events.spi.jar をプロジェクトのビルド・パスに追加します。まず Java プロジェクトを右クリックして「Properties」メニューを選択し、プロパティー・ダイアログを表示します。左側のナビゲーターから「Java Build Path」を選択し、右側のタブから「Libraries」を選択します。「Add JARs」ボタンをクリックして、lib フォルダの lc.events.spi.jar を選択すると、ビルド・パスに lc.events.spi.jar が追加されます (図 6)。

図 6. lc.events.spi.jar を Java プロジェクトのビルド・パスに追加
lc.events.spi.jar を Java プロジェクトのビルド・パスに追加

ワークスペースに戻り、Java プロジェクトの「Referenced Libraries」に lc.events.spi.jar が追加されていれば設定完了です (図 7)。

図 7. Java プロジェクトの Referenced Libraries に追加された lc.events.spi.jar
Java プロジェクトの Referenced Libraries に追加された lc.events.spi.jar

プリイベント・ハンドラーの実装

次に、プリイベント・ハンドラーを実装します。ここでは、プリイベント・ハンドラーでイベントのデータの変更ができることを確認するために、ブログでエントリーが作成された際のイベントに対して、入力されたコンテンツの中に含まれる特定の文字列を置換するようなプリイベント・ハンドラーを実装してみます。

まず、Java プロジェクトを右クリックして「New」>「Class」を選択し、プリイベント・ハンドラーのクラスを作成します。このプリイベント・ハンドラーは特に初期化処理や終了処理を行わないので、PreEventHandler インターフェースを直接実装するのではなく、プリイベント・ハンドラー用の抽象クラスである AbstractPreEventHandler クラスを継承するようにします (図 8)。

図 8. AbstractPreEventHandler を継承してプリイベント・ハンドラーのクラスを作成
AbstractPreEventHandler を継承してプリイベント・ハンドラーのクラスを作成

次に handleEvent メソッドをリスト 1 のように実装します。リスト 1 ではまず、引数として受け取った MutableEvent オブジェクトのコア・データの情報を、java.util.logging.Logger クラスを使用して WAS の標準ログ・ファイル (SystemOut.log) にログ出力しています。さらに、ブログのエントリー作成イベントの際 (イベントの名前が「blog.entry.created」である場合) には、MutableEvent オブジェクトの中の MutableContentData オブジェクトからコンテンツの情報を取得し、コンテンツの中に「IBM Lotus Connections 3.0.1」という文字列があったら「IBM Connections 3.0.1」に置換し、置換後のコンテンツを MutableContentData オブジェクトにセットしなおすことでイベント・データの変更を行っています。

リスト 1. プリイベント・ハンドラーの実装例
package com.ibm.lotus.connections.events.spi.sample;

import java.util.logging.Logger;
import com.ibm.connections.spi.events.AbstractPreEventHandler;
import com.ibm.connections.spi.events.EventHandlerException;
import com.ibm.connections.spi.events.object.mutable.MutableContentData;
import com.ibm.connections.spi.events.object.mutable.MutableEvent;

public class SamplePreEventHandler extends AbstractPreEventHandler {
    private static final String loggerName = SamplePreEventHandler.class.getName();
    private static final Logger logger = Logger.getLogger(loggerName);
    
    @Override
    public void handleEvent(MutableEvent event) throws EventHandlerException {
        // WASの標準ログ・ファイルにMutableEventオブジェクトのコア・データ情報をログ出力
        logger.info("ID: " + event.getID());
        logger.info("Source: " + event.getSource().getName());
        logger.info("Type: " + event.getType());
        logger.info("Name: " + event.getName());
        logger.info("Scope: " + event.getScope().name());
        logger.info("Timestamp: " + event.getTimestamp());        
        
        // ブログのエントリー作成イベントの場合、コンテンツの中の特定の文字列を置換
        if ("blog.entry.created".equals(event.getName())) {
            MutableContentData contentData = event.getContentData();
            String content = contentData.getContent();
            if (content.contains("IBM Lotus Connections 3.0.1")) {
                contentData.setContent(
                    content.replaceAll("IBM Lotus Connections 3.0.1", 
                                        "IBM Connections 3.0.1"), 
                    contentData.getContentType());
            }
        }
    }
}

ポストイベント・ハンドラーの実装

次にポストイベント・ハンドラーを実装します。ポストイベント・ハンドラーはすべてのイベントをトラッキングすることができるので、ここでは、WAS の標準ログ・ファイル以外の独自のイベント・ログ専用ファイルにもログ出力するようなポストイベント・ハンドラーを実装してみます。

先ほどと同様、Java プロジェクトを右クリックして「New」>「Class」を選択し、ポストイベント・ハンドラーのクラスを作成します。このポストイベント・ハンドラーは、独自ログ・ファイルへの出力をするための初期化処理および修了処理を行うので、AbstractEventHandler 抽象クラスは使用せず、ポストイベント・ハンドラー用のインターフェースである EventHandler インターフェースを実装するようにします (図 9)。

図 9. EventHandler インターフェースを実装するポストイベント・ハンドラーのクラスを作成
EventHandler インターフェースを実装するポストイベント・ハンドラーのクラスを作成

次に、リスト 2 にあるようにポストイベント・ハンドラーを実装します。まず、独自ログ・ファイルのファイル名を外部から「logFileName」というプロパティ値として設定できるようにするために、「getLogFileName」「setLogFileName」という getter/setter メソッドをこのイベント・ハンドラー・クラスに追加します。このプロパティ値は、デプロイ時に構成ファイルで設定することが可能です。このイベント・ハンドラーがロードされた際に、構成ファイルで設定されたプロパティ値がこの getter/setter を通じてシステムにより自動的にセットされるようになっています。なお、この構成ファイルによるプロパティ値設定の仕組みは、ポストイベント・ハンドラーだけでなくプレイベント・ハンドラーでも利用可能です。

この logFileName プロパティによって指定されたファイルに対してログ出力するように、init メソッドの中で初期化処理を行います。ここでは、先ほどプリイベント・ハンドラーでも使用した java.util.logging.Logger のインスタンスに対して、logFileName で指定されたファイルにログを出力するような新しい FileHandler を追加することで、WAS の標準ログ・ファイルへの出力に加えて独自ログ・ファイルへの出力も行うようにしています。このログの仕組みのカスタマイズについては、WAS の Information Center にあるサンプルを参照してください。

この init メソッドでの実装に合わせて、destroy メソッドでは終了処理として、追加した FileHandler を除去してクローズしています。最後に handleEvent メソッドにおいて、java.util.logging.Logger を使ってログを出力することで、WAS の標準ログ・ファイルと独自ログ・ファイルへの出力を同時に行っています。

リスト 2. ポストイベント・ハンドラーの実装例
package com.ibm.lotus.connections.events.spi.sample;

import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import com.ibm.connections.spi.events.EventHandler;
import com.ibm.connections.spi.events.EventHandlerException;
import com.ibm.connections.spi.events.EventHandlerInitException;
import com.ibm.connections.spi.events.object.Event;

public class SampleEventHandler implements EventHandler {
    
    private static final String loggerName = SampleEventHandler.class.getName();
    private static final Logger logger = Logger.getLogger(loggerName);
    
    private String _logFileName;
    private FileHandler _handler;
    
    // 構成ファイルからlogFileNameというプロパティ値を受け取るためのgetterとsetter
    public String getLogFileName() {
        return _logFileName;
    }
    public void setLogFileName(String logFileName) {
        _logFileName = logFileName;
    }
    
    @Override
    public void init() throws EventHandlerInitException {
        if (_logFileName != null) {
            // logFileNameが設定されていたらそのファイルにログ出力するように初期化
            try {
                _handler = new FileHandler(_logFileName, true);
                _handler.setFormatter(new SimpleFormatter());
                logger.addHandler(_handler);
            } catch (Exception e) {
                new EventHandlerInitException(e);
            }
        }
    }
    
    @Override
    public void destroy() {
        if (_handler != null) {
            // 初期化時に追加したFileHandlerを削除してクローズ
            logger.removeHandler(_handler);
            _handler.close();
            _handler = null;
        }
    }
    
    @Override
    public void handleEvent(Event event) throws EventHandlerException {
        // WASの標準ログ・ファイルとlogFileNameで指定された独自ログ・ファイルに同時にログ出力
        logger.info("ID: " + event.getID());
        logger.info("Source: " + event.getSource().getName());
        logger.info("Type: " + event.getType());
        logger.info("Name: " + event.getName());
        logger.info("Scope: " + event.getScope().name());
        logger.info("Timestamp: " + event.getTimestamp());        
    }
}

イベント・ハンドラーの JAR ファイル形式でのエクスポート

イベント・ハンドラーの実装が完了したら JAR ファイル形式でエクスポートします。ワークスペースで Java プロジェクトを右クリックして「Export」メニューを選択し、「Java」>「JAR file」を選択します。図 10 のような「JAR Export」ダイアログ・ボックスが表示されたら、プロジェクトのリソースの中から src フォルダの部分だけを選択し、それ以外のチェックを外します。「Export generated class files and resources」にチェックが付いていることを確認し、出力先と JAR ファイル名を指定して「Finish」ボタンをクリックすればエクスポート完了です。ここでは sampleEventHandler.jar という名前で JAR ファイルをエクスポートします。

図 10. イベント・ハンドラーの実装クラスを JAR ファイル形式でエクスポート
イベント・ハンドラーの実装クラスを JAR ファイル形式でエクスポート

以上でイベント・ハンドラーの開発は完了です。


イベント・ハンドラーのデプロイ手順

続いて、このイベント・ハンドラーのモジュールをデプロイして実際に動作確認するまでの手順を紹介します。なお、IBM Connections Wiki にも Deploying an event handler というイベント・ハンドラーのデプロイ手順の紹介記事が掲載されていますのでそちらも合わせて参照してください。

イベント・ハンドラーの JAR ファイルのコピー

まずは作成したイベント・ハンドラーの JAR ファイルを、IBM Connections がインストールされているサーバー上にコピーします。コピーする場所については、IBM Connections がデプロイされている WAS のすべてのノードから参照できる場所であれば特に指定はありません。ここでは Windows サーバーを例として、IBM Connections のインストール時に「共有コンテンツ・ストア」のフォルダとして指定した「C:\IBM\Connections\data\shared」フォルダに「eventHandlers」サブフォルダを作成し、その中に先ほど作成したイベント・ハンドラーの sampleEventHandler.jar をコピーします。共有コンテンツ・ストアの中にモジュールを含めておくことで他のコンテンツとあわせた管理がしやすくなります。

共用ライブラリーの登録

次に、コピーしたイベント・ハンドラーの JAR ファイルを IBM Connections がインストールされている WAS に共用ライブラリーとして登録します。ここで、IBM Connections のサーバーとして Windows サーバーを使用している場合は、JAR ファイルのパスに、共用ライブラリーのクラスパス登録時に使用できない文字である「:」 (コロン)が含まれてしまうため、まずこの JAR ファイルのパスを WebSphere 変数として登録し、その変数を使用して共用ライブラリーを登録する必要があります。ここではこの WebSphere 変数の登録も含めた手順を紹介します。

登録は WAS の Deployment Manager の管理コンソールから行います。管理コンソールにログインしたら、左側のナビゲーターから「環境」>「WebSphere 変数」を選択し、右側のペインで有効範囲が「セル」になっていることを確認して「新規作成」ボタンをクリックします。新規作成画面が表示されたら、名前を例えば「EVENT_SPI_DIR」とし、値には、先ほど JAR ファイルをコピーしたフォルダのパスである「C:\IBM\Connections\data\shared\eventHandlers」を入力します (図 11)。入力が完了したら「OK」ボタンを押して、右側のペイン上部に表示される「保管」リンクをクリックして設定を保存すれば WebSphere 変数の登録完了です。

図 11. WebSphere 変数の登録
WebSphere 変数の登録

続いて、左側のナビゲーターから「環境」>「共用ライブラリー」を選択し、右側のペインで有効範囲が「セル」になっていることを確認して「新規作成」ボタンをクリックします。新規作成画面が表示されたら、名前を例えば「SampleEventHandler」とし、クラスパスには、イベント・ハンドラーの JAR ファイルのパスを先ほど登録した WebSphere 変数を使用して「${EVENT_SPI_DIR}/sampleEventHandler.jar」と入力します (図 12)。先に述べたように、このクラスパスの指定には「:」 (コロン) の文字が使えません。最後に一番下のクラス・ロードの「この共用ライブラリーでの分離されたクラス・ローダーの使用」にチェックが付いていないことを確認します。ここにチェックがついていると、イベント・ハンドラーのクラスが IBM Connections のコンポーネントと別のクラス・ローダーでロードされるため、ClassNotFoundException が発生してしまうので注意してください。ここまで入力が完了したら「OK」ボタンを押して、右側のペイン上部に表示される「保管」リンクをクリックして設定を保存すれば共用ライブラリーの登録完了です。

図 12. 共用ライブラリーの登録
共用ライブラリーの登録

アプリケーションからの共用ライブラリーの参照設定

次に、登録した共用ライブラリーを各コンポーネントのアプリケーションから参照できるようにします。どのアプリケーションに参照設定をするかは、イベント・ハンドラーのタイプによって以下のように決まります。

  • プレイベント・ハンドラーもしくは同期処理のポストイベント・ハンドラーの場合: イベントをトラッキングしたいコンポーネントのアプリケーション (Activities、Blogs、Communities、Dogear、Files、Forums、Homepage、News、Profiles、Wikis) に参照設定します。例えばブログのイベントをトラッキングしたい場合は Blogs アプリケーションに参照設定をし、さらにアクティビティーのイベントもトラッキングしたい場合は Activities アプリケーションにも参照設定する必要があります。
  • 非同期処理のポストイベント・ハンドラーの場合: どのコンポーネントのイベントをトラッキングしたいかに関わらず、News アプリケーションのみに参照設定します。すべてイベントをトラッキングしたい場合でも、News アプリケーションに参照設定をするだけで有効になります。

ここでは、プレイベント・ハンドラーはブログのイベントのみ、ポストイベント・ハンドラーはすべてのイベントをトラッキングしたいので、Blogs アプリケーションと News アプリケーションに共用ライブラリーの参照設定をします。

再び WAS の Deployment Manager の管理コンソールにログインし、左側のナビゲーションから「アプリケーション」>「アプリケーション・タイプ」>「WebSphere エンタープライズ・アプリケーション」を選択し、右側に表示されたエンタープライズ・アプリケーションの一覧から「Blogs」を選択します。Blogs アプリケーションの設定画面が表示されたら、「参照」>「共用ライブラリー参照」をクリックします (図 13)。

図 13. Blogs アプリケーションの共用ライブラリー参照設定画面へのリンク
Blogs アプリケーションの共用ライブラリー参照設定画面へのリンク

共用ライブラリー参照設定画面が表示されたら、アプリケーションのリストにある「Blogs」にチェックを付けて「参照共用ライブラリー」ボタンをクリックします (図 14)。マッピング画面が表示されたら、「使用可能」にリストされている先ほど作成した共用ライブラリーである「SampleEventHandler」を選択し、右矢印ボタンをクリックして「選択済み」のリストに移動します。移動が完了したら「OK」をクリックします。共用ライブラリー参照設定画面に戻り、「Blogs」の共用ライブラリーに「SampleEventHandler」が表示されていることを確認して「OK」をクリックし、遷移後の画面で右側のペイン上部に表示される「保管」リンクをクリックして設定を保存すれば Blogs アプリケーションの共用ライブラリーの参照設定完了です。

図 14. Blogs アプリケーションの共用ライブラリー参照設定
Blogs アプリケーションの共用ライブラリー参照設定

続けて、同様の手順で News アプリケーションにも共用ライブラリー参照設定を行い (図 15)、設定を保管してください。

図 15. News アプリケーションの共用ライブラリー参照設定
News アプリケーションの共用ライブラリー参照設定

Java 2 セキュリティー設定の確認

引き続き Deployment Manager の管理コンソールで、左側のナビゲーターから「セキュリティー」>「グローバル・セキュリティー」を選択します。右側のペインの「Java 2 セキュリティー」のセクションで、「Java 2 セキュリティーを使用してアプリケーションのアクセスをローカル・リソースに制限する」にチェックがついているかどうかを確認します (図 16)。

図 16. Java 2 セキュリティー設定の確認
Java 2 セキュリティー設定の確認

チェックがついている場合には、共用ライブラリーからのログ・ファイルの読み書きや java.util.logging のコントロールがデフォルトで許可されていないため、このままイベント・ハンドラーの処理を実行すると SecurityException が発生します。もし WAS 全体で Java 2 セキュリティーが不要であれば、このチェックを外して設定を保存してください。もし Java 2 セキュリティーを有効にしておく必要がある場合は、共用ライブラリーに対していくつかのパーミッションを設定する必要があります。共用ライブラリーの Java 2 セキュリティー・ポリシーの設定は、<WAS の profiles フォルダ>\<Deployment Manager 名>\config\cells\<セル名>\nodes\<ノード名> フォルダにある「library.policy」という policy ファイルで行います。詳細は WAS7 の Information Center にある library.policy に関する説明を参照してください。例えば本稿のサンプルでは、リスト 3 のようにパーミッションを設定することで動作するようになります。

リスト 3. library.policy による共用ライブラリーへのパーミッションの設定
grant {
  permission java.util.logging.LoggingPermission "control";
  permission java.util.PropertyPermission "*", "read";
  permission java.io.FilePermission "C:${/}Temp${/}-", "read, write";
};

構成ファイルの設定

最後に IBM Connections の構成ファイルの設定を変更します。通常 IBM Connections の構成ファイルの設定変更の際には、wsadmin コマンドで構成ファイルをチェックアウトして変更を行うのが一般的ですが、Event SPI に関する構成ファイルについては wsadmin コマンドでのチェックアウトに現時点ではまだ対応していないため、デプロイされている構成ファイルを直接編集する必要があります。そのため、必ず編集前に構成ファイルをバックアップしておくようにしてください。

Event SPI の構成ファイルは、<WAS の profiles フォルダ>\<Deployment Manager 名>\config\cells\<セル名>\LotusConnections-config フォルダにある events-config.xml という XML ファイルです。バックアップをとった後エディタで開き、<preHandlers> という要素の中に、リスト 4 のように <preHandler> という要素を使って、実装したプレイベント・ハンドラーに関する設定を追加します。各要素とその属性については表 4 を参照してください。ここではブログのイベントのみをトラッキングするように登録しています。

リスト 4. 構成ファイルによるプレイベント・ハンドラーの設定
<preHandlers>
    <!-- 中略 -->
    <preHandler enabled="true" name="SamplePreEventHandler"
            class="com.ibm.lotus.connections.events.spi.sample.SamplePreEventHandler">
        <subscriptions>
            <subscription source="BLOGS" type="*" eventName="*"/>
        </subscriptions>
    </preHandler>
</preHandlers>
表 4. 構成ファイル内の preHandler 要素、subscription 要素の属性
preHandler 要素
属性詳細
nameイベント・ハンドラーの名前 (クラス名と同じでなくても構いません)
classイベント・ハンドラーのクラス
enabledイベント・ハンドラーが有効かどうかを示すフラグ。True のときにのみ動作する。
subscriptions / subscription 要素 (以下の 3つの属性ともに「*」 (ワイルドカード) も指定可能。複数指定したい場合には別の subscription 要素として追加。)
属性詳細
sourceトラッキングしたいイベントのソースとなるコンポーネント
例: ACTIVITIES, BLOGS, BOOKMARKS, COMMUNITIES, FILES, FORUMS, HOMEPAGE, MOBILE, NEWS, PROFILES, SEARCH, WIKIS
typeトラッキングしたいイベントのタイプ
例: ACKCOM, APPROVE, AUDIT, COMMAND, CREATE, DELETE, DISMISS, FLAG, INACTIVE_UPDATE, MEMBERSHIP, MODERATE, NOTIFY, QUARANTINE, PEND, PRECREATE, READ, REJECT, RESTORE, RETURN, UPDATE
eventNameトラッキングしたいイベントの名前。各イベントの名前については、IBM Connections Wiki のイベント・リファレンスのページを参照。

同様に、<postHandlers> という要素の中に、リスト 5 のように <postHandler> という要素を使って、実装したポストイベント・ハンドラーの設定を追加します。各要素とその属性については表 4 および表 5 を参照してください。ここでは、ポストイベント・ハンドラーを非同期呼び出しにしたいので、invoke=”ASYNC” という属性を指定します。また、独自ログ・ファイルの名前を <property> という要素を使って logFileName プロパティ値として設定しています。ターゲットとするイベントはすべてのイベントです。

リスト 5. 構成ファイルによるポストイベント・ハンドラーの設定
<postHandlers>
    <!-- 中略 -->
    <postHandler enabled="true" invoke="ASYNC" name="SampleEventHandler" 
            class="com.ibm.lotus.connections.events.spi.sample.SampleEventHandler">
        <subscriptions>
            <subscription source="*" type="*" eventName="*"/>
        </subscriptions>
        <properties>
            <property name="logFileName">C:/Temp/test.log</property>
        </properties>
    </postHandler>
</postHandlers>
表 5. 構成ファイル内の postHandler 要素、property 要素の属性
postHandler 要素 (name, class, enabled 属性は preHandler と共通なので省略)
属性詳細
invoke同期呼び出しか非同期呼び出しかの設定。
ASYNC: 非同期呼び出し、SYNC: 同期呼び出し
properties / property 要素
属性詳細
nameプロパティ名。イベント・ハンドラーのクラスにこの名前の getter/setter があればそれを通じてこのプロパティの値が設定される。

以上で、イベント・ハンドラーのデプロイおよび設定はすべて完了です。ここまで完了したら、Deployment Manager における設定内容をすべてのノードに対して同期します。再度 Deployment Manager の管理コンソールを開き、左側のナビゲーターから「システム管理」>「ノード」を選択し、それぞれのノードを選択して「完全な再同期」をクリックして同期させます (図 17)。同期が完了したら WAS を再起動すればデプロイ完了です。

図 17. ノードの完全な再同期
ノードの完全な再同期

動作の確認

デプロイが完了したので動作確認をしてみます。IBM Connections のブログにアクセスし、コンテンツに「IBM Lotus Connections 3.0.1」という文字列を含むようなブログのエントリーを新規作成してみます。すると、実際に保存されたコンテンツでは「IBM Connections 3.0.1」に文字列が置換されていることを確認できます (図 18)。

図 18. プリイベント・ハンドラーによるイベントのデータ変更の動作確認例
プリイベント・ハンドラーによるイベントのデータ変更の動作確認例

また、WAS の標準ログ出力ファイルである SystemOut.log を確認すると、リスト 6 のようにプリイベント・ハンドラーとポストイベント・ハンドラーによるブログ・エントリー作成イベントのログ出力を確認することができます。

リスト 6. WAS の標準ログ・ファイルに出力されたイベント・ハンドラーのログの例
[11/12/11 23:29:19:592 JST] 00000076 SamplePreEven I   ID: ed8e9f56-25d4-4501-910c-a6...
[11/12/11 23:29:19:608 JST] 00000076 SamplePreEven I   Source: BLOGS
[11/12/11 23:29:19:608 JST] 00000076 SamplePreEven I   Type: CREATE
[11/12/11 23:29:19:608 JST] 00000076 SamplePreEven I   Name: blog.entry.created
[11/12/11 23:29:19:608 JST] 00000076 SamplePreEven I   Scope: PUBLIC
[11/12/11 23:29:19:623 JST] 00000076 SamplePreEven I   Timestamp: 1323628159561
[11/12/11 23:29:20:217 JST] 00000032 SampleEventHa I   ID: 4a9fb521-8854-4cec-a724-f6...
[11/12/11 23:29:20:233 JST] 00000032 SampleEventHa I   Source: BLOGS
[11/12/11 23:29:20:233 JST] 00000032 SampleEventHa I   Type: CREATE
[11/12/11 23:29:20:233 JST] 00000032 SampleEventHa I   Name: blog.entry.created
[11/12/11 23:29:20:233 JST] 00000032 SampleEventHa I   Scope: PUBLIC
[11/12/11 23:29:20:248 JST] 00000032 SampleEventHa I   Timestamp: 1323628160155

さらに、ポストイベント・ハンドラーがログを出力している独自ログ・ファイルを確認すると、リスト 7 のようにブログ・エントリー作成イベントのログ出力を確認することができます。

リスト 7. 独自のログ・ファイルに出力されたポストイベント・ハンドラーのログの例
2011/12/11 23:29:20 null null
INFO: ID: 4a9fb521-8854-4cec-a724-f672d90adbb6
2011/12/11 23:29:20 null null
INFO: Source: BLOGS
2011/12/11 23:29:20 null null
INFO: Type: CREATE
2011/12/11 23:29:20 null null
INFO: Name: blog.entry.created
2011/12/11 23:29:20 null null
INFO: Scope: PUBLIC
2011/12/11 23:29:20 null null
INFO: Timestamp: 1323628160155

まとめ

本稿では、IBM Connections のバージョン 3.0 から登場した Event SPI の概要と、実際に Event SPI を使ってイベント・ハンドラーを開発、デプロイする手順について紹介しました。Event SPI を利用することで、IBM Connections 上におけるデータ変更に関するすべてのイベントをトラッキングすることが可能です。本稿では簡単なログ出力のサンプルを紹介しましたが、本格的にコンプライアンス対応を行う際などには、データベースでログ管理を行うことで詳細な監査レポートを作成することができます。他にもさまざまな用途に利用可能で、例えば収集したイベントのログを元にソーシャル分析を行ったり、イベント発生時に他のソーシャル・サービスにリアルタイムに情報を送って連携したり、といったソーシャル・ビジネス的なシナリオでも今後ますます重要な役割を果たすことが期待できます。この機会に是非 Event SPI を試してみていただければと思います。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Lotus
ArticleID=782875
ArticleTitle=IBM Connections Event SPI 概要
publish-date=01132012