IDLは、リモートに存在するオブジェクトへメッセージを送る(オペレーションを起動する)ためのインタフェースです。CORBAにおけるORBはリモートへのオペレーションを要求するクライアントと、実際にオペレーションの処理を実行するCORBAオブジェクトとの間を結ぶ仲介人(ブローカ)です。
サーバ側にはCORBAオブジェクトがあります(あるようにクライアントからは見えます)。CORBAオブジェクトは、IDLで定義されオブジェクトリファレンスで識別されます。クライアントからのCORBAオブジェクトに対するオペレーション要求は、ORBを通してサーバへ送られ、POAによってサーバントへ伝送(ディスパッチ)され、サーバントのメソッドが起動されます。また、サーバ上にはPOAマネージャ、サーバント・マネージャといった役者がいます。このようにサーバには、たくさんの登場人物がいるので最初は混乱してしまいます。
ここでは、簡単なIDLのCounterインタフェースを持つCORBAオブジェクトをサーバとして提供するプログラムを作成していきながら、サーバ側のCORBAプログラミングを見ていきましょう。
簡単なカウンタは、4つのオペレーションを定義します。Javaのパッケージ規約に合わせてmoduleを定義するために、#pragma prefixを利用してモジュールのネストを避けています。
#pragma prefix "idl.learn.torutk.java_conf.gr.jp" module counter_ex1 { interface Counter { void increment(); void decrement(); void setCount(in long aCount); long getCount(); }; }; |
このファイルを、開発ディレクトリ(D:\develop\ex1)に置きます。
d:\develop\ex1\ |
|
Counter.idl |
IDLコンパイラを実行し、IDLファイルからJavaのスタブ、スケルトンファイルを生成します。
ここでは、あらかじめidl2java.batを作成したものを実行しています。idl2java.batについては、OpenORB TipsページのIDLコンパイラ項をご覧下さい。
D:\develop\ex1>idl2java Counter.idl OpenORB IDL Compiler / (c) 2000-2001 Exolab.org compile : Counter.idl D:\develop\ex1> |
IDLコンパイラ実行後の開発ディレクトリの内容は以下のとおりです。generatedというディレクトリの下に、パッケージ名に対応するディレクトリが作成され、Javaのソースファイルが生成されます。
d:\develop\ex1\ | ||
Counter.idl | ||
d:\develop\ex1\generated\jp\gr\java_conf\torutk\learn\idl\counter_ex1\ | ||
Counter.java | ||
CounterHelper.java | ||
CounterHolder.java | ||
CounterOperations.java | ||
CounterPOA.java | POA継承方式で使用 | |
CounterPOATie.java | POA委譲方式で使用 | |
_CounterStub.java |
IDLを実装(実現)するクラスとしてSimpleCounter.javaを記述します。IDLを実装するには、次の2つの方法があります。
POA継承方式で実装する場合は、CounterPOAクラスを継承し、IDLで定義したオペレーションのJavaマッピングであるinterface CounterOperationsで定義されるメソッドを実装します。
package jp.gr.java_conf.torutk.learn.idl.counter_ex1; public class SimpleCounter extends CounterPOA { private int count = 0; public void increment() { count++; } public void decrement() { count--; } public void setCount(int aCount) { count = aCount; } public int getCount() { return count; } }// SimpleCounter |
SimpleCounter.javaは、開発ディレクトリの下に直接パッケージ名に対応するディレクトリを作成して置くことにします。(srcというディレクトリを作ってもよいでしょう)
d:\develop\ex1\ | ||
Counter.idl | ||
d:\develop\ex1\jp\gr\java_conf\torutk\learn\idl\counter_ex1\ | ||
SimpleCounter.java | IDLを実装するクラス | |
d:\develop\ex1\generated\jp\gr\java_conf\torutk\learn\idl\counter_ex1\ | ||
Counter.java | IDLコンパイラで生成されたファイル | |
CounterHelper.java | ||
CounterHolder.java | ||
CounterOperations.java | ||
CounterPOA.java | ||
CounterPOATie.java | ||
_CounterStub.java |
CORBAオブジェクトを生成し、クライアントからのリクエストに応答できるようにセットアップを行うサーバ・プログラムを記述します。サーバは以下の作業を実行します。
package jp.gr.java_conf.torutk.learn.idl.counter_ex1; import org.omg.CORBA.ORB; import org.omg.CosNaming.NameComponent; import org.omg.CosNaming.NamingContext; import org.omg.CosNaming.NamingContextHelper; import org.omg.PortableServer.POA; import org.omg.PortableServer.POAHelper; import org.omg.PortableServer.POAManager; public class Server { public static void main(String[] args) { |
|
ORB orb = ORB.init(args, null); |
ORBの起動 |
org.omg.CORBA.Object objPoa = null; POA rootPoa = null; try { objPoa = orb.resolve_initial_references("RootPOA"); rootPoa = POAHelper.narrow(objPoa); } catch (org.omg.CORBA.ORBPackage.InvalidName e) { System.out.println("RootPOAの名前が正しくありません"); System.exit(1); } if (rootPoa == null) { System.out.println("POAのオブジェクト参照が取得できません"); System.exit(1); } |
RootPOAの取得(注1) |
// Servantの作成 SimpleCounter counter = new SimpleCounter(); org.omg.CORBA.Object counterRef = null; try { rootPoa.activate_object(counter); counterRef = rootPoa.servant_to_reference(counter); } catch (Exception e) { System.out.println("Counterオブジェクト作成でエラー"); e.printStackTrace(); System.exit(1); } |
サーバントの生成 サーバントをRootPOAに結び付け サーバントのオブジェクトリファレンス作成 |
// ルートネーミングコンテクストオブジェクトの取得 org.omg.CORBA.Object objNs = null; try { objNs = orb.resolve_initial_references("NameService"); } catch (org.omg.CORBA.ORBPackage.InvalidName e) { System.out.println("ネームサービスの名前が正しくありません"); e.printStackTrace(); System.exit(1); } NamingContext rootNameContext = NamingContextHelper.narrow(objNs); if (rootNameContext == null) { System.out.println("ルートネーミングコンテクストが空です"); System.exit(1); } |
ネーミングサービスの取得 |
// NamingServiceへの登録 // カウンタアオブジェクトのネームコンポーネント作成 NameComponent[] counterNameComponent = new NameComponent[1]; counterNameComponent[0] = new NameComponent("TheCounter", "Object"); try { rootNameContext.rebind(counterNameComponent, counterRef); } catch (Exception e) { System.out.println("ネームサービス登録でエラー発生"); e.printStackTrace(); System.exit(1); } |
ネーミングサービスへの登録 |
// POAマネージャの活性化 POAManager poaManager = rootPoa.the_POAManager(); try { poaManager.activate(); System.out.println("activated POA Manager"); } catch (org.omg.PortableServer.POAManagerPackage. AdapterInactive e) { System.out.println("POAマネージャの活性化に失敗"); e.printStackTrace(); System.exit(1); } |
POAマネージャの取得と活性化 |
// クライアントからの要求の待ち合わせ System.out.println("Waiting request from client"); try { orb.run(); } catch (Exception e) { e.printStackTrace(); } } } // Server |
クライアントからの要求待ちイベントループ |
ORBの起動ページを参照。
POA(Portable Object Adapter)は、オブジェクトアダプタの一種です。オブジェクトアダプタは、ORBからリクエストを受け、リクエストを処理するメソッドを呼びだします。
POAは複数用意することができます。RootPOAと呼ばれるPOAをルートとした階層構造を取ります。POAごとにポリシーと呼ばれる様々な挙動を指定できます。ただし、RootPOAだけは既にポリシーが決められています。
注1) SunのJDK1.4標準搭載CORBAであるJavaIDLでは、POAHelperが含まれていません。そこで、
objPoa = orb.resolve_initial_references("RootPOA"); rootPoa = (POA)objPoa;
と単にキャストします。
CORBAオブジェクトとは、IDLで定義されたインタフェースを持つ仮想的なオブジェクトです。IDLで定義されたインタフェースへの要求は、実際にはサーバントと呼ばれるプログラミング言語で記述されたコードによって実行されます。
サーバントはIDLで定義されたインタフェースを持つCORBAオブジェクトの実体(実装)で、Javaの場合はPOA継承方式の場合はPOAを継承したクラスのインスタンスを生成します。
ORBは、CORBAオブジェクトに対するオペレーション要求を受け取ると、POAにディスパッチします。POAは、サーバントを管理しているので、どのサーバントを起動すればよいかを調べて呼び出します。そこで、サーバントを生成した後はサーバントをPOAに登録します。
オブジェクトをクライアントから呼び出すためには、クライアントがそのオブジェクトリファレンスを何らかの方法で獲得できるようにする必要があります。ここでは、ネーミングサービスを使用する場合のサーバ側のコーディングを示しています。他の方法については、Client Sideページのオブジェクトリファレンスの獲得の項を参照。
ネーミングサービスにサーバントを登録します。ネーミングサービスは、名前情報とCORBAオブジェクトのリファレンスを対応付けて管理しています。名前情報は木構造となっており、大量の名前情報を管理できる構造となっています。名前情報を表すのにNameComponentクラスが使われます。
Interoperable Naming Serviceで追加されたNamingContextExt型を使うとコーディングが簡単になります。
NamingContext型を使用 | NamingContextExt型使用 |
---|---|
NamingContext rootNameContext = NamingContextHelper.narrow(objNs); |
NamingContextExt rootNameContext = NamingContextExtHelper.narrow(objNs); |
NameComponent[] counterNameComponent = new NameComponent[1]; counterNameComponent[0] = new NameComponent("TheCounter", "Object"); |
NameComponent[] counterNameComponent = rootNameContext.to_name("TheCounter.Object"); |
POAマネージャは、クライアントからの要求をPOAへ結びつける役割を持ち、クライアントからの要求をキューイングしたり転送したり破棄したりします。POAマネージャ自体は、POAの作成時に暗黙的に作成されます。POAマネージャjの初期状態は、クライアントからの要求をPOAには転送せずにキューイングするHOLDING状態なので、activateメソッドを呼ぶことによってクライアントからの要求をPOAに転送するACTIVE状態へ遷移させます。
クライアントからの要求を受け付けるためのイベントループを実行します。
サーバプログラムを実行するには、先にネーミングサービスを実行している必要があります。サーバプログラムを実行する際に、先に起動したネーミングサービスのオブジェクトリファレンス情報をコマンドラインオプションで指定します。
ネーミングサービスの指定 | -ORBInitRef NameService=<オブジェクトURL> |
ネーミングサービスの起動については、使用しているCORBA製品によって異なります。OpenORBの提供するネーミングサービスについては、OpenORB TipsページのNaming Service項を参照。
D:\develop\ex1\classes>java jp.gr.java_conf.torutk.learn.idl.counter_ex1.Ser ver -ORBInitRef NameService=corbaloc:iiop:1.2@nameserver:5555/NameService |