このチュートリアルでは、既存のクラスを起動可能クラスにする手順を説明します。また、起動可能オブジェクトの作成や UnicastRemoteObject を起動可能にする方法を理解するためにも役立ちます。
JavaTM 2 SDK をリリースする前は、UnicastRemoteObject を継承しないクラスのインスタンスには、(1) リモートオブジェクトのインスタンスを生成し、かつ (2) 常時稼動中である、サーバプログラムからアクセスできました。この機能は、static メソッド UnicastRemoteObject.exportObject を呼び出してオブジェクトをエクスポートするコンストラクタを作成することにより実現されていました。exportObject メソッドは、java.rmi.Remote を継承するインタフェースを実装するオブジェクトを引数にとります。
現在では、java.rmi.activation.Activatable クラスおよび RMI デーモン rmid の導入により、常時ではなく「必要に応じて」作成され、実行されるリモートオブジェクトの実装情報を登録するプログラムの記述が可能になりました。RMI デーモン rmid は、Java 仮想マシン* (JVM) を提供します。 この JVM からほかの JVM インスタンスを生成させることも可能です。UnicastRemoteObject.exportObject の場合と同様に、起動可能オブジェクトを static メソッド Activatable.exportObject を使ってエクスポートすることもできます。 この場合、エクスポートされたオブジェクトはリモートインタフェースを実装する必要があります。
注 - 以降のチュートリアルで、「起動可能オブジェクトの実装」、「起動可能オブジェクト」、および「実装」と言った場合、すべて、リモートインタフェースを実装する起動可能クラス examples.activation.MyClass を指します。
このチュートリアルの構成は、次のとおりです。
このチュートリアルの実行に必要なファイルは、次のとおりです。Client3.java - 起動可能オブジェクトのメソッドを呼び出すクラス
	 AnotherRemoteInterface.java - 以下のクラスにより実装される java.rmi.Remote インタフェース
	MyClass.java - 起動可能に変更されるクラス
	Setup3.java - 起動可能クラスに関する情報を RMI レジストリおよび RMI デーモンに登録するクラス
ここでは、クライアントコードも示しますが、実装クラスやセットアップクラスの場合のように、手順を追った説明はしません。これは、起動可能オブジェクトのクライアントコードが、起動可能でないリモートオブジェクトにアクセスするための RMI クライアントコードと同じであるためです。起動は、厳密にはサーバ側での実装によって決定されます。
このチュートリアルで使われているソースコードは、次のファイル形式から選ぶことができます。
リモートで呼び出す各メソッドを記述するインタフェースを作成します。この例のリモートインタフェースは  examples.activation.AnotherRemoteInterface です。リモートインタフェースの作成には、次の 3 つのステップがあります。 
java.rmi.Remote を継承する
	ステップ 1:
インタフェースに対し適切なインポートを実行するimport java.rmi.*;ステップ 2:
java.rmi.Remote を継承するpublic interface AnotherRemoteInterface extends Remote {ステップ 3:
リモートに呼び出す可能性のあるメソッドをそれぞれ宣言するpublic String calltheServer(String s) throws RemoteException;
この例の実装クラスは、 examples.activation.MyClass です。Activatable または UnicastRemoteObject を継承しないクラスを起動可能にするには、次の 3 つのステップを実行します。 
ステップ 1:
実装クラスに対し適切なインポートを実行するimport java.rmi.*; import java.rmi.activation.*;ステップ 2:
クラス宣言を変更し、java.rmi.Remoteを継承するインタフェースをクラスに実装するpublic class MyClass implements examples.activation.AnotherRemoteInterface {ステップ 3:
2 つの引数をとる新しいコンストラクタを実装クラスに追加するpublic MyClass(ActivationID id, MarshalledObject data) throws RemoteException { // Register the object with the activation system // then export it on an anonymous port // Activatable.exportObject(this, id, 0); }
「セットアップ」クラスの役割は、リモートオブジェクトのインスタンスを生成しない場合でも、起動可能クラスに必要なすべての情報を作成することです。この例のセットアップクラスは、examples.activation.Setup3 です。 
セットアップクラスは、起動可能クラスに関する情報を rmid に渡し、リモート参照 (実行可能クラスのスタブクラスのインスタンス) および識別子 (名前) を rmiregistry に登録します。 そのあと、セットアップクラスは終了できます。セットアップクラスは、7 つのステップで作成します。 
SecurityManager をインストールする
	ActivationGroup のインスタンスを生成する
	ActivationDesc のインスタンスを生成する
	rmid に起動記述子を登録する
	rmiregistry の名前にバインドする
	ステップ 1:
セットアップクラスで適切なインポートを実行するimport java.rmi.*; import java.rmi.activation.* import java.util.Properties;ステップ 2:
SecurityManagerをインストールするSystem.setSecurityManager(new RMISecurityManager());ステップ 3:
ActivationGroupのインスタンスを生成する注: ここでは、例を単純にするために、すべての位置のすべてのユーザにグローバルなアクセス権を与える policy ファイルを使用します。このポリシーファイルは、実稼働環境では使用しないでください。
java.security.policyファイルを使ってアクセス権を適切に指定する方法については、次のドキュメントを参照してください。
デフォルトの Policy の実装とポリシーファイルの構文セットアップアプリケーションにおける起動グループ記述子の役割は、
rmidが適切な既存の JVM にアクセスしたり、起動可能オブジェクト用の新しい JVM を生成したりする際に必要になるすべての情報を提供することです。注 - このコードを実際にシステム上で実行するには、ポリシーファイルの位置を、ソースコードに付属するサンプルのポリシーファイルをインストールした絶対パスに変更する必要があります。
// Because of the Java 2 security model, a security policy should // be specified for the ActivationGroup VM. The first argument // to the Properties put method, inherited from Hashtable, is // the key and the second is the value // Properties props = new Properties(); props.put("java.security.policy", "/home/rmi_tutorial/activation/policy"); ActivationGroupDesc.CommandEnvironment ace = null; ActivationGroupDesc exampleGroup = new ActivationGroupDesc(props, ace); // Once the ActivationGroupDesc has been created, register it // with the activation system to obtain its ID // ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(exampleGroup);ステップ 4:
ActivationDescのインスタンスを生成する起動記述子の役割は、
rmidが実装クラスの新しいインスタンスの生成に必要とするすべての情報を提供することです。注 - このコードをシステム上で実行するには、ファイルの URL の位置を、サンプルソースコードを実際にインストールしたディレクトリの位置に変更する必要があります。
// The "location" URL specifies where the class definition // will come from when this object is requested (activated). // Don't forget the trailing slash at the end of the URL // or your classes won't be found // String location = "file:/home/rmi_tutorial/activation/"; // Create the rest of the parameters that will be passed to // the ActivationDesc constructor // MarshalledObject data = null; // The location argument to the ActivationDesc constructor will be used // to uniquely identify this class; it's location is relative to the // URL-formatted String, location. // ActivationDesc desc = new ActivationDesc (agi, "examples.activation.ActivatableImplementation", location, data);ステップ 5:
リモートインタフェースのインスタンスを宣言し、rmidに起動記述子を登録するAnotherRemoteInterface ari = (AnotherRemoteInterface)Activatable.register(desc); System.out.println("Got the stub for MyClass");ステップ 6:
Activatable.registerメソッドによって返されたスタブをrmiregistryの名前にバインドするNaming.rebind("MyClass", ari); System.out.println("Exported MyClass");System.exit(0);
コードのコンパイルおよび実行は、次の 6 つのステップで行います。 
rmic を実行する
	rmiregistry を開始する
	rmid を開始する
	ステップ 1: 
リモートインタフェース、実装、クライアント、およびセットアップの各クラスをコンパイルする 
% javac -d . AnotherRemoteInterface.java % javac -d . MyClass.java % javac -d . Client3.java % javac -d . Setup3.java
% rmic -d . examples.activation.MyClass
% rmiregistry &
注 - rmiregistry を開始する前に、registry を実行するシェルまたはウィンドウに CLASSPATH が設定されていないこと、あるいは設定されていても、クライアントにダウンロードするクラスへのパス (リモートオブジェクトの実装クラスのスタブを含む) が含まれていないことを確認してください。
rmiregistry が、その開始時に CLASSPATH 内でスタブクラスを見つけると、サーバの java.rmi.server.codebase プロパティは無視されます。その結果、クライアントは、そのリモートオブジェクトのスタブコードをダウンロードできません。
% rmid -J-Djava.security.policy=rmid.policy &
rmid.policy は、rmid のセキュリティポリシーファイル名です。
 注:  デフォルトでは、rmid は現在、セキュリティポリシーファイルを要求します。 このファイルは、起動グループ用の JVM の起動に、各 ActivationGroupDescriptor の情報を使用できるかどうかを確認するために使用されます。完全な詳細については、rmid の Solaris オペレーティング環境用マニュアルページおよび rmid の Microsoft の Windows プラットフォーム用マニュアルページを参照してください。
コードベースのプロパティを実装スタブの位置に設定して、セットアップを実行します。次の 4 つを同じコマンド行に記述する必要があります。 
 
java」コマンド
	空白文字は、java という語の直後に 1 つ、2 つのプロパティの間に 1 つ、および (ブラウザまたは紙上では判別しにくいですが) examples という語の直前に 1 つ必要です。
% java  -Djava.security.policy=/home/rmi_tutorial/activation/policy  -Djava.rmi.server.codebase=file:/home/rmi_tutorial/activation/  examples.activation.Setup3
コードベースプロパティは、URL として解釈処理されます。 このため、プロパティは http://aHost/somesource/ か file:/myDirectory/location/ の形式、またはオペレーティングシステムによっては file:///myDirectory/location/ (file:のあとにスラッシュが 3 つ続く) の形式でなければなりません。
サンプルコードを実行するには file:形式の URL の方が使いやすい場合があります。しかし、この場合、サーバにアクセスできるクライアントは、(サーバと同じマシン上で実行したり NFS などの共用ファイルシステムを使用して) サーバと同じファイルシステムにアクセスできるクライアントだけになります。HTTP サーバがまだ稼動していない場合は、米国サン・マイクロシステムズ社またはその関係会社の HTTP サーバからダウンロードすることができます。
これらのサンプル URL の各文字列には、末尾に「/」があることに注意してください。java.rmi.server.codebase プロパティで指定する URL では、実装がクラス定義を適切に解釈処理 (検索) するために、末尾のスラッシュが必要です。コマンド行からの java.rmi.server.codebase プロパティの設定についての詳細は、java.rmi.server.codebase プロパティを使用した動的なコードのダウンロードについてのチュートリアルを参照してください。
プロパティ上の末尾のスラッシュを忘れたり、ソース位置にクラスファイルが見つからない (ダウンロード可能ではない) 場合、またはプロパティ名の入力を間違えた場合は、java.lang.ClassNotFoundException がスローされます。この例外は、リモートオブジェクトを rmiregistry にバインドしようとした場合、または最初のクライアントがそのオブジェクトのスタブにアクセスしようとした場合にスローされます。後者の場合は、rmiregistry が CLASSPATH 内でスタブを検索するため、さらに問題が発生する場合があります。
サーバ側の出力は、次のようになります。
      Got the stub for MyClass
      Exported MyClass
ステップ 6: クライアントプログラムへの引数は、実装サーバのホスト名で、この場合は vector です。
% java -Djava.security.policy=/home/rmi_tutorial/activation/policy examples.activation.Client3 vector
クライアント側の出力は次のようになります。
      Got a remote reference to the class MyClass
      Called the remote method
      Result: Watson are you there?  I'm here!
rmid およびレジストリに登録されます。 そのあと、「アダプタ」クラスによってオブジェクトのインスタンスが作成され、そのインスタンスにリモートメソッドが転送されます。この方法には、元のリモートでないクラスを変更する必要がないという利点があります。
リモートでない元のクラスが次のようであるとします。
  package examples.activation;
  public class MyNonRemoteClass {
      private String result = null;
      // Here's the original class, which concatenates two strings
      //
      public String calltheServer(String takeThis) {
	  result = takeThis + "I'm here!";
	  return result;
      }
  }
同じインタフェースである examples.activation.AnotherRemoteInterface を記述して、リモートに呼び出すメソッドを記述します。
  package examples.activation;
  import java.rmi.*;
  public interface AnotherRemoteInterface extends Remote {
      public String calltheServer(String s) throws RemoteException;
  }
ただし、使用できるソースコードが MyNonRemoteClass.java にない場合もあるため、MyNonRemoteClass.java を編集するのではなく、新しいクラス examples.activation.MyNonRemoteClassAdapter を作成します。 この新しいクラスは、(イベントアダプタと同様に) 指定したインタフェースを実装し、適切な動作を実行します。前述の方法と MyNonRemoteClassAdapter を使用する方法との相違点は、MyNonRemoteClassAdapter がそのコンストラクタで MyNonRemoteClass のインスタンスを生成し、MyNonRemoteClass.calltheServer メソッドを呼び出すことです。 
  package examples.activation;
  import java.rmi.*;
  import java.rmi.activation.*;
  public class MyNonRemoteClassAdapter implements
      examples.activation.AnotherRemoteInterface
  {
      private String result = null;
      private MyNonRemoteClass mnrc;
      // The constructor for activation and export; this
      // constructor is called by the method
      // ActivationInstantiator.newInstance during
      // activation, to construct the object.
      //
      public MyNonRemoteClassAdapter(ActivationID id,
	  MarshalledObject data) throws RemoteException
      {
	  // Register the object with the activation system
	  // then export it on an anonymous port
	  //
	  Activatable.exportObject(this, id, 0);
	  // Create an instance of the class MyNonRemoteClass
	  //
	  mnrc = new MyNonRemoteClass();
      }
      // Define the method declared in AnotherRemoteInterface
      // to accept a String, modify it, and return it to
      // the client
      //
      public String calltheServer(String takeThis)
	  throws RemoteException
      {
	  // Rather than modify the String here, forward
	  // it on to the non-remote object implementation
	  //
	  result = mnrc.calltheServer(takeThis);
	  return result;
      }
  }
rmic を実行するクラスおよびセットアッププログラムによって参照されるクラスは、アダプタクラスです。セットアッププログラム examples.activation.Setup3alt は、次のようになります。 
  package examples.activation;
  import java.rmi.*;
  import java.rmi.activation.*;
  import java.util.Properties;
  public class Setup3alt {
      // This class registers information about the MyClass
      // class with rmid and the rmiregistry
      //
      public static void main(String[] args) throws Exception {
	  System.setSecurityManager(new RMISecurityManager());
	  AnotherRemoteInterface ari;
	  // Don't forget the trailing slash at the end of the URL
	  // or your classes won't be found
	  //
	  String location = "file:/home/rmi_tutorial/activation/";
	  // Create the rest of the parameters that will be passed to
	  // the ActivationDesc constructor
	  //
	  MarshalledObject data = null;
	  // The second argument to the ActivationDesc constructor
	  // will be used to uniquely identify this class; it's
	  // location is relative to theURL-formatted String, location.
	  //
	  ActivationDesc desc = new ActivationDesc
	      ("examples.activation.MyNonRemoteClassAdapter",
	      location, data);
	  ari = (AnotherRemoteInterface)Activatable.register(desc);
	  System.out.println("Got the stub for MyNonRemoteClassAdapter");
	  // Bind the stub to a name in the registry running on 1099
	  //
	  Naming.rebind("MyNonRemoteClassAdapter", ari);
	  System.out.println("Exported MyNonRemoteClassAdapter");
	  System.exit(0);
      }
  }
 * この Web サイトで使用されている用語「Java 仮想マシン」または「JVM」は、Java プラットフォーム用の仮想マシンを表します。
| Copyright © 1999 Sun Microsystems, Inc. All Rights Reserved.   コメントの送付先: rmi-comments@java.sun.com  |