Eclipseとプラグインについて

この節では、Eclipseとプラグインの関係について、ステップ2で扱った「Hello, world」を用いて説明します。

宣言と実装の分離

先ほどの「Hello, world」プラグインを起動させるとき、ランタイム・ワークベンチが起動し、そのワークベンチにはきちんとボタンとメニューが追加されていました。 同様に、このプラグインを普段使っているワークベンチに加えることもできます。

このように、自作プラグインがきちんとEclipseのワークベンチに反映されていました。普通に考えると、ボタンを追加するためには、Eclipseのワークベンチを構成するコードを書き換えて「Hello, world」ボタンを表示する処理を追加しなくてはならないように思えます。 では、どうしてプラグインを追加しただけでワークベンチに自作プラグインが反映されて起動されるのでしょう?

その答えが、XMLによる「宣言と実装の分離」です。

「Hello, world」のplugin.xmlは以下のようになっていました。

plugin.xml:

<plugin>
   <extension
         point="org.eclipse.ui.actionSets"> //拡張ポイントの設定
      <actionSet
            label="Sample Action Set"
            visible="true"
            id="sample.actionSet">
         <menu
               label="Sample &Menu"
               id="sampleMenu">
            <separator
                  name="sampleGroup">//新たなメインメニューの定義
            </separator>
         </menu>

         <action
               label="&Sample Action"
               icon="icons/sample.gif"
               class="sample.actions.SampleAction"//アクションが実装されたクラス
               tooltip="Hello, Eclipse world"
               menubarPath="sampleMenu/sampleGroup"//メニューバーに挿入
               toolbarPath="sampleGroup"           //ツールバーに挿入
               id="sample.actions.SampleAction">
         </action>
      </actionSet>
   </extension>
</plugin>

Eclipseは、起動させると、まずpluginフォルダの中にあるjarファイルをすべて調べ、中にあるplugin.xmlを読み込んでワークベンチを構成します。
そのとき、自作のプラグインも既存のプラグインも区別なくplugin.xmlを読み込んで、ワークベンチにメニューやボタンなどが組み込まれます。

その元になっているのが、上のlabel=.., やtoolbarPath=...などの部分です。Eclipseはそういった部分を読み込んで反映してくれます。これで、Eclipseはこちらの要求どおりの見た目になってくれるようになります。

インターフェースの実装

Eclipseの見た目でボタンが追加されたからといって、追加されたボタンに対するアクションはどうやって認識しているのでしょうか?
「Hello, world」では、アクションを「SampleAction.java」で書いていましたが、Eclipseのソースコードに、このクラスを使った処理を書き込んだわけではありません。

そこで使われるのが、インターフェースです。「SampleAction.java」は以下のようになっていました。

SampleAction.java:

package sample.actions;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.jface.dialogs.MessageDialog;

public class SampleAction implements IWorkbenchWindowActionDelegate {
	private IWorkbenchWindow window;

	public SampleAction() {
	}

	public void run(IAction action) {
		MessageDialog.openInformation( //ダイアログを表示
			window.getShell(),
			"Sample Plug-in",
			"Hello, Eclipse world");
	}

	public void selectionChanged(IAction action, ISelection selection) {
	}

	public void dispose() {
	}

	public void init(IWorkbenchWindow window) {
		this.window = window;
	}
}

上では、IWorkbenchWindowActionDelegateを実装しています。このインターフェースを実装することで、Eclipseがこのクラスを使うのに必要なメソッドが実装されます。

このように、プラグインは適切なインターフェースを実装しなければいけないというルールがあります。こうすることで、Eclipseはそのインターフェースを通してプラグインを呼び出せるようになります。

リフレクション

これでようやくEclipseはアクションの実装クラスの中にあるrun()メソッドを呼び出せるということが説明できたように思えます。
しかし、このままだとEclipseのソースでは、

IActionDelegate action = new SampleAction();
action.run();

のように呼び出さなければならないと予測されます。赤字の部分はやはりSampleActionがかかわってきます。これでは結局、Eclipseのソースを書き換えなければなりません。

そこで、XMLによる実装クラスの宣言が必要になります。上のplugin.xmlでは、class="sample.actions.SampleAction"という記述がありました。Eclipseはこの部分からアクションの実装クラスの名前を取ってきます。

このクラス名を使ってアクションを実行するために、リフレクションを使います。
リフレクションを使うと、上のような実装が以下のように書けます。

String className = "SampleAction";//plugin.xmlから取ってきたクラス名
Class actionClass = Class.forName(className);
IActionDelegate action = (IActionDelegate)actionClass.newInstance();
action.run();

これでクラス名からrunメソッドを実行することができました。もちろん、実際には上の実装より複雑な方法で実装されていますが、本質的な部分は一緒なはずです。 このようになっていることで、アクションを動作させたとき、plugin.xmlの中の実装クラス名からインスタンスを作り、runメソッドを実行することができるようになります。