## Synchronization Support

New in Eclipse 3.0 are APIs for managing and displaying synchronization state between workspace resources and resources in another location. We refer to a resource outside of the workspace as a variant. Synchronizing is the act of displaying the changes between resources in different locations and optionally allowing the user to affect the synchronization state by performing an action. The synchronize APIs are orthogonal to the RepositoryProvider APIs and can be used without a repository provider. The purpose of the synchronization API is to ease the task of implementing different ways of presenting the synchronization state of resources. As such, the API requires a means to query the synchronization state of resources but does not require a means to affect the state. The means of affecting the state is left to the implementer (although the UI does provide hooks for adding provider specific menu items to menus).

### Terminology

Before the synchronization API is described, it is helpful to present some of the terminology and concepts that apply when discussing workspace synchronization.

> Resource Variant: A local resource that is mapped to a resource that exists at another location can be referred to as a variant of that resource. That is, the resources are usually very similar but may differ slightly (either due to modifications to the local resource or changes made the remote copy by other users). We take a local workspace centric view of this, referring to the local copy as the resource and any remote copy as resource variants.

> Synchronize: We refer to synchronize as the action of displaying to the user the differences between resource variants. Synchronizing doesn't affect the state of the variants, but instead provides a view to help the user understand the differences between different sets of variants. It is common however to allow users to affect the states of the variants (e.g. allowing to check-in, or revert) while synchronizing.

> Two-way vs. Three-way Synchronization: There are two basic types of synchronization state determination: two-way and three-way. A two-way comparison only considers the local resource and a single resource variant, referred to as the remote resource variant. This type of comparison can only show the differences between the two resources but cannot offer hints as to how the changes interrelate. Most code repository systems support a three-way comparison for synchronization state determination. This type of comparison involves the local resource, a remote resource variant and a base resource variant. The base resource variant represents a common ancestor for the local and remote resources. This allows for more sophisticated synchronization states that indicate the direction of the change.

> Table 1: The synchronization states

> Two-Way | Three-Way
> Changed Deleted Added | Outgoing Change Incoming Change Outgoing Deletion Incoming Deletion Outgoing Addition Incoming Addition Conflicting Change Conflicting Deletion Conflicting Addition

### The Basics - SyncInfo

The classes in the org.eclipse.team.core.synchronize are used to describe the synchronization state. The most important class is SyncInfo because it is the class that actually defines the synchronization state. It can be used as follows:

    SyncInfo info = getSyncInfo(resource); // this is a simulated method of obtaining the sync info for a resource
    int changekind = info.getKind();
    if(info.getResourceComparator().isThreeWay()) {
      if((changeKind & SyncInfo.DIRECTION_MASK) == SyncInfo.INCOMING) {
        // do something
      }
    } else if(changeKind == SyncInfo.CHANGE) {
        // do something else
    }

The SyncInfo class provides both the two-way and three-way comparison algorithms, a client must provide the resources and a class that can compare the resources (IResourceVariantComparator). Here is an example variant comparator:

    public class TimestampVariantComparator implements IResourceVariantComparator {
      protected boolean compare(IResourceVariant e1, IResourceVariant e2) {
        if(e1.isContainer()) {
          if(e2.isContainer()) {
            return true;
          }
          return false;
        }
        if(e1 instanceof MyResourceVariant && e2 instanceof MyResourceVariant) {
          MyResourceVariant myE1 = (MyResourceVariant)e1;
          MyResourceVariant myE2 = (MyResourceVariant)e2;
          return myE1.getTimestamp().equals(myE2.getTimestamp());
        }
        return false;
      }
      protected boolean compare(IResource e1, IResourceVariant e2) {

      }
      public boolean isThreeWay() {
        return true;
      }
    }

    SyncInfo info = new SyncInfo(resource, variant1, variant2, new TimestampComparator());
    info.init(); // calculate the sync info

This package also contains collections specifically designed to contain SyncInfo and filters that can be applied to SyncInfo instances.

### Managing the synchronization state

As we have seen in the examples above, SyncInfo and IResourceVariantComparator classes provide access to the synchronization state of resources. But what we haven't seen yet is how the state is managed. A Subscriber provides access to the synchronization state between the resources in the local workspace and a set of resource variants for these resources using either a two-way or three-way comparison, depending on the nature of the subscriber. A subscriber provides the following capabilities:

- local workspace traversal: a subscriber supports the traversal of the local workspace resources that are supervised by the subscriber. As such, the subscriber has a set of root resources that define the workspace subtrees under the subscriber's control, as well as a members method that returns the supervised members of a workspace resource. This traversal differs from the usual workspace resource traversal in that the resources being traversed may include resources that do not exist locally, either because they have been deleted by the user locally or created by a 3rd party.
- resource synchronization state determination: For supervised resources, the subscriber provides access to the synchronization state of the resource, including access to the variants of the resource. For each supervised resource, the subscriber provides a SyncInfo object that contains the synchronization state and the variants used to determine the state.The subscriber also provides an IResourceVariantComparator which determines whether two-way or three-way comparison is to be used and provides the logic used by the SyncInfo to comparing resource variants when determining the synchronization state.
- refresh of synchronization state and change notification: Clients can react to changes that happen to local resources by listening to the Core resource deltas. When a local resource is changed, the synchronization state of the resource can then be re-obtained from the subscriber. However, clients must explicitly query the server to know if there are changes to the resource variants. For subscribers, this process is broken up into two parts. A client can explicitly refresh a subscriber. In response the subscriber will obtain the latest state of the resource variants from the remote location and fire synchronization state change events for any resource variants that have changed. The change notification is separate from the refresh since there may be other operations that contact the remote location and obtain the latest remote state.

The APIs do not not define how a Subscriber is created, this is left to the specific implementations. For example the CVS plugin creates a Subscriber when a merge is performed, another for a comparison, and another when synchronizing the local workspace with the current branch.

So let's revisit our first example of using SyncInfo and see how a Subscriber could be used to access SyncInfo.

    // Create a file system subscriber and specificy that the
    // subscriber will synchronize with the provided file system location
    Subscriber subscriber = new FileSystemSubscriber("c:\temp\repo");

    // Allow the subscriber to refresh its state
    subscriber.refresh(subscriber.roots(), IResource.DEPTH_INFINITE, monitor);

    // Collect all the synchronization states and print
    IResource[] children = subscriber.roots();
    for(int i=0; i < children.length; i++) {
      printSyncState(children[i]);
    }

    ...

    void printSyncState(Subscriber subscriber, IResource resource) {
      System.out.println(subscriber.getSyncInfo(resource).toString());
      IResource[] children = subscriber.members(resource);
      for(int i=0; i < children.length; i++) {
        IResource child = children[i];
        if(! child.exists()) {
          System.out.println(resource.getFullPath() + " doesn't exist in the workspace");
        }
        printSyncState(subscriber, children[i]);
      }
    }

The important point to remember is that the Subscriber knows about resources that do not exist in the workspace and non-existing resources can be returned from the Subscriber#members() and SyncInfo#getLocal().

### Displaying the synchronizations state in the UI

We could spend more time explaining how to manage synchronization state but instead let's see how to actually get the state shown to the user. A ISynchronizeParticipant is the user interface component that displays synchronization state and allows the user to affect its state. The Synchronize View displays synchronize participants, but it is also possible to show these in dialogs and wizards. In order to provide support for users to show any type of synchronization state to the user, even those not based on SyncInfo and Subscribers, a participant is a very generic component.

There is also an extension point called org.eclipse.team.ui.synchronizeWizards to add a synchronization creation wizard. This will put your wizard in the global synchronize action and in the Synchronize View, so that users can easily create a synchronization of your type.

However, if you have implemented a Subscriber you can benefit from a concrete participant called SubscriberParticipant which will provide the following functionality:

- Collects SyncInfo from a Subscriber in the background.
- Listens to changes in the workspace and those found when a Subscriber is refreshed and keeps the synchronization state updated dynamically.
- Provides the user interface that support modes for filtering the changes, and layouts.
- Support scheduling a refresh with the Subscriber so that the synchronization states are kept up-to-date.
- Supports refreshing a Subscriber in the background.
- Supports navigation of the changes and showing the differences between the files.
- Supports configuration of the actions, toolbars, and decorators by subclasses.

The best way to explain these concepts are to see them used in the context of a simple example. Go to the local history synchronization example to see how all of these pieces can be used together. Or if you want pointers on how to use the more advanced APIs, go to Beyond The Basics.