チーム論理モデルのサポートを利用するためにモデル・プロバイダーが実行できることを以下にリストします。
以下のセクションでは、これらのポイントのそれぞれについて詳細に説明します。 org.eclipse.team.examples.filesystem プラグインには、これらの点のいくつかを示すサンプルが含まれています。 CVS リポジトリーのプロジェクトを確認して、本チュートリアルを読む際の参考にすることができます。 特記事項: 例にあるプラグインのソース・コードは、変更される場合があります。この例で使用されているコードに一致するコピーを入手するには、 3.2 バージョン・タグ (おそらく R3_2)、または 2006 年 6 月 28 日の日付タグを使用してプロジェクトを調べてください。
リソース・マッピング API は、論理モデル操作を省略して、意図的にシンプルにしています。クライアントは、このインターフェースを使用して論理モデルを表示したり、それについての重要な追加の知識を取得したりすることはできません。これの目的は、単に 1 つ以上のモデル要素をワークスペース・リソースにマップすることです。
API は、以下のクラスで構成されています。
Object getModelObject()
: マッピングの派生元 (または適応元) のモデル・オブジェクトです。
ResourceTraversal[]
getTraversals(ResourceMappingContext, IProgressMonitor)
: モデル・オブジェクトを構成するリソースをカバーしたリソース全探索です。
ResourceTraversal
には、一連のリソースと深さフラグが含まれています。このフラグは、全探索内のリソースが発信モデル・オブジェクトに関連付けられている深さを示すものです。リソース全探索は、クライアント (リポジトリー・プロバイダーなど) がその操作を可能な限り効率的に実行できる方法でモデルのコンテンツを記述するために、リソース・マッピングによってクライアントに提供されています。重要なメソッドは、以下のものです。
getResources()
getDepth()
ResourceMappingContext
および RemoteResourceMappingContext
の使用はこれよりもやや複雑であり、リソース・マッピング・コンテキストのセクションで説明されています。
リソース・マッピングでは、以下の 2 つのタイプのプラグインが重要です。ワークスペースのリソースを構成する、またはそこに保持されるモデルを提供するプラグインと、リソース上で操作を実行するプラグインです。前者は次のセクションで、後者は論理モデル統合のリポジトリー・ロードマップで説明されています。
コンテキスト・メニューに表示されたリソース固有のアクションを取得するためにモデル・オブジェクトを IResource
に適応させたプラグインは、オブジェクトのリソースへの適応方法の詳細な説明が役立つ場合に、ResourceMapping
に適応することができます。ただし、利点がない場合、そのようにする必要はありません。例えば、現在 IFile
に適応している Java コンパイル単位 (つまり、JDT ビューに表示される *.java ファイル) は、取得されるものがないため、ResourceMapping
に適応する必要はありません。ただし、Java パッケージは、パッケージがサブフォルダーではなく対応するフォルダーのファイルでのみ構成されていることを示すために、ResourceMapping
に適応する必要があります。
モデル要素をリソース・マッピングに適応させる際に優先される方法は、アダプター・ファクトリーを使用することです。以下に、アダプター・ファクトリーをプラグイン・マニフェストに提供する XML マークアップを示します。
<extension
point="org.eclipse.core.runtime.adapters">
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Book">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Library">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
...
</extension>
アダプター・ファクトリーの実装は、以下のようになります。
public class AdapterFactory implements IAdapterFactory {
public Object getAdapter(Object adaptableObject, Class adapterType) {
if((adaptableObject instanceof EObject) && adapterType == ResourceMapping.class) {
return new EObjectResourceMapping((EObject)adaptableObject);
}
return null;
}
public Class[] getAdapterList() {
return new Class[] {ResourceMapping.class};
}
}
モデル・オブジェクトは、IAdaptable
インターフェースを実装できます。そのようにする場合は、プラットフォーム・アダプター・マネージャーを利用する必要があります。これは、PlatformObject
をサブクラス化するか、以下のコード行を使用して実行します。
Platform.getAdapterManager().getAdapter(Object, Class)
上の方法をお勧めします。ただし、モデル・オブジェクトは IAdaptable インターフェースを実装し、要求された場合は明示的に ResourceMapping
のインスタンスを作成する getAdapter(Class)
実装を提供することができます。これは、より簡単な方法ですが、リソースへの適応についての明示的な知識がモデルに必要なため、望ましくありません。
場合によっては、論理モデルのプロバイダーは、どのコンテキストでもそのモデルを IResource
に適応させたくなかったり、他のコンテキストとは異なるように、オブジェクト・コントリビューションに対してオブジェクトを適応させたかったりする場合があります。ワークベンチ UI は、これを目的とした特別な中間アダプター API IContributorResourceAdapter
を提供します。オブジェクトがオブジェクト・コントリビューションとの関連で IResource
に適応される場合、ワークベンチは、リソースを IResource
に直接適用しようとする前に、まず IContributorResourceAdapter
に適用しようとします。このインターフェースの新規サブインターフェースである IContributorResourceAdapter2
が追加されました。これは、ResourceMapping
と同じ機能を提供します。唯一の違いは、モデル・プロバイダーが IContributorResourceAdapter
のファクトリーを登録する必要があることです。これは、ワークベンチが、コントリビュートされたアダプターが IContributorResourceAdapter2
のインスタンスでもあるかどうかを確認する instanceof 検査を行うためです。
Java パッケージの ResourceMapping
サブクラスの実装は、以下のようになります。
public class JavaPackageResourceMapping extends ResourceMapping {
IPackageFragment package;
...
public getModelObject() {
return package;
}
public ResourceTraversals[] getTraversals(
ResourceMappingContext context,
IProgressMonitor monitor) {
return new ResourceTraversal[] {
new ResourceTraversal(
new IResource[] { package.getCorrespondingResource() },
IResource.DEPTH_ONE, IResource.NONE)
}
}
}
これは比較的簡単なマッピングであるため、実装は複雑ではありません。もちろん、リソース・マッピングの実装の複雑さはモデルによって異なります。
リソース・マッピング API の利点の 1 つは、プラグインがリソース・マッピングに関して必要な操作 (CVS 更新、CVS コミット、CVS タグ、編集中装飾など) を実装できるようになることです。ただし、それまでに導入された API は、モデルのローカル状態のみを処理します。開発者間で共用されていた可能性のあるモデルを使用すると、モデルのリモート状態 (つまり、別のユーザーがリポジトリーにチェックインしているモデルの状態) が、ワークスペースの状態と異なることという場合が出てきます。 CVS 更新を実行した場合は、追加ファイルを組み込んだり、一部のファイルを除去したりする必要が出てくる場合でも、モデルのローカル状態をリモート状態と一致させたい場合があります。
これは、一部の論理モデルでは問題になりません。例えば、Java パッケージは、モデルのリモート状態に関係なく、深さ 1 となるコンテナーです。これにより、リポジトリー・プロバイダーは、コミット時に発信削除を組み込む必要があるか、または更新時に着信追加を組み込む必要があるかを容易に判別できます。ただし、一部の論理モデルを構成するリソースは、時間の経過と共に変更される場合があります。例えば、モデル要素を構成するリソースは、マニフェスト・ファイル (または、他の類似したメカニズム) のコンテンツに依存する場合があります。リソース・マッピングが適切な全探索を戻すようにするには、組み込む必要がある追加リソースがあるかどうかを確認するために、マニフェスト・ファイルのリモート・コンテンツ (ローカル・コンテンツと異なる場合) にアクセスする必要があります。これらの追加リソースはワークスペースに存在しない場合がありますが、リポジトリー・プロバイダーは、選択したアクションが実行された際に、それらが確実に実行されるようにする方法を認識しています。
これらのより複雑なモデルをサポートするために、RemoteResourceMappingContext
を ResourceMapping#getTraversals
メソッドに渡すことができます。コンテキストが提供されると、マッピングはそれを使用して、すべての必要なリソースが全探索に含まれるようにすることができます。コンテキストが提供されない場合、マッピングはローカル状態のみが重要であると想定します。
モデルを構成するリソースが時間の経過と共に変更され、モデルを構成するそれらのリソース (のみ) を含むことが保証されている単純な全探索ではモデルとリソースの関係が説明できない場合にのみ、ResourceMapping
は、getTraversals
メソッドに提供されたコンテキストを心配する必要があります。例えば、Java パッケージのリソースは時間の経過と共に変更される場合がありますが、パッケージは深さ 1 のフォルダーとして説明することができるため、Java パッケージのリソース・マッピングがリソース・マッピング・コンテキストを使用する必要はありません。
より複雑な例として、複数のイメージを含む HTML ファイルを考えてみます。
HTML ファイルからのすべてのイメージ参照が、そのファイルのモデルの一部であるとします。リポジトリーから HTML ファイルのローカル・コンテンツを更新すると、ユーザーは新規イメージが組み込まれたと予想します。
HTML ファイルのモデルの ResourceMapping
の getTraversals
メソッドは、以下のようになります。
public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Look for any additional resources on the server
RemoteResourceMappingContext remoteContext = (RemoteResourceMappingContext)context;
IFile file = htmlFile.getFile();
if (remoteContext.hasRemoteChange(file, monitor)) {
IStorage storage = remoteContext.fetchRemoteContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
if (remoteContext.isThreeWay() && remoteContext.hasLocalChange(file, monitor)) {
IStorage storage = remoteContext.fetchBaseContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
}
return new ResourceTraversal[] {
new ResourceTraversal(resources, IResource.DEPTH_ZERO, IResource.NONE)};
}
}
モデルに 2 つのリソースのセットが含まれていることに注意してください。1 つは、ワークスペースの HTML ファイルのローカル・コンテンツから派生したもので、もう 1 つはリモート・ファイルおよび基本ファイルのコンテンツから取得したものです。これらの 2 つのセットのいずれかに、ワークスペースに存在しないリソースがある場合があります。例えば、ローカル HTML ファイルに、ワークスペースに存在しないイメージへの相対リンクが含まれている場合があります。リモートに存在する場合でも取り出せるように、このリソースが含まれている必要があります。リモート・ファイルについては、新規リモート・コンテンツがダウンロードされた際に取り出す必要がある追加イメージを参照する新規コピーが含まれている場合があります。
モデル・プロバイダーは、関係するリソース・マッピングをグループ化する手段です。 ModelProvider クラスへのリンク先を示します。このクラスは、3 つの主な目的を持っています。
IResourceMappingMerger
は、モデル・プロバイダーを適応することで取得されます。
modelProvider 拡張定義の例を以下に示します。
<extension
id="modelProvider"
name="Library Example"
point="org.eclipse.core.resources.modelProviders">
<modelProvider
class="org.eclipse.team.examples.library.adapt.LibraryModelProvider"
name="Library Example"/>
<extends-model id="org.eclipse.core.resources.modelProvider"/>
<enablement> <test property="org.eclipse.core.resources.projectNature" value="org.eclipse.team.examples.library.view.nature" />
</enablement>
</extension>
LibraryModelProvider
は、ModelProvider
のサブクラスです。ライブラリー・モデルがそのモデルを保持している各リソースと一致させるために、使用可能化の規則が使用されています。上記の例の場合、モデル・プロバイダーは、ライブラリー・ネーチャーを持つプロジェクトのすべてのリソースと一致します。
いったんモデル・プロバイダーが定義されたら、ResourceMapping#getModelProviderId()
メソッドは、モデル・プロバイダーの ID を戻すためにオーバーライドされる必要があります。
public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}
プロバイダーの使用可能化の規則に一致するこれらのリソース同士のマッピングの正しい逆マッピングを取得するには、getMapping
メソッドの一方または両方を上書きする必要があります。上書きする必要があるメソッドは、ご使用のモデルに複数のリソースを含む要素が含まれているかどうかによって異なります。ご使用のモデル要素が単一リソースにマップされる場合は、単一の IResource
引数を受け入れるメソッドを上書きできます。それ以外の場合は、リソースの配列を受け入れるメソッドを上書きする必要があります。以下に、単一リソースを使用する例を示します。
以下のメソッドの例では、ライブラリー・モデル・ファイルを適切なリソース・マッピング内にラップしています。また、モデル・プロバイダーにとって重要なファイルを含むフォルダーもラップしています。
public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Return a resource mapping on the file
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Create a deep resource mapping on the container
return new LibraryContainerResourceMapping(resource);
}
// The resource is not of interest to this model provider
return null;
}
}
クライアントは次にモデル・プロバイダーにアクセスして、モデル・プロバイダーが操作が行われようとしているリソースに注意するかどうかを判別できます。次のセクションでは、選択したリソースのセットまたはモデル要素に対してチーム操作が実行される場合に、操作が行われるリソース・マッピングの完全セットを判別するためにモデル・プロバイダー API を使用するチーム操作に対して提供される API について説明します。
リソースで実行される操作は、ユーザーが発生し得る副次作用を認識できるように、最初に検証される必要があります。リソース変更を検証する手順を以下に示します。
IResourceChangeDescriptionFactory
を使用して、変更の説明を作成します。ファクトリーは、操作が実行されたときの結果のリソース・デルタをミラーリングする IResourceDelta
を作成します。
ResourceChangeValidator
を使用して、変更を検証します。バリデーターは、影響を受けるリソースに対するインタレストを登録しているすべてのモデル・プロバイダーを調べます。結果は、開始元のモデルの ID およびそのモデルでの操作で発生し得る副次作用の説明が含まれる 1 つ以上の状況です。
ヘッドレス・マージを実行しようとしている場合、チーム・プロバイダーは以下のことを行います。
チーム操作との関連でモデル要素を表示するには、共通ナビゲーター・フレームワークを使用します。
上記の手順を実行すると、モデルがチーム操作で使用されるダイアログに表示されます。マージ・プレビューに統合するには、以下の追加の手順が必要です。
ファイル・ヒストリーおよびモデル要素ヒストリーの領域では、以下の点が改善されています。
リモート・ブラウズをサポートするために以下のものが提供されています。
チーム・プロバイダーは、単純なデコレーターをリソース・マッピングの作業に変換することでモデル要素を装飾できます。これは、オブジェクト・コントリビューションがリソース・マッピングの作業に変換されるのと同様です。ただし、論理モデル要素の装飾には、問題となる側面が 1 つあります。モデル要素にリソースとの 1 対 1 のマッピングがない場合、モデル要素は、基本となるリソースが変更された場合にラベルの更新を受信しないことがあります。
この問題に対処するため、チーム装飾に影響を与え得る状態変更にモデル・プロバイダーがアクセスできるように ITeamStateProvider
が導入されました。また、モデル・ビューは SynchronizationStateTester
を使用して、論理モデル要素のラベルの更新が必要になる時期を判別できます。この API は、リソースのチーム状態が変更された時期、および IDecorationContext
の一部としてチーム・デコレーターに渡すことができる時期を判別する際、ITeamStateProvider
インターフェースに依存します。