模型提供程序可以通过执行下列任务来利用小组逻辑模型支持:
下列各节更详细地描述了这些任务。org.eclipse.team.examples.filesystem 插件提供的示例演示了如何完成这些任务中的几个任务。在阅读本教程时,您可以从 CVS 资源库中检出该项目并将其用作参考。免责声明:示例插件中的源代码可能会随着时间的推移而更改。要获取与本示例中使用的源代码相匹配的副本,可以使用 3.2 版本标记(很可能是 R3_2)或者日期标记 June 28, 2006 来检出该项目。
由于特意省略了逻辑模型处理,所以资源映射 API 非常简单。客户机无法使用此接口来显示逻辑模型或者获取其他任何有关逻辑模型的信息。资源映射 API 的意图仅仅是将一个或多个模型元素映射到工作空间资源。
此 API 包含下列类:
Object getModelObject():用于派生(或改编)映射的模型对象。ResourceTraversal[] getTraversals(ResourceMappingContext, IProgressMonitor):资源遍历,此遍历涵盖模型对象中的所有资源。ResourceTraversal
包含一组资源以及深度标志,该标志指示了该遍历中与起始模型对象相关联的资源的深度。资源映射将资源遍历提供给客户机,以便以适当的方式来描述模型内容,从而使客户机(例如资源库提供程序)能够以尽可能高效的方法来执行操作。相关的方法包括:getResources()getDepth()ResourceMappingContext 和 RemoteResourceMappingContext的用法略为复杂,将在资源映射上下文一节中描述。在资源映射中,有两类插件特别重要。第一类插件提供由工作空间资源组成的模型或者保存在工作空间资源中的模型,第二类插件对资源执行操作。下一节将对第一类插件进行说明,逻辑模型集成的资源库路线图对第二类插件作了阐述。
现在,如果插件已使其模型对象适应于 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 接口并提供 getAdapter(Class)
实现,并且让该实现在接收到请求时显式地创建并返回 ResourceMapping
实例。此方法更为直接,但最不可取,这是因为模型必须明确了解对资源的适应情况。
在某些情况下,逻辑模型的提供程序可能不想让它们的模型适应于每个上下文中的
IResource,或者在对象添加项上下文与其他上下文中要以不同的方式来使对象适应。为实现此目的,工作台 UI
提供了特殊的中间适配器 API,即 IContributorResourceAdapter。如果正在对象添加项的上下文中使对象适应于
IResource,工作台就会先尝试使资源适应于
IContributorResourceAdapter,然后再尝试直接适应于
IResource。已添加了此接口的一个新子接口 IContributorResourceAdapter2,这个子接口为
ResourceMapping 提供了相同的功能。唯一的差别是,模型提供程序应该为
IContributorResourceAdapter 注册一个工厂,这是因为工作台将执行
instanceof 检查以确定添加的适配器是否也是
IContributorResourceAdapter2 的实例。
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 的其中一个优点是,它允许插件在资源映射方面实现任何所需的操作(例如,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)};
}
}
注意,在模型中包括两组资源:一组是根据工作空间中 HTML 文件的本地内容派生的资源,另一组是从远程文件和基本文件的内容中获取的资源。在这两组资源中,可能有一些资源在工作空间中不存在。例如,本地 HTML 文件包含的相对链接所指向的图像在工作空间中可能不存在。应该包括此资源,以便可以对其进行访存,就象它存在于远程位置一样。对于远程文件来说,它可能包含引用了其他下载新远程内容时应该访存的图像的新副本。
模型提供程序是一种将相关资源映射分组到一起的方法。这里是指向 ModelProvider 类的链接。这个类有三个主要用途:
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()
方法以返回该模型提供程序的标识。
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 来确定在对一组所选资源或模型元素执行小组操作时要处理的全部资源映射的小组操作来说,它们可以使用这些 API。
应该先验证对资源执行的操作,以确保用户了解任何潜在的副作用。以下是验证资源更改时必须完成的步骤。
IResourceChangeDescriptionFactory
来构建对更改的描述。此工厂将生成 IResourceDelta,后者反映了执行操作后的资源变化情况。ResourceChangeValidator 来验证更改。验证器将查询所有已注册的关注受影响资源的模型提供程序。结果将是一个或多个状态,这些状态包含起始模型的标识以及对模型执行的操作的潜在副作用描述。当小组提供程序尝试执行无外设合并时,将执行下列操作:
公共导航器框架允许在小组操作的上下文中显示模型元素。
上述步骤将允许模型出现在小组操作使用的对话框中。要集成到合并预览中,需要执行其他步骤。
在文件历史记录和模型元素历史记录领域,进行了下列改进:
提供了下列功能来支持远程浏览:
小组提供程序可以对模型元素进行修饰,其方法是将模型元素的轻量级修饰符转换为适用于资源映射,并且转换方式与将对象添加项转换为资源映射的方式相同。但是,逻辑模型元素修饰的一个方面存在问题。如果模型元素与资源之间不存在一对一的映射关系,则当底层资源改变时,该模型元素可能无法接收到标签更新。
为了解决此问题,引入了 ITeamStateProvider,以使模型提供程序能够访问可能会影响小组修饰的状态更改。此外,模型视图还可以使用 SynchronizationStateTester 来确定何时需要更新逻辑模型元素的标签。此 API 依靠
ITeamStateProvider 接口来确定资源的小组状态何时已更改,并且可以作为 IDecorationContext 的组成部分传递给小组修饰符。