Architecture要約Eclipseプラグインは、構成部品からアプリケーションを作成するためのアーキテクチャー・パターンを具体的な形で例示しています。workbenchのインスタンス内に見ることができるアーキテクチャー・パターンに関与するオブジェクトの役割と協調動作について考察します。workbenchを使ったプラグインの作成方法は扱いません。Environment:統合開発環境)を作成するための拡張可能なプラットフォームであり、プログラミング作業をサポートするために、協力して動作するツールを制御するための基本サービスを提供します。platformに与えます(contribute)。plug-in)と呼ばれ、Eclipseプラグイン契約に準じます。Eclipseにおける拡張性の基本メカニズムは、新規プラグインはすでに存在するプラグインに新しい処理要素を追加できるということです。Eclipseはこのプロセスを開始するために、基本プラグイン・セットを備えています。このサイトで入手可能な文献に、拡張可能なIDEプラットフォームとしての全般的な紹介があります。platformはIDE作成用に特化していますが、基本となる概念と機能は、複数のベンダーが開発した構成部品からアプリケーションを作成するための一般的なモデルをサポートします。Eclipseにおけるシステム構成の一般モデルは、他のソフトウェアパターンに触れるときに説明します。この記事は、プラグインの作成方法に精通しているかどうかにかかわらず、プラグインの動作原理の全体像を理解したいと思っている新規プラグインの開発者を対象にしています。この記事は、次のように構成されています。第2節では、Eclipseプラグイン・モデル、プラグインの宣言的仕様、およびモデル内でのプラグイン間の相互関係を概説し、第3節で、プラグイン開発者による拡張可能なプラグインのプログラミング方法を説明します。pattern)を対比します。第6節で、Eclipseプラグインで使用されている主要なアーキテクチャー上の概念を要約することで記事を締めくくっています。Environment:PDE)を使ったプラグインの作成、テスト方法については、一切触れていません。BeckとGamma[2]、Shavor、他[3]、オンライン・ヘルプ・マニュアル、およびこのサイトにある記事に、PDEを使ってプラグインを作成し、テストするのに必要な手順が説明されています。この記事に掲載されているプラグインのサンプルは、companionプラグインzipファイルに含まれています。サンプルのインストール方法は、この記事の最後に掲載しています。サンプルAPIリファレンスも、この記事の理解に役立ちます。workbenchのコンテキスト内で特定のサービスを提供するコンポーネントです。ここでいうコンポーネントとは、インストール時にシステムに組み込まれるオブジェクトのことです。runtimeは、協調動作するプラグイン・セットをアクティブにし操作するための基盤を備え、開発作業にシームレスな環境を提供します。class))のインスタンスとして作成されます。プラグイン・クラスは、プラグイン・インスタンスの構成と管理をサポートし、org.eclipse.core.runtime.Pluginクラスを拡張する必要があります。このクラスは、プラグインを管理するための一般的な機能を提供する抽象クラスです。個々のプラグインは、Eclipseをインストールした場所にあるpluginsフォルダーの下の独自のフォルダーにインストールされます。プラグインの仕様は、プラグイン・フォルダーにあるplugin.xmlと呼ばれるXMLマニフェスト・ファイルに記述されます。runtimeにプラグインをアクティブにするのに必要な情報を提供します。registry)と呼ばれるメモリー内のリポジトリーにキャッシュされます。runtimeは、プラグイン・レジストリーAPIを使って各プラグインをインスタンス化します。プラグイン・レジストリーAPIは、プラグインに関する情報を得るためにプロバイダー提供のプラグイン・コードで使用されることもあります。最小限必要なプラグイン・マニフェスト・ファイルは、以下のようになります。workbenchにJUnitテスト基盤を追加するプラグインが記述されています(ここでは、読みやすくするために、マニフェスト・ファイルの内容は英語にローカライズされているということに注意してください)。Specificationには、プラグイン定義で使用されるXML要素と属性の記述があります。platformヘルプ・マニュアルでも利用できます。現時点では、プラグイン・マニフェスト・ファイルの内容については詳しく触れません。各プラグインは固有の識別子(XMLのid属性)をもっているということに留意してください。固有の識別子は、他のプラグイン・マニフェスト・ファイル内でプラグインを参照するのに使用され、また以下のように、プラグインの実行インスタンスにアクセスするために、プロバイダー提供のプラグイン・コードでも使用できます。platformを使ってアクセスされます。アプリケーション・プログラムがプラグイン・インスタンスを作成することはありません。プラグインのインストールとアクティブ化Eclipseにプラグインをインストールするということは、プラグインを構成するリソース(マニフェスト・ファイル、jarファイル、および他のリソース)を、インストール先のpluginsディレクトリーの下にある個々のプラグイン・フォルダーにコピーするということです。runtimeによってアクティブ化(activate)されます。プラグインのアクティブ化とは、ランタイム・クラスをメモリーにロードし、インスタンス化してそのインスタンスを初期化するということです。プラグイン・クラスの主な機能は、プラグインのアクティブまたは非アクティブ時に、たとえばリソースの割り当てや解放などの特別な処理を行なうことです。上記のJUnitプラグインのように単純なプラグインでは、アクティブまたは非アクティブ時の処理は特に必要ないので、プラグイン設計者は独自のプラグイン・クラスを用意する必要はありません。runtimeがプラグイン・インスタンス用のデフォルト・プラグイン・クラスを自動的に提供します。プラグインのアクティブまたは非アクティブ時に独自の処理を行なう必要があれば、プラグイン設計者はorg.eclipse.core.runtime.Pluginクラスをサブクラス化し、それぞれstartup、shutdownと呼ばれるアクティブ化、非アクティブ化メソッドをオーバーライドします。対応するプラグイン・マニフェスト・ファイルの中で、class属性の値にこの独自のプラグイン・サブクラスの完全修飾名を指定します。runtimeと呼ばれるプラグイン管理カーネルと、すべてのEclipseのインストールにみられるいくつかのコアなプラグインを含んでいます。platform内にハードコーディングされているので、platformはEclipseの各実行インスタンス内でこのようなプラグインをアクティブにすることができます。コアでないプラグインは、次に示すように、他のプラグインから要求されたときにアクティブになります。Eclipseモデルでは、プラグインは次に示す関係のいずれかによって他のプラグインと関連付けられます。依存関係(dependency)。plug-in)です。必須プラグインは依存プラグインの機能をサポートします。拡張関係(extension)。plug-in)です。エクステンダー・プラグインはホスト・プラグインの機能を拡張します。このような関係は、プラグイン・マニフェスト・ファイル内でXMLのrequires要素とextension要素を通して宣言的に指定されます(後の節で詳しく説明します)。Eclipseにインストールされているコアでないプラグインは、そのプラグインが依存関係と拡張関係の組合せによってコアなプラグインから推移的に関連していれば、Eclipseの実行インスタンス内でアクティブ化されます。このようなプラグインは、プラグインの機能が他のプラグインの機能をサポートしたり、拡張するのに必要になったときにアクティブになります。プラグインがインストールされていても、依存関係および拡張関係を通してコアなプラグインから到達できないと、プラグインの観点からはインストールされていないのと同じです。到達可能なプラグインであっても、ユーザー・アクションや他のイベントがプラグインを起動するきっかけを作らなければ、一定期間(またはインスタンスのライフタイム中)実行インスタンス内で非アクティブのままです。依存関係プラグインが他のプラグインの機能に依存するとき、依存関係はプラグイン・マニフェスト・ファイル内でrequires要素によって指定されます。ここに実例を示します。UIプラグインorg.eclipse.uiに依存している(すなわち使用している)と、宣言しています。プラグイン・マニフェスト・ファイル内で定義される依存関係は、ランタイム時とコンパイル時の両方に指示を与えます。ランタイム時には、依存プラグインがアクティブになるときは、必要な必須プラグインが利用可能であることを保証する必要があります。コンパイル時には、依存プラグインをコンパイルするのに必要な必須プラグインのすべてのjarファイルをclasspathに追加する必要があります。workbenchに追加する必要があります。workbenchのヘルプ・プラグインを利用するには、ヘルプ・メニュー項目をworkbenchユーザー・インターフェイスに追加します。プラグインに処理要素を追加するプロセスは、拡張機能(extension)と呼ばれます。このプロセスはUI要素に限定されません。プラグインは、処理要素の追加によってすべてのプラグインを拡張できます。拡張機能はエクステンダー・プラグインで定義され、ホスト・プラグインの動作を変更します。workbenchへの新規メニュー項目の追加など)、エクステンダー・プラグインが提供するサービスによって、これらの追加要素の動作がカスタマイズされます。object)が、ホスト・プラグインとエクステンダー・プラグインが通信する環境に追加されます。コールバック・オブジェクトは、ホスト・プラグインやエクステンダー・プラグインのオブジェクトとは異なります。platformが自動的にインスタンス化し管理するコンポーネントですが、コールバック・オブジェクトは、プロバイダーが提供するコードが独自にインスタンス化し管理するプレーンな従来のJavaオブジェクトです。拡張機能の1つの動作は、実行環境に複数のコールバック・オブジェクトを追加できます。1つの拡張機能を通して、Eclipseユーザー・インターフェイスにメニュー・セットを追加できます。拡張モデルは本質的に非常に汎用的に設計されているので、エクステンダー・プラグインがカスタム・コールバック・オブジェクトを常に用意する必要はないということに注意してください。コンパイル時にホスト・プラグインで利用できるクラスのオブジェクトだけを使って、ホスト・プラグインの動作を完全に変更することができます。組み込みクラスのインスタンスを単にパラメーター化するだけです。同様に、拡張モデルでは本質的に、ホスト・プラグインはインターフェイス上に拡張機能の各側面を直接表示する必要はありません。拡張機能はホスト・プラグインのインターフェイス表示をいっさい変更しないで、エクステンダー・プラグインとは無関係にホスト・プラグインで発生する可能性がある特定のイベントの通知を、単に依頼することができます。プラグインは、さまざまな種類の拡張機能によってそれ自体を拡張できます。UIでは、メニューとエディターの両方を拡張できます。どの場合でも、拡張機能は独自の構成セットと動作の要件を満たす必要があります。そのため、拡張可能なプラグインは、拡張機能を組み込みことができる異なるタイプのスロットを用意します。point)と呼びます。この記事の残りの部分で、このようなスロットに相当する複合形式の拡張ポイントを扱います。拡張ポイントには、任意の数の拡張機能を組み込むことができます。拡張機能と拡張ポイントは、標準のEclipseプラグインの用語です。ホスト・プラグイン、エクステンダー・プラグイン、およびコールバック・オブジェクトは、拡張関係において異なる役割を担うオブジェクトを説明するために、この記事で使用する用語です。図1は、拡張に関与するオブジェクト間の関係を示しています。workbenchの拡張です。workbenchのユーザー・インターフェイスを実装するorg.eclipse.uiで、そのメニューがactionSetsと呼ばれる拡張ポイントを通して拡張されます。エクステンダー・プラグインは、Eclipseヘルプ・システムのユーザー・インターフェイスを実装するorg.eclipse.help.uiです。UIプラグインを拡張します。拡張機能は、エクステンダー・プラグインで定義します。UIを拡張しています。プラグイン拡張に関与するオブジェクト。UIプラグインは、独自のヘルプ関連メニュー項目を定義しているactionSets拡張機能を通して、workbenchヘルプ・プラグインによって拡張される。[5]によって考案されました)図では、拡張機能のコールバック・オブジェクト・クラス、すなわちヘルプ・システムのメニュー・ハンドラー・クラスも示しています。仕様で宣言されている名前で識別されます。Contentsメニューの仕様では、カスタム・コールバック・クラス(メニュー・ハンドラー)としてHelpContentsActionを宣言しています。拡張機能のSearch->Helpメニューの仕様では、カスタム・コールバック・クラス(メニュー・ハンドラー)としてOpenHelpSearchPageActionを宣言しています。(詳細は、下記をご覧ください)乱雑になるのを避けるために、これ以降の図では、パッケージ・プレフィックスを省略しています。ここでworkbenchプラグイン・クラスはorg.eclipse.ui.internalパッケージに属しており、ヘルプ・プラグインとその関連クラスはorg.eclipse.help.ui.internalパッケージに属しています。本節の残りの部分で、拡張ポイントと拡張機能の定義方法を詳しく説明します。拡張に関与するオブジェクト拡張に関与するオブジェクトが担うさまざまな役割について、さらに詳しく調べていきましょう。プラグインには2つの役割があります。1つは、ホストとエクステンダーとしての役割であり、もう1つは、各拡張ポイントで定義されるコールバック・オブジェクトの一般的な役割と独自の役割です。特定の拡張関係において、ホストの役割を担うプラグインは、拡張ポイントを提供し、その拡張ポイントを通して拡張されます。それ自体でサービスを提供することに加え、このようなプラグインは多数の拡張機能の調整役や管理者としても動作します。XML要素を使って宣言されます。以下に、このような要素の例を示します。workbenchのUIプラグインorg.eclipse.uiから抜粋しました。Reference/Workbench/org.eclipse.ui.actionSetsでもご覧になれます)。workbenchに追加されるメニュー・セット、メニュー項目、およびボタンに対してプラグイン・スロットを提供していることも述べられています。拡張ポイントに対してホスト・プラグイン内で一意の識別子を定義します。付加して、拡張ポイントの完全修飾(fully-qualified)識別子を形成します。UIプラグインで、actionSets拡張ポイントの完全修飾識別子はorg.eclipse.ui.actionSetsです。拡張ポイントを拡張するプラグインは、完全修飾識別子で拡張ポイントを参照します。)では、この拡張ポイントの拡張機能に対するXMLスキーマも宣言します。UIに追加されるメニュー・セット、メニュー項目、およびボタンを宣言するときのシンタックスを規定します。第2.3.3節でこのようなスキーマの構造と内容について詳しく説明します。特定の拡張関係において、エクステンダーの役割を担うプラグインは、拡張機能を定義し、通常、拡張機能を通して独自の機能をホスト・プラグインに追加します。ホスト・プラグインが独自の処理要素を実行環境に追加できるようにします。XML要素を使って宣言されます。以下に、エクステンダー・プラグインの例を示します。この例は、org.eclipse.help.uiプラグインのマニフェスト・ファイルから抜粋しました。このプラグインは、2つのメニュー項目を追加して、リスト2.3のactionSets拡張ポイントを拡張します。