一般的に、EMF プロジェクトのリソース (例えば EMF Ecore モデル) は単一のオブジェクトとしてビューアーに表示されます (図 1 の左側を参照)。この場合、モデルを検討するにはそのモデルに関連付けられたエディターを開かなければならないため、ドメイン・モデルに依存した開発では特に、厄介な制約となる可能性があります。この制約を回避する方法は、カスタム・ビューを作成し、目的とするドメイン・モデルのコンテンツにアクセスできるようにすることです。このプラグインは一から作成することも、既存のフレームワークを使って開発作業を軽減することもできます。これから概要と詳細を説明するのは、このようなプラグインを作成する手順です。この記事を読み終える頃には、Ecore モデルのナビゲーションに利用できるビューアー・プラグインが完成しているはずです (図 1 の右側を参照)。
図 1. ナビゲーターのタイプ
この ModelNavigator プラグインに求める内容は明らかですが、開発を始める前に、これから使用する Eclipse コンポーネントの基本を理解しておかなければなりません。ここで作成するのは、モデルの階層を表示するツリー・ビューアーです。ツリー・ビューアーについての詳細はこの記事の範囲外なので、「参考文献」を参照してください。注意すべき重要な点は、ツリー・ビューアーはコンテンツ・プロバイダーと呼ばれるアダプターを介してモデル・オブジェクトにアクセスし、ラベル・プロバイダーを介してオブジェクトの表示方法を決定するということです。以降のセクションではコンテンツ・プロバイダーおよびラベル・プロバイダーを介した場合のデータ・アクセス方法、そしてモデル・ナビゲーターの表示方法を詳しく説明します。
EMF モデルを対象としたエディターを作成するために通常使用されるのは、EMF.Edit フレームワークです。EMF.Edit フレームワークは EMF モデル用のエディターを作成するためのコマンド・コードの生成機能やその他のクラスを提供し、プログラムによるモデルへのアクセスを可能にします。それとは別にこのフレームワークが提供している (そしてこの記事ではとりわけ重要な) 一連のフィーチャーが、EMF モデルをビューアーに表示できるようにする便利なクラスです。これらのクラスへのアクセスに使用される汎用のコンテンツ・プロバイダーとラベル・プロバイダーが、特定タイプの EMF オブジェクトに対応したアダプターを使ってモデルを表示します。コンテンツ・プロバイダーとラベル・プロバイダーに該当するのは、それぞれ AdapterFactoryContentProvider クラスと AdapterFactoryLabelProvider クラスです。この 2 つのクラスが EMF モデルのナビゲート方法を認識するアイテム・プロバイダー・アダプターに委任して、EMF オブジェクトのビューアーにオブジェクト、ラベル、そして画像を提供するというわけです。この図式を図 2 に示します。このような図式が私たちのプロジェクトにとりわけ有用である理由は、モデルをビューに適応させる方法を理解する必要がなくなるからです。モデルのビューへの適応は、コンテンツ・プロバイダーとラベル・プロバイダーに任せてしまうのです。
図 2. Eclipse ヘルプから引用した EMF.Edit
フレームワークにはそれぞれの EMF モデル・タイプに対応したアイテム・プロバイダーが含まれますが、たいていの場合はモデル・タイプごとに別個のナビゲーターを作成するのではなく、同じ 1 つのナビゲーターからすべてのモデルのコンテンツにアクセスしたいと思うものです。そこで登場するのが複合アダプター・ファクトリーです。複数のモデルからのオブジェクトの集合に適応可能な複合アダプター・ファクトリーを提供することで、さまざまな EMF モデルのオブジェクトを同時に表示できるようになります。
EMF.Edit には、他のアダプター・ファクトリーへの共通インターフェースとして機能する ComposedAdapterFactory という便利なクラスもあります。このクラスの利点は後で説明するように、ナビゲーターには対象のモデル・タイプ用のアイテム・プロバイダーを複合アダプター・ファクトリーの一部として組み込むだけで済むことです。そうすると、後は複合アダプター・ファクトリーがその一部となっている他のプロバイダーに実装を委任してくれます。この記事のサンプル・ナビゲーターでも、例えばジェネレーター・モデル、Ecore モデル、UML モデルなどを表示するようにできます。ビューアーがこれらのモデルを表示しようとすると、コンテンツ・プロバイダーとラベル・プロバイダーがアダプター・ファクトリーに委任し、委任されたアダプター・ファクトリーが該当するアイテム・プロバイダーに委任するという仕組みです。これによって、開発作業が楽になると同時に、ModelNavigator プラグインを拡張して複数のドメイン・モデルをサポートさせることも可能になります。
フレームワーク全体が準備できて ModelNavigator プラグインでモデルのコンテンツにアクセスできるようになったら、次に必要となるコンポーネントはこのナビゲーターを収容する実際のビューアーです。ビュー・プラグインを拡張して、目的のコンテンツをツリー・ビューで表示する独自のビュー部分を実装するという方法もありますが、さまざまなドメインのコンテンツを単一のビューに結合してユーザーがビューアーでエディター・モデルを操作、ナビゲートできるようにする既存のフレームワークもあります。それが、Eclipse V3.2 に CNF として導入された org.eclipse.ui.navigator です。開発者は CNF を使用して、コンテンツ、ラベル、アクション、フィルターなどの機能を単一のナビゲーターに提供することができます。CNF は、複数のナビゲーション用ビューアーを統合して統一したユーザー・エクスペリエンスを実現する手段となります。
すべてのエディター・モデル・インテグレーターに対応した単一のビューをサポートする CNF では、リソースに左右されないモデルのコンテンツが可能になるとともに、統合されたビューアーの表示内容をユーザーが選択することができます。このフレームワークの実際の例が Project Explorer ビューという形で表示される org.eclipse.ui.navigator.resources プラグインで、IResource モデルに宣言型のビューアー拡張を提供します。ビューアーを作成するには、このフレームワークを使うのが最も簡単な方法です。ビューアー実装の詳細はフレームワークが処理してくれるので、私たちに必要なのはモデルのコンテンツ・プロバイダーとラベル・プロバイダーを実装する作業だけとなります。さらに、プラグインを他のモデルのコンテンツに応じて拡張する可能性が与えられるだけでなく、より高度なフレームワークの機能 (ソーター、フィルター、ドラッグ・アンド・ドロップなど) をビューアーで利用できるようにもなります。
以上の説明で実際のコンポーネントに目を向ける準備が整ったので、いよいよモデル・ナビゲーション・プラグインの作成に取り掛かります。
ModelNavigator プラグインの作成は 2 段階で行います。第一段階は、プラグインの基本構造をセットアップしてその動作を定義します。続く第二段階で、この単純なプラグインを拡張して EMF モデルのコンテンツを表示させます。
ModelNavigator プラグインを作成するための最初のステップとして、プラグイン・プロジェクトを作成します。それには新規プロジェクト・ウィザードを使うので、File > New > Project から Plug-in Project を選択し、Next をクリックします。
プラグイン・プロジェクトの名前として ModelNavigator と入力し、プラグイン ID をcom.ibm.navigator.example.ModelNavigator に、アクティベーターを com.ibm.navigator.example.ModelNavigator.ModelNavigatorPlugin に設定して Finish をクリックします。
図 3. プラグイン・プロジェクトの作成
これで、プラグインの開発に取り掛かる準備ができました。プラグイン開発の最初のステップは、ナビゲーターを収容するビューを作成することです。ビューを作成するには、プラグインを拡張してビュー部分およびビューを表示するカテゴリーを作成します。プラグインの xml ファイルには、ビュー拡張を追加します。
以下の作業は、Extensions タブから行います。
- Add をクリックします。
- Extension points タブで org.eclipse.ui.views を選択します。
- 以下の手順でカテゴリーを作成します。
- org.eclipse.ui.views 拡張を右クリックします。
- New > Category を選択します。
- 名前を
com.ibm.navigator.example.ModelNavigator.mncategoryに設定します。 - ID を
Model Navigatorに設定します。
- 以下の手順でビュー部分を作成します。
- org.eclipse.ui.views 拡張を右クリックします。
- New > View を選択します。
- ID を
com.ibm.navigator.example.ModelNavigator.mnviewに設定します。 - 名前を
Model Navigator Viewに設定します。 - クラスを
org.eclipse.ui.navigator.CommonNavigatorに設定します。 - カテゴリーを
com.ibm.navigator.example.ModelNavigator.mncategoryに設定します。
- 変更内容をプロジェクトに保存します。
前述したように、実装作業の一部は CNF に任せています。このビューのセットアップ方法に関して注意すべき重要な点は、ビューの ViewPart を継承する独自のクラスを作成する代わりに、ビューが共通ナビゲーター・クラスを使用するように設定していることです。これはつまり、クラス・フィールドで指定する共通ナビゲーター・クラスをプラグインのクラス・パスに追加しなければならないということでもあります。したがって、Dependencies タブで必要なプラグインに org.eclipse.ui.navigator を追加してください。
次のステップは、プラグインの CNF 属性を構成します。これらの属性によって、ナビゲーターのデフォルト動作が決まります。
まず、ビューを共通ナビゲーター・ビューアーに関連付けます。それには、Extensions タブから以下の作業を行います。
- Add をクリックします。
- Extension points タブで、org.eclipse.ui.navigator.viewer を選択して Finish をクリックします。
- 以下の手順に従ってビューを作成します。
- org.eclipse.ui.navigator.viewer 拡張を右クリックします。
- New > viewer を選択します。
-
viewerid を上記で定義したビュー ID (
com.ibm.navigator.example.ModelNavigator.mnview) に設定します。
ナビゲーター・プラグインの動作は、バインドするコンテンツとアクション、そして CNF を使用するときにプラグインに設定するその他のオプション (フィルター、ソーターなど) によって決まります。このプラグインで、ビューアーに表示する拡張を選択するのは includes 要素です。フレームワークに対しては、コンテンツ拡張がビューでのコンテンツの表示方法を指示し、アクション拡張がビューに有効なオプション (コンテキスト・メニューなど) を指示します。この必要最小限のナビゲーター・バージョンを稼動させるため、IResource モデルのコンテンツおよびアクション・バインディングを追加し、プラグインにお馴染みの Package Explorer のフィールを与えます。そのために作成するのが、ナビゲーターにリソース・コンテンツ拡張を追加する viewerContentBinding、そしてリソース・アクション拡張を追加する viewerActionBinding です。
IResource コンテンツ拡張を追加するには、Extensions タブで以下の手順に従います。
- org.eclipse.ui.navigator.viewer 拡張を右クリックします。
- New > viewerContentBinding を選択します。
-
viewerid をプラグインの viewpart ID (
com.ibm.navigator.example.ModelNavigator.mnview) に設定します。 - 以下の手順でコンテンツ・バインディングを追加します。
- 上記の手順で作成した viewerContentBinding を右クリックします。
- New > includes を選択します。
- 作成した includes 要素を右クリックします。
- New > contentExtension を選択します。
- パターンを
org.eclipse.ui.navigator.resourceContentに設定します。
IResource アクション拡張をバインドするには、Extensions タブで以下の作業を行います。
- org.eclipse.ui.navigator.viewer 拡張を右クリックします。
- New > viewerActionBinding を選択します。
- viewerid をプラグインの viewpart ID (
com.ibm.navigator.example.ModelNavigator.mnview) に設定します。 - 以下の手順でアクション・バインディングを追加します。
- 作成した viewerContentBinding を右クリックします。
- New > includes を選択します。
- 作成した includes 要素を右クリックします。
- New > actionExtension を選択します。
- パターンを
org.eclipse.ui.navigator.resources.*に設定します。
ナビゲーターの構造はこれでセットアップできました。ナビゲーター・フレームワークにどのタイプのコンテンツを表示するか、そしてナビゲーターをどのように動作させるかを指示する方法は以上のとおりです。これらの拡張は必ずしも追加しなければならないわけではありませんが、IResource モデルのコンテンツとアクションを追加すると一層有用なビューになります。コンテンツをビューアーにバインドする方法がわかれば、ビューアーをさらに拡張してカスタム・フィルターや定義済みフィルターを追加することも可能です。これらの機能についての詳細は、「参考文献」を参照してください。このナビゲーターはまだ完成したわけではありません。ビューアーに EMF モデルを表示できるようにする必要がまだ残っています。
EMF ドメイン・モデルのコンテンツをナビゲーターに表示するために、フレームワークに伝えなければならないことは、どのモデルを対象とするのか、この対象モデルからどのようにして情報を取得するのか、そしていつ、どのように情報を表示するのかといったことです。そのために作成するのが、コンテンツ拡張です。ナビゲーター・コンテンツ・サービスがこの拡張を使って EMF ドメイン・モデルを表示できるようにします。この目的を果たすには、org.eclipse.ui.navigator.navigatorContent プラグインの拡張を作成します。
ナビゲーター・コンテンツ拡張が定義するのは、EMF モデルの要素に子および親オブジェクトを提供する際に使用できるコンテンツ・プロバイダーとラベル・プロバイダーです。ナビゲーター・コンテンツ拡張は、この triggerPoints として知られる子オブジェクト、または possibleChildren として知られる親オブジェクトを提供するためにこの拡張を呼び出す条件も定義します。また、ナビゲーター・コンテンツにはその他多くの属性があり (アクション・プロバイダー、共通ウィザード、フィルターなど)、これらの属性を変更することでプラグインの動作を変更することもできます。ただし、これらの属性は追加機能なので、この ModelNavigator プラグインの作成には必要ありません。
まず始めに新しいコンテンツ拡張を作成し、そこに共通ナビゲーターが使用するコンテンツ・プロバイダーとラベル・プロバイダーを指定します。その後、この 2 つのクラスを実装することになります。
navigatorContent 拡張を追加するには、Extensions タブから以下の作業を行います。
- Add をクリックします。
-
Extension points タブで、
org.eclipse.ui.navigator.navigatorContentを選択して Finish をクリックします。 - 以下の手順でナビゲーター・コンテンツを作成します。
- org.eclipse.ui.navigator.navigatorContent 拡張を右クリックします。
- New > navigatorContent を選択します。
- ID を
com.ibm.navigator.example.ModelNavigator.emfModelContentに設定します。 - 名前を
EMF Model Contentに設定します。 - コンテンツ・プロバイダーを
com.ibm.navigator.example.ModelNavigator.MNViewContentProviderに設定します。 - ラベル・プロバイダーを
com.ibm.navigator.example.ModelNavigator.MNViewLabelProviderに設定します。 - 優先度を
normalに設定します。 - activeByDefault を
trueに設定します。
次に、このナビゲーター・コンテンツのコンテンツ・プロバイダーおよびラベル・プロバイダーとして機能するクラスを実装します。
コンテンツ・プロバイダーとラベル・プロバイダーの実際の作業を実行するには、EMF.Edit フレームワークを使用します。したがって、コンテンツ・プロバイダー・クラスとラベル・プロバイダー・クラスは EMF 編集フレームワークのアダプター・ファクトリーに含まれるサブクラスとして作成しなければなりません。AdapterFactoryContentProvider と AdapterFactoryLabelProvider にそれぞれ委任するコンテンツ・プロバイダー・クラスおよびラベル・プロバイダー・クラスを作成する前に念頭に置いておかなければならないのは、これらのアダプター・ファクトリーは各種 EMF モデルのアイテム・プロバイダーのリストを使ってインスタンス化されるということです。つまり、まずはアイテム・プロバイダーのリストを複合アダプター・ファクトリーとして作成する必要があるので、MNComposedAdapterFactory という名前の新規クラスを作成します (File > New > Class)。
図 4. 実装クラスの作成
さらに、Dependencies タブで必要なプラグインに org.eclipse.emf.codegen.ecore.ui を追加する必要があります。こうすることによって、プラグインがさまざまな EMF モデル・タイプの ComposedAdapterFactory アイテム・プロバイダーやその他の EMF.Edit のコンビニエンス・クラスを使用できるようになります。MNComposedAdapterFactory クラスの実装はリスト 1 のようになるはずです。
リスト 1. サンプル ComposedAdapterFactory クラス
...
public class MNComposedAdapterFactory
{
private static ComposedAdapterFactory mnCompAdapterFactory;
public final static ComposedAdapterFactory getAdapterFactory()
{
if (mnCompAdapterFactory == null)
mnCompAdapterFactory = new ComposedAdapterFactory(createFactoryList());
return mnCompAdapterFactory;
}
public final static ArrayList<AdapterFactory> createFactoryList()
{
ArrayList<AdapterFactory> factories = new ArrayList<AdapterFactory>();
factories.add(new ResourceItemProviderAdapterFactory());
factories.add(new EcoreItemProviderAdapterFactory());
factories.add(new ReflectiveItemProviderAdapterFactory());
return factories;
}
}
|
上記で注目すべき重要な箇所は、アイテム・プロバイダーのリストを作成する静的メソッドを作成しているところです。リストされているアイテム・プロバイダーのうち、アダプター・ファクトリーが Ecore モデルのコンテンツとラベルを提供するために委任するのは EcoreItemProviderAdapterFactory となります。
同じようにして、navigatorContent 拡張詳細で指定したコンテンツ・プロバイダー・クラスとラベル・プロバイダー・クラスを作成します。
まずはコンテンツ・プロバイダー (MNViewContentProvider) から取り掛かります。このクラスを作成するには、拡張詳細パネルに表示されたプロバイダー名の隣にあるリンクをクリックするか、File > New > Class ダイアログに進みます。コンテンツ・プロバイダーの ITreeContentProvider インターフェースを実装する代わりに、ここでは EMF.Edit クラスを使用します。それには MNViewContentProvider クラスを変更して AdapterFactoryContentProvider クラスを継承します。AdapterFactoryContentProvider クラスは、ビューアーにコンテンツを提供する ITreeContentProvider インターフェース実装の処理方法をすでに認識しているので、実際には該当するアイテム・プロバイダーに委任してビューアーにコンテンツを提供させます。
AdapterFactoryContentProvider クラスは、コンストラクターにアダプター・ファクトリーを含んでいることが前提となります。つまり、コンテンツ・プロバイダーには暗黙のコンストラクターは使用できないということです。コンテンツ・プロバイダーのコンストラクターは明示的に宣言し、必要なパラメーターを指定してスーパークラス・コンストラクターを呼び出さなければなりません。宣言したコンストラクターには super(MNComposedAdapterFactory.getAdapterFactory()); を追加します。その他にこのクラスで注目すべきメソッドには、getChildren、getParent、hasChildren、getElements があります。
getChildren メソッドは、ビューアーがドメイン・オブジェクトの子要素を表示しなければならないときに呼び出されます。するとこのメソッドは、パラメーター要素の子であるドメイン・オブジェクトの配列を返します。同様に、getElements メソッドはパラメーター要素のドメイン・オブジェクトを取得するために呼び出されます。同じように動作するこの 2 つのメソッドは、呼び出される時と場合が異なるだけにすぎません。getChildren メソッドを実装するには、AdapterFactoryContentProvider に対し、指定した親の URI の子を返すよう要求するだけです。リスト 2 に、getChildren メソッドを示します。getElements メソッドの場合は、単にこの getChildren メソッドの呼び出しを返します。
リスト 2. getChildren の実装
...
public Object[] getChildren(Object parentElement)
{
if (parentElement instanceof IFile)
{
String path = ((IFile)parentElement).getFullPath().toString();
URI uri = URI.createPlatformResourceURI(path, true);
parentElement = resourceSet.getResource(uri, true);
}
return super.getChildren(parentElement);
}
...
|
ツリー・ビューにコンテンツを表示するために重要となる次の 2 つのステップは、ツリー・ビュー内のオブジェクトが表示する必要のある子を持っている場合にそれを判断できるようにすること、そして一連の子を親オブジェクトに関連付けられるようにすることです。こうすることにより、ドメイン・オブジェクトが展開/縮小表示されているかに関わらず、ビューアーによってドメイン・オブジェクトの状態を制御できるようになります。この例の場合、ドメイン・オブジェクトは一連の子パッケージを持つ Ecore モデルということになります。これらの子パッケージに含まれるのは、同じ親パッケージに関連付けられたクラス・オブジェクトです。リスト 3 に実装方法を示します。
リスト 3. getParent の実装
...
public Object getParent(Object element)
{
if (element instanceof IFile)
return ((IResource)element).getParent();
return super.getParent(element);
}
public boolean hasChildren(Object element)
{
if (element instanceof IFile)
return true;
return super.hasChildren(element);
}
...
|
ここで、使用されているリソースを解決できないというエラーが表示される場合があります。このエラーを解決するには、Dependencies タブで必要なプラグインに org.eclipse.core.resources を追加します。また、コンテンツ・プロバイダーがビュー内のファイル・リソースの URI を取得できるようにするためには、プラットフォームのリソース・セットを使用する必要もあります。そこで、単一の静的リソース・セットの実装を作成し、MNViewContentProvider クラスに private static ResourceSetImpl resourceSet = new ResourceSetImpl(); を追加して、この実装を使ってこれらのリソースを取得できるようにします。
ラベル・プロバイダーについては、作業を EMF.Edit フレームワークの AdapterFactoryLabelProvider クラスに委任するという点ではコンテンツ・プロバイダーの形式と同じです。コンテンツ・プロバイダーの場合と同じくラベル・プロバイダーもドメイン・オブジェクトをその引数として受け取りますが、ラベル・プロバイダーが返すのは、ビューアー内でこのオブジェクトに関連付けられなければならない Image または String です。ビューアーを多少カスタマイズして、名前とアイコンを取得するタスクを委任する場合とオブジェクトに独自のアイコンを提供する場合とをプログラムによって制御することもできますが、カスタマイズはこの記事の目的ではないのでやめておきます。ここで必要なのは、EMF モデルが提供する画像とテキストだけです。ラベル・プロバイダーを実装するには、コンテンツ・プロバイダー用に取得したアイテム・プロバイダーのリストを指定してスーパークラスを呼び出し、この AdapterFactoryLabelProvider スーパークラスにオブジェクトの画像または説明を要求する呼び出しを委任します。
リスト 4. ラベル・プロバイダー
...
public MNViewLabelProvider()
{
super(MNComposedAdapterFactory.getAdapterFactory());
}
public Image getImage(Object element)
{
return super.getImage(element);
}
public String getText(Object element)
{
return super.getText(element);
}
...
|
ここまでのところで、プラグインにコンテンツ拡張を実装するという作業は完了しました。このコンテンツ拡張をビューが利用できるようにするプロセスも、同じく 2 段階で行います。第一段階は、この特定のコンテンツ拡張を使用していることを通知するイベントを定義するという作業です。そして第二段階で、ナビゲーター・コンテンツをビューにバインドします。
クラスに記述されたドメイン・モデルを表示可能なことを CNF に通知するには、<possibleChildren /> および <triggerPoints /> 要素をナビゲーター・コンテンツ拡張に追加します。この 2 つの要素は、Eclipse の中核となる式として簡単にプラグインの xml ファイルに定義することができます。この例の場合、ナビゲーター・コンテンツが呼び出されるのはビューアーに EMF モデルのインスタンスであるオブジェクトが含まれる場合です。現在目的としているのは Ecore モデルをナビゲートすることだけなので、この式はリソースの拡張が Ecore であるかどうかをチェックする単純なものにします。possibleChildren要素は、拡張がビューアー内のオブジェクトに親を提供できる場合を指定します。この例でこれらのオブジェクトに該当するのは EMF モデルのオブジェクトまたはリソースのインスタンスです。
リスト 5. triggerPoints 要素と possibleChildren要素
<triggerPoints>
<or>
<and>
<instanceof value="org.eclipse.core.resources.IResource"/>
<test
forcePluginActivation="true"
property="org.eclipse.core.resources.extension"
value="ecore"/>
</and>
</or>
</triggerPoints>
<possibleChildren>
<or>
<instanceof value="org.eclipse.emf.ecore.resource.Resource"/>
<instanceof value="org.eclipse.emf.ecore.EObject"/>
</or>
</possibleChildren>
|
最後に、IResource モデルのコンテンツ拡張をビューアー・コンテンツのバインディングに組み込んだときと同じ手法で、作成したナビゲーター・コンテンツをビューにバインドします。
ナビゲーター・コンテンツ com.ibm.navigator.example.ModelNavigator.emfModelContent を実際のビューにバインドするには、Extensions タブから以下の作業を行います。
- org.eclipse.ui.navigator.viewer 要素を展開します。
- viewerContentBinding 要素を展開します。
- 以下の手順で新しいコンテンツ拡張を作成します。
- includes 要素を右クリックします。
- New > contentExtension を選択します。
- パターンを前に定義した
navigatorContent(com.ibm.navigator.example.ModelNavigator.emfModelContent) に設定します。
- Save をクリックします。
EMF モデルのコンテンツを共通ナビゲーターに追加するのに必要なステップはこれでほとんど完了しました。後は、ModelNavigator プラグインが IResource モデルと EMF Ecore モデルのオブジェクトを表示できるようにするだけです。
ModelNavigator プラグインが機能していることを確認するため、新規のビューで ModelNavigator プロジェクトを実行して Ecore モデルを表示します。このテストを行うには、モデル・ナビゲーター (Model Navigator View) に表示される EMF プロジェクトを作成する必要があります。ここに記載する例では、SchoolLibrary の UML ファイル (「参考文献」を参照) を使用します。
ModelNavigator プロジェクトを Eclipse アプリケーションとして実行した後、以下の手順に従います。
- Window > Show View > Other をクリックして新規ワークベンチに ModelNavigator ビューを表示します。
- Model Navigator カテゴリーを探し、Model Navigator View をクリックします。
- OK をクリックします。
ランタイム・ワークスペースで EMF プロジェクトを作成する手順は以下のとおりです。
- File > New > Project をクリックして新規プロジェクトを作成します。
- Eclipse Modeling Framework 要素を展開します。
- EMF プロジェクトをクリックし、Next を選択します。
- プロジェクトに
SchoolLibraryという名前を付けて、Next を選択します。 - モデルのインポーターとして Rose class model を選択し、Next を選択します。
- モデルの URI として、schoollibrary.mdl ファイルをダウンロードした場所までブラウズします。
- Next をクリックします。
- 図 5 に示すように library パッケージと SchoolLibrary パッケージを選択します。
- Finish をクリックします。
図 5. EMF テスト・プロジェクトの作成
すべてが計画通りに行けば、モデル・ナビゲーター (Model Navigator View) に新規 SchoolLibrary プロジェクトが表示されるはずです。さらに重要な点は、ナビゲーター・コンテンツが正常に機能している場合、プロジェクトの model ディレクトリーを展開してナビゲーター・ビュー内で library および SchoolLibrary Ecore ファイルのコンテンツをナビゲートできるということです。ナビゲーターは図 6 のように表示されます。
図 6. ModelNavigator プラグインのテスト
EMF モデルのコンテンツをビューアーに表示するという目標は達成しました。しかし実際に Ecore ファイルをエディターで開いて変更を開始したとしても、現状のままでは何も起こりません。ModelNavigator プラグインが表示中のモデルに加えられた変更を認識しないため、モデルを更新しないからです。モデルが更新されるようにするには、ビューアーがエディター内での変更を認識してビューアー自体を更新するようにしなければなりません。このような同期を行わせる 1 つの手段は、リソース変更リスナーをコンテンツ・プロバイダーに追加することです。以降のセクションでは、そのために必要なステップを概説します。
コンテンツ・プロバイダーをモデルの変更に反応させるには、コンテンツ・プロバイダーがモデルのファイル・リソース (この例では Ecore ファイル) での変更をリッスンできるようにします。そのために必要なのは IResourceChangeListener および IResourceDeltaVisitor インターフェースを MNViewContentProvider クラスに実装することです。
リソースが変更され、リソースの変更を表す一連のイベントが渡されると resourceChanged(IResourceChangeEvent event) メソッドが呼び出されます。この変更一式が提供するのは、時間の差分としてのリソース・ツリーの変化です。これを利用すれば、リソース・ツリー内での変更をウォークスルーし、変更されたリソースのタイプに応じて必要なアクションを判断することができます。resourceChanged(IResourceChangeEvent event) メソッドの実装方法はリスト 6 のとおりです。このメソッドを実装することによって、変更されたリソース・セットを取得し、リソースの差分にアクセスできるようになります。
リスト 6. resourceChanged メソッド
...
try
{
IResourceDelta delta = event.getDelta();
delta.accept(this);
}
catch (CoreException e)
{
...
|
リソースの差分にアクセスされると、visit(IResourceDelta delta) メソッドが呼び出されます。このプラグインでは、変更されたリソースが Ecore の拡張子を持つ IResource ファイルである場合のみを対象としています。変更されたリソースが Ecore モデルであれば、変更が反映されるように ModelNavigator プラグインを更新しなければなりません。そのためには変更済みファイルからリソースを取得し、そのリソースが表すモデルをリロードします。
リスト 7. visit メソッド
...
IResource changedResource = delta.getResource();
if (changedResource.getType() == IResource.FILE
& changedResource.getFileExtension().equals("ecore"))
{
try
{
String path = ((IFile)changedResource).getFullPath().toString();
URI uri = URI.createPlatformResourceURI(path, true);
Resource res = resourceSet.getResource(uri, true);
res.unload();
res.load(resourceSet.getLoadOptions());
}
catch(IOException ie)
{
System.out.println("Error reloading resource - " + ie.toString());
}
return false;
}
return true;
...
|
リソース変更リスナーを利用するには、このリスナーをコンテンツ・プロバイダーに追加し、適当なときに削除する必要があります。そこで、MNContentProvider クラスでコンストラクターに ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); を挿入してリスナーを追加します。また、このクラスの dispose メソッドには ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); を挿入します。これでリソースの変更に応じた更新が行われるようになるはずですが、これは変更を処理する方法としては極めて単純なものであることを忘れないでください。この方法ではコンテンツ・プロバイダーで影響のあったモデルを更新するだけで、モデルの依存関係を調べて該当する要素を更新することまではしていません。これは、ナビゲーターを常に更新された状態にするための基本的方法です。
Ecore モデルでの変更がビューアーに反映されていることをテストするため、サンプル・アプリケーションを再び実行して変更を加えてみます。
ModelNavigator プロジェクトを Eclipse アプリケーションとして実行した後、以下の手順に従います。
- model ディレクトリーの下にある schoollibrary.ecore までナビゲートします。
- schoollibrary.ecore ファイルを該当するエディターで開きます。
- schoollibrary.ecore ノードを展開します。
- SchoolLibrary パッケージのノードを右クリックします。
- New Child > EClass を選択します。
-
Properties タブで、この新しいクラスに名前 (
Test) を設定します。 - ファイルを保存します。
上記の操作によってリソース変更リスナー・コードがトリガーされて ModelNavigator プロジェクトを実行し、モデルが更新されるはずです。すると ModelNavigator ビューが自動的にリロードされます。ツリーを展開して schoollibrary.ecore ファイルまでナビゲートし、上記で行った変更が表示されていることを確認してください (図 7 を参照)。
図 7. リソースが更新された ModelNavigator プラグイン
最後にもう 1 つ、むしろ簡単に行える ModelNavigator プラグインの拡張としては、複合アダプター・ファクトリーを利用するための拡張があります。私たちが作成したナビゲーターは Ecore モデルを表示しますが、これ以外の EMF モデルを表示させるにはどうしたらいいでしょう。これは、EMF.Edit フレームワークが実装されているおかげで意外と簡単に行えます。つまり、対象とするドメイン・モデルのアダプター・ファクトリーを ComposedAdapterFactory に追加し、これらの新しいモデルに対応したトリガーを設定するという最小限の変更で、他のドメイン・モデルのサポートを追加することができます。
例えば、genmodel オブジェクトをナビゲーターに追加するには、ただ単にコンテンツ・プロバイダーとラベル・プロバイダーが使用するアダプター・ファクトリーのリストにジェネレーター・モデルのアイテム・プロバイダーを追加するだけです。MNComposedAdapterFactory クラスでは、factories.add(new GenModelItemProviderAdapterFactory()); を createFactoryList() メソッドに追加します。その他にモデル・ナビゲーターで必要となる変更は唯一、このコンテンツ・プロバイダーをトリガーするタイミングをナビゲーターのコンテンツに指示することだけです。以下のように、トリガー・ポイント (triggerPoints) と同じ方法を使ってリソースの拡張子をチェックします。
リスト 8. genmodel のトリガー・ポイント
<and>
<instanceof value="org.eclipse.core.resources.IResource"/>
<test
forcePluginActivation="true"
property="org.eclipse.core.resources.extension"
value="genmodel"/>
</and>
|
現行のトリガーの直下に上記の新しいトリガー式を追加することで、オブジェクトが IResource のインスタンスであり、Ecore の拡張子を持っている場合、あるいは IResource のインスタンスであり、genmodel の拡張子を持っている場合にナビゲーターのコンテンツを関与させています。このプロジェクトを上記で概説したように再度実行すると、Ecore モデルと Generator EMF モデルをナビゲートできるようになっていることがわかるはずです (図 8 を参照)。ただし、これは私たちの極めて単純なリソース更新の枠組みでは計画外のことなので、ModelNavigator ビューのそれぞれのモデル同士で更新が同期されることはありません。
図 8. 複数のモデルを使用した ModelNavigator プラグイン
ビューアーに EMF モデルを表示するプラグインを作成するタスクは、これで完了です。Eclipse が提供するフレームワークを使用してこのプロセスを簡単に行えるようにする方法を実演し、さらにプラグインに単純な機能を追加する方法についても触れました。この記事で取り上げたのは、これらのフレームワークが提供する機能のほんの一部です。読者のみなさんには是非、Eclipse コンポーネントをさらに掘り下げて調べてみることをお勧めします。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Code | os-eclipse-emf.ModelNavigator.zip | 9.5KB | HTTP |
学ぶために
-
Eclipse Modeling
Framework Project の詳細を学んでください。
- Michael Elder のブログには、Common Navigator Framework に関する記事が豊富に揃っています。
- Eclipse documentation で紹介している EMF.Edit
フレームワークからモデルのコンテンツにアクセスしてください。
- Eclipse documentation で拡張 EMF モデルの生成方法を調べてください。
- Eclipse.org にアクセスして、共通ビューアーの構成 、navigatorContent、そして JFace Tree Viewer の使用方法についての詳細を学んでください。
- 「Common Navigator Tutorial 1: Hello World」を読んでください。
- EclipseCon が紹介している記事、「Common Navigator Framework for Platform/UI in 3.2」をお見逃しなく。
-
リソース更新リスナーの使用方法を学んでください。
- EclipseZone コミュニティーにアクセスして、EMF モデルのコンテンツにアクセスするもう 1 つの方法を説明している「Bridging EMF to the common navigator」を読んでください。
- 「Eclipse オススメ情報リスト」を読んでください。
- developerWorks ですべての Eclipse 関連記事を調べてください。
- Eclipse の初心者は、developerWorks の記事「Get started with Eclipse Platform」を読んでください。Eclipse の起源とアーキテクチャー、そしてプラグインで Eclipse を拡張する方法を学べます。
- IBM developerWorks の Eclipse project resources にアクセスして、Eclipse のスキルを磨いてください。
- ソフトウェア開発者を対象とした興味深いインタービューや討論については、developerWorks ポッドキャストをチェックしてください。
- Eclipse プラットフォームの紹介記事「Eclipse Platform 入門」を参照してください。
- developerWorks の Technical events and webcasts で最新情報を入手してください。
- 無料の developerWorks On demand demos で、IBM およびオープンン・ソースの技術と製品機能を調べて試してみてください。
- 世界中で近日中に予定されている IBM オープン・ソース開発者を対象とした会議、見本市、ウェブ放送やその他のイベントをチェックしてください。
- オープン・ソース技術を使用して開発し、IBM の製品と併用するときに役立つ広範囲のハウツー情報、ツール、およびプロジェクト・アップデートについては、developerWorks Open source ゾーンを参照してください。
製品や技術を入手するために
- IBM Eclipse technology downloads at IBM alphaWorks で Eclipse 技術の最新ダウンロードを調べてください。
- Eclipse Foundation から Eclipse Platform およびその他のプロジェクトをダウンロードしてください。
-
IBM 製品の評価版をダウンロードして、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を使ってみてください。
-
IBM ソフトウェアの試用版を使用して、次のオープン・ソース開発プロジェクトを革新してください。ダウンロード、あるいは DVD で入手できます。
議論するために
- Eclipse に関する質問を議論するための最初の場所として、Eclipse Platform newsgroups があります (このリンクをクリックすると、デフォルト Usenet ニュース・リーダー・アプリケーションが起動され、eclipse.platform が開きます)。
-
Eclipse newsgroups には Eclipse を利用し、拡張することに関心を持つ人達のために、さまざまなリソースが用意されています。
-
developerWorks blogs から developerWorks コミュニティーに加わってください。