blob: ba104979312a2c72325333fcfa3d9be911ff9df3 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML>
<HEAD>
<meta name="copyright" content="Copyright (c) IBM Corporation and others 2000, 2005. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." >
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
<LINK REL="STYLESHEET" HREF="../book.css" CHARSET="ISO-8859-1" TYPE="text/css">
<TITLE>
Batching resource changes
</TITLE>
<link rel="stylesheet" type="text/css" HREF="../book.css">
</HEAD>
<BODY BGCOLOR="#ffffff">
<H3>
Batching resource changes</H3>
<p>When you need to modify resources in the workspace, it is important to keep in mind that other plug-ins might be
working with the same resources. The resources API provides robust mechanisms for keeping plug-ins informed about
changes in the workspace, and for making sure that multiple plug-ins do not modify the same resource at the same time.
Where possible, your plug-in's modifications to the workspace should be batched in units of work inside a <b>workspace runnable</b>.
These runnables help to reduce the amount of change notifications generated by changes. They also allow you to declare
which part of the workspace is to be modified, so that other plug-ins can be locked out of changing the same part of the
workspace.
</p>
<p>The protocol for <b><a href="../reference/api/org/eclipse/core/resources/IWorkspaceRunnable.html">IWorkspaceRunnable</a></b>
is fairly simple. A workspace runnable looks just like a long-running operation or platform job. The actual work is done inside
a <b>run</b> method, with progress reported to the supplied
<b><a href="../reference/api/org/eclipse/core/runtime/IProgressMonitor.html">IProgressMonitor</a></b>. Code that
manipulates the workspace is performed inside the <b>run</b> method.
</p>
<pre>IWorkspaceRunnable myRunnable =
new IWorkspaceRunnable() {
<b>public void run(IProgressMonitor monitor) throws CoreException {</b>
//do the actual work in here
...
}
}
</pre>
<p>When it is time to the run the code, your plug-in tells the workspace to run the code on its behalf. This way, the
workspace can generate any necessary change events and ensure that no two plug-ins are modifying the same resource
at the same time. (Even if your plug-in is not using background jobs and the concurrency framework to modify the
workspace, other plug-ins may be doing so.)
</p>
<h4>Scheduling rules and locking</h4>
<p><b><a href="../reference/api/org/eclipse/core/resources/IWorkspace.html">IWorkspace</a></b> protocol is used to
run a workspace runnable. The preferred technique is using the long form of the <b>run</b> method which supplies
a scheduling rule and specifies how resource change events are broadcast.
</p>
<p>Specifying a scheduling rule when running a workspace runnable allows the workspace to determine whether
the resource changes will conflict with workspace changes happening in other threads. (See
<a href="runtime_jobs_rules.htm">Scheduling rules</a> for an overview of scheduling rules and
<b><a href="../reference/api/org/eclipse/core/runtime/jobs/ISchedulingRule.html">ISchedulingRule</a></b> protocol.)
Fortunately, <b><a href="../reference/api/org/eclipse/core/resources/IResource.html">IResource</a></b>
protocol includes the protocol for <b><a href="../reference/api/org/eclipse/core/runtime/jobs/ISchedulingRule.html">ISchedulingRule</a></b>,
which means that a resource can often be used as a scheduling rule for itself.
</p>
<p>Confused? Code can help to clarify this point. Suppose your plug-in is getting ready to modify a bunch of
resources in a particular project. It can use the project itself as the scheduling rule for making the changes.
The following snippet runs the workspace runnable that we created earlier:
</p>
<pre>IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.run(myRunnable, <b>myProject</b>, <b>IWorkspace.AVOID_UPDATE</b>, null);
</pre>
<p>The runnable is passed to the workspace, followed by the project that the
code is manipulating. This tells the workspace that all of the changes in the
runnable are confined to <tt>myProject</tt>. Any requests by other threads
to change <tt>myProject</tt> will be blocked until this runnable completes.
Likewise, this call will block if some other thread is already modifying
<tt>myProject</tt>. By specifying which part of the resource tree will be
modified by the runnable, you are allowing other threads to continue modifying
other portions of the workspace. It is important to be sure that your resource rule
matches the work being done inside the runnable. When a non-null scheduling
rule is used, any attempt to access a resource outside the scope of the scheduling
rule will trigger an exception.
</p>
<p>
There are two special scheduling rules that are important to consider. First,
if you use an instance of <tt>IWorkspaceRoot</tt> as the scheduling rule,
it means your thread is blocking access to <b>all</b> resources in the tree.
While a thread holds the root rule, no other thread is allowed to modify the
workspace. Conversely, a rule of <tt>null</tt> indicates that the thread
will block access to <b>no</b> resources in the tree. While a thread with the
null rule is free to modify the workspace itself, other threads will not be prevented
from performing their own modifications. The <tt>IWorkspaceRoot</tt> and
<tt>null</tt> scheduling rules occupy opposite ends of the concurrency spectrum.
With <tt>IWorkspaceRoot</tt> there is no concurrency
and only one thread is modifying the workspace at a time. With a <tt>null</tt> rule,
there is maximum concurrency as all threads can modify the workspace concurrently.
</p>
<p>The third parameter to the <b>run</b> method specifies whether any periodic resource change events should
be broadcast during the scope of this call. Using <tt>IWorkspace.AVOID_UPDATE</tt> tells the platform to suppress any
resource change events while the runnable is running and to broadcast one event at the end of the changes.
During this call, any other runnables created in the runnable will be considered part of the parent batch
operation. Resource changes made in those runnables will appear in the parent's resource change notification.
</p>
<h4>Resource rule factory</h4>
<p>In the example above, we assumed that the code inside our runnable only modified resources in a particular project.
This made it very easy to specify a scheduling rule for the runnable. In practice, it can be more difficult
to compute what parts of the workspace are affected by a particular change. For example, moving a resource from one
project to another affects both projects. <b><a href="../reference/api/org/eclipse/core/resources/IResourceRuleFactory.html">IResourceRuleFactory</a></b>
can be used to help compute an appropriate resource rule for certain kinds of resource changes. You can get
a resource rule factory from the workspace itself.
</p>
<pre>IWorkspace workspace = ResourcesPlugin.getWorkspace();
IResourceRuleFactory ruleFactory = <b>workspace.getRuleFactory()</b>;
</pre>
<p>The factory can supply rules appropriate for many kinds of operations. If your runnable is moving a resource
from one location to another, it can obtain a rule appropriate for this operation:
</p>
<pre>ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
workspace.run(myRunnable, <b>movingRule</b>, IWorkspace.AVOID_UPDATE, null);
</pre>
<p>See the javadoc for <b><a href="../reference/api/org/eclipse/core/resources/IResourceRuleFactory.html">IResourceRuleFactory</a></b>
for the list of available rules. The resources plug-in uses these rules itself to implement most resource operations.
Browsing the code that references these rule methods will help demonstrate how they are used in practice.
</p>
<p>Multiple rules can be combined using
<b><a href="../reference/api/org/eclipse/core/runtime/jobs/MultiRule.html">MultiRule</a></b>.
</p>
<pre>ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
ISchedulingRule modifyRule = ruleFactory.modifyResource(destinationResource);
workspace.run(myRunnable, <b>MultiRule.combine(movingRule, modifyRule)</b>, IWorkspace.AVOID_UPDATE, null);
</pre>
<h4>Ignoring the rules</h4>
<p>The short form of the <b>run</b> method in
<b><a href="../reference/api/org/eclipse/core/resources/IWorkspace.html">IWorkspace</a></b>
is also available. It is retained for backward compatibility. The short form does not include a rule or an update
flag.
</p>
<pre>workspace.run(myRunnable, null);
</pre>
<p>is effectively the same as calling
</p>
<pre>workspace.run(myRunnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, null);
</pre>
<p>Specifying the workspace root as the scheduling rule will put a lock on the entire workspace until the runnable
is finished. This is the most conservative way to perform a workspace update, but it is not very friendly to
other concurrency-minded plug-ins.
</p>
</BODY>
</HTML>