2.3. Transactionサービス

本節ではTransactionサービスを使ったアプリケーションプログラムの作成の方法について説明します。アプリケーションプログラムの作成の説明には、作成の流れにそった説明と実装する機能ごとに分類した説明とがあります。新規にトランザクションを構築する場合は、作成の流れにそって読むことをお勧めします。Transactionサービス上のアプリケーションプログラムは、ORBを使ったアプリケーションプログラムと同じです。ORBを使ったプログラミングの詳細については、プログラミング・開発の「Object Broker」を参照してください。

2.3.1. アプリケーションプログラムを開発する前に

本節ではWebOTX Transactionサービス上のアプリケーションプログラムの作成において、必要となる概念の説明を行います。
2.3.1.1. WebOTX Transactionサービスのトランザクションモデル
WebOTX Transactionサービスは、CORBAトランザクションサービスにしたがって、トランザクションコンテキストを使ってトランザクションの制御・管理を行います。トランザクションコンテキストとは、トランザクションのさまざまな状態を管理する論理的な概念で、 Controlオブジェクトに対応します。
アプリケーションプログラムは、WebOTX Transactionサービスが提供するさまざまなインタフェースを利用してトランザクションコンテキストの状態の更新・参照を行い、トランザクションの動作の制御・管理を行います。
トランザクションコンテキストをアプリケーションが動作するスレッドに関連付けることで、アプリケーションはトランザクション内で動作します。トランザクションコンテキストとスレッドとの関連付けには次の方法があります。
表1.2.3.1-1
関連付けの方法 説明
間接的なコンテキスト管理 Currentオブジェクトや暗黙の伝播により、WebOTX Transactionサービスがトランザクションコンテキストをスレッドに関連付け、管理を行います(一般的にはこちらが利用されます)。
直接的なコンテキスト管理 アプリケーションが Controlオブジェクトとスレッドとの関連付け、管理を行います。
WebOTX Transactionサービスでは、WebOTX Transactionサービスを利用したトランザクションプログラムを次の3つのトランザクションモデルに分類しています。
表1.2.3.1-2
モデル 説明
間接的なコンテキスト管理: クライアントトランザクション クライアントプログラムが Currentオブジェクトの提供するインタフェースを使用してトランザクションの管理を行います。 したがって、クライアントプログラムはトランザクショナルクライアントとなります。 クライアントプログラムはトランザクショナルオブジェクトや、非トランザクショナルオブジェクトを呼び出してトランザクション処理を行います。 OTS1.2では、OTSPolicyにより振る舞いを決定します。 一般的には、サーバプログラムがデータベースを参照・更新するリカバラブルサーバとして動作します。 クライアントプログラム側にデータベースがあっても、サーバプログラム側にデータベースがなくてもかまいません。
間接的なコンテキスト管理: サーバトランザクション サーバプログラムが、Currentオブジェクトの提供するインタフェースを使用してトランザクションの管理を行います。 クライアントプログラムはトランザクションとは無関係な非トランザクショナルクライアントとなります。 このモデルでは、サーバプログラムはトランザクショナルクライアントとなるか、トランザクションとして通信を行わない単独のオブジェクトになります。 したがって、CORBAトランザクションサービスの概念としてはクライアントトランザクションと差はありませんが、サーバオブジェクトはマルチスレッドで動作するため、WebOTX Transactionサービスの管理は変わります。
直接的なコンテキスト管理 アプリケーションが Currentオブジェクトを利用しないで、直接 Controlオブジェクトを利用してトランザクションコンテキストの管理を行います。 この場合、WebOTX Transactionサービスはトランザクションコンテキストの伝播を支援しませんので、明示的な伝播が行われます。 そのため、クライアントプログラム・サーバプログラムの処理の分担はアプリケーションが自由に設定することができます。
2.3.1.2. OTSPolicyにもとづく振る舞い
CORBA の Object Transaction サービス 1.1 (OTS1.1)では、TransactionalObjectインタフェースの継承有無によりトランザクションコンテキストの伝播を行うか否かを決定していましたが、OTS1.2よりPOAのポリシーにOTSPolicyを設定することによりトランザクションの振る舞いを設定します。
このPOA上で動作するオブジェクトはこの影響を受けます。
OTSPolicy値とサーバ側でのトランザクションの振る舞いの関係は以下の表のとおりです。
表1.2.3.1-3
OTSPolicy Transaction有りで呼び出し Transaction無しで呼び出し
REQUIRES トランザクション内で動作 TRANSACTION_REQUIRED例外
FORBIDS INVALID_TRANSACTION例外 トランザクション無しで動作
ADAPTS トランザクション内で動作 トランザクション無しで動作
OTS1.1でのTransactionalObjectを継承したオブジェクトは、OTSPolicyをADAPTSとした場合に相当し、TransactionalObjectを継承しないオブジェクトはOTSPolicyに何も設定されず、この場合呼び出し時のTransactionの有無にかかわらずトランザクション無しで動作します。
2.3.1.3. スレッド処理方針とオブジェクト活性化方針
Object Brokerでは、アプリケーションの動作に関する処理方針を利用者が決定することができます。
WebOTX Transactionサービスを使ったアプリケーションの開発において、間接的なコンテキスト管理を使用する場合、スレッドをトランザクションコンテキストに関連付けます。そのため、Object Brokerの方針を利用できない場合があります。
次の表は、方針の利用の可否を示しています。

Java スレッド処理方針
表1.2.3.1-5
処理方針 サポート 説明
スレッドを使用する プログラマが作成した実装部分をマルチスレッドで実行します。
スレッドを使用しない プログラマが作成した実装部分は必ずシングルスレッドで処理されます。トランザクションに参加させるリソースを実装するResourceオブジェクトやトランザクション完了時のコールバックを実装するSynchronizationオブジェクトはマルチスレッドで処理するようにしてください。


オブジェクト処理方針
表1.2.3.1-6
処理方針 サポート 説明
スレッドを使用する 指定されたオブジェクトをマルチスレッドで処理します。スレッド処理方針がスレッドを使用する場合のみ有効です。
スレッドを使用しない 指定されたオブジェクトをシングルスレッドで処理します。スレッド処理方針がスレッドを使用する場合のみ有効です。トランザクションに参加させるリソースを実装するResourceオブジェクトやトランザクション完了時のコールバックを実装するSynchronizationオブジェクトはマルチスレッドで処理するようにしてください。



2.3.2. IDLファイルの作成

IDL言語を利用して、サーバアプリケーションが提供するインタフェースを定義します。IDL言語による定義により、C++で作成したサーバアプリケーションをJavaのクライアントから呼び出すなど、アプリケーションプログラムの実装言語を意識することなく通信を行うことができます。
本節では以降のアプリケーションプログラムの開発の説明において利用するIDL定義について記述します。IDLコンパイルの方法については、プログラミング・開発の「Object Broker」もしくは「WebOTX AS CORBAアプリケーション」を参照してください。
/* Test.idl */
 
module Test {
    interface interop {
        void write( in long a, in long b);
        long read( in long a);
    };
};


2.3.3. クライアントアプリケーションの開発(Java言語、JavaApplet)

本節では、CORBAトランザクションサービスを利用したJavaクライアントアプリケーションプログラムの開発手順について、Currentオブジェクトを使ってトランザクションを管理する、「間接的なコンテキスト管理」のケースについて説明します。「直接的なコンテキスト管理」のケースについては、 [リファレンス > API > WebOTXが提供するAPI > CORBA > Transactionサービス(Java)] を参照してください。
2.3.3.1. クライアントアプリケーションプログラムのメイン処理構成
クライアントアプリケーションプログラムのメイン処理部分には、次の処理を記述します。
ORBの初期化 ORBクラスの初期化メソッドinitを呼び出し、ORBを初期化します。
Java言語の場合
import org.omg.CORBA.*;

public static void main(String args[]) {
  try {
      // Initialize ORB.
      ORB orb = ORB.init(args, null);
  } catch (Exception e) {
    e.printStackTrace();
  }
  ……
}


JavaAppletの場合
  import org.omg.CORBA.*;
 
  ……
  try {
      // Initialize ORB.
      ORB orb = ORB.init(Applet, null);
  } catch (Exception e) {
      e.printStackTrace();
  }
  ……
}

サーバプログラムのオブジェクトリファレンスの取得 サーバアプリケーションプログラム側で生成した実装オブジェクトのリファレンスを取得します。
取得方法としては、(1)名前サービスに登録してあるものをresolveして取得する。(2)文字列化したリファレンスを、格納してあるファイルから取り出してstring_to_objectメソッドを使用して取得する。などが考えられます。ここでは(1)の方法を使用した場合について説明します。
  Test.interop sv;
  try {
    // 名前コンテキストの取得
    org.omg.CORBA.Object o =
        orb.resolve_initial_references("NameService");
    NamingContext ns = NamingContextHelper.narrow(o);
    // オブジェクトリファレンスの取得
    NameComponent nc = new NameComponent("test", "");
           NameComponent ncseq[] = {nc};
    sv = Test.interopHelper.narrow(ns.resolve(ncseq));
  } catch (Exception e) {
      e.printStackTrace();
  }
Currentオブジェクトの取得 Currentオブジェクトは、プロセスに1つだけ存在します。これによりトランザクションサービスが初期化され、以降Currentオブジェクトが提供するインタフェースを利用することでトランザクションの動作が可能になります。
Currentオブジェクトを入手するには、ORBクラスのresolve_initial_referencesメソッドを使用します。
  org.omg.CosTransactions.Current cur;
  try {
    cur = (Current)orb.resolve_initial_references("TransactionCurrent");
  } catch (Exception e) {
      e.printStackTrace();
  }
トランザクションの開始 トランザクションを開始します。Currentオブジェクトの beginメソッドをコールすることで、新規トランザクションが生成されます。トランザクションが既に開始されている場合にトランザクションを開始すると、サブトランザクションが生成されます。
  try {
    cur.begin();
  } catch (Exception e) {
      e.printStackTrace();
  }
サーバプログラムの呼び出し 「サーバプログラムのオブジェクトリファレンスの取得」で取得したリファレンスを使用してサーバプログラムの呼び出しを実施します。メソッドは、IDLで定義されたインタフェースをもとにします。
トランザクションコンテキストは、暗黙的にサーバプログラムに伝播されます。
  try {
      sv.write(a, b);
  } catch (Exception e) {
      e.printStackTrace();
  }
トランザクションの終了 トランザクション処理が終わったら、トランザクションを終了します。Currentオブジェクトの commitメソッドまたは rollbackメソッドをコールすることでトランザクションは終了します。コミットまたはロールバックが完了すると、トランザクションは破棄されます。サブトランザクションが終了した場合、そのサブトランザクションを開始する前のトランザクション(親トランザクション)が再開されます。commitの引数には、2フェーズコミットの完了を待ち合わせるか、待ち合せないかを指定します。
次のトランザクションを開始する場合には、再びCurrentオブジェクトの beginメソッドを呼び出します。
  try {
      cur.commit(true);
  } catch (Exception e) {
      e.printStackTrace();
  }
 
または
 
  try {
      cur.rollback();
  } catch (Exception e) {
      e.printStackTrace();
  }
2.3.3.2. クライアントアプリケーションプログラムのコンパイルとリンク
アプリケーションプログラムのコンパイルを実行するclasspathに以下のクラスが設定されていることを確認してください。
2.3.3.3. クライアントアプリケーションプログラムの実行
クライアントアプリケーションプログラム実行時にはコンパイル時のクラスパスに加え以下を設定してください。
実行時のプロパティとして以下を追加してください。
   プロパティ名:
org.omg.CORBA.ORBInitRef
   値:
TransactionCurrent=ospiref:jp.co.nec.WebOTX_S.OTXSCur.CurrentFactory
作成したアプリケーションプログラムを実行する前に次のことを確認してください。
クライアントアプリケーションでトランザクションを開始するためには、トランザクションを管理するサーバである、Proxy RCSとObject Brokerがあらかじめ動作している必要があります。
動作していない場合は、運用管理ツール、あるいは運用管理コマンドを利用して起動します。

2.3.3.4. その他のトランザクション機能
ここまでの説明で簡単な間接的なコンテキスト管理のプログラムを作成することが可能です。本節では、間接的なコンテキスト管理のその他機能について説明します。
rollback_only(ロールバックのマーク) トランザクション中に障害があったとき、トランザクション生成者はロールバックを行えば良いですが、トランザクション生成者でないとロールバックを発行できません。このような場合にトランザクションが最終的には必ずロールバックされるように設定することができます。トランザクションがロールバックするように設定するには、Currentインタフェースの rollback_onlyメソッドをコールします。
  try {
      cur.rollback_only();
  } catch (Exception e) {
      e.printStackTrace();
  }
get_status(トランザクション状態の取得) トランザクションの状態を取得するには、Currentインタフェースの get_statusメソッドをコールします。
  CosTransactions.Status status;
  try {
      status = cur.get_status();
  } catch (Exception e) {
      e.printStackTrace();
  }
get_transaction_name(トランザクション識別名の取得) トランザクションを識別するための文字列を取得するには、Currentインタフェースの get_transaction_nameメソッドをコールします。
  String txname;
  try {
      txname = cur.get_transaction_name();
  } catch (Exception e) {
      e.printStackTrace();
  }
set_timeout(トランザクションタイムアウト時間の設定) トランザクションのタイムアウト時間を設定するには、Currentインタフェースの set_timeoutメソッドをコールします。トランザクションの処理が無限ループに入ってしまった場合でも、このインタフェースを利用することで、指定秒数経過後にロールバック処理が自動的に実行されトランザクション処理が戻ります。
set_timeoutはトランザクションを開始するbeginメソッドの前にコールします。
  try {
      cur.set_timeout(30);
  } catch (Exception e) {
      e.printStackTrace();
  }
get_timeout(トランザクションタイムアウト時間の取得) トランザクションのタイムアウト時間を取得するには、Currentインタフェースの get_timeoutメソッドをコールします。
  int timeout;
  try {
      timeout = cur.get_timeout();
  } catch (Exception e) {
      e.printStackTrace();
  }
get_control(Controlオブジェクトの取得) Controlオブジェクトを取得するには、Currentインタフェースの get_controlメソッドをコールします。 Controlオブジェクトを使用して明示的なトランザクション処理を行う場合に使います。
Controlオブジェクトの機能については、直接的なコンテキスト管理または [リファレンス > API > WebOTXが提供するAPI > CORBA > Transactionサービス(Java)] を参照してください。
  org.omg.CosTransactions.Control control;
  try {
      control = cur.get_control();
  } catch (Exception e) {
      e.printStackTrace();
  }
suspend(トランザクションのサスペンド) Currentオブジェクトは、トランザクションをアプリケーション内で動作しているスレッドと対応させて管理しています。そのスレッドからトランザクションコンテキストを切り離す場合には、Currentインタフェースの suspendメソッドをコールします。 resumeまたはトランザクションを新たに開始するまで、スレッドはトランザクションと関連を持ちません。
  org.omg.CosTransactions.Control control;
  try {
      cur.suspend();
  } catch (Exception e) {
      e.printStackTrace();
  }
resume(トランザクションのレジューム) 指定された Controlオブジェクトが示すトランザクションをスレッドに関連付けるには、Currentインタフェースの resumeメソッドをコールします。suspendしたトランザクションを再開する場合や、直接的なコンテキスト管理で入手したトランザクションを間接的なコンテキスト管理で利用する場合に使います。
  try {
      cur.resume(control);
  } catch (Exception e) {
      e.printStackTrace();
  }


2.3.4. サーバアプリケーションの開発(Java言語)

本節では、CORBAトランザクションサービスを利用したJavaサーバアプリケーションプログラムの開発手順について、「間接的なコンテキスト管理」を利用するケースについて説明します。「直接的なコンテキスト管理」のケースについては、 [リファレンス > API > WebOTXが提供するAPI > CORBA > Transactionサービス(Java)] を参照してください。
間接的なコンテキスト管理では、Currentオブジェクトを使ってトランザクションを管理します。
サーバアプリケーションはWebOTX上で動作させることになるため、IDLファイルの作成やアプリケーションのビルド、WebOTXへの登録などは一般的なWebOTX上のアプリケーションの開発を行う際と同じです。この詳細に関しては、プログラミング・開発の「WebOTX AS CORBAアプリケーション」を参照してください。
なお、WebOTX CORBAアプリケーションでTransactionサービスを利用する場合には運用管理ツールでの設定が必要となります。詳細については、ドメイン構築・基本設定ガイドを参照してください。
以下では、間接的なコンテキスト管理に必要なCurrentオブジェクトのサーバアプリケーションでの取得方法について説明します。
取得したCurrentオブジェクトの利用方法については「クライアントアプリケーションの開発(Java言語、JavaApplet)」で説明したものと同じですのでそちらを参照してください。
またクライアントアプリケーション作成時に流れで説明したORBの初期化についてはWebOTXのアプリケーション起動時に自動的に実行されます。
2.3.4.1. Currentの取得
Currentオブジェクトを取得するためにはまずORBオブジェクトを取得する必要があります。ORBオブジェクトはWoServerWrapper.TPSGetORB()により取得します。Currentオブジェクトは、ORBクラスのresolve_initial_referencesメソッドを使用して取得します。
org.omg.CORBA.ORB orb;
org.omg.CosTransactions.Current cur;
try {
  orb = jp.co.nec.WebOTX.orbsvwpr.WoServerWrapper.TPSGetORB();
  cur = (Current)orb.resolve_initial_references("TransactionCurrent");
} catch (Exception e) {
    e.printStackTrace();
}