Oracle Joltクラス・ライブラリは、Oracle Tuxedoサービスにアクセスするための、開発者向けのオブジェクト指向のJava言語クラス・セットです。クラス・ライブラリには、Jolt APIを実装するクラス・ファイルがあります。これらのクラスを使うと、アプリケーションを拡張してインターネットやイントラネットでトランザクション処理ができるようになります。Joltクラス・ライブラリを使用して、JavaアプレットからOracle Tuxedoサービスへのアクセスをカスタマイズすることもできます。
以降の項の情報を活用するには、Java言語によるプログラミングおよびオブジェクト指向プログラミングに関する全般的な知識が必要です。この章で取り上げるプログラムの例はすべてJavaコードで記述されています。
注意: | プログラムの例では、Joltの機能を示す部分を抜粋して示しています。そのままコンパイルしたり、実行しないでください。これらのプログラム例を実際に実行するには、コードを追加する必要があります。 |
Joltクラス・ライブラリには、クライアント側のアプリケーションやアプレット(独立したJavaアプリケーションとして実行するか、またはJava対応のWebブラウザで実行)を開発するためのOracle Tuxedoアプリケーション開発者向けのツールが用意されています。bea.jolt
パッケージにはJoltクラス・ライブラリが用意されています。Joltクラス・ライブラリを使用するには、クライアント・プログラムやアプレットでこのパッケージをインポートする必要があります。bea.jolt
パッケージをインポートする方法については、「Joltのファンド転送の例(SimXfer.java)」を参照してください。
ブラウザで実行するJavaプログラムは「アプレット」と呼ばれます。アプレットとは、アプリケーションの一部として特定の機能を実行し、簡単にダウンロードできるサイズの小さいプログラムのことです。多くのブラウザでは、高度なセキュリティを実現するため、Javaアプレットの機能に制限が設けられています。以下は、アプレットに対するいくつかの制限です。
Javaアプレットの制限には、大抵の場合プログラミング上の対応策があります。ブラウザでサポートされるアプレットの機能またはアプレットの制限については、お使いのブラウザのWebサイト(www.netscape.com、www.microsoft.comなど)や開発者用ドキュメントを参照してください。また、Joltリレーを使うと、ネットワーク接続に関するいくつかの制限を回避することができます。
一方、Javaアプリケーションはブラウザ上では実行されず、上記のような制限を受けることはありません。たとえば、Javaアプリケーションは、実行中のホスト・マシン上で別のアプリケーションを起動できます。アプレットがユーザー・インタフェースとしてブラウザやappletviewerのウィンドウ環境に依存するのに対し、Javaアプリケーションでは独自のユーザー・インタフェースを作成する必要があります。アプレットは、コンパクトで移植性が高くなるように設計されています。一方、Javaアプリケーションは、他のJava以外のプログラムのように機能性を高くできます。JavaアプリケーションとJavaアプレットの最大の違いは、アプレットに対して設けられているブラウザでのセキュリティの制限およびプログラムの適応範囲です。
Joltクラス・ライブラリは、JoltインタープリタのエラーおよびOracle Tuxedoのエラーを例外として返します。「Jolt Class Library Reference」では、Joltクラスと、各クラスのエラーや例外を一覧表示します。『Oracle Jolt APIリファレンス』には、エラーと例外のクラス・リファレンスが含まれています。
Oracle Joltは、分散型のクライアント/サーバー環境で動作し、JavaクライアントをOracle Tuxedoをベースとするアプリケーションに接続します。
図5-1は、JoltプログラムとJoltサーバーの間のクライアント/サーバー関係を示しています。
図に示すように、JoltサーバーはネイティブなOracle Tuxedoクライアントのプロキシとして動作し、ネイティブなOracle Tuxedoクライアントで利用できる機能を実装します。Oracle Joltサーバーは、Oracle Joltクライアントからのリクエストを受け取ると、Oracle Tuxedo ATMIインタフェースを介してこれらのリクエストをOracle Tuxedoサービス・リクエストにマッピングします。リクエストおよび関連付けられたパラメータは、メッセージ・バッファにパッケージされ、ネットワーク経由でOracle Joltサーバーに配信されます。Oracle JoltサーバーとOracle Joltアプレットの間のすべての通信は、Oracle Jolt接続マネージャにより、Oracle Joltトランザクション・プロトコルを使用して処理されます。Oracle Joltサーバーは、メッセージからデータを取り出し、必要に応じてデータ変換(数値形式や文字セットなど)を行ってから、メッセージで指定された適切なサービスをOracle Tuxedoにリクエストします。
Oracle Tuxedoシステムが受け取ったサービス・リクエストは、ほかのOracle Tuxedoのリクエストとまったく同じ方法で処理されます。結果はATMIインタフェースを通してOracle Joltサーバーに返され、そこで結果とエラー情報がメッセージにパッケージ化されると、Oracle Joltのクライアント・アプレットに送信されます。Oracle Joltクライアントはメッセージの中身を様々なOracle Joltクライアント・インタフェース・オブジェクトにマップして、リクエストを完了します。
クライアント側では、ユーザー・プログラムにクライアント・アプリケーション・コードが含まれています。Joltクラス・ライブラリが提供するJoltSessionとJoltTransactionがサービス・リクエストを処理します。
表5-1で、簡単なプログラムの例におけるクライアント側のリクエストおよびJoltサーバー側のアクションについて説明します。
「Joltクライアント/サーバーの相互作用」をまとめると、次のようになります。
上記のアクティビティは、Joltクラス・ライブラリのクラスによって処理されます。これらのクラスには、データの設定や消去を行ったり、リモート・サービスのアクションを処理するメソッドが用意されています。Joltクラス・ライブラリの詳細は、「Joltオブジェクト間の関係」を参照してください。
図5-2は、Joltクラス・ライブラリのクラスをインスタンス化したオブジェクト間の関係を示しています。
Joltクラスは、オブジェクトとして様々な関係で相互作用します。上の図は、3種類の基本的なカテゴリを示しています。
Joltクラスを使用すると、ログオン/ログオフ、同期型のサービス呼び出し、トランザクションの開始、トランザクションのコミット、トランザクションのロールバックなどの基本的なトランザクション処理を実行できます。次の項では、これらの機能を実行するためのJoltクラスの使い方を説明します。
Joltクラス・ライブラリを使用して、マルチスレッド化されたアプリケーションを開発したり、Tuxedo固有のバッファ型を定義したり、イベントや非請求メッセージのサブスクライブを実行することもできます。これらの機能については、後の項で説明します。
クライアント・アプリケーションには、トランザクション処理を行う前にOracle Tuxedo環境にログオンしておく必要があります。Joltクラス・ライブラリには、Oracle Tuxedoシステムとの接続を確立するためのJoltSessionAttributesクラスとJoltSessionクラスが用意されています。
JoltSessionAttributesクラスには、様々なプロパティのほか、JoltおよびOracle Tuxedoシステムへの接続プロパティが格納されます。接続を確立するには、クライアント・アプリケーション側でJoltSessionクラスのインスタンスを作成する必要があります。このインスタンスがJoltSessionオブジェクトです。開発者がJoltセッションおよびOracle Tuxedoオブジェクトをインスタンス化すると、JoltおよびOracle Tuxedoのログオン機能が有効になります。endSessionメソッドを呼び出すと、セッションは終了し、ユーザーのログオフが可能になります。
リクエストや応答などのトランザクションは、JoltRemoteServiceオブジェクト(JoltRemoteServiceクラスのインスタンス)を使用して処理されます。各JoltRemoteServiceオブジェクトは、エクスポートされたOracle Tuxedoのリクエスト/応答サービスを参照します。JoltRemoteServiceオブジェクトを使用する前には、サービス名とJoltSessionオブジェクトを指定して、JoltRemoteServiceオブジェクトをインスタンス化しておく必要があります。
JoltRemoteServiceオブジェクトを使用するには、次の手順に従います。
効率を高めるため、Joltでは入力パラメータ・オブジェクトはコピーされません。オブジェクトへの参照(文字列とバイト配列)だけが保存されます。JoltRemoteServiceオブジェクトは、ステートフル・オブジェクトです。そのため、このオブジェクトの入力パラメータとリクエスト属性は、オブジェクトの寿命がある限り維持されます。JoltRemoteServiceオブジェクトを再利用する前に、clear()
メソッドを使用して、属性や入力パラメータをリセットできます。
Joltはマルチスレッド環境用に設計されているので、Javaのマルチスレッド機能を使用して複数のJoltRemoteServiceオブジェクトを同時に呼び出すことができます。詳細は、「マルチスレッド・アプリケーション」を参照してください。
Joltでは、トランザクションはJoltTransactionクラスのオブジェクトとして表されます。トランザクションは、トランザクション・オブジェクトがインスタンス化されると開始されます。次に示すように、トランザクション・オブジェクトの作成時には、タイムアウト値とJoltSessionオブジェクトのパラメータが設定されます。
trans = new JoltTransaction(timeout, session)
Joltでは、トランザクションに関与するすべてのサービスに対して明示的なトランザクション・モデルを使用します。トランザクション・サービスを呼び出すには、JoltTransactionオブジェクトがパラメータとして必要です。また、サービスとトランザクションが同じセッションに属していることも必要です。Joltでは、同じセッションにバインドされていないサービスとトランザクションを使用することはできません。
「Joltのファンド転送の例(SimXfer.java)」のサンプル・コードは、Joltクラス・ライブラリの使い方を示しています。ここでは、JoltSessionAttributes、JoltSession、JoltRemoteService、およびJoltTransactionクラスを使用しています。
例では、ユーザー定義された2つのOracle Tuxedoサービス(WITHDRAWALとDEPOSIT)をバインドして、TRANSFERトランザクションを擬似的に実行します。WITHDRAWAL操作が失敗した場合は、ロールバックが実行されます。それ以外の場合はDEPOSITが実行され、commitによりトランザクションが完了します。
「Joltのファンド転送の例(SimXfer.java)」のサンプル・コードに示すトランザクション・プロセスのプログラミング手順は、以下のとおりです。
hostname
やportnumber
などの接続属性をJoltSessionAttributeオブジェクトに設定します。 sattr = new JoltSessionAttributes();
sattr.checkAuthenticationLevel()
を使うと、サーバーへのログオンに必要なセキュリティ・レベルをアプリケーション側で決定できます。 switch (sattr.checkAuthenticationLevel())
session = new JoltSession (sattr,userName
,userRole
,userPassword
,appPassword
);
この例では、SessionException
エラーを明示的に取得しません。
JoltSession()
から返されたセッション・キーが必要です。 withdrawal = new JoltRemoteService(“WITHDRAWAL”, session);
deposit = new JoltRemoteService(“DEPOSIT”, session);
これらの呼出しは、Joltリポジトリに格納されているWITHDRAWALおよびDEPOSITのサービス定義を、withdrawalオブジェクトおよびdepositオブジェクトにそれぞれバインドします。WITHDRAWALおよびDEPOSITサービスがJoltリポジトリで定義されていないと、ServiceExceptionがスローされます。この例では、ServiceExceptionエラーを明示的に取得しません。
withdrawal.addInt(“ACCOUNT_ID”, 100000);
withdrawal.addString(“SAMOUNT”, “100.00”);
add*()
メソッドでは、IllegalAccessError
またはNoSuchFieldError
例外がスローされる場合があります。
trans = new JoltTransaction(5,session);
withdrawal.call(trans)
メソッドを呼び出すと、withdrawalサービスが呼び出されます。 withdrawal.call(trans);
trans.rollback();
deposit.call(trans);
trans.commit();
リスト5-1に、Joltクラスを使用して資金の振替えを行うための簡単なアプリケーションの例を示します。
/* Copyright 1999 Oracle Systems, Inc. All Rights Reserved */
import bea.jolt.*;
public class SimXfer
{
public static void main (String[] args)
{
JoltSession session;
JoltSessionAttributes sattr;
JoltRemoteService withdrawal;
JoltRemoteService deposit;
JoltTransaction trans;
String userName=null;
String userPassword=null;
String appPassword=null;
String userRole=”myapp”;
sattr = new JoltSessionAttributes();
sattr.setString(sattr.APPADDRESS, “//bluefish:8501”);
switch (sattr.checkAuthenticationLevel())
{
case JoltSessionAttributes.NOAUTH:
System.out.println(“NOAUTH\n”);
break;
case JoltSessionAttributes.APPASSWORD:
appPassword = “appPassword”;
break;
case JoltSessionAttributes.USRPASSWORD:
userName = “myname”;
userPassword = “mysecret”;
appPassword = “appPassword”;
break;
}
sattr.setInt(sattr.IDLETIMEOUT, 300);
session = new JoltSession(sattr, userName, userRole,
userPassword, appPassword);
// Simulate a transfer
withdrawal = new JoltRemoteService(“WITHDRAWAL”, session);
deposit = new JoltRemoteService(“DEPOSIT”, session);
withdrawal.addInt(“ACCOUNT_ID”, 100000);
withdrawal.addString(“SAMOUNT”, “100.00”);
// Begin the transaction w/ a 5 sec timeout
trans = new JoltTransaction(5, session);
try
{
withdrawal.call(trans);
}
catch (ApplicationException e)
{
e.printStackTrace();
// This service uses the STATLIN field to report errors
// back to the client application.
System.err.println(withdrawal.getStringDef(“STATLIN”,”NO
STATLIN”));
System.exit(1);
}
String wbal = withdrawal.getStringDef(“SBALANCE”, “$-1.0”);
// remove leading “$” before converting string to float
float w = Float.valueOf(wbal.substring(1)).floatValue();
if (w < 0.0)
{
System.err.println(“Insufficient funds”);
trans.rollback();
System.exit(1);
}
else // now attempt to deposit/transfer the funds
{
deposit.addInt(“ACCOUNT_ID”, 100001);
deposit.addString(“SAMOUNT”, “100.00”);
deposit.call(trans);
String dbal = deposit.getStringDef(“SBALANCE”, “-1.0”);
trans.commit();
System.out.println(“Successful withdrawal”);
System.out.println(“New balance is: “ + wbal);
System.out.println(“Successful deposit”);
System.out.println(“New balance is: “ + dbal);
}
session.endSession();
System.exit(0);
} // end main
} // end SimXfer
Joltでは、次のOracle Tuxedo組込みのバッファ型がサポートされています。
注意: | X_OCTETの使用方法はCARRAYと同じです。 X_COMMONおよびX_C_TYPEの使用方法はVIEWと同じです。 |
Joltアプリケーションのプログラマは、Oracle Tuxedoに組み込まれているバッファ型のうち、特にCARRAY (文字配列)およびSTRINGの扱い方を知っておく必要があります。
Oracle Tuxedoの型付きバッファ、データ型、バッファ型に関するすべての情報については、以下のドキュメントを参照してください。
STRINGバッファ型は、null以外の文字配列で構成され、最後がnull文字で終了します。CARRAYとは違って、null文字までの文字数を指定して転送長を設定できます。STRINGバッファは、自己記述型です。そのため、異なる文字セットを使用するマシン間でデータを交換する場合は、Oracle Tuxedoシステムによってデータが自動的に変換されます。
注意: | JoltからSTRINGへのデータ変換時には、STRINGバッファの終端にnull終結文字が自動的に追加されます。Java文字列はnullで終結しないためです。 |
STRINGバッファ型を使うには、次の2つの操作が必要です。
次の2つの項では、これらの手順について例を挙げて説明します。
「STRINGバッファ型の使い方(ToUpper.java)」に示すコードToUpper
は、STRINGバッファ型が設定されたサービスがJoltでどのように動作するかを示しています。Oracle TuxedoサービスToUpper
は、Oracle Tuxedoのサンプルsimpapp
で利用できます。
ToUpper.java
を実行する前に、Joltリポジトリ・エディタを使用してTOUPPER
サービスを定義する必要があります。
注意: | サービスを定義したり、新しいパラメータを追加する方法については、「Joltリポジトリ・エディタの使用」を参照してください。 |
リスト5-2内のJavaコードToUpper.java
は、STRINGバッファ・タイプが設定されたサービスがJoltでどのように動作するかを示しています。この例では、STRINGバッファ・タイプを使用するJoltクライアントがサーバーにデータを渡す様子を示しています。Oracle Tuxedoサーバーはバッファを受け取り、文字列をすべて大文字に変換し、変換後の文字列をクライアントに返します。次の例では、セッション・オブジェクトがすでにインスタンス化されていることが前提となっています。
/* Copyright 1996 Oracle Systems, Inc. All Rights Reserved */
import bea.jolt.*;
public class ToUpper
{
public static void main (String[] args)
{
JoltSession session;
JoltSessionAttributes sattr;
JoltRemoteService toupper;
JoltTransaction trans;
String userName=null;
String userPassword=null;
String appPassword=null;
String userRole=”myapp”;
String outstr;
sattr = new JoltSessionAttributes();
sattr.setString(sattr.APPADDRESS, “//myhost:8501”);
switch (sattr.checkAuthenticationLevel())
{
case JoltSessionAttributes.NOAUTH:
break;
case JoltSessionAttributes.APPASSWORD:
appPassword = “appPassword”;
break;
case JoltSessionAttributes.USRPASSWORD:
userName = “myname”;
userPassword = “mysecret”;
appPassword = “appPassword”;
break;
}
sattr.setInt(sattr.IDLETIMEOUT, 300);
session = new JoltSession(sattr, userName, userRole,
userPassword, appPassword);
toupper = new JoltRemoteService (“TOUPPER”, session);
toupper.setString(“STRING”, “hello world”);
toupper.call(null);
outstr = toupper.getStringDef(“STRING”, null);
if (outstr != null)
System.out.println(outstr);
session.endSession();
System.exit(0);
} // end main
} // end ToUpper
CARRAYバッファ型は、Oracle Tuxedoシステムに組み込まれている文字配列による単純なバッファ型です。CARRAYバッファ型のデータはシステム側で解釈されないため、データ型が明らかであってもJoltクライアント・アプリケーションでデータの長さを指定する必要があります。このバッファ型を処理するときは、常にJoltクライアントでデータの長さを指定してください。
たとえば、Oracle TuxedoサービスがCARRAYバッファ型を使用する場合、ユーザーが32ビットのintegerを設定すると(Javaではintegerはビッグ・エンディアン・バイト順)、そのデータは変換されずにOracle Tuxedoサービスに送信されます。
CARRAYバッファ型を使用するには、まずバッファ型で使用するTuxedoサービスを定義します。次に、そのバッファ型を使用するコードを記述します。次の2つの項では、これらの手順について説明します。
注意: | X_OCTETの使用方法はCARRAYと同じです。 |
例を実行する前に、TuxedoのECHOサービスを作成し、起動する必要があります。ECHOサービスは、バッファを取得し、Joltクライアントに返します。Joltリポジトリ・エディタを使用してECHOサービスを定義します。
注意: | サービスを定義したり、新しいパラメータを追加する方法については、「Joltリポジトリ・エディタの使用」を参照してください。 |
次の手順に従い、リポジトリ・エディタでECHOサービスを追加します。
注意: | X_OCTETバッファ型を使用する場合は、「Input Buffer Type」フィールドと「Output Buffer Type」フィールドを「X_OCTET」に変更しなければなりません。 |
次のリスト内のコードは、CARRAYバッファ・タイプが設定されたサービスがJoltでどのように動作するかを示しています。JoltはCARRAYデータ・ストリームの内部のデータを調べないので、JoltクライアントとCARRAYサービスのデータ形式を一致させるのはプログラマ側の役割になります。リスト5-3の例では、セッション・オブジェクトがすでにインスタンス化されていることが前提となっています。
/* Copyright 1996 Oracle Systems, Inc. All Rights Reserved */
/* This code fragment illustrates how Jolt works with a service
* whose buffer type is CARRAY.
*/
import java.io.*;
import bea.jolt.*;
class ...
{
...
public void tryOnCARRAY()
{
byte data[];
JoltRemoteService csvc;
DataInputStream din;
DataOutputStream dout;
ByteArrayInputStream bin;
ByteArrayOutputStream bout;
/*
* Use java.io.DataOutputStream to put data into a byte array
*/
bout = new ByteArrayOutputStream(512);
dout = new DataOutputStream(bout);
dout.writeInt(100);
dout.writeFloat((float) 300.00);
dout.writeUTF("Hello World");
dout.writeShort((short) 88);
/*
* Copy the byte array into a new byte array "data". Then
* issue the Jolt remote service call.
*/
data = bout.toByteArray();
csvc = new JoltRemoteService("ECHO", session);
csvc.setBytes("CARRAY", data, data.length);
csvc.call(null);
/*
* Get the result from JoltRemoteService object and use
* java.io.DataInputStream to extract each individual value
* from the byte array.
*/
data = csvc.getBytesDef("CARRAY", null);
if (data != null)
{
bin = new ByteArrayInputStream(data);
din = new DataInputStream(bin);
System.out.println(din.readInt());
System.out.println(din.readFloat());
System.out.println(din.readUTF());
System.out.println(din.readShort());
}
}
}
FML (フィールド操作言語)は、型付きバッファとして使用できる柔軟性のあるデータ構造です。FMLは、タグ付きの値を格納するデータ構造です。このタグ付きの値には型が付いており、長さを変更することができ、複数のオカレンスを持つ場合があります。FMLでは、型付きバッファを抽象的なデータ型として扱います。
FML操作を用いると、データ構造やデータの格納方法を知らなくても、データに対してアクセスしたり、更新を行うことができます。アプリケーション・プログラムでは、単に識別子を使ってフィールド化されたバッファのフィールドにアクセスしたり更新するだけで済みます。操作の実行時には、FMLのランタイム・システムによってフィールドの場所と操作を行うデータ型が決定されます。
FMLは、クライアントとサーバーがそれぞれ別のコード(Java言語とC言語など)で記述されている場合、プラットフォームで扱われるデータ型の仕様が異なる場合、またはクライアント/サーバー間のインタフェースが頻繁に変わる場合のJoltクライアントでの使用に特に適しています。
次のtryOnFml
は、FMLバッファ型の使用方法を示しています。この例では、FMLバッファを使用するJoltクライアントがサーバーにデータを渡す様子を示しています。サーバーはバッファを取得し、データを格納するための新しいFMLバッファを作成し、バッファをJoltクライアントに返します。以下は、サンプル・コードの説明です。
リスト5-4内のJavaコードtryOnFml.java
は、FMLバッファ・タイプが設定されたサービスがJoltでどのように動作するかを示しています。この例では、セッション・オブジェクトがすでにインスタンス化されていることが前提となっています。
/* Copyright 1997 Oracle Systems, Inc. All Rights Reserved */
import bea.jolt.*;
class ...
{
...
public void tryOnFml ()
{
JoltRemoteService passFml;
String outputString;
int outputInt;
float outputFloat;
...
passFml = new JoltRemoteService("PASSFML",session);
passFml.setString("INPUTSTRING", "John");
passFml.setInt("INPUTINT", 67);
passFml.setFloat("INPUTFLOAT", (float)12.0);
passFml.call(null);
outputString = passFml.getStringDef("OUTPUTSTRING", null);
outputInt = passFml.getIntDef("OUTPUTINT", -1);
outputFloat = passFml.getFloatDef("OUTPUTFLOAT", (float)-1.0);
System.out.print("String =" + outputString);
System.out.print(" Int =" + outputInt);
System.out.println(" Float =" + outputFloat);
}
}
次の「tryOnFml.f16のフィールド定義」は、「tryOnFml.javaのサンプル・コード」のFMLフィールド定義を示しています。
#
# FML field definition table
#
*base 4100
INPUTSTRING 1 string
INPUTINT 2 long
INPUTFLOAT 3 float
OUTPUTSTRING 4 string
OUTPUTINT 5 long
OUTPUTFLOAT 6 float
BULKPKGパッケージには、PASSFMLサービスが含まれており、tryOnFml.java
およびtryOnFml.c
のコードで使用されます。tryOnFml.java
を使用する前に、Joltリポジトリ・エディタを使用してPASSFMLサービスを変更する必要があります。
注意: | サービスの定義に関しては、「Joltリポジトリ・エディタの使用」を参照してください。 |
「「Repository Editor」ウィンドウ: PASSFMLサービスを編集する」は、PASSFMLサービスおよび入力バッファ型FMLと出力バッファ型FMLを示しています。
リスト5-6に、FMLバッファ・タイプを使用するためのサーバー側のコードを示します。PASSFMLサービスは入力FMLバッファを読み取り、FMLバッファを出力します。
/*
* tryOnFml.c
*
* Copyright (c) 1997 Oracle Systems, Inc. All rights reserved
*
* Contains the PASSFML Oracle Tuxedo server.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include <fml.h>
#include <fml32.h>
#include <Usysflds.h>
#include <atmi.h>
#include <userlog.h>
#include "tryOnFml.f16.h"
/*
* PASSFML service reads in a input fml buffer and outputs a fml buffer.
*/
void
PASSFML( TPSVCINFO *rqst )
{
FLDLEN len;
FBFR *svcinfo = (FBFR *) rqst->data;
char inputString[256];
long inputInt;
float inputFloat;
FBFR *fml_ptr;
int rt;
if (Fget(svcinfo, INPUTSTRING, 0, inputString, &len) < 0) {
(void)userlog("Fget of INPUTSTRING failed %s",
Fstrerror(Ferror));
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
}
if (Fget(svcinfo, INPUTINT, 0, (char *) &inputInt, &len) < 0) {
(void)userlog("Fget of INPUTINT failed %s",Fstrerror(Ferror));
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
}
if (Fget(svcinfo, INPUTFLOAT, 0, (char *) &inputFloat, &len) < 0) {
(void)userlog("Fget of INPUTFLOAT failed %s",
Fstrerror(Ferror));
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
}
/* We could just pass the FML buffer back as is, put lets */
/* store it into another FML buffer and pass it back. */
if ((fml_ptr = (FBFR *)tpalloc("FML",NULL,rqst->len))==(FBFR *)NULL) {
(void)userlog("tpalloc failed in PASSFML %s",
tpstrerror(tperrno));
tpreturn(TPFAIL, 0, rqst->data, 0L, 0);
}
if(Fadd(fml_ptr, OUTPUTSTRING, inputString, (FLDLEN)0) == -1) {
userlog("Fadd failed with error: %s", Fstrerror(Ferror));
tpfree((char *)fml_ptr);
tpreturn(TPFAIL, 0, NULL, 0L, 0);
}
if(Fadd(fml_ptr, OUTPUTINT, (char *)&inputInt, (FLDLEN)0) == -1) {
userlog("Fadd failed with error: %s", Fstrerror(Ferror));
tpfree((char *)fml_ptr);
tpreturn(TPFAIL, 0, NULL, 0L, 0);
}
if(Fadd(fml_ptr, OUTPUTFLOAT, (char *)&inputFloat, (FLDLEN)0) == -1) {
userlog("Fadd failed with error: %d\n", Fstrerror(Ferror));
tpfree((char *)fml_ptr);
tpreturn(TPFAIL, 0, NULL, 0L, 0);
}
tpreturn(TPSUCCESS, 0, (char *)fml_ptr, 0L, 0);
}
VIEWはOracle Tuxedo組込みのバッファ型です。VIEWは、Oracle TuxedoシステムでC構造体およびCOBOLレコードを使用するために提供されています。この型付きバッファにより、Oracle Tuxedoのランタイム・システムは、実行時に読み込まれるview記述に基づいてCの構造体やCOBOLのレコードのフォーマットを認識します。
VIEWを割り当てると、アプリケーションはバッファ型としてVIEWを指定し、viewの名前(view記述ファイル内の名前)を示すサブタイプを指定します。また、パラメータ名とview内のフィールド名は一致していなければなりません。Oracle Tuxedoのランタイム・システムは構造体のサイズに応じて必要な空間を割り当てるため、アプリケーション側でバッファ長を指定する必要はありません。また、ランタイム・システムは、リクエストまたはレスポンスの際に送信されるデータ量の計算や、異なるマシン間で送受信されるメッセージのエンコードやデコードを自動的に行います。
次は、Joltクライアントとサーバー側アプリケーションがある環境でのVIEWバッファ型の使い方の例です。
Joltクライアントでは、VIEWバッファの文字列に含まれるnull文字は行末文字として扱われ、null文字の後の文字列は切り捨てられます。
simpview.java
およびsimpview.c
の例を実行する前に、Joltリポジトリ・エディタを使用してVIEWサービスを定義する必要があります。
注意: | サービスの定義に関しては、「Joltリポジトリ・エディタの使用」を参照してください。 |
次の手順に従って、リポジトリ・エディタでVIEWサービスを追加します。
注意: | バッファ型としてX_COMMONまたはX_C_TYPEを使用する場合は、「Input Buffer Type」フィールドと「Output Buffer Type」フィールドに正しいバッファ型を指定する必要があります。また、「Input View Name」フィールドと「Output View Name」フィールドにも、対応する名前を指定してください。 |
「simpview.javaのサンプル・コード」は、VIEWバッファ型が指定されたサービスがJoltでどのように動作するかを示しています。クライアント・コードは、FMLサービスにアクセスするときに使用されるコードと同じです。
注意: | 次のコード・リスト内のコードでは、例外は取得されません。Jolt例外はすべてjava.lang.RunTimeException に由来するため、アプリケーションが例外を取得しない場合はJava仮想マシン(JVM)によって捕捉されます。(よいアプリケーションは、これらの例外を捕捉して適切な処理を行います。) |
次のコード・リストに示す例を実行する前に、Joltリポジトリ・エディタを使用してSIMPAPPパッケージにVIEWサービスを追加し、Oracle Tuxedoアプリケーションsimpview.c
を記述する必要があります。このサービスは、クライアントのVIEWバッファからデータを取り出し、新しいバッファを作成して、新しいVIEWバッファとしてクライアントに返します。次の例では、セッション・オブジェクトがすでにインスタンス化されていることを想定しています。
/* Copyright 1997 Oracle Systems, Inc. All Rights Reserved */
/*
* This code fragment illustrates how Jolt works with a service whose buffer
* type is VIEW.
*/
import bea.jolt.*;
class ...
{
...
public void simpview ()
{
JoltRemoteService ViewSvc;
String outString;
int outInt;
float outFloat;
// Create a Jolt Service for the Oracle Tuxedo service "SIMPVIEW"
ViewSvc = new JoltRemoteService("SIMPVIEW",session);
// Set the input parameters required for SIMPVIEW
ViewSvc.setString("inString", "John");
ViewSvc.setInt("inInt", 10);
ViewSvc.setFloat("inFloat", (float)10.0);
// Call the service. No transaction required, so pass
// a "null" parameter
ViewSvc.call(null);
// Process the results
outString = ViewSvc.getStringDef("outString", null);
outInt = ViewSvc.getIntDef("outInt", -1);
outFloat = ViewSvc.getFloatDef("outFloat", (float)-1.0);
// And display them...
System.out.print("outString=" + outString + ",");
System.out.print("outInt=" + outInt + ",");
System.out.println("outFloat=" + outFloat);
}
}
「simpview.v16のフィールド定義」は、前のコード・リストsimpview.java
のOracle Tuxedo VIEWフィールド定義を示しています。
#
# VIEW for SIMPVIEW. This view is used for both input and output. The
# service could also have used separate input and output views.
# The first 3 params are input params, the second 3 are outputs.
#
VIEW SimpView
$
#type cname fbname count flag size null
string inString - 1 - 32 -
long inInt - 1 - - -
float inFloat - 1 - - -
string outString - 1 - 32 -
long outInt - 1 - - -
float outFloat - 1 - - -
END
リスト5-9では、入力バッファ・タイプと出力バッファ・タイプはVIEWです。このコードは、VIEWバッファ・タイプの入力データを受け入れ、同じVIEWバッファ・タイプのデータを出力します。
/*
* SIMPVIEW.c
*
* Copyright (c) 1997 Oracle Systems, Inc. All rights reserved
*
* Contains the SIMPVIEW Oracle Tuxedo server.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include <fml.h>
#include <fml32.h>
#include <Usysflds.h>
#include <atmi.h>
#include <userlog.h>
#include "simpview.h"
/*
* Contents of simpview.h.
*
*struct SimpView {
*
* char inString[32];
* long inInt;
* float inFloat;
* char outString[32];
* long outInt;
* float outFloat;
*};
*/
/*
* service reads in a input view buffer and outputs a view buffer.
*/
void
SIMPVIEW( TPSVCINFO *rqst )
{
/*
* get the structure (VIEWSVC) from the TPSVCINFO structure
*/
struct SimpView *svcinfo = (struct SimpView *) rqst->data;
/*
* print the input params to the UserLog. Note there is
* no error checking here. Normally a SERVER would perform
* some validation of input and return TPFAIL if the input
* is not correct.
*/
(void)userlog("SIMPVIEW: InString=%s,InInt=%d,InFloat=%f",
svcinfo->inString, svcinfo->inInt, svcinfo->inFloat);
/*
* Populate the output fields and send them back to the caller
*/
strcpy (svcinfo->outString, "Return from SIMPVIEW");
svcinfo->outInt = 100;
svcinfo->outFloat = (float) 100.00;
/*
* If there was an error, return TPFAIL
* tpreturn(TPFAIL, ErrorCode, (char *)svcinfo, sizeof (*svcinfo), 0);
*/
tpreturn(TPSUCCESS, 0, (char *)svcinfo, sizeof (*svcinfo), 0);
}
XMLバッファ型を使用すると、Oracle TuxedoアプリケーションでXMLを使用して、アプリケーション内やアプリケーション間でデータを交換できるようになります。Oracle Tuxedoアプリケーションでは、XML型バッファの送受信や、それらのバッファを適切なサーバーにルーティングできます。解析など、XMLドキュメントのすべての処理ロジックはアプリケーション側にあります。
XMLバッファ型を使用するには、まずバッファ型で使用するTuxedoサービスを定義します。次に、そのバッファ型を使用するコードを記述します。次の2つの項では、これらの手順について説明します。
注意: | CARRAY同様に、XMLバッファ型はSTRINGではなくバイト配列として扱われます。JoltクライアントとOracle Tuxedoサービス間でのデータ変換は行われません。 |
例を実行する前に、TuxedoのXMLサービスを作成し、起動する必要があります。XMLサービスは、バッファを取得し、Joltクライアントに返します。Joltリポジトリ・エディタを使用してXMLサービスを定義します。
注意: | サービスを定義したり、新しいパラメータを追加する方法については、「Joltリポジトリ・エディタの使用」を参照してください。 |
次の手順に従い、リポジトリ・エディタでXMLサービスを追加します。
次のリスト内のコードは、XMLバッファ・タイプが設定されたサービスがJoltでどのように動作するかを示しています。JoltはXMLデータ・ストリームの内部のデータを調べないので、JoltクライアントとXMLサービスのデータ形式を一致させるのはプログラマ側の役割になります。リスト5-10の例では、セッション・オブジェクトがすでにインスタンス化されていることが前提となっています。
/* Copyright 2001 Oracle Systems, Inc. All Rights Reserved */
/*
* This code fragment illustrates how Jolt works with a service whose buffer
* type is XML.
*/
import java.io.*;
import java.lang.*;
import bea.jolt.*;
public class xmldoc {
public static void main (String[] args) {
JoltSessionAttributes sattr;
JoltSession session;
JoltRemoteService echo_xml;
String inString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ORDER><HEADER DATE=\"05/13/1999\" ORDERNO=\"22345\"/><COMPANY>ACME</COMPANY><LINE><ITEM MODEL=\"Pabc\" QUANTITY=\"5\">LAPTOP</ITEM></LINE><LINE><ITEM MODEL=\"P500\" QUANTITY=\"15\">LAPTOP</ITEM></LINE></ORDER>";
byte data[];
DataInputStream din;
DataOutputStream dout;
ByteArrayInputStream bin;
ByteArrayOutputStream bout;
byte odata[];
String outString = null;
String appAddress = null;
//...Create Jolt Session
try {
/*
* Use java.io.DataOutputStream to put data
* into a byte array
*/
bout = new ByteArrayOutputStream(inString.length());
dout = new DataOutputStream(bout);
dout.writeBytes(inString);
/*
* Copy the byte array into a new byte array "data".
* Then issue the Jolt remote service call.
*/
data = bout.toByteArray();
} catch (Exception e) {
System.out.println("toByteArray error");
return;
}
try {
echo_xml = new JoltRemoteService("ECHO_XML", session);
System.out.println("JoltRemoteService Created");
echo_xml.setBytes("XML", data, data.length);
} catch (Exception e) {
System.out.println("RemoteService call error" + e);
return;
}
echo_xml.call(null);
System.out.println("Service Call Returned");
odata = echo_xml.getBytesDef("XML", null);
try {
System.out.println("Return String is:" + new String(odata));
} catch (Exception e) {
System.err.println("getByteDef Error");
}
}
}
// end of class
Tuxedo 9.0以降、JoltではMBSTRINGバッファ・タイプがサポートされています(Tuxedo ATMIではTuxedo 8.1以降ですでにサポートされています)。
Javaではマルチ・バイト文字のエンコーディングの標準としてUnicodeが使用され、Unicodeの文字列データ用にStringクラスが提供されているので、Jolt MBSTRINGのサポートではJavaクライアント側のMBSTRINGコンテナとしてStringクラスが使用されます。Joltでは、JoltクライアントとTuxedoサーバーの間でデータが転送されるときに、Stringオブジェクト内のUnicode MBSTRINGデータがバイト配列MBSTRINGデータ(ATMIのMBSTRING表現)に、またはその逆に自動的に変換されます。
次の各メソッドが、bea.jolt.Message
インタフェース、bea.jolt.JoltMessage
クラスおよびbea.jolt.JoltRemoteService
クラスに追加されています。
addMBString
setMBString
setMBStringItem
getMBStringDef
getMBStringItemDef
MBSTRINGバッファ・タイプの使用方法はSTRINGバッファ・タイプとほとんど同じですが、Joltリポジトリ・エディタで指定されるバッファ・タイプはMBSTRINGで、MBSTRINGデータを取得および設定するためのJavaメソッドは前述のメソッドです。
さらに、次のJavaシステム・プロパティは、Tuxedoサーバーに送信されるMBSTRINGデータの文字エンコーディング名を指定するために使用されます。
bea.jolt.mbencoding
bea.jolt.mbencodingmap
jolti18n.jar
をCLASSPATH
に追加する必要があります。jolti18n.jar
がCLASSPATH
に存在しない場合、エンコーディング名はISO-8859-1に設定され、Javaコマンドラインでこれらのプロパティを指定しても、JavaとTuxedoの間でエンコーディング名のマッピングは行われません。
Javaベースのクラス・セットであるJoltでは、マルチスレッド・アプリケーションをサポートしていますが、Java言語の様々な実装は特定の言語および環境の機能によって異なります。Joltのプログラマは、次のことを知っておく必要があります。
「スレッドの状態の種類」では、様々なJava実装でスレッドを使用する際に発生する問題について説明し、Joltプログラムでのスレッドの使用例を示します。
注意: | ほとんどのJava実装では、ノンプリエンティブなスレッドではなくプリエンプティブなスレッドが使用されます。プリエンティブなスレッドとノンプリエンティブなスレッドでは、パフォーマンスやプログラミングの要件が大きく異なります。 |
Java仮想マシンで同時に実行される個々のタスクは、スレッドです。スレッドの主要な状態には、RUNNING、RUNNABLEおよびBLOCKEDがあります。
注意: | Java仮想マシン(VM)は、優先度が同じスレッドがラウンドロビン・モードで実行されるようスケジュールします。 |
2つのスレッド・モデルの主要なパフォーマンス上の違いは、実行中のスレッドにJava仮想マシン(VM)の制御を放棄するよう指示するかどうかにあります。プリエンプティブなスレッド環境では通常、ハードウェアのタイマーが定期的にオフになるように設定します。タイマーがオフになると現在のスレッドの状態がRUNNINGからRUNNABLEになり、かわって別のスレッドが選択されて実行されます。
ノンプリエンプティブなスレッド環境においては、スレッドは自発的にCPUの制御を放棄し、RUNNABLEな状態に移行します。Java言語クラス内の多くのメソッドには、制御を自発的に放棄するコードが含まれており、通常は長い処理時間のかかる操作に関連付けられています。たとえば、ネットワークからデータを読み取ると、スレッドは通常パケットの到着を待機します。イベントやリソースが使用可能になるまで待機するスレッドは、BLOCKED状態になります。イベントが発生するか、リソースが使用可能になると、そのスレッドはRUNNABLEになります。
ノンプリエンプティブなスレッドを使用する仮想マシン(Sun Solarisなど)でJoltベースのJavaプログラムを実行する場合、プログラムで次のいずれかが行われる必要があります。
通常は、実行するコードが長い部分または時間がかかりそうなループすべてで次のコールを行います。
Thread.currentThread.yield();
このメッセージを送信しないと、Joltライブラリで使用されるスレッドはスケジューリングされず、Jolt操作に不具合が生じます。
ノンプリエンプティブなスレッドを使用する仮想マシンとして知られている唯一のマシンは、Sunプラットフォーム用のJava Developer's Kit (JDK)です。アプレットをJDK 1.3で実行するには、yieldメッセージを必ず送信してください。すでに述べたように、メソッドの中にはyieldを含むものがあります。例外はSystem.in.read
メソッドです。このメッセージはスレッドの切替えを行いません。これらのメッセージを使用するかわりに、yieldを明示的に使用することをお薦めします。
スレッドを使用して、Oracle Tuxedoのtpacall()
に似た非同期的な処理をJoltで行うことができます。この機能があれば、非同期的にサービスをリクエストする機能は必要ありません。この機能が使えるのはJoltがスレッド・セーフであるためです。たとえば、Joltクライアント・アプリケーションは、Oracle Tuxedoサービスにリクエストを送信するスレッドを開始した後で直ちにOracle Tuxedoサービスに別のリクエストを送信する別のスレッドを開始することができます。したがって、Joltによるtpacall()
の呼出しが同期的であっても、2つのスレッドが同時に実行されているため、アプリケーションは非同期的です。
Joltクライアント側のプログラムまたはアプレットは完全にスレッド・セーフです。Joltがサポートするマルチスレッド・アプリケーションでは、クライアント側に次の特徴があります。
リスト5-11に、Joltアプリケーションで2つのスレッドを使用する方法を示します。
/* Copyright 1996 Oracle Systems, Inc. All Rights Reserved */
import bea.jolt.*;
public class ThreadBank
{
public static void main (String [] args)
{
JoltSession session;
try
{
JoltSessionAttributes dattr;
String userName = null;
String userPasswd = null;
String appPasswd = null;
String userRole = null;
// fill in attributes required
dattr = new JoltSessionAttributes();
dattr.setString(dattr.APPADDRESS,”//bluefish:8501”);
// instantiate domain
// check authentication level
switch (dattr.checkAuthenticationLevel())
{
case JoltSessionAttributes.NOAUTH:
System.out.println(“NOAUTH\n”);
break;
case JoltSessionAttributes.APPASSWORD:
appPasswd = “myAppPasswd”;
break;
case JoltSessionAttributes.USRPASSWORD:
userName = “myName”;
userPasswd = “mySecret”;
appPasswd = “myAppPasswd”;
break;
}
dattr.setInt(dattr.IDLETIMEOUT, 60);
session = new JoltSession (dattr, userName, userRole,
userPasswd, appPasswd);
T1 t1 = new T1 (session);
T2 t2 = new T2 (session);
t1.start();
t2.start();
Thread.currentThread().yield();
try
{
while (t1.isAlive() && t2.isAlive())
{
Thread.currentThread().sleep(1000);
}
}
catch (InterruptedException e)
{
System.err.println(e);
if (t2.isAlive())
{
System.out.println(“job 2 is still alive”);
try
{
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e1)
{
System.err.println(e1);
}
}
else if (t1.isAlive())
{ System.out.println(“job1 is still alive”);
try
{
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e1)
{
System.err.println(e1);
}
}
}
session.endSession();
}
catch (SessionException e)
{
System.err.println(e);
}
finally
{
System.out.println(“normal ThreadBank term”);
}
}
}
class T1 extends Thread
{
JoltSession j_session;
JoltRemoteService j_withdrawal;
public T1 (JoltSession session)
{
j_session=session;
j_withdrawal= new JoltRemoteService(“WITHDRAWAL”,j_session);
}
public void run()
{
j_withdrawal.addInt(“ACCOUNT_ID”,10001);
j_withdrawal.addString(“SAMOUNT”,”100.00”);
try
{
System.out.println(“Initiating Withdrawal from account 10001”);
j_withdrawal.call(null);
String W = j_withdrawal.getStringDef(“SBALANCE”,”-1.0”);
System.out.println(“-->Withdrawal Balance: “ + W);
}
catch (ApplicationException e)
{
e.printStackTrace();
System.err.println(e);
}
}
}
class T2 extends Thread
{
JoltSession j_session;
JoltRemoteService j_deposit;
public T2 (JoltSession session)
{
j_session=session;
j_deposit= new JoltRemoteService(“DEPOSIT”,j_session);
}
public void run()
{
j_deposit.addInt(“ACCOUNT_ID”,10000);
j_deposit.addString(“SAMOUNT”,”100.00”);
try
{
System.out.println(“Initiating Deposit from account 10000”);
j_deposit.call(null);
String D = j_deposit.getStringDef(“SBALANCE”,”-1.0”);
System.out.println(“-->Deposit Balance: “ + D);
}
catch (ApplicationException e)
{
e.printStackTrace();
System.err.println(e);
}
}
}
Joltを使用してクライアント・アプリケーションを開発するプログラマは、Oracle TuxedoサービスまたはほかのOracle Tuxedoクライアントからイベント通知を受信することができます。Joltクラス・ライブラリには、イベントに基づく通信を処理するため、次のOracle Tuxedo通知をサポートするクラスが用意されています。
tpbroadcast()
を呼び出してブロードキャストを発行するか、またはATMI呼出しのtpnotify()
を使用してJoltクライアント宛てに直接対象のメッセージを発行した結果、Joltクライアントが受信する通知です。tppost()
呼出しを発行する場合にのみ受信されます。Joltクラス・ライブラリには、Joltクライアント・アプリケーション用の非同期通知メカニズムを実装するための4つのクラスが用意されています。
これらのクラスについては、Oracle Jolt APIリファレンスを参照してください。
Joltクライアント・アプリケーションでは、非請求メッセージとブローカ経由のイベント通知の両方に対してイベント・ハンドラ・ルーチン(通知の受信時に呼び出される)が必要になります。Joltでは、1セッションでサポートされるハンドラは1つです。Oracle Tuxedoでは、通知の生成元であるイベントを特定することはできません。したがって、特定のイベントが発生したときに、そのイベント特有のハンドラを呼び出すことはできません。
クライアント・アプリケーション側では、セッションごとに1つのハンドラを用意(onReply()
メソッドをオーバーライド)し、そのセッションでクライアントが受信するすべての通知に対して呼び出されるようにしなければなりません。単一ハンドラによるコールバック関数は、非請求とイベント通知型の両方で使用されます。ハンドラ呼出しの原因となったイベントを特定し、適切な措置を取ることは(ユーザー定義の)ハンドラ・ルーチンの役割です。ユーザーがセッション・ハンドラをオーバーライドしないと、通知メッセージはデフォルトのハンドラによって暗黙のうちに廃棄されます。
Joltクライアントは、JoltSessionクラスのサブクラスを作成し、onReply()
メソッドをユーザー定義されたonReply()
メソッドでオーバーライドすることによって、コールバック関数を提供します。
Oracle Tuxedo/ATMIクライアントでは、ハンドラ・コールバック関数内では、ATMI呼出しのサブセットしか使うことができません。この制約は、Joltクライアントには適用されません。別々のスレッドを使用して、通知をモニターし、イベント・ハンドラ・メソッドを実行します。Joltがサポートするすべての機能をハンドラ内から実行することが可能です。Joltクライアント・プログラムに適用される通常の規則(1セッションにつき1トランザクションなど)は、すべてハンドラにも適用されます。
ハンドラ・メソッドの呼出しは、独立したスレッド内で行われます。別々のスレッドがonReply()
メソッドを同時に実行しないようにするため、アプリケーション開発者は必ずそのメソッドにsynchronizedキーワードを付けるか、またはそのメソッドがスレッド・セーフになるように記述します。
Joltでは、ハンドラ・ルーチンを有効にする暗黙的なモデルが使用されます。クライアントがイベントをサブスクライブすると、Joltはそのクライアントのハンドラを内部で有効にしますが、その結果、非請求メッセージの受信も有効になります。Joltクライアントがイベント通知をサブスクライブする場合は、同時に必ず非請求メッセージも受信します。さらに、これらの2種類の通知に対して、単一のonReply()
メソッドが呼び出されます。
Joltは、コネクション保持モードまたはコネクションレス・モードで稼動しているクライアントの通知の受信をサポートします。コネクション保持モード(RETAINED)のクライアントは、すべての通知を受信します。コネクションレス・モードで動作するJoltクライアントは、Joltセッション・ハンドラ(JSH)へのネットワーク接続がアクティブな間は通知を受信します。ネットワーク接続が切断されている場合、JSHはクライアント宛ての通知のログを記録し、その通知を廃棄します。コネクションレス・モードで稼動しているJoltクライアントは、ネットワーク接続がアクティブでない間は非請求メッセージまたはイベント通知を受信しません。この間に受信されたメッセージは、JSHによって記録され、廃棄されます。
接続モードでの通知処理には、Oracle Tuxedo環境でのJoltクライアントへの確認付きメッセージ通知の処理も含まれます。JSHがクライアントへの確認付きメッセージ通知を受信し、そのクライアントに対してアクティブなネットワーク接続が確立されていない場合、JSHはエラーのログを記録し、通知メッセージに対して失敗を示す確認を返します。
クライアントが通知を受信する場合、通知にはデータ・バッファが付随しています。データ・バッファはどのOracle Tuxedoデータ・バッファ型でもかまいません。Joltクライアント(ハンドラ)はこれらのバッファをJoltMessage
オブジェクトとして受信し、適切なJoltMessage
クラスのget*()
メソッドを使用してこのオブジェクトからデータを取り出します。
通知に使用するバッファの定義をJoltリポジトリに格納する必要はありません。ただし、Joltクライアント・アプリケーションのプログラマは、フィールド名を知っておく必要があります。
Joltシステムには、Oracle Tuxedoのtptypes()
と同様の機能はありません。FMLおよびVIEWのバッファ型の場合は、適切なフィールド名を指定してget*()
メソッドを使用してデータにアクセスします。たとえば、次のように入力します。
getIntDef ("ACCOUNT_ID", -1);
STRINGおよびCARRAYのバッファ型の場合は、バッファ型と同じ名前でデータにアクセスします。たとえば、次のように入力します。
getStringDef ("STRING", null);
getBytesDef ("CARRAY", null);
STRINGとCARRAYのバッファ型には、単一のデータ要素しか含まれていません。この要素全体は、get*()
メソッドで返されます。
Oracle Tuxedoのブローカ経由のイベント通知により、Oracle Tuxedoプログラムは、どのプログラムがイベントの発生通知を受信するかを気にしないで、イベントをポストすることができます。また、Joltのイベント通知機能により、Joltクライアント・アプリケーションは、Oracle Tuxedoのtpnotify()
またはtpbroadcast()
を呼び出してブロードキャストまたはポストされるOracle Tuxedoイベントをサブスクライブすることができます。
Joltクライアントがサブスクライブできるのは、Oracle Tuxedoの他のコンポーネントによって生成されたイベントまたはメッセージ通知(Oracle Tuxedoのサービスまたはクライアントなど)のみです。Joltクライアントは、イベントまたはメッセージ通知を送信することはできません。
Joltでは、メッセージ通知型のサブスクリプションしかサポートされません。サブスクリプションが実行されるとonReply()
メソッドが呼び出されます。JoltのAPIでは、メッセージ通知の受信時にサービス・ルーチンをディスパッチしたり、アプリケーション・キューにメッセージを入れる機能はサポートされていません。
Joltクライアントが単一のイベント通知をサブスクライブする場合、クライアントは、非請求メッセージとイベント通知を両方とも受信します。イベントをサブスクライブすることにより、暗黙的に非請求メッセージも利用できるようになります。つまり、たとえばアプリケーションがイベントXに対してJoltUserEventオブジェクトを作成した場合にtpnotify()
またはtpbroadcast()
を呼び出すと、クライアントは自分宛てのメッセージを自動的に受信します。
注意: | 単一のイベント通知をサブスクライブするために非請求メッセージを用いることはお薦めしません。非請求メッセージを受信したい場合は、アプリケーション側で明示的に指定してください(JoltUserEventクラスで説明)。次の項では、通知のアンサブスクライブについて説明します。 |
イベント通知または非請求メッセージのいずれか、または両方のサブスクライブを停止するには、JoltUserEventのunsubscribeメソッドを使う必要があります。Joltでは、unsubscribeメソッドを使用して非請求メッセージの受信を停止しても、すべてのサブスクリプション通知が停止されるわけではありません。この点がOracle Tuxedoと異なります。Oracle Tuxedoでは、NULLハンドラを指定してtpsetunsol()
を呼び出すと、すべてのサブスクリプション通知が停止します。
イベントの通知をアンサブスクライブする場合、次の点に注意してください。
クライアント・アプリケーションで非請求メッセージの受信を停止したい場合は、すべてのイベントをアンサブスクライブする必要があります。
「非同期型通知」のコード・リストは、Joltクラス・ライブラリを使用して通知を受信する方法を示しています。ここでは、JoltSession
クラス、JoltReply
クラス、JoltMessage
、およびJoltUserEvent
クラスが使用されています。
class EventSession extendsJoltSession
{
public EventSession(JoltSessionAttributes
attr, String user,
String role, String upass, String apass )
{
super(attr, user, role, upass, apass);
}
/**
* Override the default unsolicited message handler.
* @param reply a place holder for the unsolicited message
* @see bea.jolt.JoltReply
*/
public voidonReply
( JoltReply reply )
{
// Print out the STRING buffer type message which contains
// only one field; the field name must be "STRING". If the
// message uses CARRAY buffer type, the field name must be
// "CARRAY". Otherwise, the field names must conform to the
// elements in FML or VIEW.
JoltMessage
msg = (JoltMessage) reply.getMessage();
System.out.println(msg.getStringDef("STRING", "No Msg"));
}
public static void main( Strings args[] )
{
JoltUserEvent
unsolEvent;
JoltUserEvent helloEvent;
EventSession session;
...
// Instantiate my session object which can print out the
// unsolicited messages. Then subscribe to HELLO event
// and Unsolicited Notification which both use STRING
// buffer type for the unsolicited messages.
session = new EventSession(...);
helloEvent = new JoltUserEvent("HELLO", null, session);
unsolEvent = new JoltUserEvent(JoltUserEvent.UNSOLMSG, null,
session);
...
// Unsubscribe the HELLO event and unsolicited notification.
helloEvent.unsubscribe
();
unsolEvent.unsubscribe();
}
}
Joltクラス・ライブラリには、オブジェクトの既存の属性値を消去し、事実上オブジェクトの再利用ができるようにするclear()
メソッドが用意されています。「Joltオブジェクトの再利用(reuseSample.java)」は、clear()
メソッドを使用してパラメータ値をクリアする方法とJoltRemoteServiceのパラメータ値を再利用する方法を示しています。この例では、再利用するためにサービスを破棄する必要がないことを示しています。代わりに、svc.clear()
;文を使用して既存の入力パラメータ値を廃棄してからaddString()
メソッドを再度使用しています。
/* Copyright 1999 Oracle Systems, Inc. All Rights Reserved */
import java.net.*;
import java.io.*;
import bea.jolt.*;
/*
* This is a Jolt sample program that illustrates how to reuse the
* JoltRemoteService after each invocation.
*/
class reuseSample
{private static JoltSession s_session;
static void init( String host, short port )
{
/* Prepare to connect to the Tuxedo domain. */
JoltSessionAttributes attr = new JoltSessionAttributes();
attr.setString(attr.APPADDRESS,”//”+ host+”:” + port);
String username = null;
String userrole = “sw-developer”;
String applpasswd = null;
String userpasswd = null;
/* Check what authentication level has been set. */
switch (attr.checkAuthenticationLevel())
{
case JoltSessionAttributes.NOAUTH:
break;
case JoltSessionAttributes.APPASSWORD:
applpasswd = “secret8”;
break;
case JoltSessionAttributes.USRPASSWORD:
username = “myName”;
userpasswd = “BEA#1”;
applpasswd = “secret8”;
break;
}
/* Logon now without any idle timeout (0). */
/* The network connection is retained until logoff. */
attr.setInt(attr.IDLETIMEOUT, 0);
s_session = new JoltSession(attr, username, userrole,
userpasswd, applpasswd);
}
public static void main( String args[] )
{
String host;
short port;
JoltRemoteService svc;
if (args.length != 2)
{
System.err.println(“Usage: reuseSample host port”);
System.exit(1);
}
/* Get the host name and port number for initialization. */
host = args[0];
port = (short)Integer.parseInt(args[1]);
init(host, port);
/* Get the object reference to the DELREC service. This
* service has no output parameters, but has only one input
* parameter.
*/
svc = new JoltRemoteService(“DELREC”, s_session);
try
{
/* Set input parameter REPNAME. */
svc.addString(“REPNAME”, “Record1”);
svc.call(null);
/* Change the input parameter before reusing it */
svc.setString(“REPNAME”, “Record2”);
svc.call(null);
/* Simply discard all input parameters */
svc.clear();
svc.addString(“REPNAME”, “Record3”);
svc.call(null);
}
catch (ApplicationException e)
{
System.err.println(“Service DELREC failed: “+
e.getMessage()+” “+ svc.getStringDef(“MESSAGE”, null));
}
/* Logoff now and get rid of the object. */
s_session.endSession();
}
}
次の「Joltリモート・サービスを拡張する(extendSample.java)」は、JoltRemoteServiceクラスをサブクラス化する1つの方法を示しています。この例では、JoltRemoteServiceクラスをサブクラス化してTransferServiceクラスを作成します。TransferServiceクラスはJoltRemoteServiceクラスを拡張し、Oracle TuxedoのBANKAPPのTRANSFERサービスを利用するTransfer機能を追加しています。
リスト5-14では、Java言語のextends
キーワードが使用されています。extends
キーワードは、Javaでベース(親)クラスをサブクラス化するために使用されています。次のコードは、JoltRemoteServiceを拡張する方法の1つを示しています。
/* Copyright 1999 Oracle Systems, Inc. All Rights Reserved */
import java.net.*;
import java.io.*;
import bea.jolt.*;
/*
* This Jolt sample code fragment illustrates how to customize
* JoltRemoteService. It uses the Java language “extends” mechanism
*/
class TransferService extends JoltRemoteService
{
public String fromBal;
public String toBal;
public TransferService( JoltSession session )
{
super(“TRANSFER”, session);
}
public String doxfer( int fromAcctNum, int toAcctNum, String amount )
{
/* Clear any previous input parameters */
this.clear();
/* Set the input parameters */
this.setIntItem(“ACCOUNT_ID”, 0, fromAcctNum);
this.setIntItem(“ACCOUNT_ID”, 1, toAcctNum);
this.setString(“SAMOUNT”, amount );
try
{
/* Invoke the transfer service. */
this.call(null);
/* Get the output parameters */
fromBal = this.getStringItemDef(“SBALANCE”, 0, null);
if (fromBal == null)
return “No balance from Account “ +
fromAcctNum;
toBal = this.getStringItemDef(“SBALANCE”, 1, null);
if (toBal == null)
return “No balance from Account “ + toAcctNum;
return null;
}
catch (ApplicationException e)
{
/* The transaction failed, return the reason */
return this.getStringDef(“STATLIN”, “Unknown reason”);
}
}
}
class extendSample
{
public static void main( String args[] )
{
JoltSession s_session;
Stringhost;
short port;
TransferService xfer;
String failure;
if (args.length != 2)
{
System.err.println(“Usage: reuseSample host port”);
System.exit(1);
}
/* Get the host name and port number for initialization. */
host = args[0];
port = (short)Integer.parseInt(args[1]);
/* Prepare to connect to the Tuxedo domain. */
JoltSessionAttributes attr = new JoltSessionAttributes();
attr.setString(attr.APPADDRESS,”//”+ host+”:” + port);
String username = null;
String userrole = “sw-developer”;
String applpasswd = null;
String userpasswd = null;
/* Check what authentication level has been set. */
switch (attr.checkAuthenticationLevel())
{
case JoltSessionAttributes.NOAUTH:
break;
case JoltSessionAttributes.APPASSWORD:
applpasswd = “secret8”;
break;
case JoltSessionAttributes.USRPASSWORD:
username = “myName”;
userpasswd = “BEA#1”;
applpasswd = “secret8”;
break;
}
/* Logon now without any idle timeout (0). */
/* The network connection is retained until logoff. */
attr.setInt(attr.IDLETIMEOUT, 0);
s_session = new JoltSession(attr, username, userrole,
userpasswd, applpasswd);
/*
* TransferService extends from JoltRemoteService and uses the
* standard Oracle Tuxedo BankApp TRANSFER service. We invoke this
* service twice with different parameters. Note, we assume
* that “s_session” is initialized somewhere before.
*/
xfer = new TransferService(s_session);
if ((failure = xfer.doxfer(10000, 10001, “500.00”)) != null)
System.err.println(“Tranasaction failed: “ + failure);
else
{
System.out.println(“Transaction is done.”);
System.out.println(“From Acct Balance: “+xfer.fromBal);
System.out.println(“ To Acct Balance: “+xfer.toBal);
}
if ((failure = xfer.doxfer(51334, 40343, “$123.25”)) != null)
System.err.println(“Tranasaction failed: “ + failure);
else
{
System.out.println(“Transaction is done.”);
System.out.println(“From Acct Balance: “+xfer.fromBal);
System.out.println(“ To Acct Balance: “+xfer.toBal);
}
}
}
Joltクラス・ライブラリを使うと、クライアントのWebブラウザから実行するJavaアプリケーションを作成することができます。この種のアプリケーションを作成するには、次のアプリケーション開発作業を行います。
次の項では、アプリケーションを開発する際のこれらの注意点について説明します。
Joltアプレットをデプロイするときは、次の要件を検討してください。
JoltアプリケーションでOracle TuxedoサーバーとJoltサーバーを使うための構成については、Oracle Tuxedoシステムのインストールを参照してください。次の項では、Joltアプレットをデプロイする際に一般的にクライアントやWebサーバーで考慮すべき点について説明します。
Joltクラスを使用してJavaアプレットを記述すると、HTMLページで動作するJavaアプレットと同じように機能します。JoltアプレットはHTMLアプレットのタグを使用してHTMLページに埋め込むことができます。
<applet code=“applet_name.class”> </applet>
JoltアプレットをHTMLページに埋め込むと、HTMLページのロード時にアプレットがダウンロードされます。アプレットは、ダウンロード直後に実行されるように記述することができます。また、ユーザーによる操作の実行時、タイムアウト値の到達時、または指定した間隔で実行されるようにコードを記述することもできます。さらに、アプレットのダウンロード時に別のウィンドウが開かれるように設定したり、指定した間隔で周期的に音楽を鳴らすこともできます。プログラマは、アプレットを最初にコーディングする際に、さまざまな設定を行うことができます。
注意: | 新しいHTMLページをブラウザにロードすると、アプレットの実行が停止します。 |
JavaアプレットでJoltクラスを使用する場合、WebサーバーにJoltリレーがインストールされていない限り、JoltサーバーとWebサーバー(Javaアプレットのダウンロード元のWebサーバー)は同じマシンで実行する必要があります。
Web管理者がWebサーバーをセットアップすると、すべてのHTMLファイルの格納先ディレクトリが指定されます。指定されたディレクトリに「classes」という名前のサブディレクトリを作成し、Javaクラスのすべてのファイルとパッケージを格納してください。例:
<html-dir>/classes/bea/jolt
または、すべてのJoltクラスを含むjolt.jar
ファイルを指すようにCLASSPATH
を設定することもできます。
注意: | Joltクラスのサブディレクトリは、任意の場所に置くことができます。アクセスしやすいようにHTMLファイルと同じディレクトリに置くと便利です。Joltクラスのサブディレクトリに関する唯一の条件は、Webサーバーで利用できることです。 |
JoltアプレットのHTMLファイルは、jolt.jar
ファイルまたはclasses
ディレクトリを参照している必要があります。例:
/export/html/
|___ classes/
| |_____ bea/
| | |______ jolt/
| | |_____ JoltSessionAttributes.class
| | |_____ JoltRemoteServices.class
| | |_____ ...
| |_____ mycompany/
| |________ app.class
|___ ex1.html
|___ ex2.html
Web管理者は、次のようにex1.html
に「app」アプレットを指定することができます。
<applet codebase=“classes” code=mycompany.app.class width=400 height=200>
Joltアプリケーションを多言後で使用する場合は、ローカライズに関わる問題を考慮する必要があります。クライアント側のWebブラウザで実行するアプリケーション、およびWebブラウザ環境以外で実行するよう設計されたアプリケーションの両方でこの問題を考慮する必要があります。ローカライズの作業は次の2つです。
ローカライズの際、Joltクラス・ライブラリのパッケージは、Java言語およびOracle Tuxedoシステムの仕様に従います。JoltはJavaの16ビットUnicode文字をJSHに転送します。JSHには、Unicodeをローカルな文字セットに変換するメカニズムが組み込まれています。
UnicodeのJava実装および文字エスケープの詳細は、Java Development Kit (JDK)のドキュメントを参照してください。
Joltでは、デフォルトのリンク・レベルの暗号化のかわりに、安全な優先トランスポート・メカニズムとしてSSLを使用できます。JoltでSSLを使用できるようにするには、JSLに対してTUXEDO UBBCONFIGファイルで「-s secure_port」を構成する必要があります。
JSL接続ポートがSSLポートである場合、Joltクライアント・ライブラリは自動的にSSLを選択します。SSLの場合、Joltクライアントは、X.509証明書の場所、秘密鍵、パスフレーズの暗号化に使用されるパスフレーズなどの情報を提示する必要があります。
これらの要件に対応するために、JoltSessionAttributesに5つの属性が追加されています。
Joltクライアント・ライブラリでは、SSL通信に対応するサード・パーティのJava Secure Socket Extension (JSSE)実装を使用します。以下のJSSE実装がテスト済みです。
リスト5-15は、JSL/JSHとの通信時にSSLを使用できるようにするためのJoltクライアント・コードのサンプルです。
import java.util.*;
import bea.jolt.*;
public class simpcl extends Object {
private String userName = null;
private String userRole = null;
private String appPassword = null;
private String userPassword = null;
private JoltSessionAttributes attr = null;
private JoltSession session = null;
private JoltRemoteService toupper = null;
private JoltTransaction trans = null;
// JSL is configured with '-s 5555'
// the communication between jolt client and JSH will use SSL
private String address = new String('//cerebrum:5555');
public static void main(String args[]) {
simpcl c = new simpcl();
c.doTest();
}
public void doTest() {
attr = new JoltSessionAttributes();
// adding these session attribute
attr.setString(attr.APPADDRESS, address);
attr.setString(attr.TRUSTSTORE,'c:\\samples\\samplecacerts');
attr.setString(attr.KEYSTORE, 'c:\\samples\\client\\testkeys');
// Only key store and key will be protected by passphrase in this sample.
// But optionly the trust store can also be protected by a passphrase
// although it is not in this sample.
attr.setString(attr.KSPASSPHRASE, 'passphrase');
attr.setString(attr.KEYPASSPHRASE, 'passphrase');
attr.setInt(attr.IDLETIMEOUT, 300);
userName = 'juser';
userRole = 'JUSER';
userPassword = 'abcd';
appPassword = 'abcd';
session = new JoltSession(attr, userName, userRole, userPassword,
appPassword);
// access a Tuxedo TOUPPER service
toupper = new JoltRemoteService('TOUPPER', session);
toupper.addString('STRING', 'string');
trans = new JoltTransaction(60, session);
try {
toupper.call(trans);
} catch (ApplicationException ae) {
ae.printStackTrace();
System.exit(1);
}
String retString = toupper.getStringDef('STRING', null);
trans.commit();
System.out.println(' returned: ' + retString);
session.endSession();
return;
}
}