エンタープライズへの適用

CORBAの動作を試す簡単な方法はありませんか?

テンアートニ 中越智哉
2001/8/10

 CORBAについて学習したいと思っても、必要なソフトがないと思っていらっしゃる方も多いのではないかと思います。実は、Javaを使ってCORBAオブジェクトを作るのであれば、特別なソフトは必要ありません。JDK(J2SE)だけがあればいいのです。

 ここでは、CORBAそのものについての解説は割愛しますが、J2SEに含まれるJava IDLを使って、簡単なCORBAのサンプルを動作させる手順についてご説明していきます(CORBAやJava IDLについての詳しい解説は、ほかの文献やJ2SE付属のドキュメントなどをご覧ください)。

※ この記事では、Java IDLの仕様はJ2SE 1.4 ベータ版に基づいて解説しています。

■Java IDL

 Java IDLとは、CORBAで規定されている、いわゆるInterface Difinition Languageのことだけを指しているのではなく、JDKにバンドルされて提供されるORB(Request Object Broker)などの、いわゆるCORBAオブジェクトの開発、実行環境を提供します。Java IDLには、以下のようなツールが含まれています。

  • idlj
    CORBAのIDL定義ファイルをJavaに変換したソースを生成するプリプロセッサです。

  • orbd
    CORBAのORB(Object Request Broker)のデーモンプログラムです。また、それ以外に、ネームサービスも含まれています。このネームサービスは永続的(Persistent)な機能、つまりサービスプロセスをシャットダウンしても、登録したディレクトリ内容を保持できる機能を提供します。

  • servertool
    CORBAサーバオブジェクトの管理をするためのコンソールベースのツールです。

  • tnameserv
    orbdの古いバージョンにあたるもので、基本的な機能はorbdと同じです。ただしネームサービスは、一時的(Transient)な機能に限定されており、サービスプロセスをシャットダウンすると、登録したディレクトリ内容は破棄されます。


■Java IDLによる実装の手順

 では、Java IDLを使ったCORBAの実装手順についてご説明しましょう。

(1)IDLのコーディング
 ここでいうIDLは、CORBAの仕様で規定されているInterface Difinition Languageのことで、Javaのインターフェイス定義によく似ています。IDLでは、クライアントがアクセスすることのできる操作(Javaのメソッドに相当)、例外、型付きの属性を定義することができます。

(2)IDLから、Javaソースへのコンパイル
 idljを用いて、IDLをJavaソースに変換します(idljはプリプロセッサなので、Javaのクラスファイルは生成されません)。

(3)サーバアプリケーションの作成
 上記で作成されたソースを用いて、サーバントクラスと、ネームサービスにサーバントを登録するための、サーバクラスを作成します。

(4)クライアントアプリケーションの作成
 ORBからオブジェクト参照を取得してメソッドを実行するための、クライアントクラスを作成します。

(5)コンパイルと実行
 作成したクラスすべてをコンパイルします。実行は、orbdの起動、サーバクラスの実行を順に行い、その後、クライアントクラスを実行します。

■サンプルの作成と実行

 では、J2EE付属のドキュメントを参考にして、簡単なサンプルを作成、実行してみましょう。

 ここでは、C:\javaに必要なファイルを配置すると仮定します。JavaのCLASSPATHに、このディレクトリもしくはカレントディレクトリをあらかじめ追加しておいてください。また、PATHに、J2SEのbinディレクトリを追加するのも忘れないでください。OSは、Windows NTを想定しています。

(1)IDLのコーディング
 作成するCORBAオブジェクトには、「Hello Java IDL World!」という文字列を返す操作を実装します。これをIDLで記述すると、次のようになります。

Hello.idl
module HelloMod
{
  interface Hello
  {
    string getMessage();
    oneway void shutdown();
  };
};

(2)IDLから、Javaソースへのコンパイル
 このIDLファイルを、idljコマンドでJavaソースに変換します。DOSプロンプトなどで、

C:\>c:
C:\>cd \java
C:\java>idlj -fall Hello.idl

と実行します。idljのオプション-fallは、クライアント、サーバ双方のファイルを生成するための指定です(-fclient-fserverと指定すると、それぞれ、クライアント用、サーバ用のファイルだけが生成されます)。このとき、エラーが出なければ、作成は成功しています。この場合、IDLでmodule名として指定したものが、Javaではパッケージに相当しますので、C:\java\HelloModというディレクトリができていて、そのディレクトリ上には、

HelloMod\HelloPOA.java
HelloMod\_HelloStub.java
HelloMod\Hello.java
HelloMod\HelloHelper.java
HelloMod\HelloHolder.java
HelloMod\HelloOperations.java

という6つのファイルができていると思います。
(注:J2SE 1.3以前では、ファイルの種類が多少異なります)

(3)サーバアプリケーションの作成
 (2)で生成された、HelloPOAを継承したサーバントクラスと、ネームサービスにオブジェクトを登録する処理を行うサーバクラスを作成します。サーバントクラスには、IDLで定義した操作のJavaでの実装を記述していきます。IDLでの操作を、Javaのメソッド定義に変換したものが、HelloOperations.javaなので、これをもとに、サーバントのメソッドを実装していきます。

HelloOperations.javaダウンロード
package HelloMod;

/**
* HelloMod/HelloOperations.java
* IDL-to-Java コンパイラ (ポータブル), バージョン "3.0" で生成
* 生成元: Hello.idl
* 2001年7月18日 17時13分52秒JST
*/

public interface HelloOperations
{
  String getMessage ();
  void shutdown ();
} // interface HelloOperations

 さらに、サーバクラスを作成します。サーバクラス内では、ORBオブジェクトと、サーバントのインスタンスを作成し、ORBオブジェクトを用いて、サーバントのインスタンスをネームサービスに登録します。これにより、クライアントが ネームサービスにアクセスして、サーバントの参照を取得することができるようになります。

HelloServer.javaダウンロード
import HelloMod.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;
import org.omg.PortableServer.POA;

class HelloImpl extends HelloPOA {
  private ORB orb;

    public void setORB(ORB orb_val) {
      orb = orb_val;
    }

    public String getMessage() {
      return "\nHello Java IDL world !\n";
    }


    public void shutdown() {
      orb.shutdown(false);
    }
  }


  public class HelloServer {


    public static void main(String args[]) {
    try{
      // ORBの生成と初期化
      ORB orb = ORB.init(args, null);


      // RootPOAへの参照を取得し、POAManagerをactivateする
      POA rootpoa = (POA)orb.resolve_initial_references("RootPOA");
      rootpoa.the_POAManager().activate();


      // サーバントのインスタンスを作成し、ORBにセットする
      HelloImpl helloImpl = new HelloImpl();
      helloImpl.setORB(orb);


      // サーバントを登録するためのオブジェクト参照を取得
      org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl);
      Hello href = HelloHelper.narrow(ref);


      // ネームサービスを検索
      org.omg.CORBA.Object objRef =
          orb.resolve_initial_references("NameService");


      // ネームサービスの参照を取り出す
      NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

       // サーバントの参照をネームサービスに登録
      String name = "Hello";
      NameComponent path[] = ncRef.to_name( name );
      ncRef.rebind(path, href);
      System.out.println("HelloServer が起動しました。");
      // wait for invocations from clients
      orb.run();
    }
    catch (Exception e) {
      System.err.println("ERROR: " + e);
      e.printStackTrace(System.out);
    }

    System.out.println("HelloServer を終了します。");

  }
}

(4)クライアントアプリケーションの作成
 クライアントでは、サーバアプリケーションによって登録されたサーバントの参照を取得します。そのサーバントのメソッドを呼び出して結果を取得し、コンソールに表示します。

HelloClient.javaダウンロード
import HelloMod.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

public class HelloClient {
  static Hello helloImpl;


  public static void main(String args[]) {
    try{
      // ORBの生成と初期化
      ORB orb = ORB.init(args, null);


      // ネームサービスへの参照を取得
      org.omg.CORBA.Object objRef =
       orb.resolve_initial_references("NameService");
      NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);


      // ネームサービスから、「Hello」という名前のサーバントを検索し、参照を取得
      String name = "Hello";
      helloImpl = HelloHelper.narrow(ncRef.resolve_str(name));


      // サーバントのメソッドを呼び出し
      System.out.println(helloImpl.getMessage());


    } catch (Exception e) {
      System.out.println("ERROR : " + e) ;
      e.printStackTrace(System.out);
    }
  }
}

(5)コンパイルと実行
 ここまで作成したクラスを、すべてコンパイルします。ファイルは、以下の8つです。

C:\java\HelloMod\HelloPOA.java
C:\java\HelloMod\_HelloStub.java
C:\java\HelloMod\Hello.java
C:\java\HelloMod\HelloHelper.java
C:\java\HelloMod\HelloHolder.java
C:\java\HelloMod\HelloOperations.java
C:\java\HelloServer.java
C:\java\HelloClient.java


C:\java>javac *.java HelloMod\*.java

 コンパイルが成功したら実行してみましょう。orbd、サーバアプリケーションの順に実行し、起動が成功したらクライアントアプリケーションを実行します。

 まず、orbdを起動します。コマンドラインには、必ず-ORBInitialPortで、ポート番号を、-ORBInitialHostでホスト名を指定する必要があります。ポート番号は、空いている番号を適当に指定してください。

C:\java>start orbd -ORBInitialPort 1050 -ORBInitialHost localhost

※もし、すぐにウィンドウが閉じてしまう場合は、起動に失敗しています。ポート番号を変えるなどして、再度実行してみてください。

 次に、サーバアプリケーションを実行します。orbdと同じく、コマンドラインにポート番号とホスト名を指定してください。このときの値は、当然、orbdと同じにします。

C:\java>java HelloServer -ORBInitialPort 1050 -ORBInitialHost localhost

 両方が正常に起動したら、クライアントアプリケーションを実行します。

C:\java>java HelloClient -ORBInitialPort 1050 -ORBInitialHost localhost

 上の画面のように、コンソールに「Hello Java IDL World!」と表示されれば成功です。せっかくの分散オブジェクトですから、サーバとクライアントを分けて、LAN上のほかのマシンから実行してみても面白いかもしれませんね。

 また、参考までに、サーブレットで作ったクライアントのリストも載せますので(とはいいましてもコアな部分はコンソール版と同じですが…)興味がありましたら、こちらも試してみてください(Tomcatで動作確認しています)。

HelloServlet.javaダウンロード
import java.io.*;
import javax.rmi.*;
import HelloMod.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloServlet extends HttpServlet {

  public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException {

    String message = null;

    Hello helloImpl;

    try{
      ORB orb = ORB.init(new String[]{}, null);

      org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
      NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

      String name = "Hello";
      helloImpl = HelloHelper.narrow(ncRef.resolve_str(name));

      System.out.println("Obtained a handle on server object: " + helloImpl);
      message = helloImpl.getMessage();

    } catch (Exception e) {
      System.out.println("ERROR : " + e) ;
      e.printStackTrace(System.out);

      PrintWriter out = response.getWriter();
      response.setContentType("text/html;charset=Shift_JIS");
      out.println("<html>");
      out.println("<body>");
      out.println("<pre>");
      out.println("ERROR : " + e) ;
      e.printStackTrace(out);
      out.println("</pre>");
      out.println("</body>");
      out.println("</html>");
      return;
    }

    PrintWriter out = response.getWriter();
    response.setContentType("text/html;charset=Shift_JIS");
    out.println("<html>");
    out.println("<body>");
    out.println("<h1>"+message+"</h1>");
    out.println("</body>");
    out.println("</html>");
    out.close();
  }
}


参考URL:

J2SE 1.4 の Java IDLに関するドキュメント(英語)
http://java.sun.com/j2se/1.4/docs/guide/idl/index.html

J2SE 1.3 の Java IDLに関するドキュメント(日本語)
http://java.sun.com/j2se/1.3/ja/docs/ja/guide/idl/index.html

J2SE 1.4のJava IDLは、1.3からいくつか大きな変更が加わっています。1.3から1.4への変更点は、以下のURLで確認できます。
http://java.sun.com/j2se/1.4/docs/guide/idl/jidlChanges.html

 

「Java Solution FAQ」




Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間