CORBA の機能はすべてインターフェースから始まります。インターフェースについて考える一番良い方法は、皆さんの車を想像することです。そうです、日頃運転されている皆さんの 車です。インターフェースという言葉にはなじみがないかもしれませんが、「わたしの車を使って、お昼のサンドイッチを取ってきてくれ」と言われた場合、自分が他人の車を運転することができるかどうか、ということは自問しません。気になるのは、どこに駐車するかや、安全運転できるかということですが、他人の車を運転することは、自分の車を運転することと同じだ、と思うはずです。人と車のインターフェースは非常に標準化されており、車によって異なることはまずないからです。セダンとスポーツ・カーという違いはあるかもしれませんか、アクセル、ブレーキ、ハンドルの位置はどの車も同じであるため、簡単に、何の苦労もなく運転できるはずです。
CORBA は言語に依存していないので、クライアントが、インターフェースを実装するサービスを要求する方法を表す場合には、インターフェース定義言語 (IDL) を利用します。ここで示すインターフェースは 1 つのメソッドadd() です。このメソッドは、2 つの数値 (IDL long 型) を取り、それらの数値の和を戻します。次に、インターフェース calculator を示します。
リスト 1. calcsimpl.idl
module corbasem {
module gen {
module calcsimpl {
interface calculator {
long add(in long x, in long y);
};
};
};
}; |
このインターフェースでの IDL キーワードは、module、interface、long、および in です。IDL はmodule キーワードを使用してネーム・スペースを作成し、非常に正確に Java キーワードpackage にマップします。IDL - Java コンパイラーを実行すると、生成された Java ファイルは、calcsimpl という名前のサブディレクトリーに挿入されます。IDL キーワードinterface は、Java インターフェースに完全にマップし、どちらの場合もオブジェクトとの通信方法しか定義しない抽象的な型を表します。つまり、オブジェクトの実装に関する情報は示されません。IDL キーワードlong は、最低 4 バイトの型、つまり Java コードでは int 型にマップする基本的な整数型です。
リモート・メソッド呼び出しを作成する機能について考える場合は、パラメーターが移動する方向、つまりクライアントからサーバーの方向、サーバーからクライアントの方向、またはその両方向を定義することだと考えれば間違いありません。IDL の操作では、これらはin キーワード、out キーワード、およびinout キーワードで宣言します。すべてのパラメーターの方向を宣言しなければならないので、オブジェクト・リクエスト・ブローカー (ORB) は、パラメーターが移動する方向を認識します。これは、送信するパラメーターのパック、パラメーターのアンパック、およびメモリー管理に影響します。ORB は、パラメーターについて認識している情報が多いほど、効率的になることができます。キーワードin は、long x とlong y をクライアントからサーバーに渡すことを表します。
図 1. CORBA 要求の参加プログラム
インターフェースを定義し終えたら、ORB ベンダー提供の IDL - Java コンパイラーを介して実行しなければなりません。IDL コンパイラーは、IDL スタブやスケルトン、およびその他のサポート・ファイルを生成するすばらしいユーティリティーです。これらの生成された大半のソース・ファイルで、CORBA 標準で定義されている、指定された IDL 型のマーシャルの一部が簡易化されます。コンパイラーにより、分散環境では大掛かりな、ネットワーク・プラミングの大半が生成されます。最も簡単に言えば、IDL - Java コンパイラーは、CORBA 2.3 仕様に定義されているとおりに IDL から Java への言語マッピングを実装する単なるプログラムにすぎません。このコードを手動で生成するとなると、面倒で時間もかかり、間違いも起こりやすくなります。こうしたことはすべて IDL - Java コンパイラーが処理してくれるので、何も行う必要はありません。同時に、このコンパイラーを使用すれば、自動的に特定の仕様に準拠して、カプセル化が実行されます。IDL - Java コンパイラーにより、システムは強制的に CORBA 世界の法律に従うことになるわけです。
Orbacus の IDL - Java コンパイラーを実行するために次のコマンドを入力しました。生成されるすべてのファイルの宛先は、CLASSPATH 内の出力ディレクトリーです。
jidl --output-dir c:\_work\corbasem calculator.idl |
何が生成されましたか。実装の構築のベースとなる Java ソース・ファイルはすべて、このコマンドによって生成されます。IDL - Java コンパイラーにより、定義されているインターフェースは、CORBA 仕様により設定された規則に確実に従うことになります。
図 2. IDL - Java コンパイラーによるファイル生成
次に、ファイルを示します。
- calculator.java - このファイルは、シグニチャー・インターフェース・ファイルと言います。CORBA 仕様では、このファイルは IDLEntity を拡張したもので、名前は IDL インターフェース名と同じでなければならないと明記されています。このファイルは、型シグニチャーを提供するので、このインターフェースは、他のインターフェースのメソッド宣言に使用することができます。
-
calculatorOperations.java - このファイルには、Java パブリック・インターフェースである calculatorOperations が入っています。仕様では、このファイルの名前は、IDL インターフェース名と同じで、拡張子は
Operationsでなければならず、ファイルには、インターフェース用のマップ済みオペレーション・シグニチャーが入っていると明記されています。上記に定義されているシグニチャー・インターフェース (calculator.java) は、このインターフェースを拡張したものです。 -
calculatorHelper.java - ヘルパー・クラスは、必要なハウスキーピング機能の多くをインターフェースからは除外するけれども、実装では簡単に利用できるように作られています。ヘルパー・ファイルには、
org.omg.CORBA.Objectの範囲を、より特定の型 (この場合は、calculator の型) のオブジェクト・リファレンスに制限することができる、重要な静的 narrow メソッドが入っています。 - calculatorHolder.java - ホルダー・クラスは、参照で受け渡さなければならないすべての型に対して生成される、特殊なクラスです。この例ではホルダー・クラスは使用しませんが、今後、使うケースがよくあるでしょう。
-
calculatorPOA.java - スケルトン・クラスは、CORBA 機能の要求応答プラミングの多くを提供します。デフォルト実装は継承ベースであるため、
calculatorPOA.javaが生成されます。代理ベースの実装を選択した場合の出力は異なります。このトピックについては、また次の機会に詳しく説明します。 - _calculatorStub.java - 名前からわかるように、これはスタブ・クラスです。このクラスがなければ、クライアントは何も動作することができません。
生成されたファイルは、インターフェースを実装しているサーバーに送り、そこで動作させなければなりません。うれしいことに、プラミングの多くは自動的に実行されますが、すぐに喜ぶわけにはいきません。実行すべき作業はまだたくさんあります。すなわち、これらのファイルはすべて正しい場所で使用しなければなりません。
まず、メソッドadd() の実装から始めましょう (SimpleCalcSvr.java ファイルを完全な形でダウンロードできます)。
SimpleCalcServant extends calculatorPOA {
public int add(intx, inty) {
return x + y;
}
} |
実装クラスは、生成されたクラスcalculatorPOA を拡張したものであることに注意しましょう。クライアントから要求が送られると、その要求は、ORB を介してスケルトンに入ります。スケルトンは、SimpleCalcServant を呼び出して、要求を完了し、応答を開始します。このインターフェースは簡単だったので、実装も簡単です。
サーバーのその他の部分を実装するには、このインターフェース実装のまわりに CORBA アーキテクチャーを設定する必要があります。移植性と柔軟性の理由から、これらの呼び出しの多くは CORBA 仕様で指定します。
最初に実行しなければならないタスクは、どの ORB を使用したいかを詳細に指定し、それを初期設定することです。このタスクを処理するのは、次のコード (ファイルSimpleCalcSvr.java 内の行 18 ~ 29) です。
java.util.Propertiesprops = System.getProperties();
props.put("org.omg.CORBA.ORBClass",
"com.ooc.CORBA.ORG");
props.put("org.omg.CORBA.ORBSingletonClass",
"com.ooc.CORBA.ORBSingleton");
org.omg.CORBA.ORBorb =null;
// initialize the ORB
orb = org.omg.CORBA.ORB.init(args, props); |
ORB を初期設定する場合は、どのクラスが ORBClass クラスの役割を果たし、どのクラスが ORBSingleton の役割を果たしているかを ORB に正確に伝える必要があります。この実装では関係ありませんが、関連するプラミングすべてに必要です。前に説明したように、この例では、Object Oriented Concepts, Inc. の Orbacus ORB を使用しています。OOC クラスは、2 つのprops.put() 呼び出しで提供されます。プロパティーを指定したら、props をパラメーターとしてORB.init() メソッドに渡します。実際には、状況は異なります。このサーバーを別の ORB に移動したい場合、サーバーを再コードしたくはないでしょう。そのため、理論上は、別の ORB クラスを指すように構成ファイルを変更して、再始動するだけですませたいわけです。
ORB を所定の位置に配置し、初期設定し、実装は適正な場所にありますが、まだ作成していません。この時点で、実装を配置する正確な場所を作成する必要があります。これは、思ったほど簡単ではありません。分散環境では、実装ごとに、環境的なわずかな違いが必要になることがあります。実装に提供できる特性はたくさんあります。単一スレッドでも、マルチスレッドでも、また非常にスケーラブルなオブジェクトのブールでも、シングルトンでも構いません。このようにサーバー特性が多様であることから、ポータブル・オブジェクト・アダプター (POA) が作成されました。POA を利用することで、常駐する実装に適した完全な環境を作り出すことができます。2.3 準拠のすべての ORB には、ルート以外のすべての POA を作成する元となるルート POA があります。この簡単な例では、実装固有のコードを切り離し、独自のメソッドruncalc() にしました。
実装に適した環境を作成することが最初のタスクであるので、POA を設定しなければなりません。本来、CORBA サーバーは基本オブジェクト・アダプター (BOA) を使用していましたが、BOA はベンダーごとにすべて異なります。CORBA 仕様の最新版では、BOA は完全に POA に置き換えられています。
// setup the Portable Object Adapter
// from the always present rootPOA
org.omg.PortableServer.POArootPOA =
org.omg.PortableServer.POAHelper.narrow(
orb.resolve_initial_references("RootPOA"));
org.omg.PortableServer.POAManagermanager =
rootPOA.the_POAManager(); |
タイトルと定義によれば、これは簡単な例です。新しい POA を作成するのではなく、ルート POA を使用することで、単純さを保っています。POA マネージャーは、POA の処理状態をカプセル化するオブジェクトです。したがって、POA マネージャーを使用して、サーバントへの要求のキュー作成を開始します。
次に、実装のインスタンスを生成しなければなりません。
// create servant for calculator interface
SimpleCalcServantcalcSvt =new SimpleCalcServant();
calculatorcalc = calcSvt._this(orb); |
CORBA 2.3 仕様に従い、すべてのスケルトンは_this() メソッドを提供し、サーバントは、このメソッドにより、これらの要求に関連付けられているターゲット CORBA オブジェクトのオブジェクト・リファレンスを取得することができます。
実装のインスタンスの生成が終了したら、機能を、クライアントが見つけることができる場所に配置しなければなりません。インターフェースへの要求を満たすオブジェクトを探す場合に利用できるメソッドやサービスはたくさんあります。CORBA サービスでは、特にクライアントが要求を処理するオブジェクトを探す場合に役立つ、命名サービスとトレーダー・サービスが定義されています。オブジェクトは、メソッドの呼び出しでも渡すことができます。
この例では、中でも一番簡単なメソッド、つまり、クライアントが選択するファイルのオブジェクト・リファレンスを作成する方法を使用します。オブジェクト・リファレンスのストリング表現の作成、およびその逆のストリングからオブジェクト・リファレンスの作成は、すべての ORB に必要な機能です。
// write the object reference to a file
PrintWriterrefstr =new PrintWriter(
new FileWriter("calcref.ior"));
refstr.println(orb.object_to_string(calc));
refstr.close(); |
最後に実行するのは、POA をアクティブにして、クライアント要求のキューの作成を開始し、サーバーをそのイベント・ループに入れて、これらの着信要求を受け取らせることです。
リスト 8. SimpleCalcSvr.java -- Activate POA
// make the implementation available
manager.activate();
System.out.println("SimpleCalcSvr is running!");
orb.run(); |
発生しているもののしくみを考える場合は、クライアントとサーバーは実際には互いのイメージをミラーしている、ということを理解しなければなりません。クライアントは、すべてのパラメーターをパックし、要求を送信することで、要求を作成します。サーバーは、要求のパラメーターをアンパックし、操作を実行し、戻り値とアウト・パラメーターをパックして、応答をクライアントに戻すだけです。クライアントは、戻り値とアウト・パラメーターをアンパックし、処理を続けます。したがって、クライアントがパッケージしたものは、サーバーがアンパックし、サーバーがパッケージしたものは、クライアントがアンパックすることになります。
つまり、クライアントとサーバーの構造は似ていると考える必要があります。クライアントは ORB の作成と初期設定も行わなければなりません。ORB は、例で使用していたのと同じ ORB でも、別のベンダーの ORB でも構いません。ただし、ORB なら何でもよいわけではありません。IIOP、つまりオブジェクト管理グループ (OMG) で定義されている TCP/IP ベースのインターオペラビリティー・プロトコルをサポートする ORB でなければなりません。古い ORB の場合は、他の ORB とやり取りしない可能性があるので、注意してください。
まず、サーバーの場合と同じように、ORB を作成します (完全なSimpleCalcClient.java ファイルをダウンロードできます)。
リスト その 9. SimpleCalcClient.java -- ORB の初期設定
java.util.Propertiesprops = System.getProperties();
props.put("org.omg.CORBA.ORBClass",
"com.ooc.CORBA.ORG");
props.put("org.omg.CORBA.ORBSingletonClass",
"com.ooc.CORBA.ORBSingleton");
org.omg.CORBA.ORBorb =null;
// initialize the ORB
orb = ORB.init(args, props);
|
見たことがありますね。サーバーとまったく同じです。これでクライアントは ORB に接続しますが、目標は、システム内のどこかにあるサービスを呼び出すことです。要求を満たすオブジェクトを探す必要があります。この例では、サーバーで作成したファイルからオブジェクト・リファレンスを取得します。calculator サーバーを探すには、ファイルに格納されているオブジェクト・リファレンスのストリング・バージョンを取得して、呼び出しで使用できるオブジェクト・リファレンスに変換します。
リスト 10. SimpleCalcClient.java -- Get object reference
System.out.println("Getting reference from string...");
BufferedReaderin = new BufferedReader(
new FileReader("calcref.ior"));
Stringior = in.readLine();
in.close();
calculatorcalc = calculatorHelper.narrow(
orb.string_to_object(ior));
|
IDL - Java コンパイラーによって生成されたcalculatorHelper クラスの使用には注意してください。
calcref.ior ファイルには、calculator のリファレンスではないオブジェクト・リファレンスが含まれています。
calculatorHelper クラスの narrow メソッドを使用して、抽象的な型の焦点を特定の calculator 型に当てます。
calculatorcalc によく注意してください。これは、サイバースペース内のどこかにあるサーバーを表しています。最後にすることは、calc 上でメソッドadd() を呼び出すことです。
リスト 11. /software/developer/library/exploring-corba/simplecalcclient.java -- Invoke add()
System.out.println( calc.add(2,3) ); |
いろいろと説明してきましたが、ここでまとめましょう。クライアントは、サーバーから完全に切り離されています。クライアントは、どのようなハードウェアが実行されているか、どのようなオペレーティング・システムが使用されているか、どのような言語で作成されているか、マルチスレッドであるかどうか、また、どこに配置されているか (隣の部屋にあるか、地球に反対側にあるか) といったことを知りません。クライアントが知っているのは、calc でadd() を呼び出すと、必要な応答を取得できる、ということだけです。
これは、電話会社や電気会社のようなサービスの提供とまったく同じです。電話を取れば、発信音が聞こえ、呼び出しに対応する正確な接続が得られます。呼び出しが光ファイバー・ケーブルを介して転送されたか、衛星を経由したか、といったことは関係ありません。同じことは、情報産業にも当てはまります。OMG とインフラストラクチャーのおかげで、簡単ですが、非常に強力な例を取り入れることができました。
来月は、もう少し掘り下げて、表面下で発生している IIOP のマジックについて説明します。
-
CORBA についての詳細は、OMG の Web サイトを参照してください。
- Java プログラミングについては、Bruce Eckel のMindview.net およびThinking in Java の第 2 版を参照してください。
- 前回の CORBA ジャンクションのコラム「法律と自由: CORBA と Java テクノロジーをなぜ選ぶのか (Laws and liberties: Why choose CORBA and Java technology?)」を参照してください。

ペンシルベニア州、ベルウィン (Berwyn) 在住。Dave Bartlett は、独立系コンサルタントであると同時に、フリーランスの作家およびインストラクターです。大学の授業や社内で行われる 5 日間コースのHands-On CORBA with Java の作者です。現在、Dave は、このコース教材をThinking in CORBA with Java という 1 冊の本にまとめています。ペンシルベニア州立大学でエンジニアリングおよびビジネスの博士号を取得しています。メール・アドレスは dbartlett@pobox.com です。