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 with 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.

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 functionality 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, FileModificationValidator 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):