目次 前項目 次項目

サーバインタフェース


サーバを実装する場合、クライアントのインタフェースを利用することができ、またこれらを使ってリモートオブジェクトの定義、作成、エクスポートを拡張することができます。

トピックス:

RemoteObject クラス

java.rmi.server.RemoteObject クラスはリモートオブジェクト向けに java.lang.Object の動作を実装します。hashCodeequals メソッドの実装によりリモートオブジェクト参照をハッシュテーブルに保存して比較できるようになります。equals メソッドはもし2つの Remote オブジェクトが同一のリモートオブジェクトを参照している場合に true を返します。このメソッドは2つのリモートオブジェクトの参照同士を比較します。

toString メソッドはリモートオブジェクトを説明した文字列を返します。この文字列の内容とシンタックスは実装に固有のものであり、変更されることもあります。

java.lang.Object の他の全部のメソッドはオリジナルの実装のままです。

package java.rmi.server;
public abstract class RemoteObject
	implements java.rmi.Remote, java.io.Serializable
{
	public int hashCode();
	public boolean equals(Object obj);
	public String toString();
}

RemoteServer クラス

java.rmi.server.RemoteServer クラスは全てのサーバの実装に共通なスーパークラスであり、広い範囲のリモート参照セマンティクスの枠組みを提供するものです。現在のところサポートされているサブクラスは UnicastRemoteObjectのみです。

package java.rmi.server;
public abstract class RemoteServer
	extends RemoteObject {

	public static String getClientHost()
		throws ServerNotActiveException;

	public static void setLog(java.io.OutputStream out);
	public static java.io.PrintStream getLog();
}
getClientHost メソッドにより、アクティブメソッドは現在実行中のスレッドでアクティブなリモートメソッドをスタートさせたのがどのホストであるかを決定することができます。 現在のスレッドでアクティブなリモートメソッドがない場合には ServerNotActiveException がスローされます。 setLog メソッドは RMI コールのログを作り、指定された出力ストリームへ出力します。 もし、出力ストリームが null である場合には、ログ操作は起動されません。 getLog メソッドは RMI コールのログに使われるストリームを返します。これによりアプリケーションに特有な情報をコールログに同期を取りながら記録することができます。

UnicastRemoteObject クラス

java.rmi.server.UnicastRemoteObject クラスは TCP ベースのストリームを使ってポイント間でのアクティブオブジェクト参照をサポートします。 このクラスは次の特性を持ったリモートサーバオブジェクトを実装します。

新しいリモートオブジェクトを作成する

サーバとして実行中の Java 仮想マシン上では、開発者により定義されたリモートオブジェクトはサーバアプリケーションによって作成することができます。 リモートオブジェクトのクラスが UnicastRemoteObject を拡張したクラスである場合には、構築子がリモートオブジェクトを生成してエクスポートします。構築子の呼び出しはリモートオブジェクトクラスの対応する構築子が行います。デフォルト構築子は無名ポートを使用して新規のユニキャストリモートオブジェクトを生成します。

初期値が同じである UnicastRemoteObject を作成するにはクローンメソッドを使用しますが、これはリモートコールを受け付けるためにエクスポートされ、オリジナルのオブジェクトとは明確に異なるものです。

RemoteObject からの拡張ではない実装のエクスポート

exportObject メソッドは、UnicastRemoteObject クラスを拡張することによっては実装されない単純なピアツーピアリモートオブジェクトをエクスポートするために使用します。exportObject メソッドは、無名ポート上でエクスポート対象のオブジェクトを使用して呼び出します。そのオブジェクトは、パラメータまたは返り値として RMI コールに初めて渡される前にエクスポートして置かなければなりません。そうしない場合には、java.rmi.server.StubNotFoundException が、リモートコールが試みられる中で「未エクスポートの」リモートオブジェクトが引数または返り値として渡されるときに発生します。

一度エクスポートされてしまえば、オブジェクトは RMI コールの引数、または RMI コールの返り値として渡すことができるようになります。リモートオブジェクトが渡され、転送のための一体化をされている間にそのリモートオブジェクト実装に一致するリモートスタブが検索され、もしあれば代わりにスタブが引数または返り値として渡されます。

exportObject メソッドはリモートオブジェクト obj のスタブであり、リモートオブジェクトの代わりに RMI コールで渡された RemoteStub を返します。

RMI コールで UnicastRemoteObject を渡す

上述したように、RMI コールの中で UnicastRemoteObject 型のオブジェクトが渡されると、同オブジェクトは、リモートオブジェクトのスタブが取って代わります。リモートオブジェクトの実装は、それが作成された仮想マシン中に留まり、仮想マシンから (値渡しによってさえ) 移動されません。すなわち、リモートオブジェクトは、RMI コールでは参照渡しであり、値では渡すことができないということになります。

UnicastRemoteObject を直列化する

UnicastRemoteObject に含まれている情報は非常駐であり、その型のオブジェクトがユーザ定義の ObjectOutputStream に書き込まれ場合には保存されません (たとえば、オブジェクトが直列化を使用してファイルに書き込まれる場合)。ただし、UnicastRemoteObject のユーザ定義サブクラスのインスタンスであるオブジェクトは、そのオブジェクトが直列化された場合でも保存できる非常駐データでないデータを持つことができます。

UnicastRemoteObjectObjectInputStream から読み込まれる場合には、そのオブジェクトは、RMI コールを受け取れるように RMI ランタイムに自動的にエクスポートされます。オブジェクトのエクスポートが何らかの原因で失敗した場合には、オブジェクトの直列化復元は、例外とともに途中で終了します。

Unreferenced インタフェース

package java.rmi.server;
public interface Unreferenced {
	public void unreferenced();
}
java.rmi.server.Unreferenced インタフェースを使うと、サーバオブジェクトは現在どのクライアントからも参照されていないという通知を受けることができます。 分散ガベージコレクションメカニズムは各リモートオブジェクトについて、そのリモートオブジェクトを参照しているクライアント仮想マシンのセットを保持しています。 あるクライアントがあるリモートオブジェクトに対するリモート参照を持っている間は、RMI ランタイムもそのリモートオブジェクトへのローカル参照を保持し続けます。「参照」のセットが空になると、(もしサーバが Unreferenced インタフェースを実装していれば)Unreferenced.unreferenced メソッドが呼び出されます。リモートオブジェクトが Unreferenced インタフェースをサポートするのは必須ではありません。

リモートオブジェクトに対するローカル参照が存在している間は、それをリモートコールで渡すこともできますし、クライアントへの返り値にもなります。 参照を受け取ったプロセスはその参照に対するセットに追加されます。 参照セットが空になったとき、Unreferenced が呼び出されます。 このような動作をするため、Unreferenced メソッドは参照セットが新しく空になる度に何回でも呼び出されます。 リモートオブジェクトはそれに対する参照(ローカル参照またはクライアントが保持している参照)がもはや無くなったときに回収されます。

RMISecurityManager クラス

package java.rmi;

public class RMISecurityManager extends java.lang.SecurityManager {

	// Constructor
	public RMISecurityManager();

	// Returns implementation specific security context 
	public Object getSecurityContext();

	// Disallow creating classloaders or execute ClassLoader methods
	public synchronized void checkCreateClassLoader()
		throws RMISecurityException;

	// Disallow thread manipulation
	public synchronized void checkAccess(Thread t)
		throws RMISecurityException;

	// Disallow thread group manipulation.
	public synchronized void checkAccess(ThreadGroup g)
		throws RMISecurityException;

	// Disallow exiting the VM
	public synchronized void checkExit(int status)
		throws RMISecurityException;

	// Disallow forking of processes
	public synchronized void checkExec(String cmd)
		throws RMISecurityException;

	// Disallow linking dynamic libraries
	public synchronized void checkLink(String lib)
		throws RMISecurityException;

	// Disallow accessing of all properties except those labeled OK
	public synchronized void checkPropertiesAccess()
		throws RMISecurityException;
	// Access system property key only if key.stub is set to true
	public synchronized void checkPropertyAccess(String key)
		throws RMISecurityException;

	// Check if a stub can read a particular file.
	public synchronized void checkRead(String file)
		throws RMISecurityException;

	// No file reads are valid from a stub
	public void checkRead(String file, Object context)
		throws RMISecurityException;

	// Check if a Stub can write a particular file.
	public synchronized void checkWrite(String file)
		throws RMISecurityException;

	// Check if the specified system dependent file can be deleted.
	public void checkDelete(String file)
		throws RMISecurityException;

	// Disllow opening file descriptor for reading unless via socket
	public synchronized void checkRead(FileDescriptor fd)
		throws RMISecurityException;

	// Disallow opening file descriptor for writing unless via socket
	public synchronized void checkWrite(FileDescriptor fd)
		throws RMISecurityException;

	// Disallow listening on any port.
	public synchronized void checkListen(int port)
		throws RMISecurityException;

	// Disallow accepting connections on any port.
	public synchronized void checkAccept(String host, int port)
		throws RMISecurityException;

	// Disallow stubs from using IP multicast.
	public void checkMulticast(InetAddress maddr)
		throws RMISecurityException;

	// Disallow stubs from using IP multicast
	public void checkMulticast(InetAddress maddr, byte ttl)
		throws RMISecurityException;

	// Downloaded classes (including stubs) can make connections if
	// called through the RMI transport.
	public synchronized void checkConnect(String host, int port)
		throws RMISecurityException;

	// Downloaded classes (including stubs) can make connections if
	// called through the RMI transport.
	public void checkConnect(String host, int port, Object context)
		throws RMISecurityException;

	// Allow caller to create top-level windows.
	// Allow stubs to create windows with warnings.
	public synchronized boolean checkTopLevelWindow(Object window)
		throws RMISecurityException;

	// Check if a stub can access a package.
	public synchronized void checkPackageAccess(String pkg)
		throws RMISecurityException;

	// Check if a stub can define classes in a package.
	public synchronized void checkPackageDefinition(String pkg)
		throws RMISecurityException;

	// Check if a stub can set a networking-related object factory.
	public synchronized void checkSetFactory()
		throws RMISecurityException;

	// Disallow printing from stubs.
	public void checkPrintJobAccess()
		throws RMISecurityException;

	// Disallow stubs from accessing system clipboard.
	public void checkSystemClipboardAccess()
		throws RMISecurityException;

	// Disallow stubs from accessing AWT event queue.
	public void checkAwtEventQueueAccess()
		throws RMISecurityException;

	// Checks to see if client code can access class members.
	// Allow access to all public information. Allow non-stubs to
	// access default, package, and private declarations and data).
	public void checkMemberAccess(Class clazz, int which)
		throws RMISecurityException;

	// Stubs cannot perform security provider operations.
	public void checkSecurityAccess(String provider)
		throws RMISecurityException;
}
アプリケーションが特別なセキュリティは必要としませんが、標準提供される保護が必要である場合に RMISecurityManager を使うことができます。 この単純なセキュリティマネジャークラス定義とアクセスを除く全ての機能を利用できなくして、リモートオブジェクト以外のクラス、引数、返り値が必要に応じてロードできるようにします。ダウンロードクラスは、それが RMI トランスポートを介して開始されたものであれば、接続を作成することができます。

何のセキュリティマネージャも設定されていない場合は、スタブのローディングができなくなります。 これは、どれかのセキュリティマネージャに、リモートメソッド呼び出しの一部としての、スタブやクラスのローディングの責任を負わせるためです。 セキュリティマネージャは System.setSecurityManagerを使って設定します。

RMIClassLoader クラス

java.rmi.server.RMIClassLoader はアプリケーションが URL経由でクラスをロードするためのユーティリティクラスです。

package java.rmi.server;

public class RMIClassLoader {

    public static Class loadClass(String name)
	    throws MalformedURLException, ClassNotFoundException;

    public static synchronized Class loadClass(URL codebase,
		String name) throws MalformedURLException, 
		ClassNotFoundException;

	public static Object getSecurityContext(ClassLoader loader);
}
最初の loadClass メソッドは、java.rmi.server.codebase プロパティで定義される URL を介して指定されたクラス名をロードします。そのクラスはロードされ、定義され、そして戻されます。

第二の形式の loadClass メソッドは指定されたクラス名を URL パラメーター codebase 経由でロードします。

getSecurityContext メソッドは指定されたクラスローダ、ローダのセキュリティコンテキストを返します。セキュリティコンテキストは LoaderHandlergetSecurityContext メソッドを使って問い合わせることにより得られます。

RMI ランタイムは自分自身のクラスローダを使ってスタブ、スケルトン、そしてスタブやスケルトンが必要とする他のクラスのローディングを行います。 これらのクラスと、その使用方法は、Java RMI ランタイムの安全性に対するプロパティをサポートするものです。このクラスローダは常にローカルに利用可能なクラスを優先します。 ローカルマシンとネットワーク間の選択が起こるのはセキュリティマネージャがそれを強制するときのみです。クラスローダはローダのキャッシュを持っていて、個々の URL (Uniform Resource Locator) とそこからロードされたクラスを記憶しています。 スタブやスケルトンがロードされると、パラメータあるいは返り値として現れるどのクラス参照も(それらの発起側 codebase ホストから)ロードされ、同じセキュリティ規則に従うことになります。サーバプロセスは RMI ランタイムに対してクラス(スタブ、パラメーター/返り値)のロケーションを宣言しなければならず、この情報はクライアントも利用できます。 java.rmi.server.codebase プロパティは URL でなければならず、ここからスタブクラスと、スタブが使用するクラスが通常の http や fpt プロトコルを使ってロードされます。

LoaderHandler インタフェース

package java.rmi.server;

public interface LoaderHandler {

    Class loadClass(String name)
	    throws MalformedURLException, ClassNotFoundException;

    Class loadClass(URL codebase,String name) 
		throws MalformedURLException, ClassNotFoundException;

	Object getSecurityContext(ClassLoader loader);
}
LoaderHandler インタフェースは必ず LoaderHandlerというクラス名で実装しなければなりません。LoaderHandler クラスは java.rmi.loader.packagePrefixプロパティで指定されるパッケージの中で定義されていなければなりません。 LoaderHandlerのメソッドは java.rmi.server.RMIClassLoader クラスがそのオペレーションを実行するために使用します。

RMISocketFactory クラス

java.rmi.server.RMISocketFactory abstract クラスはトランスポートがソケットを取得する方法を指定するインタフェースを提供します。

package java.rmi.server;
public abstract class RMISocketFactory {

	public abstract java.net.Socket createSocket(String h,int p)
		throws IOException;

	public abstract java.net.ServerSocket createServerSocket(int p)
		throws IOException;

	public static void setSocketFactory(RMISocketFactory fac)
		throws IOException;

	public static RMISocketFactory getSocketFactory();

	public static void setFailureHandler(RMIFailureHandler fh);

	public static RMIFailureHandler getFailureHandler();
}
static メソッド setSocketFactory は RMI がソケットを取得するためのソケットファクトリを設定します。アプリケーションが自分の RMISocketFactory インスタンスのためにこのメソッドを呼び出せるのは一回だけです。 アプリケーションの定義による RMISocketFactory の実装は、例えば接続要求に対して事前のフィルタリングを行って例外をスローし、あるいは自分自身を拡張による java.net.Socket または java.net.ServerSocket クラスを返して確実なコミュニケーションチャネルを確保します。 RMISocketFactory を設定できるのは実行中のセキュリティマネージャがソケットファクトリの設定を許している場合だけであることに注意してください。ソケットファクトリが許可されていない場合には、SecurityException がスローされます。

static メソッド getSocketFactory は RMI によるソケットファクトリを返します。 ソケットファクトリが設定されていなければこのメソッドは null を返します。

トランスポートレイヤは、トランスポートがソケット作成を必要とすると getSocketFactory メソッドが値を返した RMISocketFactory 上で createSocketcreateServerSocket メソッドを呼び出します。

例えば:

RMISocketFactory.getSocketFactory().createSocket(myhost, myport)
createSocket メソッドは指定されたホストとポートに接続されたクライアントソケットを作成するものです。 createServerSocket は指定されたポート上にサーバソケットを作成するものです。 デフォルトトランスポートにおける RMISocketFactory の実装は次のように、HTTP を使ってファイアウオールを通り抜ける透過性のある RMI を提供します。

setFailureHandler メソッドはサーバソケットの作成に失敗すると失敗用ハンドラを RMI ランタイムにより呼び出されるよう設定する。 失敗用ハンドラはブール値を返して、リトライを行ってよいかどうかを示します。 デフォルトの失敗用ハンドラは false を返し、デフォルト条件ではランタイムはソケット作成のリトライを行わないことを示します。

getFailureHandler メソッドはソケット作成失敗の現在のハンドラを返し、もし失敗用ハンドラが設定されていなければ null を返します。

RMIFailureHandler インタフェース

java.rmi.server.RMIFailureHandler インタフェースは、サーバソケットの作成に失敗した場合に、RMI ランタイムがどのように動作すればよいかを指定する手段を提供します。

package java.rmi.server;
public interface RMIFailureHandler {
	public boolean failure(Exception ex);
}
failure メソッドは、RMI ランタイムが java.net.Socketjava.net.ServerSocket の作成に失敗した時の例外を引数として呼び出されます。 ランタイムがリトライするべきならはメソッドは true を返し、そうでないならば false を返します。

このメソッドが呼び出される前に、失敗用ハンドラが RMISocketFactory.setFailureHandler コールによって登録されていなければなりません。もし失敗用ハンドラが設定されていなければ、ソケット作成は試みられません。

LogStream クラス

LogStream クラスはシステムをモニタしている人が興味を持つであろうエラーロギングのメカニズムを表現します。このクラスはサーバコールのログ作成のために内部使用されるものです。

package java.rmi.server;

public class LogStream extends java.io.PrintStream {

	public static LogStream log(String name);

	public static synchronized PrintStream getDefaultStream();

	public static synchronized void setDefaultStream(
		PrintStream newDefault);

	public synchronized OutputStream getOutputStream();

	public synchronized void setOutputStream(OutputStream out);

	public void write(int b);

	public void write(byte b[], int off, int len);

	public String toString();

	public static int parseLevel(String s);

	// constants for logging levels
	public static final int SILENT  = 0;
	public static final int BRIEF   = 10;
	public static final int VERBOSE = 20;
}
log メソッドは指定された名前の LogStream を返します。該当する名前のログが存在しなければ、デフォルトストリームを使ったログが作成されます。

getDefaultStream メソッドは新規ログのために、現在のデフォルトストリームを返します。

setDefaultStream メソッドは新規ログのためにデフォルトストリームの設定を行います。

getOutputStream メソッドはこのログの出力が送られる現在のストリームを返します。

setOutputStream メソッドはこのログ出力が送られるストリームを設定します。

1番目の形式のメソッド write は1データバイト(オクテット)をストリームに書き出します。 それが改行コード (new line) でなければ、そのバイトデータは内部のバッファにアペンドされ、 もし改行コードならばバッファリングされていた一行がログの出力ストリームへ適当なロギング前置子が付けられて出力されます。メソッド 2番目のメソッド write の形式はバイトのサブアレイを書き出します。

toString メソッドはログの名前を文字列表現で返します。

parseLevel メソッドはロギングレベルを文字列表現から整数による内部表現に変換します。

スタブとスケルトンコンパイラ

rmic スタブ/スケルトンコンパイラは指定されたリモートオブジェクトを実装する適切なスタブとスケルトンをコンパイルします。 コンパイラはそのリモートオブジェクトのパッケージ修飾されたクラス名を引数として呼び出されます。そのクラスは事前にコンパイルに成功したものでなければなりません。



目次 前項目 次項目

Copyright (C) 1996, 1997 Sun Microsystems, Inc. All rights reserved.