ORB の輪

〜 第二回 〜

株式会社 オージス総研
UML ソリューション部
永田 博靖
Nagata_Hiroyasu@ogis-ri.co.jp

目次

1. はじめに
2. システム構成
3. CORBA オブジェクト
4. ネーミングサービス
5. サーバの実装:名前の登録 ( VisiBroker,JacORB )
5-1. サーバントの実装
5-2. CORBA サーバの実装
6. クライアントの実装:名前の検索 ( JavaIDL )
7. オブジェクト URL
8. アプリケーションの実行
9. まとめ
10. 参考資料 ・ URL
補足. 環境設定

1. はじめに

第一回目では、CORBA の仕組みと簡単な CORBA アプリケーションの作成方法について取り上げました。銀行口座の CORBA オブジェクトを IDL で定義し、その CORBA オブジェクトの IOR をファイル経由で CORBA サーバから CORBA クライアントに渡しました。IOR は、分散システムの中に存在する CORBA オブジェクトの位置を特定するための識別子のようなものであり、CORBA クライアントが何らかの方法で取得できれば良いものです。今回は、その IOR をファイル経由ではなく、ネーミングサービスを利用して入手する方法を解説します。ネーミングサービスは、CORBA サービスの一つであり、CORBA オブジェクトの位置情報を名前で検索、登録するための機能をアプリケーション開発者に提供します。

ちなみに、CORBA サービスはアプリケーションを開発する上で便利な共通のサービスを定義したものであり、他にも トレーダサービスやトランザクションサービスなどの 10 種類以上のサービスが仕様で定義されております。次回以降、出来るだけ多くの CORBA サービスを取り上げていきたいと思います。

さて、第二回目では、 CORBA 準拠の ORB 製品として VisBroker ( BES VisiBroker Edition )、JavaIDL ( J2SE 1.4.1 )、そして、新しく JacORB を利用します。JacORB は、 CORBA 2.3 準拠のフリーの ORB 製品です。現在の最新バージョンである JacORB 1.4.1 を利用します。

2. システム構成

まず、最初に今回作成するシステムの構成についてみておきましょう ( 図 1 )。

システム構成
図 1: システム構成

サーバ側に VisiBroker と JacORB を利用し、クライアント側に JavaIDL を利用します。そして、ネーミングサービスには、VisiBroker のネーミングサービスを利用します。また、Java と C++ の実装の違いを比較するために、JacORB では Java を、VisiBroker では C++ を使用することにします。

次に、準備する環境について見ておきましょう。3 つの CORBA 製品を利用しますが、1 台の PC 上で動作させます。Windows 2000 マシンを用意して以下のようなディレクトリ構成を作成してください。 bat ファイルでそれぞれの CORBA 製品の環境を切り替え、対応するディレクトリの中で CORBA サーバまたは CORBA クライアントを実装していきます。

CORBA
VisiBroker
BES VisiBroker Edtion 5.1 用のディレクトリ
JavaIDL
Java IDL (J2SE 1.4) 用のディレクトリ
JacORB
JacORB 1.4.1 用のディレクトリ

VisiBroker では、C++ を使用するので、Windows 2000 環境では Microsoft の Visual C++ 6.0 のコンパイラが必要になります。VisiBroker、JavaIDL、JacORB の環境設定に関しては、補足を参照してください。

3. CORBA オブジェクト

今回も引き続き銀行口座オブジェクトを利用します ( 図 2 )。銀行口座オブジェクトの変更点はありません。今回も UML で表現するクラス図には UML Profile for CORBA [2] で定められているステレオタイプを利用します。CORBAInterface は CORBA オブジェクトを表すステレオタイプです。

銀行口座 CORBA オブジェクトのクラス図
図 2: 銀行口座 CORBA オブジェクトのクラス図

Account CORBA オブジェクトの IDL を以下に示します。IDL の内容については、第一回目の「 4. IDL で CORBA オブジェクトを定義する 」を見てください。

Bank.idl
// Bank.idl

module Bank {
  interface Account {
    long getBalance();
    string getName();
  };
};

4. ネーミングサービス

ネーミングサービスは、CORBA オブジェクトのオブジェクトリファレンスに名前を付けて登録し、逆に名前からオブジェクトリファレンスを検索する機能をアプリケーション開発者に提供します。また、関連付ける名前は、ファイルシステムのようにディレクトリ構造を作成することによって階層的に管理することができます。ネーミングサービスでは、ディレクトリに相当するオブジェクトをネーミングコンテキストと呼びます。

ネーミングサービスの利用イメージ図
図 3: ネーミングサービスの利用イメージ

図 3 はネーミングサービスを利用したイメージ図です。最上位にあるルートコンテキストの直下にある Bank ネーミングコンテキストに CORBA オブジェクトのリファレンスを Nagata という名前で登録しています。また、Bank ネーミングコンテキストに別の CORBA オブジェクトのリファレンスを OGIS-RI という名前で登録しています。そして、クライアントは、ネーミングサービスに対して名前で検索することによって Nagata に関連付けられた CORBA オブジェクトのリファレンスを取得しています。

では、ネーミングサービスが提供するサービスについて見ていくことにしましょう。まず、全体像を知ってもらうためにネーミングサービスが提供する CosNaming モジュールを 図 4 に示します。UML Profile for CORBA [2] を使用して表現しているため、IDL で定義している型がステレオタイプとして表記されています。IDL で定義している型との対応関係を知りたい方は、CosNaming.idl ファイルと図 4 を見比べてください。図 4 をクリックすると大きな画像が別ウィンドウとして表示されます。

ネーミングサービスのクラス図
図 4: ネーミングサービスのクラス図 (CosNaming.idl)

最も使用される頻度が高いサービスを赤色の背景で示しています。ここでは、赤色の背景のサービスだけを説明することにします。

まず、ネーミングサービスで利用される名前ですが、これは以下のような idkind の 2 つの string 型の属性からなる構造体 (NameComponent) で表現されます。これはネームコンポーネントと呼ばれます。そして、このネームコンポーネントの idkind の属性によって、ネーミングコンテキストの中で一意なオブジェクトが識別されます。

module CosNaming {
    typedef string Istring;
    struct NameComponent {
        Istring id;
        Istring kind;
    };
    typedef sequence<NameComponent> Name;
};

ネームコンポーネントの idkind の属性は、null 文字と印刷不可能な文字を除く ISO 8859-1 (Latin-1) 文字セットの文字である必要があります。従って、日本語等のマルチバイト文字列は使用することはできません。どちらの文字列も、最大文字数は 255 文字までです。ネームコンポーネントの id 属性は空の文字列にすることはできませんが、kind 属性は可能です。 kind 属性は、名前に対する追加の特性を記述します。また、ネームコンポーネントのシーケンスは、コンパウドネームと呼ばれます。これは、IDL の typedef を利用して NameComponent のシーケンス( Name 型 ) として定義されています。このコンパウドネームを利用すると、ネーミングコンテキストからみた相対名を指定して、CORBA オブジェクト、または、ネーミングコンテキストを取得することが出来ます。

次は、ネーミングコンテキストが提供するサービスについて見てみましょう。

module CosNaming {  
    interface NamingContext {
        void    bind(in Name n, in Object obj)      
                    raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
        void    rebind(in Name n, in Object obj)    
                    raises(NotFound, CannotProceed, InvalidName);
        void    bind_context(in Name n, in NamingContext nc)        
                    raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
        void    rebind_context(in Name n, in NamingContext nc)  
                    raises(NotFound, CannotProceed, InvalidName);
        Object  resolve (in Name n)
                    raises(NotFound, CannotProceed, InvalidName);
        void    unbind(in Name n)
                    raises(NotFound, CannotProceed, InvalidName);
        NamingContext   new_context();
        NamingContext   bind_new_context(in Name n)
                    raises(NotFound, AlreadyBound, CannotProceed, InvalidName);
        void    destroy()
                    raises(NotEmpty);
        void    list(in unsigned long how_many, out BindingList bl, out BindingIterator bi);
    };
};

IDL のさまざまなキーワードが出てきましたので併せて説明しておきます。まず、オペレーションの引数ですが、よくみると型名の前に inout などのキーワードが付いています。これは、オペレーションの引数として渡すデータのモードを表すキーワードであり、以下の 3 つの種類が存在します。

in
入力引数を表す(クライアントからサーバに対してデータが渡される)
out
出力引数を表す(サーバからクライアントに対してデータが渡される)
inout
入出力引数を表す( inout を併せたモード )

また、オペレーションの後に raises というキーワードがあります。これは、そのオペレーションが発生させる(可能性のある)例外を定義したものです。CORBA の IDL で定義した例外を raises キーワードの ( ) の中に、「,」区切りで例外名を並べて定義します。これらの例外名も CosNaming モジュールの中で exception キーワードを使って定義されています。

IDL について理解できたところで、ネーミングコンテキストが提供するオペレーションについて見てみましょう。それぞれのオペレーションは以下の機能を提供します。

bind
指定された Object を指定された Name で登録します。
rebind
指定された Name で既に別のオブジェクトが登録されている場合、その登録されているオブジェクトを指定された Object に置き換えます。
bind_context
指定された NamingContext を指定された Name で登録します。
rebind_context
指定された Name で既に別のネーミングコンテキストが登録されている場合、そのネーミングコンテキストを指定された NamingContext に置き換えます。
resolve
指定された Name を解決し、オブジェクトリファレンスを返します。
unbind
指定された Name に関連付けられている登録を削除します。
new_context
新しいネーミングコンテキストを作成します。
bind_new_context
新しいネーミングコンテキストを作成し、指定された Name にそのコンテキストを登録します。
destroy
ネーミングコンテキストを非活性化します。このネーミングコンテキストに登録されているオブジェクトをすべて unbind オペレーションによって登録を削除しておく必要があります。
list
ネーミングコンテキストに保持されているすべての登録情報を返します。how_many 個までの登録情報が BindList に返されます。残りの登録情報は、BindingIterator を介して返されます。

例えば、bind オペレーションは、ネーミングコンテキスト内に CORBA オブジェクトを登録します。また、bind_context オペレーションでは、ネーミングコンテキスト内にネーミングコンテキストを登録することができます。ネーミングサービスから CORBA オブジェクトを検索するときは、resolve オペレーションを使用します。resolve オペレーションの引数に名前を指定することによって、ネーミングコンテキストに登録されている CORBA オブジェクト、または、ネーミングコンテキストのリファレンスを取得することができます。

さて、 ネーミングサービスでは、もう一つよく使うインタフェースとして NamingContextExt インタフェースがあります。NamingContextExtインタフェースは NamingContext インタフェースを拡張したインタフェースであり、名前の指定方法が NamingContext インタフェースよりも簡単になっています。NamingContext インタフェースでは、Name 型を作成してオペレーションの引数に渡す必要がありましたが、NamingContextExt では、Name 型を作成してなくても、文字列形式で名前を指定することが可能となっています。こちらの利用方法は 「 6. クライアントの実装:名前の検索 ( JavaIDL ) 」 で取り上げることにします。

では、ネーミングサービスに登録するサーバの処理について見ていきましょう。

5. サーバの実装:名前の登録 ( VisiBroker,JacORB )

サーバでは、CORBA クライアントのリクエストを受け付ける CORBA サーバと CORBA オブジェクトの実装であるサーバントを実装します。

5-1. サーバントの実装

まず、サーバントについて見ていきましょう。

先に、JacORB を使用して Java の Account サーバントを実装します。Account のスケルトンを作成するために Bank.idl ファイルを JacORB の IDL コンパイラである idl コマンドを使ってコンパイルしてください。idl コマンドは補足で作成する bat ファイルです。実際は、java コマンドで org.jacorb.idl.parser クラスを起動していることに注意してください。

JacORB> idl Bank.idl

idl コマンドを実行すると、実行したディレクトリに Bank というディレクトリが作成され、スタブソース、スケルトンソース、各種ユーティリティソースが生成されます。サーバントの実装は第一回目と同一です。実装の詳しい説明については、第一回目の「 7. CORBA オブジェクトの実装:サーバント 」を見てください。

AccountImpl.java
// AccountImpl.java

public class AccountImpl extends Bank.AccountPOA {
  private String _name;
  private int   _balance;

  public AccountImpl(String name, int balance) {
    _name = name;
    _balance = balance;
  }
  public int getBalance() {
    return _balance;
  }
  public String getName() {
    return _name;
  }
}

次は、VisiBroker を使用して C++ の Account サーバントを実装します。C++ でも、Account のスケルトンを作成して実装します。Bank.idl ファイルを C++ 用 IDL コンパイラである idl2cpp コマンドを使用してコンパイルします。-src_suffix オプションは生成される C++ のソースファイルの拡張子を .cpp にするためのオプションです。

VisiBroker> idl2cpp -src_suffix cpp Bank.idl

以下のスタブソース、スケルトンソースが自動生成されます。

実装するべきオペレーションは、Bank_s.hh ヘッダファイルの以下の 2 つのオペレーションになります。

Bank_s.hh
class  POA_Bank {
public:

  class  Account : public Bank::Account_ops ,public virtual PortableServer_ServantBase {
        ・
        ・
        ・
    // The following operations need to be implemented
    virtual ::CORBA::Long getBalance() = 0;

    virtual char* getName() = 0;
        ・
        ・
        ・
  };

};

では、サーバントを実装します。今回は、サーバントの実装を BankImpl.h というヘッダファイルの中に実装することにします。

BankImpl.h
#include "Bank_s.hh"

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

class AccountImpl : public virtual POA_Bank::Account, 
                    public virtual PortableServer::RefCountServantBase
{
  public:
    AccountImpl(CORBA::Long balance, char *name){
        _balance = balance;
		_name    = name;
	};

    CORBA::Long getBalance() { return _balance; }
    char * getName() { return _name; }

  private:
    CORBA::Long       _balance;
    CORBA::String_var _name;
};

Java と C++ のサーバントの実装の違いについて比較してみてください。Java も C++ もスケルトン(Java の場合:Bank.AccountPOA、C++ の場合:POA_Bank::Account )を継承している部分においては共通です。しかし、C++ では、PortableServer::RefCountServantBase クラスも継承しています。

PortableServer::RefCountServantBase クラスを継承するのは、C++ ではメモリ管理を意識する必要があるためです。 new によって確保したサーバントのためのメモリ領域は、不要になった後、delete によって開放すれば良いのですが、サーバントのメモリ領域は ORB からも参照されている可能性があるため不用意に開放することはできません。プログラマ側で不用意にサーバントのメモリ領域を開放してしまうと、メモリアクセスエラー等を発生させる可能性があります。そこで、CORBA ではサーバントのメモリ領域を自動的に管理するためのリファレンスカウンタが導入されております。

リファレンスカウンタとは、そのサーバントを指しているリファレンスの個数を記録するカウンタです。サーバントに対するリファレンスが 1 個増えるごとに、リファレンスカウンタに 1 を加えます。サーバントを指していたリファレンスが 1 つ減るごとに、リファレンスカウンタから 1 を引きます。そして、リファレンスカウンタの値が 0 になったら、そのサーバントのメモリ領域を解放します。このリファレンスカウンタの働きによって、不要になったサーバントのメモリ領域が確実に解放されることになります。

PortableServer::RefCountServantBase クラスには、リファレンスカウンタに関する操作の実装があります。従って、PortableServer::RefCountServantBase クラスを継承することによって、サーバントに対してリファレンスカウンタの機能が追加されます。

5-2. CORBA サーバの実装

では、クライアントからのリクエストを受け付ける CORBA サーバを実装します。 CORBA サーバの処理は基本的に第一回目と同一です。5 と 9 の間でネーミングサービスに対して CORBA オブジェクトのリファレンスを登録している部分が異なります。

  1. ORB の初期化
  2. RootPOA のリファレンスの取得
  3. サーバントのインスタンス化
  4. RootPOA のアクティブオブジェクトマップにサーバントを登録
  5. POA マネージャの活性化
  6. ネーミングサービスのオブジェクトリファレンスの取得
  7. 登録する名前の作成
  8. ネーミングサービスに対して CORBA オブジェクトのオブジェクトリファレンスを登録
  9. イベントループ

では、JacORB を使用する Java の CORBA サーバから見ていきましょう。

Server.java
  1:// Server.java
  2:
  3:import org.omg.PortableServer.*;
  4:import org.omg.CosNaming.*;
  5:import org.omg.CosNaming.NamingContextPackage.*;
  6:import java.io.*;
  7:
  8:public class Server {
  9:
 10:  public static void main(String[] args) {
 11:    try {
 12:      // ORB の初期化
 13:      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
 14:
 15:      // RootPOA のオブジェクトリファレンスを取得
 16:      org.omg.CORBA.Object obj = orb.resolve_initial_references("RootPOA");
 17:      POA rootPOA = POAHelper.narrow(obj);
 18:
 19:      // サーバントの生成
 20:      AccountImpl accountServant = new AccountImpl("OGIS-RI",5000);
 21:
 22:      // RootPOA 上でサーバントを活性化
 23:      rootPOA.activate_object(accountServant);
 24:
 25:      // POA マネージャの活性化
 26:      rootPOA.the_POAManager().activate();
 27:
 28:      // サーバントからオブジェクトリファレンスを取得
 29:      org.omg.CORBA.Object reference = rootPOA.servant_to_reference(accountServant);
 30:
 31:      // ネーミングサービスのルートコンテキストのリファレンスを取得
 32:      obj = orb.resolve_initial_references("NameService");
 33:
 34:      // ルートコンテキストのリファレンスを NamingContext 型に変換
 35:      NamingContext rootCtx = NamingContextHelper.narrow(obj);
 36:
 37:      // 名前を作成する
 38:      NameComponent[] nameCtx = { new NameComponent("Bank", "") };
 39:
 40:      NamingContext bankCtx;
 41:      try{
 42:          // ネーミングコンテキストを取得する
 43:          obj = rootCtx.resolve(nameCtx);
 44:          bankCtx = NamingContextHelper.narrow(obj);
 45:      }catch(NotFound e){
 46:          // ネーミングコンテキストが存在しない場合
 47:          // 作成した名前でネーミングコンテキストを登録
 48:          System.out.println("Exception: " + e);
 49:          bankCtx = rootCtx.bind_new_context(nameCtx); 
 50:      }
 51:
 52:      // 登録する名前を作成する
 53:      NameComponent[] nameObj = { new NameComponent("OGIS-RI", "Account") };
 54:      try{
 55:          // 作成した名前で Account のオブジェクトリファレンスを登録
 56:          bankCtx.bind(nameObj,reference); 
 57:      }catch(AlreadyBound e){
 58:          // 既にオブジェクトリファレンスが登録されている場合
 59:          // 再度、作成した名前でオブジェクトリファレンスを登録
 60:          System.out.println("Exception: " + e);
 61:          bankCtx.rebind(nameObj, reference);
 62:      }
 63:      
 64:      // クライアントからのリクエストに待機
 65:      System.out.println("Server is ready.");
 66:      orb.run();
 67:    }
 68:    catch (Exception e) {
 69:      e.printStackTrace();
 70:    }
 71:  }
 72:}

31 行目から 72 行目までがネーミングサービスに対して CORBA オブジェクトを登録するために追加されたコードです。それ以外のコードについては、第一回目の 「 9. CORBA サーバの実装 ( VisiBroker ) 」 を見てください。

ネーミングサービスを利用するには、まず、ネーミングサービスのルートコンテキストのリファレンスを取得する必要があります。これは、32 行目にあるように、resolve_initial_references メソッドの引数に対して NameService の識別名 (文字列) を指定することによって取得します。resolve_initial_references メソッドは、ネーミングサービスに限らず、さまざまなサービスのリファレンスを取得するときに利用するメソッドです。RootPOA のリファレンスを取得するときにも利用されています。

次に、ネーミングサービスに対して登録する名前を作成します。登録する名前は、ネームコンポーネントのシーケンスである Name 型を利用する必要があります。Java では、NameComponent[] として表現します。38 行目で登録する Bank という名前を作成しています。43 行目では、その Bank という名前で検索を行なっています。既に Bank という名前が登録されていれば、登録された名前から取得したリファレンスをネーミングコンテキストに変換します。もし、Bank という名前が存在しなければ、resolve メソッドは、NotFound 例外をスローします。NotFound 例外がスローされると、新しい Bank という名前のネーミングコンテキストを作成します ( 49 行目)。

何からの方法で Bank ネーミングコンテキストのリファレンスを取得した後、Account の CORBA オブジェクトを登録するための名前を作成しています ( 53 行目 )。ここでは、ネームコンポーネントの idkind に対して、それぞれ "OGIS-RI""Account" を設定しています。そして、その名前で Bank ネーミングコンテキストに対して Account CORBA オブジェクトのリファレンスを登録しています。もし、その名前が既に使用されていると bind メソッドは、AlreadyBound 例外をスローします。AlreadyBound 例外がスローされると、rebind メソッドを利用して、その名前で登録されている CORBA オブジェクトを、強制的に登録する Account の CORBA オブジェクトのリファレンスに置き換えています。

以上が、ネーミングサービスに対して CORBA オブジェクトのリファレンスを登録する流れです。

では、VisiBroker の C++ のサーバを見てみましょう。

Server.C
  1:#include "BankImpl.h"
  2:#include "CosNaming_c.hh"
  3:#include "CosNamingExt_c.hh"
  4:
  5:// USE_STD_NS is a define setup by VisiBroker to use the std namespace
  6:USE_STD_NS
  7:
  8:int main(int argc, char* const* argv) 
  9:{
 10:  try {
 11:    // ORB の初期化
 12:    CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
 13:
 14:    // RootPOA のオブジェクトリファレンスを取得
 15:    CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
 16:    PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
 17:    
 18:    // サーバントの生成
 19:    AccountImpl accountServant(10000.0,"NAGATA"); 
 20:
 21:    // RootPOA 上でサーバントの活性化
 22:    rootPOA->activate_object(&accountServant);
 23:
 24:    // POA マネージャの取得
 25:    PortableServer::POAManager_var poa_manager = rootPOA->the_POAManager();
 26:
 27:    // POA マネージャの活性化
 28:    poa_manager->activate();
 29:
 30:    // サーバントからオブジェクトリファレンスを取得
 31:    CORBA::Object_var reference = rootPOA->servant_to_reference(&accountServant);
 32:
 33:    // ネーミングサービスのルートコンテキストのリファレンスを取得
 34:    obj = orb->resolve_initial_references("NameService");
 35:
 36:    // ルートコンテキストのリファレンスを NamingContext 型に変換
 37:    CosNaming::NamingContext_var rootCtx = CosNaming::NamingContext::_narrow(obj);
 38:
 39:    // 名前を作成する
 40:    CosNaming::Name nameCtx; 
 41:    nameCtx.length(1); 
 42:    nameCtx[0].id = CORBA::string_dup("Bank"); 
 43:    nameCtx[0].kind = CORBA::string_dup(""); 
 44:
 45:    CosNaming::NamingContext_var bankCtx;
 46:    try{
 47:        // ネーミングコンテキストを取得する
 48:        obj = rootCtx->resolve(nameCtx);
 49:        bankCtx = CosNaming::NamingContext::_narrow(obj);
 50:    }catch(const CosNaming::NamingContext::NotFound& e){
 51:        cout << "Exception: " << e << endl;
 52:        // ネーミングコンテキストが存在しない場合
 53:        // 作成した名前でネーミングコンテキストを登録
 54:        bankCtx = rootCtx->bind_new_context(nameCtx); 
 55:    }
 56:
 57:    // 登録する名前を作成する
 58:    CosNaming::Name nameObj; 
 59:    nameObj.length(1);
 60:    nameObj[0].id   = CORBA::string_dup("Nagata"); 
 61:    nameObj[0].kind = CORBA::string_dup("Account"); 
 62:
 63:    try{
 64:        // 作成した名前で Account のオブジェクトリファレンスを登録
 65:        bankCtx->bind(nameObj,reference); 
 66:    }catch(const CosNaming::NamingContext::AlreadyBound& e){
 67:        // 既にオブジェクトリファレンスが登録されている場合
 68:        // 再度、作成した名前でオブジェクトリファレンスを登録
 69:        cout << "Exception: " << e << endl;
 70:        bankCtx->rebind(nameObj, reference);
 71:    }
 72:
 73:    // クライアントからのリクエストに待機
 74:    cout << "Server is ready" << endl;
 75:    orb->run();
 76:  }
 77:  catch(const CORBA::Exception& e) {
 78:    cerr << e << endl;
 79:    return 1;
 80:  }
 81:  return 0;
 82:}

Java のコードと比較するとわかると思いますが、基本的には同じです。注意点としては、変数の型として <名前>_var クラスを利用しているところです。C++ には、CORBA の変数の型として <名前>_ptr 型と <名前>_var 型が存在します。<名前>_var 型を利用することによって、メモリ管理を意識せずに実装ができるので、 C++ では <名前>_var 型を利用することが推奨されています。

<名前>_ptr
<名前> クラスに対するポインタを typedef で宣言した型。従って、この型を使用する場合は、確保したメモリ領域を明示的に開放しなければなりません。
<名前>_var
メモリ管理を簡単するために用意されたクラス。このクラスを使用した場合は、オブジェクトのインスタンスが破棄されたり、新しい値がオブジェクトに割り当てられたときに自動的にメモリ領域が解放されます。また、スコープから抜ける場合にも自動的にメモリ領域が開放されます。

では、Java と C++ の両サーバの実装が完成したのでそれぞれをコンパイルしましょう。JacORB では、javac コマンドを利用します。

JacORB> javac -classpath %CLASSPATH%;. *.java

VisiBroker では、nmake コマンドを使ってコンパイルします。

VisiBroker> nmake -f Makefile.cpp

コンパイルには、Makefile.cpp ファイルと stdmk_nt ファイルが必要になります。これは、VisiBroker の環境を設定するための make ファイルです。

6. クライアントの実装:名前の検索 ( JavaIDL )

CORBA クライアントは、JavaIDL の ORB を利用します。まず、CORBA クライアントを実装するためのスタブを IDL ファイルから生成します。

JavaIDL> idlj -fclient Bank.idl

CORBA クライアントでは、基本的に次のような流れで処理を実装します。

  1. ORB の初期化
  2. ネーミングサービスのオブジェクトリファレンスの取得
  3. 検索する名前の作成
  4. ネーミングサービスから CORBA オブジェクトのオブジェクトリファレンスを取得
  5. CORBA オブジェクトに対するオペレーション呼び出し

では、CORBA クライアントのコードを見ながら、どのようにネーミングサービスに対して名前を検索するのか見ていきましょう。

Client.java
  1:// Client.java
  2:
  3:import org.omg.CosNaming.*;
  4:import java.io.*;
  5:
  6:public class Client {
  7:
  8:  public static void main(String[] args) {
  9:    try {
 10:      // ORB の初期化
 11:      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);
 12:
 13:      // ネーミングサービスのルートコンテキストのリファレンスを取得
 14:      org.omg.CORBA.Object obj = orb.resolve_initial_references("NameService");
 15:
 16:      // ルートコンテキストのリファレンスを NamingContextExt 型に変換
 17:      NamingContextExt rootCtx = NamingContextExtHelper.narrow(obj);
 18:
 19:      Bank.Account account;
 20:
 21:      System.out.println("");
 22:      System.out.println("------------------- Case 1 -------------------");
 23:      // Bank のネーミングコンテキストを取得してから Account オブジェクトの
 24:      // リファレンスを取得する方法
 25:
 26:      // Bank のネーミングコンテキストを取得する
 27:      obj = rootCtx.resolve(rootCtx.to_name("Bank"));
 28:      NamingContextExt bankCtx = NamingContextExtHelper.narrow(obj);
 29:
 30:      // JacORB で登録した Account オブジェクトを取得する
 31:      // NamingContextExt の to_nmae() メソッドを利用して文字列から名前を作成している
 32:      obj = bankCtx.resolve(bankCtx.to_name("OGIS-RI.Account"));
 33:      account = Bank.AccountHelper.narrow(obj);
 34:
 35:      // Account オブジェクトの情報を表示する
 36:      infoAccount(account);
 37:
 38:      // VisiBrokerORB で登録した Account オブジェクトを取得する
 39:      // NamingContextExt の resolve_str() メソッドを利用して
 40:      // 文字列から直接リファレンスを取得している
 41:      obj = bankCtx.resolve_str("Nagata.Account");
 42:      account = Bank.AccountHelper.narrow(obj);
 43:
 44:      // Account オブジェクトの情報を表示する
 45:      infoAccount(account);
 46:
 47:      System.out.println("------------------- Case 2 -------------------");
 48:      // Account オブジェクトの名前階層を直接指定して取得する方法
 49:
 50:      // 取得したいオブジェクトの名前を作成する
 51:      NameComponent[] name = { new NameComponent("Bank", "")
 52:                              ,new NameComponent("OGIS-RI", "Account") };
 53:
 54:      // JacORB で登録した Account オブジェクトを取得する
 55:      obj = rootCtx.resolve(name);
 56:      account = Bank.AccountHelper.narrow(obj);
 57:
 58:      // Account オブジェクトの情報を表示する
 59:      infoAccount(account);
 60:
 61:      // VisiBrokerORB で登録した Account オブジェクトを取得する
 62:      // NamingContextExt の to_name メソッドを利用して文字列から名前を作成している
 63:      obj = rootCtx.resolve(rootCtx.to_name("Bank/Nagata.Account"));
 64:      account = Bank.AccountHelper.narrow(obj);
 65:
 66:      // Account オブジェクトの情報を表示する
 67:      infoAccount(account);
 68:
 69:      System.out.println("");
 70:      System.out.println("------------------- Case 3 -------------------");
 71:      // 名前を指定せずに名前階層を検索して Account オブジェクトを取得する方法
 72:      listAccount(rootCtx);
 73:    }
 74:    catch(Exception e) {
 75:      e.printStackTrace();
 76:    }
 77:  }
 78:
 79:  // 指定された Account オブジェクトの情報を表示するメソッド
 80:  private static void infoAccount(Bank.Account account){
 81:      System.out.println
 82:        ("The balance in " + account.getName() + "'s account is "
 83:                           + account.getBalance() + " yen.");
 84:  }
 85:
 86:  // 指定されたネーミングコンテキスト以下の名前階層を検索し、
 87:  // Account オブジェクトの情報を表示するメソッド
 88:  private static void listAccount(NamingContext ctx){
 89:    try{
 90:      int how_many = 0;
 91:
 92:      // list メソッドに渡す out モードの Holder クラスを作成
 93:      BindingListHolder listHdr = new BindingListHolder();
 94:      BindingIteratorHolder iteratorHdr = new BindingIteratorHolder();
 95:
 96:      // ctx ネーミングコンテキストに登録されているオブジェクトを取得する
 97:      ctx.list(how_many, listHdr, iteratorHdr);
 98:
 99:      //  list メソッドの結果を Holder クラスから取り出す
100:      BindingIterator iterator = iteratorHdr.value;
101:
102:      // iterator メソッドに渡す out モードの Holder クラスを作成
103:      BindingHolder nodeHdr = new BindingHolder();
104:
105:      // ctx ネーミングコンテクスト直下に登録されている
106:      // すべてのオブジェクトに対して以下の処理を繰り返す
107:      while( iterator.next_one(nodeHdr) == true ){
108:        // next_one メソッドの結果を Holder クラスから取り出す
109:        Binding node = nodeHdr.value;
110:
111:        // 登録タイプがネーミングコンテキストの場合
112:        if( node.binding_type == BindingType.ncontext ){
113:           try{
114:             // 登録されているネーミングコンテキストを取得し、
115:             // そのネーミングコンテキスト以下に Account オブジェクトが
116:             // 存在するかどうか検索する
117:             org.omg.CORBA.Object obj = ctx.resolve(node.binding_name);
118:             NamingContext subCtx = NamingContextHelper.narrow(obj);
119:             listAccount(subCtx);
120:           }catch(Exception e){
121:             e.printStackTrace();
122:           }
123:        }
124:
125:        // 登録タイプが CORBA オブジェクトの場合 
126:        if( node.binding_type == BindingType.nobject ){
127:           try{
128:             // 登録されている CORBA オブジェクトのリファレンスを取得する
129:             // 登録されている CORBA オブジェクトが Account オブジェクトで
130:             // ない場合は、CORBA.BAD_PARAM 例外が発生する
131:             org.omg.CORBA.Object obj = ctx.resolve(node.binding_name);
132:             Bank.Account account = Bank.AccountHelper.narrow(obj);
133:
134:             // Account オブジェクトの情報を表示する
135:             infoAccount(account);
136:           }catch(org.omg.CORBA.BAD_PARAM exp){
137:             // Account オブジェクトでない場合は何もしない
138:           }catch(Exception e){
139:             e.printStackTrace();
140:           }
141:        }
142:      }
143:    }catch(Exception e){
144:        e.printStackTrace();
145:    }
146:  }
147:}

クライアントでは Account オブジェクトを取得するための検索例を 3 つ紹介しています。それぞれの例について説明します。

Case 1

ルートコンテキストから一旦 Bank ネーミングコンテキストを取得し、その Bank ネーミングコンテキストから 2 つの Account CORBA オブジェクトのリファレンスを取得している例です。27 行目や 32行目では NamingContextExt インタフェースの to_name メソッドを利用して、名前の文字列形式から CORBA オブジェクトのリファレンスを取得しています。名前の文字列形式では、ネームコンポーネントの idkind"<id 名>.<kind 名>" という文字列で表現します。kind が空文字の場合は、「.」も省略することができます。

 22:      System.out.println("------------------- Case 1 -------------------");
 23:      // Bank のネーミングコンテキストを取得してから Account オブジェクトの
 24:      // リファレンスを取得する方法
 25:
 26:      // Bank のネーミングコンテキストを取得する
 27:      obj = rootCtx.resolve(rootCtx.to_name("Bank"));
 28:      NamingContextExt bankCtx = NamingContextExtHelper.narrow(obj);
 29:
 30:      // JacORB で登録した Account オブジェクトを取得する
 31:      // NamingContextExt の to_nmae() メソッドを利用して文字列から名前を作成している
 32:      obj = bankCtx.resolve(bankCtx.to_name("OGIS-RI.Account"));
 33:      account = Bank.AccountHelper.narrow(obj);
 34:
 35:      // Account オブジェクトの情報を表示する
 36:      infoAccount(account);
 37:
 38:      // VisiBrokerORB で登録した Account オブジェクトを取得する
 39:      // NamingContextExt の resolve_str() メソッドを利用して
 40:      // 文字列から直接リファレンスを取得している
 41:      obj = bankCtx.resolve_str("Nagata.Account");
 42:      account = Bank.AccountHelper.narrow(obj);
 43:
 44:      // Account オブジェクトの情報を表示する
 45:      infoAccount(account);

Case 2

ルートコンテキストから一気に 2つ の Account CORBA オブジェクトのリファレンスを取得している例です。55 行目では、51 行目で作成したコンパウドネームを使用して名前解決を行なっています。63 行目では、NamingContextExt インタフェースの to_name メソッドを利用して、名前の文字列形式から CORBA オブジェクトのリファレンスを取得しています。名前の文字列形式では、名前階層の区切りを "/" で表現します。

 47:      System.out.println("------------------- Case 2 -------------------");
 48:      // Account オブジェクトの名前階層を直接指定して取得する方法
 49:
 50:      // 取得したいオブジェクトの名前を作成する
 51:      NameComponent[] name = { new NameComponent("Bank", "")
 52:                              ,new NameComponent("OGIS-RI", "Account") };
 53:
 54:      // JacORB で登録した Account オブジェクトを取得する
 55:      obj = rootCtx.resolve(name);
 56:      account = Bank.AccountHelper.narrow(obj);
 57:
 58:      // Account オブジェクトの情報を表示する
 59:      infoAccount(account);
 60:
 61:      // VisiBrokerORB で登録した Account オブジェクトを取得する
 62:      // NamingContextExt の to_name メソッドを利用して文字列から名前を作成している
 63:      obj = rootCtx.resolve(rootCtx.to_name("Bank/Nagata.Account"));
 64:      account = Bank.AccountHelper.narrow(obj);
 65:
 66:      // Account オブジェクトの情報を表示する
 67:      infoAccount(account);

Case 3

Account CORBA オブジェクトの登録名がわからない場合の検索例です。BindingListBindIterator を引数にとる list メソッドを利用しています。

list メソッドは、引数として out モードの BindingListBindIterator を受け取ります。Java では、out モードの引数に対しては、Holder クラスを利用します。93 行目から 100 行目までを見てください。それぞれの Holder クラスのオブジェクトを生成し、それらの Holder オブジェクトを out モードの引数に渡しています。out モードの引数に Holder オブジェクトを渡すと、そのオペレーションの実行結果が、Holder オブジェクトの value 属性に格納されます。100 行目では、list メソッドの結果を Holder オブジェクトから取り出しています。

さて、プログラムの中身についてですが、少々複雑です。list メソッドを使用して、ネーミングコンテキスト内に登録されているオブジェクトを BindIterator 経由で取得しています。BindIterator によって参照できる Binding オブジェクトが CORBA オブジェクトのタイプであれば、Account CORBA オブジェクトかどうかを確認して内容を表示しています。一方、Binding オブジェクトがネーミングコンテストのタイプであれば、そのネーミングコンテキスト内に Account オブジェクトが存在するか検索を行います。これは、listAccount メソッドを再帰的に呼び出すことで実現しています。これによって、listAccount メソッドに渡された最初のネーミングコンテキスト以下のすべての Account オブジェクトが検索されます。

 70:      System.out.println("------------------- Case 3 -------------------");
 71:      // 名前を指定せずに名前階層を検索して Account オブジェクトを取得する方法
 72:      listAccount(rootCtx);

 86:  // 指定されたネーミングコンテキスト以下の名前階層を検索し、
 87:  // Account オブジェクトの情報を表示するメソッド
 88:  private static void listAccount(NamingContext ctx){
 89:    try{
 90:      int how_many = 0;
 91:
 92:      // list メソッドに渡す out モードの Holder クラスを作成
 93:      BindingListHolder listHdr = new BindingListHolder();
 94:      BindingIteratorHolder iteratorHdr = new BindingIteratorHolder();
 95:
 96:      // ctx ネーミングコンテキストに登録されているオブジェクトを取得する
 97:      ctx.list(how_many, listHdr, iteratorHdr);
 98:
 99:      //  list メソッドの結果を Holder クラスから取り出す
100:      BindingIterator iterator = iteratorHdr.value;
101:
102:      // iterator メソッドに渡す out モードの Holder クラスを作成
103:      BindingHolder nodeHdr = new BindingHolder();
104:
105:      // ctx ネーミングコンテクスト直下に登録されている
106:      // すべてのオブジェクトに対して以下の処理を繰り返す
107:      while( iterator.next_one(nodeHdr) == true ){
108:        // next_one メソッドの結果を Holder クラスから取り出す
109:        Binding node = nodeHdr.value;
110:
111:        // 登録タイプがネーミングコンテキストの場合
112:        if( node.binding_type == BindingType.ncontext ){
113:           try{
114:             // 登録されているネーミングコンテキストを取得し、
115:             // そのネーミングコンテキスト以下に Account オブジェクトが
116:             // 存在するかどうか検索する
117:             org.omg.CORBA.Object obj = ctx.resolve(node.binding_name);
118:             NamingContext subCtx = NamingContextHelper.narrow(obj);
119:             listAccount(subCtx);
120:           }catch(Exception e){
121:             e.printStackTrace();
122:           }
123:        }
124:
125:        // 登録タイプが CORBA オブジェクトの場合 
126:        if( node.binding_type == BindingType.nobject ){
127:           try{
128:             // 登録されている CORBA オブジェクトのリファレンスを取得する
129:             // 登録されている CORBA オブジェクトが Account オブジェクトで
130:             // ない場合は、CORBA.BAD_PARAM 例外が発生する
131:             org.omg.CORBA.Object obj = ctx.resolve(node.binding_name);
132:             Bank.Account account = Bank.AccountHelper.narrow(obj);
133:
134:             // Account オブジェクトの情報を表示する
135:             infoAccount(account);
136:           }catch(org.omg.CORBA.BAD_PARAM exp){
137:             // Account オブジェクトでない場合は何もしない
138:           }catch(Exception e){
139:             e.printStackTrace();
140:           }
141:        }
142:      }
143:    }catch(Exception e){
144:        e.printStackTrace();
145:    }
146:  }
147:}

では、Client.java ファイルをコンパイルしてみましょう。JavaIDL を利用するので、次のように java コマンドを使用してコンパイルしてください。

JavaIDL> javac Client.java

7. オブジェクト URL

これで、サーバ、クライアントが完成しましたが、サーバ、クライアントはどのようにしてネーミングサービスのリファレンスを取得しているのでしょうか。resolve_initial_references("NameService") メソッドで返されるリファレンスはどのリファレンスになるのでしょうか。

初期のネーミングサービスの仕様では、ネーミングサービスのリファレンスの取得方法はベンダ依存となっていました。つまり、resolve_initial_references ("NameService") メソッドで返されるリファレンスは ORB の実装に依存していました。従って、ネーミングサービスを利用したシステムを構築する場合には、同一の CORBA 製品を利用する必要がありました。しかし、1999 年にインタオペラブルネーミングサービスが仕様化されることによって、ネーミングサービスのリファレンス(初期ネーミングコンテキスト)の与え方が規定されました。つまり、このインタオペラブルネーミングサービスが仕様化されたことによって、他のベンダのネーミングサービスとの相互運用が可能となったのです。

インタオペラブルネーミングサービスでは、従来のネーミングサービスに対して以下の機能が追加されています [5]

「名前の文字列形式」と「名前の文字列形式とオブジェクト URL を使用したオペレーション」については、クライアントの実装で取り上げました。NamingContextExt インタフェースの to_name オペレーション等がそれに該当します。

ここでは、初期ネーミングコンテキストの与え方とオブジェクト URL について説明します。

初期ネーミングコンテキストは、クライアント、サーバの起動時に -ORBInitRef を利用することによって与えます。例えば、以下のようにコマンドライン引数として -ORBInitRef を指定したとします。ここで、IOR:00000000000....... は文字列形式の IOR を表しています。

prompt> java Server -ORBInitRef NameService=IOR:00000000000.......

この場合、-ORBInitRef で渡されたコマンドライン引数は、ORB::ORB_init オペレーションに渡されます。そして、ORB::resolve_initial_references オペレーションの引数として NameService という識別名が指定された場合、-ORBInitRef で指定されたオブジェクトリファレンスが返されることになります。これによって、ORB::resolve_initial_references オペレーションに与える任意の識別名の初期リファレンスを与えることができます。

さて、-ORBinitRef を使用して、ネーミングサービスの初期リファレンスを与える方法はわかりましたが、文字列化された IOR を渡すのは非常に面倒です。これを回避するための方法として corbaloc URL または corbaname URL によるオブジェクト URL の指定方法があります。ちなみに、文字列化された IOR を渡す方法もオブジェクト URL に含まれます。

IOR 形式のオブジェクト URL は、GIOP のエンコーディング規則である CDR でエンコードされた IOR を 16 進表示したものです。従って、人が読んですぐに理解できる形式ではありません。これに比べて、corbaloc URL と corbaname URL は非常にわかりやすい形式を提供してくれます。

corbaloc URL

corbaloc URL 形式では、例えば、ローカルホスト上で起動されているポート番号 10000 のオブジェクトキー NameService を持ったオブジェクトに対するリファレンスは以下のように表されます。

corbaloc:iiop:1.2@localhost:10000/NameService

この corbaloc URL 形式を利用して -ORBInitRef に以下のように指定すると、ORB は内部的にローカルホストのポート番号 10000 に IIOP のバージョン 1.2 を使って、オブジェクトキー NameService に対するオブジェクトリファレンスを要求します。そして、ローカルホストのポート番号 10000 で起動されているネーミングサービスからそのリファレンスが返されます。

prompt> java Server -ORBInitRef NameService=corbaloc:iiop:1.2@localhost:10000/NameService

IIOP のプロトコル名とバージョン番号は省略することができます。その場合は、以下のような形式になります。なお、バージョンが省略された場合は、バージョン 1.0 が利用されます。

corbaloc::localhost:10000/NameService

corbaname URL

corbaname URL は、URL でネーミングサービス内のエントリまで指定できるように corbaloc URL を拡張したものです。例えば、corbaname URL を使って "OGIS-RI.Account" の名前で登録された CORBA オブジェクトのリファレンスを取得する場合には、以下の形式で表現されます。

corbaname::localhost:10000/NameService#Bank/OGIS-RI.Account

この corbaname URL を使うと、例えば、ORB::string_to_object オペレーションを使用して、指定した CORBA オブジェクトのリファレンスが取得できます。

Java の例
org.omg.CORBA.Object obj = orb.string_to_object("corbaname::localhost:10000/NameService#Bank/OGIS-RI.Account");

8. アプリケーションの実行

では、実際に動かしてみましょう。まず、VisiBroker のネーミングサービスを起動します。

VisiBroker> nameserv -J-Dvbroker.se.iiop_tp.scm.iiop_tp.listener.port=10000 \
                    -J-Dvbroker.agent.enableLocator=false

正常に起動すると、ネーミングサービスの文字列化された IOR がコンソール上に出力されます。また、その IOR も ns.ior というファイル名に出力されます。IOR の中身について知りたい方は、VisiBroker の printIOR コマンドを使用して ns.ior ファイルの中身を見てください。

-Dvbroker.se.iiop_tp.scm.iiop_tp.listener.port プロパティは、ネーミングサービスが起動するポート番号を設定するプロパティです。今回は、ポート番号を 10000 に設定しています。また、-Dvbroker.agent.enableLocator プロパティは、VisiBroker が提供する Smart Agent の機能を設定するためのプロパティです。false に設定することで無効にしています。このプロパティは第一回目の 「 11.アプリケーションの実行 」でも出てきました。

次は、CORBA サーバを起動します。JacORB または VisiBroker のどちらの CORBA サーバを先に起動しても問題ありません。ここでは、VisiBroker の CORBA サーバを先に起動することにしましょう。

VisiBroker> Server -ORBInitRef NameService=corbaloc::localhost:10000/NameService \
                 -Dvbroker.agent.enableLocator=false
Exception: Exception: ::CosNaming::NamingContext::NotFound

Server is ready

-ORBInitRef を指定して、resolve_initial_references メソッドで取得する初期ネーミングコンテキストをネーミングサービスのルートコンテキストに指定しています。また、Bank ネーミングコンテキストの名前が解決できなかったため、NotFound 例外をキャッチしています。「 5-2. CORBA サーバの実装 」 のプログラムを見てもらえればわかりますが、NotFound 例外をキャッチすると、Bank ネーミングコンテキストを新たに作成します。「Server is ready」というメッセージがコンソール上に表示されたら O.K. です。

続いて、JacORB の CORBA サーバを起動しましょう。JacORB をネーミングサービスを利用して動かすには、jacorb.properties というプロパティファイルが必要になります。JacORB のインストールディレクトリに jacorb_properties.template というファイルが存在するので、このファイル名を jacorb.properties に変更して、CORBA サーバを実行するディレクトリに置いてください。 また、jacorb_properties.template ファイル中に存在する以下の行をコメントアウトしてください。以上で、起動のための設定は終了です。

ORBInitRef.NameService=https://www.x.y.z/~user/NS_Ref

JacORB のCORBA サーバは以下のコマンドで起動します。こちらも -ORBInitRef を使用して初期ネーミングコンテキストを指定しています。

JacORB> jaco Server -ORBInitRef NameService=corbaloc::localhost:10000/NameService
        JacORB V 1.4.1, www.jacorb.org
        (C) Gerald Brose, FU Berlin/XTRADYNE Technologies, July 2002
[ POA RootPOA - ready ]
[ Connected to 127.0.0.1:10000 ]
[ Connected to 158.201.101.62:10000 ]
Server is ready.

今度は、NotFound 例外はキャッチされませんでした。これは、VisiBroker の CORBA サーバが既に Bank ネーミングコンテキストを作成しているためです。こちらも最後に 「Server is ready」というメッセージがコンソール上に表示されたら O.K. です。

ちなみに、jaco コマンドは bat ファイルです。bat ファイルの内容は補足を参照してください。 java コマンドに対して JacORB の ORB を利用するようにプロパティで設定しています。

では、最後に JavaIDL のCORBA クライアントを起動しましょう。当然、クライアントからも -ORBInitRef で初期ネーミングコンテキストを指定する必要があります。

JavaIDL> java Client -ORBInitRef NameService=corbaloc::localhost:10000/NameService
------------------- Case 1 -------------------
The balance in OGIS-RI's account is 5000 yen.
The balance in NAGATA's account is 10000 yen.

------------------- Case 2 -------------------
The balance in OGIS-RI's account is 5000 yen.
The balance in NAGATA's account is 10000 yen.

------------------- Case 3 -------------------
The balance in OGIS-RI's account is 5000 yen.
The balance in NAGATA's account is 10000 yen.

上記メッセージがコンソール上に表示されましたか。

9. まとめ

さて、今回は、ネーミングサービスについて取り上げ、ネーミングサービスに対する CORBA オブジェクトの登録方法と検索方法について見ていきました。また、CORBA クライアントからの様々な検索方法も紹介しました。 ネーミングサービスの機能についてすべてを紹介したわけではありませんが、この記事をきっかけとしてネーミングサービスに対する理解を深めていただけると嬉しいです。

本記事は、実際に動かすのに必要な情報をすべて掲載しています。もし、本記事を参考に動かして頂いた方がおられましたら、ご意見、ご感想を頂けると大変嬉しいです。また、取り上げて欲しい CORBA の技術、または、CORBA サービス等がありましたら、アンケートのコメント欄にでもご記入お願いします。出来る限り取り上げたいと思います。

10. 参考資料 ・ URL

  1. 『 CORBA 3.0.2 specification 』 OMG Document formal/02-12-02
  2. 『 UML Profile for CORBA specification 』 OMG Document formal/02-04-01
  3. 『 Naming Service Specification 』 OMG Document formal/02-09-02
  4. 『 CORBA 完全解説 (基礎編) −Java でかんたん CORBA−』 小野沢 博文/著, ソフト・リサーチ・センター.
  5. 『 CORBA 完全解説 (応用編) −POA を使いこなす−』 小野沢 博文/著, ソフト・リサーチ・センター.
  6. Borland Enterprise Server Documentation
  7. Java IDL テクノロジドキュメント
  8. JacORB Documentation

補足. 環境設定

今回使用する ORB 製品の環境の設定方法について説明します。本記事では、複数の ORB 製品を利用することになるので、基本的にシステム環境変数には、ソフトウェアに関する環境変数を設定しません。替わりにバッチファイルを利用して、利用する ORB 製品を切り替えます。

BES VisiBroker Edition 5.1、J2SE 1.4.1、JacORB 1.4.1 を以下のサイトよりダウンロードして下さい。

ダウンロードが完了したらインストールを行ってください。 インストールディレクトリ以外はデフォルトのままでインストールしてかまいません。以下のディレクトリにインストールすると仮定します。

JacORB 1.4.1 は、zip ファイルを展開するだけでインストール完了です。展開したファイルを C:\JacORB141 ディレクトリに移動してください。そして、bin ディレクトリ以下に存在する idltemplate.bat と jacotemplate.bat をそれぞれ idl.bat と jaco.bat にファイル名を変更し、ファイルの内容を以下のように修正してください。

idl.bat
@echo off
java org.jacorb.idl.parser %*
jaco.bat
@echo off
rem call java interpreter
java -Dorg.omg.CORBA.ORBClass=org.jacorb.orb.ORB -Dorg.omg.CORBA.ORBSingletonClass=org.jacorb.orb.ORBSingleton %*

また、各 ORB 製品の環境を切り替えるための次のようなバッチファイルを作成してください。

bes51.bat
@echo off

set VBROKERDIR=C:\bes51
set VBROKER_ADM=%VBROKERDIR%\var\servers\%COMPUTERNAME%\adm

set JAVA_HOME=%VBROKERDIR%\jdk

set include=%include%;%VBROKERDIR%\include;
set lib=%lib%;%VBROKERDIR%\lib

set PATH=%VBROKERDIR%\bin;%JAVA_HOME%\bin;%path%

echo Set Environment for Borland Enterprise Server 5.1
jdk141.bat
@echo off

set JAVA_HOME=C:\jdk141
set PATH=%JAVA_HOME%\bin;%PATH%

echo Set Environment for JDK 1.4.1
JacORB141.bat
@echo off

REM JacORB 1.4.1 Enviroment
set JACORB_HOME=C:\JacORB141
set CLASSPATH=%JACORB_HOME%\lib\jacorb.jar;%CLASSPATH%
set CLASSPATH=%JACORB_HOME%\lib\idl.jar;%CLASSPATH%

set PATH=%JACORB_HOME%\bin;%PATH%

echo Set Environment for JacORB 1.4.1

2. システム構成 」 で示した各ディレクトリで対応する製品の bat ファイルを実行してください。これによって今回使用する ORB 製品の環境が構築できます。なお、JacORB 1.4.1 は、別途 JDK 1.2 以上の JDK が必要になります。



© 2003 OGIS-RI Co., Ltd.
Prev Index
Prev. Index