J2SE 5.0 では、コネクタと TransportService の実装を開発および配置できるように、新しいサービスプロバイダインタフェースが Java Debug Interface (JDI) に追加されています。TransportService は、5.0 の新しいクラスです。このクラスは、コネクタによって使用される基盤のトランスポートサービスを表し、デバッガとターゲット VM 間の接続の確立、および Java Debug Wire Protocol (JDWP) パケットのトランスポートに使用されます。
JDI の新しいサービスプロバイダインタフェースに加え、J2SE 5.0 には Java™ Debug Wire Protocol Transport Interface (jdwpTransport) と呼ばれる新しいトランスポートライブラリインタフェースも含まれています。これは、トランスポートライブラリの開発および配置を可能にするネイティブ (C/C++) インタフェースです。トランスポートライブラリは、debuggee 側の JDWP エージェントによってロードされ、デバッガへの接続の確立、およびデバッガと VM 間の JDWP パケットのトランスポートに使用されます。
このページでは、新しいインタフェースが使用される可能性のあるいくつかのシナリオについて説明します。また、新しいコネクタとトランスポートの実装の開発および配置に関連するタスクの概要についても説明します。
サービスプロバイダインタフェースとネイティブトランスポートインタフェースは、次のユーザーによって使用されることが想定されています。
これらのユーザーを考慮して、新しいインタフェースを使用する場合のいくつかのシナリオについて説明します。
debuggee 側では、jdwpTransport インタフェースを実装することにより、新しいトランスポートのトランスポートライブラリを開発できます。デバッガの場合は、TransportService 実装を開発できます。TransportService 実装を配置すると、JDI VirtualMachineManager 実装によって自動的に AttachingConnector および ListeningConnector が作成され、ターゲット VM に対するリモートデバッグが可能になります。
これらの例の場合は、AttachingConnector 実装を開発できます。AttachingConnector 実装は、com.sun.jdi.connect.AttachingConnectors を拡張し、配置されると、VirtualMachineManager の attachingConnectors() メソッドによって返される接続コネクタのリストに表示されます。
この例では、IDE の実装者が jdwpTransport インタフェースを使用してトランスポートライブラリを開発します。この結果、debuggee では新しいトランスポートの使用が可能になります。デバッガ側では、IDE の実装者に選択肢があります。1 つのオプションは、TransportService 実装を開発および配置することです。このオプションでは、リモートデバッグに新しいトランスポートを使用できます。
あるいは、IDE の実装者が、トランスポートをカプセル化するコネクタ実装を作成することを決定する可能性があります。このオプションは、IDE の実装者が新しいコネクタ引数を追加するときに適しています。たとえば、セキュリティー保護されたトランスポートを使う場合、IDE の実装者が、セキュアな接続を構成するために必要なキーストア、パスフレーズなどのオプションを指定するコネクタ引数を持つコネクタを使用する場合があります。新しいコネクタが適している場合、IDE の実装者は、debuggee 側のトランスポートライブラリとデバッガ側のコネクタを開発します。コネクタのタイプは、実装者が選択できます。1 つの例として、debuggee を起動し、デバッガと debuggee の間のセキュアな接続を確立する LaunchingConnector があります。
どのコネクタ実装にも、すべてのコネクタメソッドの実装のほかに、public で引数なしのコンストラクタが必要です。コンストラクタは、初期化中に VirtualMachineManager によって呼び出されます。コンストラクタは無操作の場合や、トランスポートサービスのロードなどの初期化タスクを実行する場合があります。コンストラクタはチェック例外をスローしないため、初期化中の問題はすべて、エラーまたはその他の非チェック例外としてスローされるべきです。
コネクタで TransportService を使用する必要はありません。コネクタによっては、トランスポート以外のメカニズムを使用してターゲット VM に接続する場合があります (「シナリオの例」のセクションでは、クラッシュダンプやハングプロセスに接続する AttachingConnectors の例を示しています)。TransportService 実装を使用するコネクタの場合、コネクタは TransportService 実装を直接参照するか、実行時に実装をロードできます。Sun が提供するトランスポートを使用しようとするコネクタは、次のようなコードを使用してトランスポートサービスをロードするようにしてください。
try { Class c = Class.forName("com.sun.tools.jdi.SocketTransportService"); ts = (TransportService)c.newInstance(); } catch (Exception x) { throw new Error(x); }
Java SE の実装には、Sun のソケットトランスポートサービスまたは共用メモリートランスポートサービスが含まれている必要がないため、この例では、トランスポートサービスが存在しない場合、エラーがスローされます。
コネクタのタイプが認識されていると仮定する場合、実装を開発するときに次のことに注意する必要があります。
VirtualMachine vm = Bootstrap.virtualMachineManager().createVirtualMachine(conn);
VirtualMachineManager には、LaunchingConnectors で使用するための createVirtualMachine の別の形式も含まれています。別の形式では、LaunchingConnector で debuggee を表す java.lang.Process を指定できます。詳細は、com.sun.jdi.VirtualMachineManager の仕様を参照してください。
LaunchingConnector の例のソースコードを見るには、ここをクリックしてください。コネクタには、ターゲット VM で実行するクラスのクラス名を指定する class という 1 つの Connector.Argument があります。この例では、Connector.Argument、トランスポートの命名、createVirtualMachine メソッドの使用を含む、前述のすべての要点を示しています。
コネクタを配置するには、コネクタの完全修飾クラス名のリストを含むサービス構成ファイルと一緒にコネクタ実装のクラスを jar ファイルにパッケージ化する必要があります。その後、jar ファイルはシステムクラスローダーから可視の場所に配置されます。
META-INF/services/com.sun.jdi.connect.Connector というサービス構成ファイルが jar ファイルに含まれている必要があります。このファイルには、jar ファイルに含まれているコネクタの完全修飾クラス名のリストがあるだけです。複数のコネクタ実装が同じ jar ファイルに含まれている場合があります。この場合、各コネクタのクラス名は別の行に記載されます。
SimpleLaunchingConnector という起動コネクタを配置すると仮定します。このコネクタを配置するために、次のような META-INF/services/com.sun.jdi.connect.Connector ファイルを作成します。
# Our very simple launching connector SimpleLaunchingConnector
このサービス構成ファイルは、コネクタの実装を構成するクラスと一緒に jar ファイルにパッケージ化されます。
jar cf SimpleLaunchingConnector.jar \ META-INF/services/com.sun.jdi.connect.Connector \ SimpleLaunchingConnector.class
次に、jar ファイルはシステムクラスローダーから可視の場所にコピーされます。
ファイルが配置されると、デバッガの再起動時にコネクタが配置されます。つまり、VirtualMachineManager の allConnectors() メソッドによって返されるコネクタのリストに SimpleLaunchingConnector が含まれます。また、これは起動コネクタであるため、launchingConnectors() メソッドによって返される起動コネクタのリストにも表示されます。
トランスポートサービスを開発するには、次の 2 つのコンポーネントを開発する必要があります。
トランスポートサービスの開発には、トランスポートと基盤になる通信プロトコルについての高度な知識が必要です。トランスポートサービスは、JDWP を基盤となる通信プロトコルにバインドします。提供するサービスは信頼性が高く、JDWP パケットはデバッガと debuggee の間で重複したりデータが失われることなく、交換されます。パケットを信頼性の高い方法で交換しなければならないことを考えると、トランスポートサービスは、基盤となる通信プロトコルが提供するサービスを超えるプロトコルサポートを提供するべきです。たとえば、処理されていない信頼性の低いシリアル接続を介したデバッグが必要な場合、トランスポートサービスの実装者は、エラーの検出と回復を実装に組み込んで、デバッガと debuggee の間で JDWP パケットを信頼性の高い方法で転送できるようにする必要があります。
トランスポートと基盤の通信プロトコルの詳細を理解したら、次のことを考慮します。
/dev/ttya;9600,1
上記の内容が解決したら、TransportService の作成によって com.sun.jdi.connect.spi.TransportService を拡張し、実装を提供します。attach メソッドと accept メソッドは、com.sun.jdi.connect.spi.Connection のインスタンスを返します。このため、Connection を実装して、デバッガが debuggee と JDWP パケットを交換できるようにする必要があります。
TransportService 実装の例として、Sun のソケットトランスポートのソースコードを見るには、ここをクリックしてください。この例は、参照用として提供されています。
ネイティブトランスポートライブラリを開発するには、jdwpTransport 仕様に記載されている各関数を実装する必要があります。関数のプロトタイプおよび定義は、${java_home}/include/jdwpTransport.h に定義されています。
トランスポートライブラリの実装者は、関数実装をコンパイルし、ダイナミックライブラリ (またはこれに相当するもの) にリンクします。ライブラリは、トランスポートライブラリがロードされるときに JDWP エージェントから呼び出される jdwpTransport_OnLoad 関数をエクスポートします。一部の組み込み環境は、動的リンクをサポートしていません。そういった環境では、トランスポートライブラリに静的にリンクしなければならない場合があります。その場合、ライブラリのロードはありませんが、トランスポートライブラリを初期化し、環境ポインタを取得するために、jdwpTransport_OnLoad 関数が引き続き呼び出されます。
jdwpTransport 実装の例として、Sun のソケットトランスポートライブラリ (dt_socket) のソースコードを見るには、ここをクリックしてください。この例は、あくまでも参照用として提供されています。
TransportService は、コネクタと同様の方法で配置されます。TransportService を配置するには、TransportService の完全修飾クラス名のリストを含むサービス構成ファイルと一緒に TransportService 実装のクラスを jar ファイルにパッケージ化する必要があります。その後、jar ファイルはシステムクラスローダーから可視の場所に配置されます。
META-INF/services/com.sun.jdi.connect.spi.TransportService というサービス構成ファイルが jar ファイルに含まれている必要があります。コネクタの配置と同様に、jar ファイルに複数の実装が含まれている場合は、複数のトランスポートサービス実装のクラス名が構成ファイルに記載されることがあります。
トランスポートサービス com.sun.SerialTransportService の場合、サービス構成ファイルは次のようになります。
# Serial line transport com.foo.SerialTransportService
このサービス構成ファイルは、実装を構成するクラスと一緒に jar ファイルにパッケージ化されます。この例では、実装に多数のクラスが含まれると仮定します。
jar cf SerialTransportService.jar \ META-INF/services/com.sun.jdi.connect.spi.TransportService \ com/foo/SerialTransportService.class \ com/foo/SerialConnection.class \ com/foo/SerialCapabilities.clas \ com/foo/SerialIO.class \ com/foo/SerialProtocol.class
コネクタの配置と同様に、jar ファイルはシステムクラスローダーから可視の場所にコピーされます。
TransportService は、ネイティブメソッドを使用する場合もあれば、ネイティブライブラリを必要とするほかの API に依存する場合もあります。その場合、ネイティブライブラリは、System.loadLibrary を使用してロードできる場所に存在する必要があります。
ネイティブトランスポートライブラリは、JDWP エージェントによってロードされます。このため、ネイティブトランスポートライブラリは、オペレーティングシステムの通常の実行時ライブラリ検索パス上に存在する必要があります。たとえば、Solaris または Linux システムの場合は、LD_LIBRARY_PATH 環境変数によって指定された検索パス上に存在する必要があります。