批处理资源更改

当需要修改工作空间中的资源时,一定要注意其它插件可能正在使用相同的资源。资源 API 提供了可靠的机制来保证让插件通知工作空间中的更改并且确保多个插件不会同时修改同一资源。在可能的情况下,就应该在工作空间可运行程序内的工作单元中批处理插件对工作空间进行的修改。这些可运行程序会帮助减少由更改产生的更改通知的数量。它们还允许您声明要修改工作空间的哪一部分,以便可以禁止其它插件更改该工作空间的同一部分。

IWorkspaceRunnable 的协议相当简单。工作空间可运行程序看起来就象长时间运行的操作或平台作业。实际工作是在 run 方法中完成的,并将进度报告给所提供的 IProgressMonitor。用来处理工作空间的代码是在 run 方法中执行的。

IWorkspaceRunnable myRunnable = 
        new IWorkspaceRunnable() {
		public void run(IProgressMonitor monitor) throws CoreException {
			//do the actual work in here
			...
		}
}

当可以运行代码时,插件会告诉工作空间代表它运行代码。这样,工作空间就可以生成任何必需的更改事件,并且可以确保没有两个插件在同时修改同一资源。(即使插件未使用后台作业和并行框架来修改工作空间,其它插件也可能正在这样做。)

调度规则和锁定

IWorkspace 协议用来运行工作空间可运行程序。首选技术是使用 run 方法的长格式,该方法提供调度规则并指定如何广播资源更改事件。

当运行工作空间可运行程序时指定调度规则允许工作空间确定资源更改是否将与其它线程中发生的工作空间更改发生冲突。(有关调度规则和 ISchedulingRule 协议的概述,请参阅调度规则。)幸好,IResource 协议包括 ISchedulingRule 的协议,这意味着资源可以经常用作它本身的调度规则。

有点迷惑了吗?代码可以帮助阐明这一点。假定插件正准备修改特定项目中的资源束。它可以将该项目本身用作完成更改的调度规则。以下片段运行我们先前创建的工作空间可运行程序:

    IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.run(myRunnable, myProject, IWorkspace.AVOID_UPDATE, null);

可运行程序被传递至工作空间,接着是代码正在处理的项目。这告知工作空间可运行程序中的所有更改都被限制到 myProject。在此可运行程序完成之前,将阻塞其它线程发出的更改 myProject 的任何请求。类似地,如果其它某些线程已经在修改 myProject,则将阻塞此调用。通过指定可运行程序将修改资源树的哪一部分,就可允许其它线程继续修改工作空间的其它部分。一定要确保资源规则与在可运行程序内完成的工作相匹配。在调度规则的作用域之外访问资源的任何尝试都将产生异常。

run 方法的第三个参数指定是否任何定期资源更改事件都应该在此调用的作用域期间广播。使用 IWorkspace.AVOID_UPDATE 则告诉平台在可运行程序正在运行时禁止任何资源更改事件,并在更改结束时广播一个事件。在此调用期间,在可运行程序中创建的任何其它可运行程序将被看作是父代批处理操作的一部分。而在那些可运行程序中所作的资源更改将出现在父代的资源更改通知中。

资源规则工厂

在上面的示例中,假定可运行程序内的代码只修改特定项目中的资源。这使得指定可运行程序的调度规则变得非常容易。实际上,找出工作空间的哪些部分受到特定更改的影响可能更困难。例如,将资源从一个项目移至另一个项目将同时影响这两个项目。IResourceRuleFactory 可以用来帮助估计某些种类的资源更改的适当资源规则。可以从工作空间本身获取资源规则工厂。

    IWorkspace workspace = ResourcesPlugin.getWorkspace();
IResourceRuleFactory ruleFactory = workspace.getRuleFactory();

该工厂可以提供适用于许多种类的操作的规则。如果可运行程序正在将资源从一个位置移至另一个位置,则它可以包含适用于此操作的规则:

ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
workspace.run(myRunnable, movingRule, IWorkspace.AVOID_UPDATE, null);

有关可用规则的列表,请参阅 IResourceRuleFactory 的 Javadoc。资源插件本身使用这些规则来实现大多数资源操作。浏览引用这些规则方法的代码将帮助说明实际上是如何使用它们的。

可以使用 MultiRule 来组合多条规则。

ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
ISchedulingRule modifyRule = ruleFactory.modifyResource(destinationResource);
workspace.run(myRunnable, MultiRule.combine(movingRule, modifyRule), IWorkspace.AVOID_UPDATE, null);

忽略规则

还提供了 IWorkspace 中的 run 方法的简短格式。保留它是为了实现向后兼容性。简短格式不包括规则或更新标志。

workspace.run(myRunnable, null);

与调用以下内容同样有效

workspace.run(myRunnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, null);

指定工作空间根作为调度规则将锁定整个工作空间,直到可运行程序完成为止。这是执行工作空间更新的最稳当方法,但是它不太支持其它重视并行的插件。