The resources plug-in includes an event mechanism for notifying interested parties of changes to resources. If you need to keep track of changes to the resource tree while your plug-in is running, you can register an IResourceChangeListener with the workspace. Your listener will be notified of the changes via an IResourceChangeEvent object, which describes the changes.
To track changes to resources, you must register a resource change listener with the workspace.
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener( listener, IResourceChangeEvent.POST_CHANGE);
Your listener will be notified after modifications to the workspace resources have been made. Resource API methods that modify resources trigger these events as part of their documented behavior. The method comment for a resource API method explicitly states whether or not it triggers a resource change event. For example, the following is included in the IFile.setContents() comment:
This method changes resources; these changes will be reported in a subsequent resource change event, including an indication that this file's content have been changed.
Methods that create, delete, or change a resource typically trigger these events. Methods that read, but do not write, resources typically do not trigger these events.
If you need to modify a number of resources at once, you can batch your resource change API calls so that only one resource change event will be sent for the entire set of changes. IWorkspace.run(runnable, monitor) is used to batch the operations. Resource change events are only sent to registered listeners when the specified runnable is completed. Any additional (nested) Runnables created in the runnable will be considered part of the parent batch operation and the resource changes made in those runnables will appear in the parent's resource change notification.
You should batch your changes whenever possible to limit the overhead of broadcasting many granular changes. Failure to use batching will likely flood the system with resource change notifications and auto-builds.
The resource change event describes the specifics of the change (or set of changes) that have occurred in the workspace. The event contains a resource delta that describes the net effect of the changes. For example, if you add a resource and later delete it during one batch of changes, the resource will not appear in the delta.
The resource delta is structured as a tree rooted at the workspace root. The resource delta tree describes these types of changes:
To traverse a resource delta tree, you may implement the IResourceDeltaVisitor interface or traverse the tree explicitly using IResource.getAffectedChildren. Resource delta visitors implement a visit method that is called by the resource delta as it enumerates each change in the tree.
Note: Changes made to resource session properties or resource persistent properties are not identified in the resource delta.
Resource change events are sent whenever a change (or batched set of changes) is made to the workspace. In addition, resource change events are sent for certain specific workspace operations. The table below summarizes the types of resource change events and when they are reported.
Event type |
Description |
---|---|
PRE_CLOSE |
Notifies listeners that a project is about to be closed. This event can be used to extract and save necessary information from the in-memory representation (e.g., session properties) of a project before it is closed. (When a project is closed, the in-memory representation is disposed). The workspace is locked (no resources can be updated) during this event. The event contains the project that is being closed. |
PRE_DELETE |
Notifies listeners that a project is about to deleted. This event can be used to perform clean-up operations, such as removing any saved state that is related to the project from your plug-in's directory. The workspace is locked (no resources can be updated) during this event. The event contains the project that is being deleted. |
PRE_AUTOBUILD |
Notifies listeners before any auto-building occurs. This event is broadcast when the platform detects an auto-build needs to occur, regardless of whether auto-building is actually enabled. The workspace is not locked during this event (resources can be updated). The event contains a resource delta describing the changes that have occurred since the last POST_CHANGE event was reported. |
POST_AUTOBUILD |
Notifies listeners after any auto-building has occurred. This event is broadcast after the platform would have performed an auto-build, regardless of whether auto-building is actually enabled. The workspace is not locked during this event (resources can be updated). The event contains a resource delta describing the changes that have occurred since the last POST_CHANGE event was reported. |
POST_CHANGE |
Describes a set of changes that have occurred to the workspace since the last POST_CHANGE event was reported. Triggered after a resource change API is used individually or in a batched set of workspace changes. Also triggered after any PRE_AUTOBUILD or POST_AUTOBUILD notification is complete. The event contains a resource delta describing the net changes since the last POST_CHANGE event. The workspace is locked (no resources can be updated) during this event. |
The following example implements a console-based resource change listener. A resource change listener is registered for specific types of events and information about these events is printed to the console:
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_AUTO_BUILD | IResourceChangeEvent.POST_AUTO_BUILD | IResourceChangeEvent.POST_CHANGE);
The listener checks for each event type and reports information about the resource that was changed and the kinds of changes that occurred. Although this example is designed to show a general listener that handles all the types of resource events, a typical listener would register for just one type of event.
The implementation for POST_CHANGE uses another class that can be used to visit the changes in the resource delta.
import org.eclipse.resources.*; import org.eclipse.runtime.*; public class MyResourceChangeReporter implements IResourceChangeListener { public void resourceChanged(IResourceChangeEvent event) { IResource res = event.getResource(); switch (event.getType()) { case IResourceChangeEvent.PRE_CLOSE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to close."); break; case IResourceChangeEvent.PRE_DELETE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to be deleted."); break; case IResourceChangeEvent.POST_CHANGE: System.out.println("Resources have changed."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.PRE_AUTO_BUILD: System.out.println("Auto build about to run."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.POST_AUTO_BUILD: System.out.println("Auto build complete."); event.getDelta().accept(new DeltaPrinter()); break; } } }
The DeltaPrinter class implements the IResourceDeltaVisitor interface to interrogate the resource delta. The visit() method is called for each resource change in the resource delta. The visitor uses a return value to indicate whether deltas for child resources should be visited.
class DeltaPrinter implements IResourceDeltaVisitor { public boolean visit(IResourceDelta delta) { IResource res = delta.getResource(); switch (delta.getKind()) { case IResourceDelta.ADDED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was added."); break; case IResourceDelta.REMOVED" System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was removed."); break; case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" has changed."); break; } return true; // visit the children } }
Further information can be obtained from the supplied resource delta. The following snippet shows how the IResourceDelta.CHANGED case could be implemented to further describe the resource changes.
... case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(delta.getFullPath()); System.out.println(" has changed."); int flags = delta.getFlags(); if ((flags & IResourceDelta.CONTENT) != 0) { System.out.println("--> Content Change"); } if ((flags & IResourceDelta.REPLACED) != 0) { System.out.println("--> Content Replaced"); } if ((flags & IResourceDelta.MARKERS) != 0) { System.out.println("--> Marker Change"); IMarkerDelta[] markers = delta.getMarkerDeltas(); // if interested in markers, check these deltas } break; ...
For a complete description of resource deltas, visitors, and marker deltas, consult the API specification for IResourceDelta, IResourceDeltaVisitor, and IMarkerDelta.
Note: Resource change listeners are useful for tracking changes that occur to resources while your plug-in is activated. If your plug-in registers a resource change listener during its startup code, it's possible that many resource change events have been triggered before the activation of your plug-in. The resource delta contained in the first resource change event received by your plug-in will not contain all of the changes made since your plug-in was last activated. If you need to track changes made between activations of your plug-in, you should use the support provided for workspace saving. This is described in Workspace save participation.