WebSphere Liberty 用のダミー・リソース・マネージャー

WebSphere Liberty 21.0.0.9 から利用可能になったトランザクションのピア・リカバリーに関して、以下の記事で紹介・検証しました。
これらの記事では、ダミー・リソース・マネージャー(ダミーRM)を使って２フェーズ・コミット(2 phase commit, 以下、2pc)を中断させ、WebSphere Liberty （が稼働するノード）をダウンさせることで、トランザクションのピア・リカバリーの動作を検証しました。

* [WebSphere Liberty でトランザクションのピア・リカバリーを試してみる(3/1)](https://qiita.com/splendormy/items/d1d6d76de43e32a7d553)
* [WebSphere Liberty でトランザクションのピア・リカバリーを試してみる(3/2)](https://qiita.com/splendormy/items/e74dd478faba00c8c715)
* [WebSphere Liberty でトランザクションのピア・リカバリーを試してみる(3/3)](https://qiita.com/splendormy/items/ddf41b9cadd8f95359c9)

今回は、上記の記事で使用したダミー RM に関して説明します。
ダミー RM のソースは、github で公開しています。

* [github: dummy-resource-manager](https://github.com/splendormy/dummy-resource-manager/tree/main/src/dummyrm)

# 実装（ソースの説明）

上記の記事で使用したダミー RM 用のダミー・リソースは、特定のメソッド内でスリープ(処理を中断)するだけなので、簡単に実装できます。

## ユーティリティー・クラス DummyXAUtil

ダミー・リソースをトランザクションに登録する処理から説明した方が見通しが良さそうなので、このクラスから始めます。

このユーティリティー・クラスの enlist メソッドをトランザクション内で呼び出すことで、指定した名前のダミー・リソースがトランザクションに登録(enlist)されます。
enlist メソッドの処理概要とソース抜粋は以下の通りです。（ソースの詳細は [github](https://github.com/splendormy/dummy-resource-manager/blob/main/src/dummyrm/DummyXAUtil.java) を参照。）

1. ダミー・リソース(後述の DummyXAResource クラスのインスタンス)を作る。
1. WebSphere Liberty の ExtendedTransactionManager を取得する。
1. ExtendedTransactionManager にリソース情報を登録する。登録に必要な情報は以下の２つ。
    1. ダミー・リソースのファクトリー・クラス(後述の XAResourceFactory クラス)の名前
    1. ダミー・リソース情報(後述の DummyXAResourceInfo のオブジェクト)
1. トランザクションにダミー・リソースを登録(enlist)する。

```java
	/**
	 * 
	 * @param name The name of Dummy XA Resource.
	 * @param sleepPosition Sleep Position of created Dummy XA Resource.
	 * @param sleepDuration Sleep Duration of created Dummy XA Resource.
	 * @return DummyXAResource
	 */
	public static DummyXAResource enlist( String name,
			                              DummyXAResource.SleepPosition sleepPosition,
			                              int sleepDuration ) throws RollbackException, SystemException {
		// Create DummyXAResource
		DummyXAResource res = new DummyXAResource( name );
		res.setSleepPosition( sleepPosition );
		res.setSleepDuration( sleepDuration );
		// Get ExtendedTransactionManager
		ExtendedTransactionManager etm = TransactionManagerFactory.getTransactionManager();
		// Register DummyXAResourceInfo to ExtendedTransactionManager
		int id = etm.registerResourceInfo( DummyXAResourceFactory.class.getName(), res.getInfo() );
		// Enlist DummyXAResource.
		etm.enlist( res, id );
		return res;
	}
```

この処理の中に現れた、３つのクラス（下記参照）を実装すれば良いわけです。
* ダミー・リソース DummyXAResource
* ダミー・リソース情報 DummyXAResourceInfo
* ダミー・リソースのファクトリー DummyXAResourceFactory

enlist メソッドでは、WebSphere Liberty の TransactionManagerFactory と ExtendedTransactionManager を使って、ダミー・リソースをトランザクションに組み込んでいます。JavaEE 仕様に沿った方法ではありませんが、これらは WebSphere Liberty の公開されている API なので支障はないはずです。この方法を使うことで、大幅に実装が楽になります。

参照：[TransactionManagerFactory の JavaDoc](https://www.ibm.com/docs/en/was-liberty/base?topic=SSEQTP_liberty/com.ibm.websphere.javadoc.liberty.doc/com.ibm.websphere.appserver.api.transaction_1.1-javadoc/com/ibm/tx/jta/TransactionManagerFactory.html)
参照：[ExtendedTransactionManager の JavaDoc](https://www.ibm.com/docs/en/was-liberty/base?topic=SSEQTP_liberty/com.ibm.websphere.javadoc.liberty.doc/com.ibm.websphere.appserver.api.transaction_1.1-javadoc/com/ibm/tx/jta/ExtendedTransactionManager.html)

## ダミー・リソース DummyXAResource

WebSphere Liberty に 2pc のリソースとして登録されるオブジェクト用のクラスで、ダミー RM の中核となるクラスです。

JavaEE の仕様に従って、javax.transaction.xa.XAResource インターフェースを実施することになります。2pc の各段階に合わせて、トランザクション・マネージャーである WebSphere Liberty から該当のメソッドが呼び出されます。
実装する内容は、[javax.transaction.xa.XAResource の JavaDoc](https://docs.oracle.com/javase/8/docs/api/javax/transaction/xa/XAResource.html) に記載されている通りですが、大方のメソッドでは条件に応じてスリープするだけで、残りのメソッドに関しても、実装は容易です。（ソースは [github](https://github.com/splendormy/dummy-resource-manager/blob/main/src/dummyrm/DummyXAResource.java) を参照）

* commit, end, forget, prepare, rollback, start メソッド
    * 条件に応じてスリープする。
* recover メソッド
    * RM が認識しているプリペア済みのトランザクションのリストを返すメソッドですが、ダミー RM では空のリストを返すだけの空の処理にしています。
* isSameRM メソッド
    * 自分がパラメーターで渡された RM と同じかチェックするメソッドです。クラスの比較と、ダミー・リソース情報の比較でチェックできます。
* getTransactionTimeout/setTransactionTimeout  メソッド
    * 名前の通り、トランザクションのタイムアウトを設定/取得するメソッドで、保持している値をget/setするだけです。

XAResource インターフェースで定義されていないメソッドとして、DummyXAResourceInfo のオブジェクトを返す getInfo メソッドがありますが、こちらに関しては後述の通りです。その他にもメソッドがありますが、スリープする場所(メソッド)やスリープする長さを設定するものです。

以上のように、DummyXAResource の実装は非常に簡単に済みます。

## ダミー・リソース情報 DummyXAResourceInfo
このクラスは、ダミー・リソースの情報を保持するためのもので、ダミー・リソースのファクトリーがダミー・リソースを作成する時に使用されます。また、ダミー・リソースの isSameRM メソッドで、リソースが同じものであるかをチェックするためにも利用されます。

このクラスのオブジェクトは、WebSphere Liberty のトランザクション・ログのパートナー・ログに書き込まれます。WebSphere Liberty がダウンし、再起動またはピア・リカバリーでトランザクションのリカバリーが実行されるときに、パートナー・ログから復元され、更に、ファクトリーを利用してリソースが復元されます。
パートナー・ログに保存されるので、このクラスは Serializable を実装する必要があります。

ダミー・リソース情報の実装では、ダミー・リソースの名前だけを保持するようになっています。スリープする場所(メソッド)やスリープする長さは保持していませんので、リカバリー後はこれらの情報が失われ、スリープ設定は無効になります。

ソースは [github](https://github.com/splendormy/dummy-resource-manager/blob/main/src/dummyrm/DummyXAResourceInfo.java) を参照。

## ダミー・リソースのファクトリー DummyXAResourceFactory
このクラスは、渡されたダミー・リソース情報からダミー・リソースを作成したり、渡されたダミー・リソースを破棄するクラスです。尚、破棄では何も行う必要がありません。

ソースは [github](https://github.com/splendormy/dummy-resource-manager/blob/main/src/dummyrm/DummyXAResourceFactory.java) を参照。

# パッケージング
ダミー RM は、フィーチャーとして WebSphere Liberty に組み込みます。詳細は省略しますが、フィーチャーとして組み込むために次の２つファイルが必要になります。

* jar ファイルの `META-INF/MANIFEST.MF` ファイル
    * フィーチャーは通常の jar ファイルと同様にパッケージングできますが、jar ファイル内に格納する `META-INF/MANIFEST.MF` ファイルには OSGi 固有の指定が必要となります。
    * 内容は [github](https://github.com/splendormy/dummy-resource-manager/blob/main/BundleContent/META-INF/MANIFEST.MF) を参照。
    * パッケージング済みの jar ファイルは [こちら](https://github.com/splendormy/dummy-resource-manager/blob/main/dummy-resource-manager.jar) からダウンロードできます。
* フィーチャー用のマニフェスト・ファイル `dummy-resource-manager.mf`
    * フィーチャーの情報を記述したファイルです。
    * 内容は [github](https://github.com/splendormy/dummy-resource-manager/blob/main/dummy-resource-manager.mf) を参照。

# インストール
ダミー RM は、ユーザー・フィーチャーとして簡単に WebSphere Liberty に組み込むことができます。

まず、パッケージングした jar ファイル `dummy-resource-manager.jar` とフィーチャー用のマニフェスト・ファイル `dummy-resource-manager.mf` を所定のディレクトリーに配置します。ディレクトリーが存在しない場合は、ディレクトリーを作成してください。

|ファイル名|配置先ディレクトリー|
|:---|:---|
|dummy-resource-manager.jar|\<wlp_root\>/**usr**/extension/lib/|
|dummy-resource-manager.mf|\<wlp_root\>/**usr**/extension/lib/features/|

次に、server.xml でユーザー・フィーチャーとしてロードするように指定すれば、ダミー RM が利用可能な状態になります。

```:server.xml
<featureManager>
    <feature>usr:dummy-resource-manager</feature>
</featureManager>
```

# 終わりに
ダミー RM をご紹介しましたが、内容が分かってしまえば、極簡単なものであることご理解いただけたのではないでしょうか。
ダミー RM の使い方に関しても、ご紹介する予定です。