プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

Eclipse プラグイン開発:拡張ポイントの実装

Eclipse プラグイン開発 目次


 さて、前回に引き続き、Eclipse Extension  Point(拡張ポイント)の実装を行っていこう。

 ………え?前回が1年半前?

 さぁて、何のことかな?

 あ、今回から環境がJava10、Eclipse Photonになっております。

拡張ポイントを取得する

 プラグイン開発において、拡張ポイントはIExtensionPointによって表現される。 各プラグインがplugin.xmlに記述する拡張ポイントの宣言は、IExtensionで表現される。

インターフェース 対応するファイル 取得方法
IExtensionPoint sample.core.books.exsd IExtensionRegistry.getExtensionPoint
IExtension plugin.xml IExtensionPoint.getExtension

 

 拡張ポイントは、IExtensionRegistryによって管理される。 IExtensionRegistryはPlatformから取得可能だ。

// import org.eclipse.core.runtime.IExtensionRegistry;
IExtensionRegistry registry=Platform.getExtensionRegistry();

 拡張ポイントの取得はIExtensionRegistoryからgetExtensionPoint(String)により取得する。

// import org.eclipse.core.runtime.IExtensionPoint;
IExtensionPoint point = registry.getExtensionPoint("sample.core.books");

 拡張ポイントの宣言情報はIExtensionPointからgetExtensionで取得する。  拡張ポイントの宣言は拡張ポイントそのものと違って、複数回定義されうるものなので、配列で返される。

// import org.eclipse.core.runtime.IExtension;
IExtension[] extensions = point.getExtensions();

要素を処理する

 IExtensionを取得出来たら、ようやくbook要素やauthor要素といった情報を解析する処理が始まる。  XMLを直接解析する必要はなく、DOMの様なデータ構造であるIConfigurationElementを処理する。

 IExtenstion直下のIConfigurationElementを取得するには、getConfigurationElementsを使う。

// import org.eclipse.core.runtime.IConfigurationElement;
IConfigurationElement[] elements = extension.getConfigurationElements();

 IConfigurationElementで扱うデータは、以下の物を理解しておけば十分だ。

データ 取得方法
子要素 getChildren
要素名 getName
属性 getAttribute
属性(kind = java) createExecutableExtension
名前空間 getNamespaceIdentifier

 

 ただし、kindがjavaである属性の取得だけは注意が必要だ。

 というのも、各バンドル(プラグイン)ごとにClassLoaderが異なる為、Class.forNameでクラスを見つけることが出来ないからだ。 createExecutableExtensionはその辺を解決して、インスタンスを生成してくれる。

 (単にクラス名だけが必要なら普通にgetAttributeで取得しても良い。)

リソースの取得

 前回の例で定義している、author.imageなど、リソースを取得する必要がある場合もある。

 リソースは、拡張を定義した各プラグイン内のリソースを取得する必要がある為、Bundleを使って取得する必要がある。(Eclipseプラグイン開発:  バンドルリソース関連を参照)

 BundleはIExtensionやIConfigurationElementのgetNamespaceIdentifierで得られる名前空間名から取得可能だ。

Bundle bundle = Platform.getBundle(extension.getNamespaceIdentifier());

 以下の様な関数を定義しておけば、利用する際に便利だろう。

public static URL findResource(Bundle bundle,String path){
  return path == null || path.isEmpty()?null:FileLocator.find(bundle,new Path(path));
}
public static ImageDescriptor findImage(Bundle bundle,String path){
  return path == null || path.isEmpty()?null:AbstractUIPlugin.imageDescriptorFromPlugin(bundle.getSymbolicName(),path);
}

Expression

 前回、最後に導入したenablementの要素はorg.eclipse.core.expressionsパッケージが処理を行う。

 処理の流れを以下に示す。

  1. IConfigurationElementをExpressionに変換
  2. ExpressionContextを用意し、式を評価(evaluate)し、ExpressionResultを取得
  3. 扱いやすい様にbooleanに変換

 2の処理を行うタイミングは、式の内容による。  一度計算すれば二度と変化しないなら、最初に計算してしまえば良い。  一方で、設定などに依存する場合はその都度計算する必要があるだろう。

boolean enable = true;

IConfigurationElement[] enablement=book.getChildren("enablement");
if(enablement.length==1){
  Expression exp= ExpressionConverter.getDefault().perform(enablement[0]);

  EvaluationContext ctx = new EvaluationContext(null,"");
  ctx.addVariable("hoge","HOGE"); // hogeという変数を定義

  EvaluationResult r = exp.evaluate(ctx);
  enable = r == EvaluationResult.TRUE;
}

拡張ポイントを処理するタイミング

 拡張を定義するplugin.xmlは起動時に読み込まれる為、基本的に変化しない。  従って、Bundleがアクティブになった後、必要になった時に1回だけ読み込む様にするのが良いだろう。

(無論、メモリを圧迫するなどの理由で毎回読み込んでも良いが)

 一応、Bundleが破棄されたら、それらの情報も破棄した方が良い。

 

拡張ポイントの読み込みサンプルプログラム

 Github:extension_point_sampleに前回定義したcore.sample.booksを読み込むサンプルプログラムを用意した。

 このプログラムはsample.internal.core.Extensionsクラスで拡張ポイントを処理してBookクラスにコンバートする。  コンバートした結果はActivatorのstartで取りこまれ、stopで破棄される。