このドキュメントでは、Internet Inter-ORB Protocol (IIOP) を使用してリモートオブジェクトにアクセスすることができる、Java Remote Method Invocation (RMI) プログラムの作成方法について説明します。RMI プログラムにごくわずかな制約を課すことによって、任意の言語の CORBA クライアントから RMI-IIOP サーバーにアクセスできるようになります。RMI-IIOP によって、RMI を簡単に使用できるようになり、CORBA/IIOP 言語の相互運用性が実現されます。
RMI は通信プロトコルとして CORBA-IIOP を使用しないので、その他の言語との相互運用性に欠けています。
Java(TM) 2 Platform, Standard Edition (J2SE) の 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 インタフェースです。
質問: J2SE 1.3 で動作する RMI-IIOP アプリケーションを持っています。rmic -iiop -poa <RMI インタフェース> を使って新しいスタブおよびスケルトンを生成すると動作しなくなってしまいました。なぜですか。
回答: 次に挙げるように、RMI-IIOP プログラムのコンパイルおよび実行方法は 2 とおりあります。次の方法を組み合わせるのは避けてください。
今回の Java SE のリリースには、-iiop -poa オプションが追加されています。-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 Language to IDL Mapping (OMG) を参照してください。
注:生成された IDL は、IDL に対する CORBA 2.3 拡張機能がサポートされている IDL コンパイラを使用しないとコンパイルできません。
rmic についての詳細は、RMIC ツールのページ (Solaris 版/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