JDK 1.1 での java.net
クラスのいくつかの改善によって、ソケット (Socket/ServerSocket) を final でない拡張可能なクラスにできるようになりました。基本的な目標は、アプリケーションコードを書き直さずに、基底クラス Socket が使用されているところではどこでも拡張されたソケットを使用できるようにすることです。そこでたとえば、既存の電子メールクライアントには、Socket のサブクラスが透過的に処理するピア認証または暗号化を行う Socket のサブクラスを渡すことが可能です。ほかの例としては、圧縮を透過的に使用するソケット、または複数のサーバーにトラフィックのミラーリングなどの機能を追加するソケットがあります (信頼できる順番付けられたマルチキャストの使用など)。
このドキュメントには次のセクションがあります。
JDK 1.0 では、ある非常に特別な方法でユーザーがソケットの機能を拡張できるようにしました。ユーザーは java.net.SocketImpl
をサブクラス化し、必要に応じてこのようなクラスを返す拡張された java.net.SocketImplFactory() を提供できます。
SocketImpl/SocketImplFactory スキームは、異なるトランスポートメカニズムを使用する環境間で移植性のある Java アプレットおよびアプリケーションを作成するのに有用であり、そのために設計されました。java.net.Socket を使用するクライアントアプリケーションは、ネットワーク接続が特定のことを実行する必要のある環境においてだけでなく、一般的なケース (Java Runtime が PlainSocketImpl を使用する) でも動作することができます。たとえば、その環境で適切な種類の SocketImpl が Java Runtime に対して設定されていると仮定すると、SOCKS のようなプロキシプロトコルを経由してインターネットに接続する必要があるファイアウォールの背後でも、Java のプログラムは動作できなければなりません。
SocketImpl は Java のアプレットにプロキシサポートを透過的に提供するようなものにとって有用ですが、このユーティリティーは、ネットワークトランスポートの追加機能を提供する方法、あるいは TCP の上部にほかのプロトコルを階層化する方法としては限定されています。さらに、Java Runtime に対しては単一型の SocketImpl をインストールすることだけが可能なため、大規模なアプリケーションを制限することになります。ServerSocket および Socket を拡張可能にする方法は明確であり、直感的にわかりやすいものです。
SocketImpl メカニズムは Socket のサブクラスが提供する機能に直交するように設計されています。たとえば、そのストリーム上で圧縮を実行できる Socket のサブクラスは、依然システムデフォルトの SocketImpl を使用し、ある種のファイアウォールの背後でプロキシサポートを得たいと希望する可能性があります。システムデフォルトの SocketImpl は、アプリケーション側からの配慮を必要としないトランスポート層の拡張として考えることができます。そして、Socket/ServerSocket のサブクラスはアプリケーション層で豊富な機能を提供します。
JDK 1.1 では、Socket および ServerSocket は非 final になり、これはきわめて簡単な変更です。主にセキュリティー上の理由で、サブクラスは、基底クラスの配下の SocketImpl に直接アクセスできないことに注意してください。しかし、それ以外では Socket/ServerSocket のサブクラスは、そのスーパークラスのメソッドを継承しオーバーライドできます。
JDK は次のように変更されました。
Socket
および ServerSocket
クラスから final
修飾子を削除。final
修飾子を、セキュリティーマネージャーの呼び出しを迂回しないようにするために必要なメソッドだけに再接続。protected final void implAccept(Socket client)
とともに定義。Socket
コンストラクタを公開。これは、ServerSocket サブクラスが accept() から正しい Socket サブクラスを返すためにも必要 (FooServerSocket.accept() は FooSocket を返すなど)次の一般形式の Socket の public コンストラクタは、スーパークラスを初期化するために使用できます。
Socket(String host, int port) { ... }ただし、これらはまたシステムデフォルトの SocketImpl を生成し、それを指定したホスト、ポートに接続します。Socket は、Socket に接続せずにスーパークラスを初期化するために 2 つの protected コンストラクタを持ちます。
protected Socket() { /* install system-default SocketImpl */ ... } protected Socket(SocketImpl impl) { this.impl = impl; }最初のコンストラクタはシステムデフォルトの SocketImpl をインストールします (ファクトリまたは PlainSocketImpl のどちらかから)。2 番目のコンストラクタは、Socket のサブクラスが必要に応じて自分の impl をインストールできるようにします。Socket サブクラスがデフォルトの SocketImpl を必要としない場合、2 番目のコンストラクタを使ってそれに null を渡すことは完全に有効です。ただし、このケースでは、サブクラスはすべて配下の SocketImpl に依存しているため、すべての基底クラスメソッドをオーバーライドする必要があります。
ServerSocket のサブクラスはまた、これらに公開される protected コンストラクタを持ち、このコンストラクタは基底クラス内でデフォルトの SocketImpl を生成します。しかし、そうでない場合、これを初期化します。たとえば、impl.create()、impl.bind()、impl.listen() を呼び出しません。ServerSocket の public コンストラクタは、配下の SocketImpl を初期化します。
protected ServerSocket() { /* install system-default SocketImpl */ ... }このほかに ServerSocket の拡張に関して説明が必要なこととしては、次のことだけです。Socket/ServerSocket の配下の SocketImpl がサブクラスにアクセス可能でない場合の、accept() のオーバーライドの方法があります。基底クラスはこれを行うことができるため、ServerSocket はサブクラスの代わりに配下の SocketImpl に対して必要な呼び出しを行うための次のメソッドを持ちます。
public class ServerSocket { ... protected final void implAccept(Socket s) throws IOException { ... // on return from this call s will be connected to a client } ...SocketImpl を使用しない Socket/ServerSocket のサブクラスは、このメソッドを使用する必要はありません。この機能方法について、次に SSL コードの例を示します。
class SSLServerSocket extends ServerSocket {
...
public Socket accept () throws IOException
{
SSLSocket s = new SSLSocket (certChain, privateKey);
// create an unconnected client SSLSocket, that we'll
// return from accept
implAccept (s);
s.handshake ();
return s;
}
...
}
class SSLSocket extends java.net.Socket {
...
public SSLSocket(CertChain c, PrivateKey k) {
super();
...
}
...
}