Repository Roadmap for Logical Model Integration

To provide full support for logical models, a repository provider can perform the following steps:

  1. Contribute the appropriate repository operations to elements that adapt to ResourceMapping.
  2. Ensure that operations performed on resource mappings include all the appropriate model elements and resources by using an ISynchronizationScope and supporting API.
  3. Allow model providers to participate in headless merging through the IMergeContext interface and supporting API.
  4. Allow model providers to participate in merge previews by using the teamContentProviders for the models involved in the merge. A ModelSynchronizeParticipant class is provided to help manage the relationship between the model content, a merge context and the Compare framework.
  5. Provide access to the history of workspace files through the IFileHistoryProvider API
  6. Provide access to remote configurations using the Eclipse File System API in the org.eclipse.core.filesystem plug-in and link this to workspace projects through the ProjectSetCapability
  7. Support logical model element decoration by providing a workspace Subscriber for use with the SynchronizationStateTester API.
  8. Allow models to group related changes by implementing the IChangeGroupingRequestor API.

The following sections describe each of these points in more detail. The org.eclipse.ui.examples.filesystem plug-in contain an example that illustrate several of these points. You can check the project out from the Git repository and use it as a reference while you are reading this tutorial. Disclaimer: The source code in the example plug-ins may change over time. To get a copy that matches what is used in this example, you can check out the project using the 3.3 version tag (most likely R3_3) or a date tag of June 30, 2007.

Contributing Actions to Resource Mappings

The Basic Resource Mapping API

The resource mapping API consists of the following classes:

There are two types of plugins that should be interested in resource mappings. Those who provide a model that consists of, or is persisted in, resources in the workspace and those that want to perform operations on resources. The former case will be covered in the model roadmap and the later case is covered in the next section.

Resource Mappings and Object Contributions

Plug-ins that contribute extensions to adaptable extension points will have to make two changes to support the new ResourceMapping APIs:

  1. Update any objectContributions of the popupMenus extension point in their plugin.xml file to target ResourceMapping instead of IResource (for those for which this is appropriate).
  2. Update their actions to work on ResourceMapping instead of IResource and respect the depth constraints provided in the traversals.

Plug-ins that add object contributions to IResource can now add them to ResourceMapping instead, if the action can apply to multiple resources. Here is an XML snippet that contributes a menu action to objects that adapt to resource mappings:

   <extension
       point="org.eclipse.ui.popupMenus">
      <objectContribution
            objectClass="org.eclipse.core.resources.mapping.ResourceMapping"
            adaptable="true"
            id="org.eclipse.team.ccvs.ui.ResourceMapperContributions">
         <enablement>
<adapt type="org.eclipse.core.resources.mapping.ResourceMapping">
<test
property="org.eclipse.core.resources.projectPersistentProperty"
args="org.eclipse.team.core.repository,org.eclipse.team.cvs.core.cvsnature" />
</adapt>
</enablement>
<action
label="%UpdateAction.label"
definitionId="org.eclipse.team.cvs.ui.update"
class="org.eclipse.team.internal.ccvs.ui.actions.UpdateAction"
tooltip="%UpdateAction.tooltip"
menubarPath="team.main/group2"
id="org.eclipse.team.cvs.ui.update">
</action>
...
</objectContribution>
</extension>

Contributions to ResourceMapping will automatically apply to objects that adapt to IResource. This transitive association is handled by the Workbench. Filtering of the contributions to resource mappings can be done using enablement expressions. An expression for filtering by project persistent property has been added to allow repository providers to have their menus appear on projects that are mapped to their repositories.

Actions that have been contributed to the ResourceMapping class will be given a selection that contains one or more ResourceMappings. It is the actions responsibility to translate the resource mapping into a set of resources to be operated on. This can be done by calling getTraversals to get the traversals of the mapping. Traversals are used to allow the clients of the traversal to optimize their operations based on the depth of the resources being traversed. A client may traverse the resource manually or may use the resource and the depth as input into an operation that the action delegates to do the work. As an example, if the user performs a CVS update on a java package and the java package resource mapping maps to a folder of depth one, CVS would issue an appropriate command ("cvs update -l" for those who are curious) which would perform a shallow update on the folder the package represents.

Although it is possible to obtain a set of traversals directly from the selected resource mappings, there are model relationships (or repository relationships) that may require the inclusion of additional resources or model elements in an operation. The next section describes how to ensure that all required resources are included in an operation

Operation Scope

For team operations, the selected mappings need to be translated into the set of mappings to be operated on. This process involves consulting all model providers to ensure that they get included in operations on resources that match their enablement rules. The term we use to describe the complete set of resource mappings to be operated on is the operation scope. The following API has been provided for this:

The initialize(IProgressMonitor) method of the SynchronizationScopeManager class handles the entire process of converting an input set of resource mappings into the complete set of mappings that need to be operated on as well as the complete set of traversals that cover these mappings. A repository provider can tailor the process by:

  1. Providing a RemoteResourceMappingContext for use when obtaining resource traversals from resource mappings.
  2. Overriding SynchronizationScopeManager to tailor the scope management process as required.

The next two sections describe these points in more detail.

Remote Resource Mapping Context

In order to guarantee that all necessary resources get included in a team operation, the model provider may need the ability to glimpse at the state of one or more resources in the repository. For some models, this may not be required. For instance, a java package is a container visited to a depth of one, regardless of the remote state of the model. Given this, a repository provider can easily determine that outgoing deletions should be included when committing or that incoming additions should be included when updating. However, the resources that constitute some logical models may change over time. For instance, the resources that constitute a model element may depend of the contents of a manifest file (or some other similar mechanism). In order for the resource mapping to return the proper traversal, it must access the remote contents of the manifest file (if it differs from the local contents) in order to see if there are additional resources that need to be included. These additional resources may not exist in the workspace but the repository provider would know how to make sure they did when the selected action was performed.

In order to support these more complex models, a RemoteResourceMappingContext can be passed to the ResourceMapping#getTraversals method. When a context is provided, the mapping can use it to ensure that all the necessary resources are included in the traversal. If a context is not provided, the mapping can assume that only the local state is of interest.

The remote resource mapping context provides three basic queries:

The answer to the first question above depends on the type of operation that is being performed. Typically, updates and merges are three-way while comparisons and replace operations (at least for CVS) are two-way.

The Eclipse Team API includes a Subscriber class that defines an API for providing the synchronization state between the local workspace and a remote server. A SubscriberResourceMappingContext is provided that uses a Subscriber to access the necessary remote state. Clients that have a Subscriber do not need to do any additional work to get a resource mapping context.

Subclassing SynchronizationScopeManager

The SynchronizationScopeManager class can be subclassed to tailor the scope generation and management process. The two main reasons for subclassing the scope manager are:

  1. The repository provider needs to include additional resources due to some repository level relationship (e.g. change set). This can be accomplished by overriding the adjustInputTraversals(ResourceTraversal[]) method.
  2. The synchronization has a longer lifecycle (e.g. Synchronize view vs. dialog) and needs the potential to react to scope changes. The ISynchronizationScopeParticipant interface defines the API that model providers can use to participate in the scope management process. The SubscriberScopeManager class is a Subscriber based subclass of SynchronizationScopeManager that involves participants in the scope management process. An example of why this type of process is needed is working sets. If a working set is one of the resource mappings in a scope, the set of traversals covered by the scope would increase if resources were added to the working set.

Model-based Merging

The main repository operation type that requires model participation is merging. In many cases, models only need to participate at the file level. For this, the IStorageMerger API was introduced to allow model providers to contribute mergers that should be used to merge files of a particular extension or content type. However, in some cases, models may need additional context to participate properly in a merge. For this purpose, we introduced the IResourceMappingMerger and IMergeContext APIs.

Merge operations are still triggered by actions associated with a repository provider. However, once a merge type operation is requested by the user, the repository provider needs to involve the model providers in the merge process to ensure that the merge does not corrupt the model in some way.

There are two main pieces of repository provider API related to the model-based merging support.

  1. API to describe the synchronization state of the resources involved in the merge.
  2. API to allow model providers to merge model elements.
The following sections describe these two pieces.

API for Synchronization State Description

An important aspect of model-based merging is the API used to communicate the synchronization state of the resources involved to the model provider. The following interfaces are used to describe the synchronization state:

Abstract classes are provided for all these interfaces with the convention that the class names match the interface names with the "I" prefix removed. The only class that repository providers must override is the ResourceDiff class so that appropriate before and after file revisions can be provided.

API for Model Merging

The IMergeContext interface extends synchronization context with additional methods that support merging. Callback methods exist for:

An abstract MergeContext class is provided that contains default implementations for much of the merging behavior and also uses the IStorageMerger to perform three-way merges. A SubscriberMergeContext class is also provided which handles the population and maintenance of the synchronization state description associated with the merge context.

An operation class, ModelMergeOperation is provided which uses the IResourceMappingMerger API to perform a model-based merge operation. Subclasses need to override the initializeContext(IProgressMonitor) method to return a merge context. The operation uses this context to attempt a headless model-based merge. If conflicts exist, the preview of the merge is left to the subclass. As we'll see in the next section, there is a ModelParticipantMergeOperation that provides preview capabilities using a ModelSynchronizeParticipant.

Model Content in Team Viewers

Support for the display of logical models in a team operation is provided using the Common Navigator framework which was introduced in Eclipse 3.2. Logical models can associate a content extension with a model provider using the org.eclipse.team.ui.teamContentProviders extension point. Team providers access these content providers through the ITeamContentProviderManager.

There are several places where a team provider may wish to display logical models:

The ModelSynchronizeParticipant provides integration into the Synchronize view or any container that can display ISynchronizePages. The participant makes use of both the pre-existing synchronization participant capabilities and the Common Navigator capabilities to allow for team providers and models to tailor the toolbar, context menu and other aspects of the merge preview. The ModelSynchronizeParticipant provides the following:

Here's a checklist of steps for tailoring a model synchronize participant for a particular Team provider:

The following XML snipets illustrate how the CVS participant class is registered and how it's viewer is defined.

   <extension point="org.eclipse.team.ui.synchronizeParticipants">
      <participant
            name="CVS"
            icon="$nl$/icons/full/eview16/cvs_persp.gif"
            class="org.eclipse.team.internal.ccvs.ui.mappings.WorkspaceModelParticipant"
            id="org.eclipse.team.cvs.ui.workspace-participant">
      </participant>
   </extension>
   
   <extension point="org.eclipse.ui.navigator.viewer">
       <viewer viewerId="org.eclipse.team.cvs.ui.workspaceSynchronization">
           <popupMenu
                allowsPlatformContributions="false"
                id="org.eclipse.team.cvs.ui.workspaceSynchronizationMenu"> 
             <insertionPoint name="file"/>
             <insertionPoint name="edit" separator="true"/>       
             <insertionPoint name="synchronize"/>
             <insertionPoint name="navigate" separator="true"/>
             <insertionPoint name="update" separator="true"/>
             <insertionPoint name="commit" separator="false"/>
             <insertionPoint name="overrideActions" separator="true"/>
             <insertionPoint name="otherActions1" separator="true"/>
             <insertionPoint name="otherActions2" separator="true"/>
             <insertionPoint name="sort" separator="true"/>
             <insertionPoint name="additions" separator="true"/>             
             <insertionPoint name="properties" separator="true"/>
          </popupMenu>
       </viewer>
   </extension>

File History

A file history API has been added to allow models to access the history of files. The file history API consists of the following interfaces:

Along with this API, a generic file History view has been added. This will allow Team providers to display their file/resource history in a shared view and also allows models to display model element history for elements that do not map directly to files. The History view is a page-based view which obtains a page for the selected element in the following way:

Project Set Capability

Methods have been added to ProjectSetCapability to support the translation between a reference string used to identify a mapping between a project and remote content and URIs that identify a file-system scheme registered with the org.eclipse.core.filesystem.filesystems extension point. Team providers can optionally provide support for this in order to allow logical models to performing remote browsing and project loading.

Decorating Model Elements

Team providers can decorate model elements by converting their lightweight decorators to work for resource mappings in the same way object contributions are converted to work for resource mappings. However, there is one aspect of logical model element decoration that is problematic. If a model element does not have a one-to-one mapping to a resource, the model element may not receive a label update when the underlying resources change.

To address this issue, the ITeamStateProvider was introduced in order to give model providers access to state changes that may affect team decorations. In addition, model views can use a SynchronizationStateTester to determine when the labels of logical model elements need to be updated. This API relies on the ITeamStateProvider interface to determine when the team state of resource has changed and can be passed to a team decorator as part of an IDecorationContext.

Grouping Related Changes

Some logical models need to ensure that a set of changed files get committed or checked-in to the repository at the same time. To facilitate this, repository providers can adapt their RepositoryProviderType to an instance of IChangeGroupingRequestor. This API allows models to request that a set of files get committed or checked-in as a single unit.