## Repository providers

A repository provider (RepositoryProvider) is the central class in the implementation of your repository. This class is responsible for configuring a project for repository management and providing the necessary hooks for resource modification. Providers are mapped to a project using project persistent properties. The mechanism for mapping providers to a project is not central to the team API, but you'll need to be aware of it when filtering out resources in your UI. For the most part, you'll be using team API to work with projects and associate them to your provider.

To implement a provider, you must define a repository using org.eclipse.team.core.repository and supply a class derived from RepositoryProvider. We'll use the CVS client as an example to see how this works.

### Extension point

The org.eclipse.team.core.repository extension point is used to add a repository definition. Here is the markup for the CVS client.

    <extension
        point="org.eclipse.team.core.repository">
          <repository
                class="org.eclipse.team.internal.ccvs.core.CVSTeamProvider"
                id="org.eclipse.team.cvs.core.cvsprovider">
          </repository>
    </extension>

This registers your team provider with the team support plug-in and assigns an id that should be used when your provider is associated with a project. The specified class for the repository must extend RepositoryProvider.

### Implementing a RepositoryProvider

The class identified in the extension must be a subclass of RepositoryProvider. Its primary responsibilities are to configure and deconfigure a project for repository support, and supply any necessary resource modification hooks. The CVS client serves as a good example. Its repository provider is CVSTeamProvider.

    public class CVSTeamProvider extends RepositoryProvider {
    ...

RepositoryProvider defines two abstract methods, configureProject and deconfigure. All providers must implement these methods.

A project is configured when it is first associated with a particular repository provider. This typically happens when the user selects a project and uses the team wizards to associate a project with your repository. Regardless of how the operation is triggered, this is the appropriate time to compute or cache any data about the project that you'll need to provide your repository function. (Assume that mapping the project to your provider has already happened. You'll be taking care of this in your configuration wizard.)

The CVS provider simply broadcasts the fact that a project has been configured:

    public void configureProject() throws CoreException {
    	CVSProviderPlugin.broadcastProjectConfigured(getProject());
    }

We won't follow the implementation of the plug-in broadcast mechanism. Suffice to say that any parties that need to compute or initialize project specific data can do so at this time.

A project is deconfigured when the user no longer wants to associate a team provider with a project. It is up to your plug-in to implement the user action that causes this to happen (and unmapping the project from your team provider will happen there). The deconfigure method is the appropriate time to delete any project related caches or remove any references to the project in the UI. The CVS provider flushes project related caches kept in its views and broadcasts the fact that the project is deconfigured.

    public void deconfigure() throws CoreException {
    	...
    	try {
    		EclipseSynchronizer.getInstance().flush(getProject(), true, true /*flush deep*/, null);
    	} catch(CVSException e) {
    		throw new CoreException(e.getStatus());
    	} finally {
    		CVSProviderPlugin.broadcastProjectDeconfigured(getProject());
    	}
    }

### Configuring a project

Typically, the first step in building a team UI is implementing a wizard page that allows users to configure a project for your plug-in's team support. This is where your team provider's id will be added to the project's properties. You participate in project configuration by contributing to the org.eclipse.team.ui.configurationWizards extension point. This wizard is shown when the user chooses Team->Share Project...

We'll look at this in the context of the CVS client implementation. Here is the CVS UI markup for its configuration wizard:

    <extension
          point="org.eclipse.team.ui.configurationWizards">
       <wizard
            name="%SharingWizard.name"
            icon="icons/full/wizards/newconnect_wiz.png"
            class="org.eclipse.team.internal.ccvs.ui.wizards.SharingWizard"
            id="org.eclipse.team.ccvs.ui.SharingWizard">
       </wizard>
    </extension>

As usual, plug-ins supply a class that implements the extension and a unique id to identify their extension. The name and icon are shown in the first page of the project configuration wizard if there are multiple providers to choose from.

Once the user has selected a provider, the next page shows the specific configuration information for your provider. (If your provider is the only team provider plug-in installed, then the wizard skips directly to your page.) Your wizard must implement IConfigurationWizard, which initializes the wizard for a specified workbench and project. The rest of the implementation depends on the design of your wizard. You must gather up any information needed to associate the project with your team support.

When the wizard is completed, you must map your team provider to the project using RepositoryProvider.map(IProject, String). Mapping handles the assignment of the correct project persistent property to your project.

The CVS client does this work in its provider's setSharing method, which is called when its wizard is finished:

    public void setSharing(IProject project, FolderSyncInfo info, IProgressMonitor monitor) throws TeamException {

    	// Ensure provided info matches that of the project
    	...
    	// Ensure that the provided location is managed
    	...
    	// Register the project with Team
    	RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
    }

### Finding a provider

Static methods in RepositoryProvider make it easy for clients to map projects to providers and to find the providers associated with a given project.

- map(IProject, String) - instantiates a provider of the specified provider id and maps the specified project to it. This call sets the proper project persistent property on the project.
- unmap(IProject, String) - removes the association of the specified provider id from the specified project. Leaves the project unassociated with any team provider.
- getProvider(IProject) - answers the provider for a given project. Can be used to find any team provider for a project.
- getProvider(IProject, String) - answers the provider for a given project with the specified provider id. Can be used to check whether a particular team provider type is associated with a given project. It is commonly used by providers to quickly check whether a given project is under their care. This call is safer for clients since it does not return a provider that does not match the client's id.

### Repository Providers and Capabilities

If a product chooses to add a Repository plug-in to a capability, it should bind the capability to the repository id. Here are the two steps to take to enable a RepositoryProvider as a capability:

1. Bind the capability to the repository provider id. This allows the Team plug-in to activate/disable based on repository provider ids.

       <activityPatternBinding
           activityId="org.eclipse.team.cvs"
           pattern="org\.eclipse\.team\.cvs\.core/.*cvsnature">
       </activityPatternBinding>

2. Next bind the capability to all UI packages for the provider:

       <activityPatternBinding
            activityId="org.eclipse.team.cvs"
            pattern="org\.eclipse\.team\.cvs\.ui/.*">
       </activityPatternBinding>

There are two capability triggers points defined by the Team plug-ins. The first is the Team > Share Project... wizard which allows filtering of repository providers based on the enabled/disabled state of workbench capabilities, and the other is the Team plug-in auto-enablement trigger.

### Resource modification hooks

Most of the interesting function associated with a repository provider occurs as the user works with resources in the project that is configured for the provider. In order to be aware of changes the user makes to a resource, the provider can implement resource modification hooks. The resources plug-in provides these hooks as extension points. The documentation for IMoveDeleteHook, IFileModificationValidator and ResourceRuleFactory describe the details for implementing these hooks.

The team plug-in optimizes and simplifies the association of the hook with appropriate resources by registering generic hooks with the resources plug-in. These generic hooks simply look up the repository provider for a given resource and obtain its hook. This has the advantage of calling only one provider hook rather than having each provider implementation register a hook that must first check whether the resource is managed by the provider.

What this means to your plug-in is that you provide any necessary hooks by overriding methods in RepositoryProvider. The default implementation of these methods answers null, indicating that no hook is necessary (except for the resource rule factory, as described below):

- getMoveDeleteHook - answers an IMoveDeleteHook appropriate for the provider. This hook allows providers to control how moves and deletes occur and includes the ability to prevent them from happening. Implementors can provide alternate implementations for moving or deleting files, folders, and projects. The CVS client uses this hook to monitor folder deletions and ensure that any files contained in deleted folders are remembered so that they can later be deleted from the repository if desired.
- getFileModificationValidator - answers an IFileModificationValidator appropriate for the provider. This hook allows providers to pre-check any modifications or saves to files. This hook is typically needed when a repository provider wants to implement pessimistic versioning. In pessimistic versioning, a file must be checked out before modifying it, and only one client can check out a file at any given time. Pessimistic versioning could be implemented by checking out a file (if not already checked out) whenever a file is edited, and checking the file back in when it is saved. Since CVS uses an optimistic versioning scheme, it does not implement this hook.
- getRuleFactory - answers a resource rule factory appropriate for the provider. Providers should always override this method as the default factory locks the workspace for all operations for backwards compatibility reasons. Provides should subclass ResourceRuleFactory and override those rules required to ensure that the proper rules are obtained for operations that invoke the move/delete hook and file modification validator. The rule methods of particular interest to repository providers are:
  - deleteRule - move/delete hook
  - moveRule -move/delete hook
  - validateEditRule - file modification validator validateEdit
  - modifyRule - file modification validator validateSave