このドキュメントでは、Internet Inter-ORB Protocol (IIOP)を使用してリモート・オブジェクトにアクセスすることができる、Java Remote Method Invocation (RMI)プログラムの作成方法について説明します。 RMIプログラムにごくわずかな制約を課すことによって、任意の言語のCORBAクライアントからRMI-IIOPサーバーにアクセスできるようになります。 RMI-IIOPによって、RMIを簡単に使用できるようになり、CORBA/IIOP言語の相互運用性が実現されます。
RMIは通信プロトコルとしてCORBA-IIOPを使用しないので、その他の言語との相互運用性に欠けています。
Java SEのCORBA/IIOP実装は、Java IDLとして知られています。 idljコンパイラおよびJava IDLを使用して、Javaプログラミング言語からCORBAオブジェクトを定義、実装、およびアクセスを行うことができます。
Java IDLのWebページでは、CORBA/IIOPプログラミングについてJavaを中心にしてわかりやすく説明されています。 Java IDLプログラムの作成についての概要は、入門: Hello WorldのWebページを参照してください。
次は、CORBA/IIOP機能をサポートする主なrmicフラグです。
-iiop -- IIOPスタブ/タイを生成する。次のオプションは、-idlオプションと同時に使用されます。
-noValueMethods -- IDLのvaluetype内にメソッドとコンストラクタのIDLが生成されないようにする。rmicコンパイラの詳細については、rmicのドキュメントを参照してください。
スタブ・クラスは、abstractインタフェースにも生成されます。 abstractインタフェースは、java.rmi.Remoteを継承したインタフェースではありませんが、そのインタフェースのメソッドはすべてjava.rmi.RemoteExceptionか、java.rmi.RemoteExceptionのスーパー・クラスをスローします。 また、java.rmi.Remoteを継承せず、メソッドを持たないインタフェースも、abstractインタフェースです。
質問: Java SEで動作するRMI-IIOPアプリケーションを持っています。 rmic -iiop -poa <RMIインタフェース>を使って新しいスタブおよびスケルトンを生成すると動作しなくなってしまいました。 なぜですか。
回答: 次に挙げるように、RMI-IIOPプログラムのコンパイルおよび実行方法は2とおりあります。 次の方法を組み合わせるのは避けてください。
-iiopフラグに-poaオプションを指定すると、継承がorg.omg.CORBA_2_3.portable.ObjectImplからorg.omg.PortableServer.Servantに変わります。 この種のマッピングは非標準であり、Java Language to OMG IDL Language Mapping Specificationには指定されていません。
POA (Portable Object Adapter)のPortableServerモジュールには、ネイティブServant型を定義します。 Javaプログラミング言語では、Servant型がJava org.omg.PortableServer.Servantクラスにマッピングされます。 このクラスは、すべてのPOAサーバント実装の基底クラスとして機能し、アプリケーション・プログラマが呼び出すことのできるいくつかのメソッドのほかに、POAそのものによって呼び出され、サーバントの動作を制御するためにユーザーがオーバーライドできるメソッドも提供します。
ノート: rmic -idlでOMG IDLが生成されたあと、IDL-to-Javaコンパイラではなく、IDL-to-C++またはその他の言語へのコンパイラで生成されたIDLを使用します。 「ラウンド・トリップ」は非推奨であり、不要です。 IDL生成機能は、C++などのその他の言語で使用されることになっています。 Javaクライアントまたはサーバーは、元のRMI-IIOP型を使用できます。
IDLを使用すると、オブジェクトに対してAPIを指定するときに、プログラミング言語に依存せずに、単に宣言することができます。 IDLは、メソッドおよびデータの仕様として使用します。CORBAバインディングを提供する任意の言語で、メソッドおよびデータの作成および呼出しを行うことができます。 これらの言語には、JavaおよびC++が含まれています。 詳細は、「Java言語とIDLのマッピング」(OMG)を参照してください。
ノート: 生成されたIDLは、IDLに対するCORBA 2.3拡張機能がサポートされているIDLコンパイラを使用しないとコンパイルできません。
rmicの詳細は、RMICツールのページ(Solaris、LinuxまたはMac OS X版/Windows版)を参照してください。
import javax.naming.*; ... Context ic = new InitialContext();
import java.rmi.*; ... Naming.rebind("MyObject", myObj);次を使用します。
import javax.naming.*; ... ic.rebind("MyObject", myObj);
import java.util.*; import javax.naming.*; ... Hashtable env = new Hashtable(); env.put("java.naming.applet", this); Context ic = new InitialContext(env);
サーバー側では、PortableRemoteObject.toStub()呼出しを使用してスタブを取得し、writeObject()を使用してそのスタブをObjectOutputStreamに直列化します。 これらの処理を行うコードは、たとえば次のようになります。
org.omg.CORBA.ORB myORB = org.omg.CORBA.ORB.init(new String[0], null); Wombat myWombat = new WombatImpl(); javax.rmi.CORBA.Stub myStub = (javax.rmi.CORBA.Stub)PortableRemoteObject.toStub(myWombat); myStub.connect(myORB); // myWombat is now connected to myORB. To connect other objects to the // same ORB, use PortableRemoteObject.connect(nextWombat, myWombat); FileOutputStream myFile = new FileOutputStream("t.tmp"); ObjectOutputStream myStream = new ObjectOutputStream(myFile); myStream.writeObject(myStub);クライアント側では、readObject()を使用して、ObjectInputStreamから、リモート参照の直列化復元をオブジェクトに対して行います。次のようなコードが使用されます。
FileInputStream myFile = new FileInputStream("t.tmp"); ObjectInputStream myStream = new ObjectInputStream(myFile); Wombat myWombat = (Wombat)myStream.readObject(); org.omg.CORBA.ORB myORB = org.omg.CORBA.ORB.init(new String[0], null); ((javax.rmi.CORBA.Stub)myWombat).connect(myORB); // myWombat is now connected to myORB. To connect other objects to the // same ORB, use PortableRemoteObject.connect(nextWombat, myWombat);
_<implementionName>_Tie.class _<interfaceName>_Stub.class
orbd -ORBInitialPort port#ORBDの起動時にポート番号を指定する必要があります。
java -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url=iiop://<hostname>:1050 <appl_class>この例では、ネーム・サービス・ポート番号1050を使用します。 ステップ7でそれ以外のポートを指定した場合、プロバイダのURLに同じポート番号を使用する必要があります。 プロバイダのURLの<hostname>は、ステップ7でCosNamingサーバーを起動したときに使用したホスト名です。
java.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory java.naming.provider.url=iiop://<hostname>:1050この例では、ネーム・サービス・ポート番号1050を使用します。 ステップ7でそれ以外のポートを指定した場合、プロバイダのURLに同じポート番号を使用する必要があります。 プロバイダのURLの<hostname>は、ステップ7でCosNamingサーバーを起動したときに使用したホスト名です。
新しいRMI-IIOPアプリケーションの作成方法に関するチュートリアルは、「入門: RMI-IIOPの使用法POAベースのサーバー側モデルの使用例」または「チュートリアル: 入門: RMI-IIOPの使用法」で参照できます。
PortableRemoteObject.exportObject()呼出しは、Tieオブジェクトを作成し、将来の使用に備えてキャッシュに格納するだけです。 作成されたTieには、委譲やORBとの関連付けがありません。 これを「明示的呼出し」と呼びます。
PortableRemoteObject.exportObject()は、サーバー・インスタンスの作成時に自動的に生成されます。 これは、PortableRemoteObjectコンストラクタを基底クラスとして呼び出したときに生成されます。 これを「暗黙の呼出し」と呼びます。
PortableRemoteObject.toStub()は、あとでアプリケーションによって呼び出されたときに対応するStubオブジェクトを生成し、キャッシュに格納されているTieオブジェクトと関連付けます。 ただし、Tieは接続されておらず、委譲を持たないので、新しく作成されたスタブも委譲やORBを持ちません。
スタブに委譲が設定されるのは、アプリケーションがStub.connect(orb)を呼び出すときのみです。 このため、ORB接続が確立される前にスタブを操作しようとしても失敗します。
「Java Language to IDL Mapping Specification」では、Stub.connect()メソッドは次のように規定されています。
connectメソッドにより、スタブは指定されたORBオブジェクトorbを使ってリモート接続を確立できる状態になります。 通常、接続は、リモート・メソッド呼出しでスタブが引数として受け渡されるときに暗黙的に確立されます。ただし、明示的な呼出しによって接続を確立する方が都合がよい場合もあります(直列化復元後など)。 スタブがすでにorbに接続されていて、orbの委譲セットを持っている場合、接続は機能しません。 スタブがその他のORBに接続されている場合、RemoteExceptionがスローされます。 それ以外の場合、このスタブとORBオブジェクトorbの委譲が生成されます。POAが有効になっていないサーバントの場合、必須設定としてStub.connect(orb)が必要になります。
ノート: 異なる言語で書かれたORB間での通信が可能なはずなのは本当ですが、Java ORBとほかのベンダーのORBとの相互運用性はまだテストしていません。
UnicastRemoteObject
は、RMIプログラミングのオブジェクト実装のスーパー・クラスとして使用し、このシナリオでは、分散アプリケーションが同質なJava環境で開発され、JRMPがリモート呼出しメカニズムとして使用されます。 PortableRemoteObject
は、分散アプリケーションを開発するときに、IIOPが望ましい呼出しメカニズムである場合に使用します。IIOPによって、さらに標準化された呼出し基盤が提供され、Java以外の分散アプリケーション・コンポーネントとの相互運用が可能になります。 RMI-IIOPは、OMG CORBA標準に基づく分散アプリケーション・コンポーネントとの相互運用性を提供し、Javaや、C、C++、Pythonなどの他の言語で開発されます。
サーバーがデュアル・スタック相互運用性を提供するように設計することによって、JRMPとIIOPの両方でサービスのデュアル・エクスポートを同時に提供するようにJavaサーバー・コンポーネントを構成することもできます。 UnicastRemoteObject
とPortableRemoteObject
のexportObject
メソッドを使用してサービス・オブジェクトを「登録」するようサーバー・アプリケーション・コンポーネントを構造化することで、それぞれJRMPとIIOPを使用して、サービス・オブジェクトを呼び出すことができます。 このアプローチにより、分散アプリケーションの開発者は、継承ではなくexportObject
メソッドを使用して、アプリケーション・オブジェクトをエクスポートします。 PortableRemoteObject.exportObject()
メソッドを呼び出してそのサービスを使用可能にするサーバー・オブジェクトは、通常そのオブジェクトの名前をCosNamingサービスに公開します。 UnicastRemoteObject.exportObject()
メソッドによってエクスポートされるサーバー・オブジェクトは、通常その名前をrmiregistryに公開し、RMI /JRMPのデフォルト・ネーム・サービス(java.rmi.Naming)を提供します。
JMXフレームワークでは、このような形態のリモート呼出しの二面性が提供されます。
ulimit -n 90