Java Platform Debugger Architecture -
サービス・プロバイダ・インタフェース

Java Debug Interface (JDI)のサービス・プロバイダ・インタフェースを使用すると、ConnectorTransportServiceの実装を開発および配備できます。TransportServiceクラスは、Connectorで使用される基盤のトランスポート・サービスを表し、デバッガとターゲットVM間の接続の確立、およびJava Debug Wire Protocol (JDWP)パケットのトランスポートに使用されます。

JDIのサービス・プロバイダ・インタフェースに加えて、JDKにはJava Debug Wire Protocol Transport Interface (jdwpTransport)と呼ばれるトランスポート・ライブラリ・インタフェースも含まれています。これは、トランスポート・ライブラリの開発および配置を可能にするネイティブ(C/C++)インタフェースです。トランスポート・ライブラリは、debuggee側のJDWPエージェントによってロードされ、デバッガへの接続の確立、およびデバッガとVM間のJDWPパケットのトランスポートに使用されます。

このページでは、新しいインタフェースが使用される可能性のあるいくつかのシナリオについて説明します。また、新しいコネクタとトランスポートの実装の開発および配置に関連するタスクの概要についても説明します。


シナリオの例

サービス・プロバイダ・インタフェースとネイティブ・トランスポート・インタフェースは、次のユーザーによって使用されることが想定されています。

これらのユーザーを考慮して、新しいインタフェースを使用する場合のいくつかのシナリオについて説明します。


Connectorの開発

Connectorの開発には、LaunchingConnectorAttachingConnector、またはListeningConnectorの固定実装が含まれます。

どのConnector実装にも、すべてのConnectorメソッドの実装の他に、publicで引数なしのコンストラクタが必要です。コンストラクタは、初期化中にVirtualMachineManagerによって呼び出されます。コンストラクタは無操作の場合や、トランスポート・サービスのロードなどの初期化タスクを実行する場合があります。コンストラクタはチェック例外をスローしないため、初期化中の問題はすべて、エラーまたはその他の非チェック例外としてスローされるべきです。

ConnectorTransportServiceを使用する必要はありません。Connectorによっては、トランスポート以外のメカニズムを使用してターゲットVMに接続する場合があります(「シナリオの例」のセクションでは、クラッシュ・ダンプやハング・プロセスに接続するAttachingConnectorsの例を示しています)。TransportService実装を使用するConnectorの場合、ConnectorTransportService実装を直接参照するか、実行時に実装をロードできます。Oracleが提供するトランスポートを使用しようとするConnectorは、次のようなコードを使用してトランスポート・サービスをロードするようにしてください。

try {
    Class c = Class.forName("com.sun.tools.jdi.SocketTransportService");
    ts = (TransportService)c.newInstance();
} catch (Exception x) {
    throw new Error(x);
}

Java SEの実装には、Oracleのソケット・トランスポート・サービスまたは共用メモリー・トランスポート・サービスが含まれている必要がないため、この例では、トランスポート・サービスが存在しない場合、エラーがスローされます。

Connectorのタイプが認識されていると仮定する場合、実装を開発するときに次のことに注意する必要があります。

LaunchingConnectorのソース・コード(SimpleLaunchingConnector.java)を参照できます。Connectorには、ターゲットVMで実行するクラスのクラス名を指定するclassという1つのConnector.Argumentがあります。この例では、Connector.Argument、トランスポートの命名、createVirtualMachineメソッドの使用を含む、前で説明したすべての要点を示しています。


Connectorの配備

Connectorを配備するには、Connectorの完全修飾クラス名のリストを含むサービス構成ファイルと一緒にConnector実装のクラスをjarファイルにパッケージ化する必要があります。その後、jarファイルはシステム・クラス・ローダーから可視の場所に配置されます。

META-INF/services/com.sun.jdi.connect.Connectorというサービス構成ファイルがjarファイルに含まれている必要があります。このファイルには、jarファイルに含まれているConnectorの完全修飾クラス名のリストがあるだけです。複数のConnector実装が同じjarファイルに含まれている場合があります。この場合、各Connectorのクラス名は別の行に記載されます。

SimpleLaunchingConnectorという起動コネクタを配備すると仮定します。このコネクタを配備するために、次のようなMETA-INF/services/com.sun.jdi.connect.Connectorファイルを作成します。

# A very simple launching connector
SimpleLaunchingConnector

このサービス構成ファイルは、コネクタの実装を構成するクラスと一緒にjarファイルにパッケージ化されます。

jar cf SimpleLaunchingConnector.jar \
    META-INF/services/com.sun.jdi.connect.Connector \
    SimpleLaunchingConnector.class

次に、jarファイルはシステム・クラス・ローダーから可視の場所にコピーされます。

ファイルが配備されると、デバッガの再起動時にConnectorが配備されます。つまり、VirtualMachineManagerallConnectors()メソッドによって返されるConnectorのリストにSimpleLaunchingConnectorが含まれます。また、これは起動コネクタであるため、launchingConnectors()メソッドによって返される起動コネクタのリストにも表示されます。


TransportServiceの開発

トランスポート・サービスを開発するには、次の2つのコンポーネントを開発する必要があります。

トランスポート・サービスの開発には、トランスポートと基盤になる通信プロトコルについての高度な知識が必要です。トランスポート・サービスは、JDWPを基盤となる通信プロトコルにバインドします。提供するサービスは信頼性が高く、JDWPパケットはデバッガとdebuggeeの間で重複したりデータが失われることなく、交換されます。パケットを信頼性の高い方法で交換しなければならないことを考えると、トランスポート・サービスは、基盤となる通信プロトコルが提供するサービスを超えるプロトコル・サポートを提供するべきです。たとえば、処理されていない信頼性の低いシリアル接続を介したデバッグが必要な場合、トランスポート・サービスの実装者は、エラーの検出と回復を実装に組み込んで、デバッガとdebuggeeの間でJDWPパケットを信頼性の高い方法で転送できるようにする必要があります。

トランスポートと基盤の通信プロトコルの詳細を理解したら、次のことを考慮します。

上記の内容が解決したら、TransportServiceの作成によってcom.sun.jdi.connect.spi.TransportServiceを拡張し、実装を提供します。attachメソッドとacceptメソッドは、com.sun.jdi.connect.spi.Connectionのインスタンスを返します。このため、Connectionを実装して、デバッガがデバッグ対象とJDWPパケットを交換できるようにする必要があります。

Oracleのソケット・トランスポートのTransportService実装の一例(SocketTransportService.java)を参照できます。この例は、参照用として提供されています。

ネイティブ・トランスポート・ライブラリを開発するには、jdwpTransport仕様に記載されている各関数を実装する必要があります。関数のプロトタイプおよび定義は、${java_home}/include/jdwpTransport.hに定義されています。

トランスポート・ライブラリの実装者は、関数実装をコンパイルし、ダイナミック・ライブラリ(またはこれに相当するもの)にリンクします。ライブラリは、トランスポート・ライブラリがロードされるときにJDWPエージェントから呼び出されるjdwpTransport_OnLoad関数をエクスポートします。一部の組込み環境は、動的リンクをサポートしていません。そういった環境では、トランスポート・ライブラリに静的にリンクしなければならない場合があります。その場合、ライブラリのロードはありませんが、トランスポート・ライブラリを初期化し、環境ポインタを取得するために、jdwpTransport_OnLoad関数が引き続き呼び出されます。

jdwpTransport実装の例として、Oracleのソケット・トランスポート・ライブラリ(dt_socket)のソース(socketTransport-example.c)をダウンロードできます。この例は、あくまでも参照用として提供されています。


TransportServiceの配備

TransportServiceは、Connectorと同様の方法で配備されます。TransportServiceを配備するには、TransportServiceの完全修飾クラス名のリストを含むサービス構成ファイルと一緒にTransportService実装のクラスをjarファイルにパッケージ化する必要があります。その後、jarファイルはシステム・クラス・ローダーから可視の場所に配置されます。

META-INF/services/com.sun.jdi.connect.spi.TransportServiceというサービス構成ファイルがjarファイルに含まれている必要があります。Connectorの配備と同様に、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 

Connectorの配備と同様に、jarファイルはシステム・クラス・ローダーから可視の場所にコピーされます。

TransportServiceは、ネイティブ・メソッドを使用する場合もあれば、ネイティブ・ライブラリを必要とする他のAPIに依存する場合もあります。その場合、ネイティブ・ライブラリは、System.loadLibraryを使用してロードできる場所に存在する必要があります。

ネイティブ・トランスポート・ライブラリは、JDWPエージェントによってロードされます。このため、ネイティブ・トランスポート・ライブラリは、オペレーティング・システムの通常の実行時ライブラリ検索パス上に存在する必要があります。たとえば、SolarisまたはLinuxシステムの場合は、LD_LIBRARY_PATH環境変数によって指定された検索パス上に存在する必要があります。


Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.