サーバの開発


このセクションでは、Java IDL による、一時 CORBA オブジェクトのサーバサポートについて説明します。 Hello World の例には、一時オブジェクトサーバが含まれています。

ここでは、以下の項目について説明します。

一時オブジェクトと持続オブジェクト

一時 CORBA オブジェクトの有効期間は、オブジェクトを作成したサーバプロセスの実行期間と同じです。サーバが停止すると、その一時オブジェクトも消失し、クライアントからのオブジェクト参照はすべて無効になります。一時オブジェクトは、アプリケーションとオブジェクト間の非同期処理およびコールバック通信に使用されます。たとえば、タイミングサービスがインターバルの期限が切れたことをクライアントアプリケーションに通知する場合、以下の手順が実行されます。

この処理方法は、手続き型プログラミングのコールバックに似ています。

これとは対照的に、持続オブジェクトは、明示的に破棄されるまで存在します。クライアントが持続 CORBA オブジェクトを参照している場合、そのオブジェクトのサーバが実行中ではなくても参照は使用可能です。ORB がオブジェクトの呼び出しを受け取ると、ORB デーモンがサーバを起動するからです。

現時点では、Java IDL は、一時オブジェクトサーバだけをサポートしています。まだ Java IDL を使用して持続オブジェクトサーバを記述することはできませんが、持続 CORBA オブジェクトのサーバが C++ 等の他の言語で記述されているか、またはほかの Java ORB を実装していれば、Java アプレットおよびアプリケーションをその持続 CORBA オブジェクトのクライアントにすることができます。

サーバントおよびサーバント基底クラス

一時 CORBA オブジェクトのサーバを実装する場合、オブジェクトの種類によっては 「サーバント」と呼ばれる Java クラスを記述する必要があります。このクラスは、「サーバント基底」というクラスから継承されます。サーバント基底クラスは、idltojava コンパイラでオプションを指定することにより生成されます。一時 CORBA オブジェクトのインスタンスは、そのサーバントクラスのインスタンスにより実装されます。

サーバント基底クラスは、ORB とその型に対応するサーバントコード (スケルトン) 間の、型固有の CORBA インタフェースです。サーバント基底クラスは、渡されるパラメータを非整列化し、サーバントメソッドを呼び出し、結果を整列化し、ORB が結果をクライアント ORB に返すように指示します。

サーバントクラスは、実装する IDL インタフェース定義内の各オペレーション用のメソッドを使ってサーバント基底を拡張します。(OMG IDL 属性は、読み取り専用の場合は 1 つのメソッド、書き込み可能な場合は 2 つのメソッドを必要とします。) 次のコードは、OMG IDL の使用例です。

module Notifiers {
   interface SimpleNotifier {
      void alert (in long alert_id);
   };
};

この型のサーバントは次のようになります。

import Notifiers.*
 
class SimpleNotifierServant extends _SimpleNotifierImplBase {
   
   void alert (int alert_id) {
      // do something about the alert ...
      return;
   }
}

サーバクラスは、次のようにして SimpleNotifierServant のインスタンスを生成できます。

  SimpleNotifierServant SimpleNotifier = new SimpleNotifierServant(); 
  orb.connect(SimpleNotifier); 

orb.connect() 呼び出しは、オブジェクトおよびサーバントを ORB とともに登録するので、CORBA オブジェクトの呼び出し時に ORB によりサーバントが呼び出されます。サーバが停止すると、ORB はそのサーバの CORBA オブジェクトのレコードを破棄するため、そのあとの呼び出しでは OBJECT_NOT_EXIST 例外が発生します。サーバは、orb.disconnect() 呼び出しにより自らが停止してしまう前に、CORBA オブジェクトを無効にすることもできます。

サーバントオブジェクトの使用

一時 CORBA オブジェクトは Java サーバントオブジェクトにより実装されます。サーバントオブジェクトは、その型の CORBA オブジェクト参照を必要とするどのメソッドにもパラメータとして渡すことができます。たとえば、Java プログラムにより米国 Sun Microsystems, Inc の株価がいつ 150 を超すのかを調べるとします。このプログラムは、次のオペレーションを提供する CORBA 株価監視オブジェクトへの参照を取得します (オペレーションは IDL および Java の両方で記述されている)。

// IDL
interface StockWatcher {
void set_threshold(
   in string stock_symbol,
   in short stock_price,
   in Notifiers::SimpleNotifier notifier_obj);
};
 
// Java
void set_threshold(
   String stock_symbol, 
   short stock_price, 
   Notifiers.SimpleNotifier notifier_obj)
  { // set the threshold ... 
  }
 

set_threshold() を呼び出すには、SimpleNotifier CORBA オブジェクトを作成する必要があります。SimpleNotifierImpl というサーバントクラスをすでにインポートしている場合には、このオブジェクトは次の方法で作成できます。

SimpleNotifier SUNWnotifier = new SimpleNotifierImpl(); 
int stockPrice = 150;
orb.connect(SUNWnotifier);
StockWatcher aStockWatcher = // code to get a stock-watcher reference; 
 
aStockWatcher.set_threshold ("SUNW", stockPrice, SUNWnotifier);
 

Dynamic Skeleton Interface

Dynamic Skeleton Interface (DSI) を使用すると、オブジェクトのインタフェースを前もって (コンパイル時に) 知っていない場合でも、サーバはサーバントオブジェクトを提供することができます。サーバは、IDL インタフェース定義からコンパイルされたスケルトンコードの代わりに、オペレーションの呼び出しを動的に構築します。

DSI を使用する利点

コンパイル時にサーバが実装インタフェースについて知らない場合に DSI を使用します。たとえば、COM クライアントが CORBA 領域に常駐するサービスにアクセスできるようにしながら、同時に COM 環境に常駐するサービスを CORBA クライアントが呼び出せるようにする場合、ブリッジアプリケーションが必要になることがあります。各環境には、要求および応答を作成する独自の方法があります。

このブリッジアプリケーションは、DSI を使用して CORBA クライアント要求を COM サーバが認識可能な形式に変換します。また DII を使用して、COM クライアント要求を CORBA サーバが認識可能な形式に変換します。このアプリケーションのプログラマは、この作業を実行するためのコードをすべて記述する必要があります。

この処理を一般的な静的オブジェクトの呼び出しと比較してみてください。サーバは、呼び出そうとするインタフェース用のコンパイル済みのスケルトンにアクセスします。これらのスケルトンは、IDL インタフェース定義を idltojava コンパイラでコンパイルすることにより生成されます。ORB は、要求を受け取ると、スケルトンコードを使ってサーバ側のオペレーション引数を作成し、結果を送り返します。

DSI の使用方法

DSI を使用するには、次の手順に従って動的サーバントを実装および登録します。

  1. クラスを宣言して org.omg.CORBA.DynamicImplementation を拡張します。

  2. invoke() メソッドを実装します。
    invoke() メソッドのコードを記述し、ServerRequest オブジェクトに対して次の処理を実行できるようにします。
    1. op_name() を呼び出してオペレーション名を抽出する
    2. オペレーションパラメータの NVList を構築する (この操作には通常、インタフェースリポジトリからのパラメータの型情報が必要になる)
    3. NVList を渡し、params() を呼び出してパラメータ値を抽出する
    4. オペレーションを実行し、適宜 NVList の out および inout パラメータに新しい値を代入する
    5. result() または except() のどちらかを呼び出す
    注: params() を呼び出し、そのあと result() または except() を呼び出す場合、必ず正しい呼び出し順序に従ってください。まず、params() を呼び出し、そのあと result() または except() のどちらかを 1 度に 1 つだけ呼び出します。これらの制限事項に従わなかった場合には、BAD_INV_ORDER 例外が発生します。

  3. _ids() メソッドを実装します。
    このメソッドは、DynamicImplementation のスーパークラスである org.omg.CORBA.portable.ObjectImpl から継承されます。これは、動的サーバにより実装されたインタフェースのリポジトリ ID を返します。

  4. DSI オブジェクトのインスタンスを作成し、org.omg.CORBA.ORB.connect() を呼び出して、このインスタンスを ORB とともに登録します。

DSI の使用例

次に示す DSI.idl は、動的に実装可能な非常に簡単なインタフェースを定義します。

//IDL
module JavaIDL {
  interface DSIExample {
    void print_args(in string arg1, in short arg2);
  };
};

次に、DSIServer.java ファイルから、対応する Java コードを示します。ここでは、invoke() の実装、および DSI.idl で定義された print_args() オペレーションの動的処理を行います。

//Java
import java.util.*;
import org.omg.CORBA.*;

// Dynamic servant class implementation
class DSIExampleServantImpl extends DynamicImplementation {

  // Store the repository ID for the interface implemented 
  static String[] myIds = {"IDL:JavaIDL/DSIExample:1.0"};

  // Create a reference to the ORB
  ORB orb;
  DSIExampleServantImpl(ORB orb) {
    this.orb = orb;
  }

  // Implementation of invoke() for handling dynamic requests
  public void invoke(ServerRequest request) {
    try {
      System.out.println("DSI: invoke called, op = "+ request.op_name());
    
      // Create an NVList to hold the parameters
      NVList nvlist = orb.create_list(0);

      // Check if the request is for the operation
      // "print_args"
      if (request.op_name().equals("print_args") == true) {

        // Add first argument to NVList
        Any any1 = orb.create_any();
        any1.insert_string("");
        nvlist.add_value("arg1", any1, ARG_IN.value);

        // Add second argument to NVList
        Any any2 = orb.create_any();
        any2.insert_short((short)0);
        nvlist.add_value("arg2", any2, ARG_IN.value);    

        //Pass the NVList to the request, to get values
        request.params(nvlist);

        // Extract values and print arguments
        System.err.println("Argument 1: In value: " 
			    + nvlist.item(0).value().extract_string());
        System.err.println("Argument 2: In value: "
			    + nvlist.item(1).value().extract_short());
        TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void);
        Any result_any = orb.create_any(); 
        result_any.type(result_tc);

	// Set the void result
        request.result(result_any);
      }
    } 
    catch ( Exception ex ) {
      ex.printStackTrace();
      System.out.println("DSIExample: Exception thrown: " + ex);
    }
  }

  // Implement the _ids() method to return repository ID of interface
  public String[] _ids() {
    return myIds; 
  }

} 
// File DSIServer.java continues
以下は、DSIServer.java の残りのコードで、標準サーバを実装します。静的サーバントで使用するのと同じオペレーションを使用して、動的サーバントを ORB とともに登録する点に注目してください。
// Java

// DSIServer implementation
public class DSIServer {

  // Main
  public static void main(String[] args) {
    try {
      // Access and initialize the ORB
      org.omg.CORBA.ORB orb = ORB.init(args, null);

      // Create an instance of the dynamic implementation
      DSIExampleServantImpl servant = new DSIExampleServantImpl(orb);

      // Register the dynamic servant with the ORB
      orb.connect(servant);

      // Write IOR into file. 
      // Alternatively, the naming service could be used.
      OutputStream f = new FileOutputStream(
            System.getProperty("user.home") + 
	    System.getProperty("file.separator") + "DSI.ior") ;
      DataOutputStream out = new DataOutputStream(f) ;
      String ior = orb.object_to_string(servant) ;
      out.writeBytes(ior) ;
      out.close();

      System.out.println("IOR is " + ior) ;

      // Wait for requests from client
      java.lang.Object sync = new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }

    } 
    catch (Exception ex) {
      ex.printStackTrace();
      System.err.println("DSIServer: Exception thrown: " + ex);
    }   
  }
}

委譲スケルトン (Tie)

Java では、クラスが実装を継承できるのは 1 つのスーパークラスからだけなので、クラス階層に正規に属するオブジェクトに CORBA オブジェクトの実装を提供するのは不便なことがあります (サーバント基底クラスは唯一の利用可能なスーパークラスの位置を占有する) 。これらのオブジェクトは、委譲スケルトンを使用することにより、簡単に CORBA サーバントにすることができます。

委譲スケルトンは、要求された CORBA オペレーションをサーバント基底クラス (オブジェクトが継承すべきクラス) から生成された Tie クラスへ移動します。Tie クラスは、オブジェクトのスケルトンとして機能し、ORB からの呼び出しを受け取り、実際に処理を行うサーバントにその呼び出しを委譲します。

注: 次のセクションで説明する IDL コンパイルの手順を実行する前に idltojava コンパイラをダウンロードする必要があります。

Tie の使用

Tie を使用するには、最初に -ftie フラグを使用して IDL インタフェースをコンパイルする必要があります。このコマンドを使用すると、通常の Java ファイルに加え、Operations インタフェースおよび Tie クラスも作成されます。それからクラスを記述し、生成された Operations インタフェースを実装します。

Tie の使用例

次のコードは、簡単な IDL インタフェースの例です。
// IDL
interface Frog{
  void croak();
};

Frog.idl を idltojava でコンパイルすると、標準クライアント、サーバントクラス等のサーバファイル、および委譲スケルトンに特有のファイルである _FrogTie と _FrogOperations が生成されます。 この IDL の標準的な実装は、次のようになります。

// FrogImpl.java--without using ties, inherits required
// CORBA functionality from _FrogImplBase

public class FrogImpl extends _FrogImplBase {
  public void croak() {
    getAudioClip(getCodeBase(), "frog.au").play();
  }
  
  public static void main(String[] args) {
    ORB orb = ORB.init();
    Frog frogRef = new FrogImpl();
    orb.connect(frogRef);
    // remainder of code deleted 
  }
}

FrogImpl.java は、その CORBA 機能 (ORB からのディスパッチアップコールなど) を _FrogImplBase から継承するため、残りのメソッドの実装コードを含んでいる必要があります。FrogImpl.java は、残りのメソッドが他のクラスのメソッドと同一であっても、それらを継承することはできません。

委譲スケルトンを使用する同じクラスは、次のようになります。

// Amphibian.java--provides general behavior

public class Amphibian extends Applet {
  public void breathWater(){
    // implementation deleted
  }
}

// FrogImpl.java--using ties

public class FrogImpl extends Amphibian implements _FrogOperations {
  public void croak() {
    // croak method must still be here; it is in the Operations interface
    getAudioClip(getCodeBase(), "frog.au").play();
  }
  
  public static void main(String[] args) {
    ORB orb = ORB.init();
    FrogImpl servant = new FrogImpl();
    Frog frogRef = new _FrogTie(servant);
    orb.connect(frogRef);
    // remainder of code deleted 
  }
}

Tie を使用して、FrogImpl は IDL インタフェース (および _FrogOperations) で定義された CORBA オペレーションの実装と同時に、2 通りの動作の継承用にスーパークラススロットを予約します。

orb.connect() 呼び出しの違いに注目してください。委譲スケルトンを使用して、実際のオブジェクトの実装を渡す代わりに ORB に新しい Tie クラスのインスタンスを渡します。


クライアント | サーバ | 例外 | 初期化 | ネームサービス

ホーム

概念

プログラミング

リファレンス

チュートリアル


Copyright © 1996, 1997 Sun Microsystems, Inc., 2550 Garcia Ave., Mtn. View, CA. 94043-1100 USA., All rights reserved.