Organigramme des modèles pour l'intégration des modèles logiques

Ci-dessous figure une liste des opérations que les fournisseurs de modèles peuvent faire pour tirer parti du support des modèles logiques d'équipe :

  1. Adaptez les éléments de modèle dans les vues de modèle à ResourceMapping afin de permettre aux opérations basées sur des ressources d'apparaître sur vos éléments de modèle.
  2. Enregistrez un ModelProvider de sorte que votre modèle soit consulté lorsque des opérations sont effectuées sur les ressources associées à votre modèle.
  3. Utilisez l'élément ResourceChangeValidator lorsque vous effectuez des opérations sur les ressources pour s'assurer que tous les effets secondaires éventuels sur les éléments de modèle associés à ces ressources sont portés à la connaissance de l'utilisateur.
  4. Implémentez un élément IResourceMappingMerger pour participer à des fusions en arrière-plan qui impliquent les ressources associées à votre modèle.
  5. Enregistrez un élément teamContentProvider afin de participer à des afficheurs d'équipe tels que des aperçus de fusion.
  6. Fournissez un élément IHistoryPageSource destiné à afficher l'historique des modèles logiques dans la vue Historique de l'équipe.
  7. Utilisez l'API Système de fichiers Eclipse pour accéder à l'état distant des projets de modèle.
  8. Utilisez l'API SynchronizationStateTester pour s'assurer de la décoration adéquate des éléments de modèle qui ne disposent pas d'un mappage un à un aux ressources.

Les sections suivantes décrivent plus en détail chacun de ces points. Le plug-in org.eclipse.team.examples.filesystem contient un exemple illustrant plusieurs de ces points. Vous pouvez réserver le projet du référentiel CVS et l'utiliser comme référence lorsque vous lisez de didacticiel. Clause de protection : Le code source dans l'exemple de plug-in peut varier dans le temps. Pour obtenir une copie qui correspond à ce qui est utilisé dans cet exemple, vous pouvez réserver le projet à l'aide de la balise de version 3.2 (R3_2, le plus souvent) ou une balise en date du 28 juin 2006.

Mappages de ressources

L'API de mappage des ressources de base

L'API de mappage des ressources est volontairement simple en ignorant les opérations de modèles logiques. Un client ne peut pas utiliser cette interface pour afficher des modèles logiques ou obtenir des informations complémentaires intéressantes sur celle-ci. Son but est simplement de mapper un ou plusieurs éléments de modèle aux ressources de l'espace de travail.

L'API comprend les classes suivantes :

Deux types de plug-ins devraient s'intéresser aux mappages des ressources. Ceux qui fournissent un modèle qui comprend des ressources, ou qui est conservé dans des ressources de l'espace de travail et ceux qui souhaitent effectuer des opérations sur les ressources. Le premier est traité dans la section suivante tandis que le deuxième est abordé dans la section Organigramme des référentiels pour l'intégration des modèles logiques.

Adaptation d'un modèle à un mappage des ressources

Les plug-ins ayant adapté leurs objets de modèle à IResource pour extraire les actions spécifiques aux ressources affichées dans le menu contextuel peuvent à présent s'adapter à ResourceMapping si une description plus détaillée de la manière dont les objets s'adaptent est utile. Toutefois, s'il n'y a aucun intérêt à le faire, cette opération n'est pas obligatoire. Par exemple, une unité de compilation Java (par exemple, un fichier *.java affiché dans une vue JDT) qui s'adapte actuellement à IFile ne doit pas s'adapter à ResourceMapping puisque rien n'est acquis. Toutefois, un package Java doit s'adapter à ResourceMapping pour indiquer que le package comprend uniquement les fichiers dans le dossier correspondant et non pas les sous-dossiers.

La méthode recommandée pour adapter les modèles d'élément à un mappage des ressources consiste à utiliser une fabrique d'adaptateur. Ci-dessous figure le marquage XML permettant d'ajouter une fabrique d'adaptateur dans un manifeste de plug-in.

   <extension
point="org.eclipse.core.runtime.adapters">
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Book">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Library">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
...
</extension>

L'implémentation de la fabrique d'adaptateur doit ressembler à ceci :

public class AdapterFactory implements IAdapterFactory {
public Object getAdapter(Object adaptableObject, Class adapterType) {
if((adaptableObject instanceof EObject) && adapterType == ResourceMapping.class) {
return new EObjectResourceMapping((EObject)adaptableObject);
}
return null;
}

public Class[] getAdapterList() {
return new Class[] {ResourceMapping.class};
}
}

Les objets de modèle peuvent implémenter l'interface IAdaptable. Si tel est le cas, ils doivent s'assurer que le gestionnaire de l'adaptateur de la plateforme est consulté. Il peut le faire en sous-classant PlatformObject ou en utilisant la ligne de code suivante :

Platform.getAdapterManager().getAdapter(Object, Class)

Cette méthode est préférable. Cependant, l'objet de modèle peut implémenter l'interface IAdaptable et fournir une implémentation getAdapter(Class) qui crée des renvois d'une instance de ResourceMapping de manière explicite, si besoin est. Cette méthode est plus directe, mais est moins conseillée, dans la mesure où le modèle doit disposer d'une connaissance explicite de l'adaptation aux ressources.

Dans certains cas, le fournisseur d'un modèle logique peut ne pas souhaiter que son modèle s'adapte à IResource dans chaque contexte ou peut vouloir que son objet s'adapte différemment pour les contributions d'objet que pour les autres contextes. L'interface utilisateur du plan de travail fournit une API d'adaptateur intermédiaire spécial, IContributorResourceAdapter, à cette fin. Lorsque des objets sont adaptés à IResource dans le contexte de contributions d'objet, le plan de travail tente premièrement d'adapter la ressource à IContributorResourceAdapter avant de tenter de s'adapter à IResource directement. Une sous-interface de cette interface, IContributorResourceAdapter2, qui offre la même fonctionnalité pour ResourceMapping, a été ajoutée. La seule différence réside dans le fait que le fournisseur de modèles doit enregistrer une fabrique pour IContributorResourceAdapter car le plan de travail effectue une vérification de instanceof afin de déterminer si l'adaptateur ajouté est également une instance de IContributorResourceAdapter2.

L'implémentation de la sous-classe ResourceMapping d'un package Java ressemblerait à ceci.

public class JavaPackageResourceMapping extends ResourceMapping {
IPackageFragment package;
...
public getModelObject() {
return package;
}
public ResourceTraversals[] getTraversals(
ResourceMappingContext context,
IProgressMonitor monitor) {
return new ResourceTraversal[] {
new ResourceTraversal(
new IResource[] { package.getCorrespondingResource() },
IResource.DEPTH_ONE, IResource.NONE)
}
}
}

Ce mappage est relativement direct. Par conséquent, l'implémentation n'est pas complexe. La complexité de l'implémentation du mappage des ressources varie, bien entendu, d'un modèle à un autre.

Contexte de mappage des ressources

Un des avantages d'une API de mappage des ressources est de permettre aux plug-ins de mettre en oeuvre toutes les opérations qu'ils désirent en termes de mappage des ressources (par exemple, mise à jour CVS, validation CVS, balise CVS, décoration modifiée, etc.). Toutefois, l'API qui a été introduite jusqu'à présent ne concerne que l'état local du modèle. Lorsque vous utilisez un modèle susceptible d'être partagé entre les développeurs, vous vous retrouvez dans une situation dans laquelle l'état distant du modèle (à savoir, l'état du modèle qu'un utilisateur a libéré dans le référentiel) peut différer de l'état indiqué dans l'espace de travail. Si vous avez effectué une mise à jour CVS, vous voudrez que l'état local du modèle corresponde à l'état distant même si cela implique que des fichiers supplémentaires soient inclus ou que certains fichiers doivent être supprimés.

Ce n'est pas un problème pour certains modèles logiques. Par exemple, un package java est un conteneur visité à une profondeur de une, quel que soit l'état distant du modèle. En dépit de ceci, un fournisseur de référentiels peut aisément déterminer si des suppressions sortantes doivent être incluses lors de la validation ou si des ajouts entrants doivent être inclus lors de la mise à jour. Toutefois, les ressources qui constituent certains modèles logiques sont susceptibles de changer. Par exemple, les ressources qui constituent un élément de modèle peuvent dépendre du contenu d'un fichier manifeste (ou d'autres mécanismes similaires). Pour que le mappage des ressources renvoie le balayage correspondant, il doit accéder au contenu distant du fichier manifeste (s'il diffère du contenu local) afin de voir si des ressources supplémentaires doivent être incluses. Ces ressources supplémentaires peuvent ne pas exister dans l'espace de travail, mais le fournisseur de référentiels saurait le vérifier lors de l'exécution de l'action sélectionnée.

Pour prendre en charge ces modèles plus complexes, un élément RemoteResourceMappingContext peut être transmis à la méthode ResourceMapping#getTraversals. Lorsqu'un contexte est fourni, le mappage peut l'utiliser pour vérifier que toutes les ressources nécessaires sont incluses dans le balayage. Dans le cas contraire, le mappage peut présumer que seul l'état local est utile.

Quand un élément ResourceMapping doit-il se soucier de RemoteResourceMappingContext ?

Un élément ResourceMapping doit seulement se préoccuper d'un contexte fourni à la méthode getTraversals dans les cas où les ressources qui composent un modèle changent et que la relation entre le modèle et les ressources ne peut pas être décrite par un simple balayage garanti pour englober les ressources qui composent ce modèle (et seulement celles-ci). Par exemple, bien que les ressources d'un package Java puissent varier, le package peut être décrit en tant que dossier d'une profondeur de un de sorte qu'un mappage de ressources pour les packages java n'ait pas besoin de recourir au contexte du mappage des ressources.

A titre d'exemple plus complexe, imaginons un fichier HTML contenant plusieurs images. Supposons que toutes les références d'images du fichier HTML fassent partie du modèle de ce fichier. Lors de la mise à jour du contenu local du fichier HTML à partir d'un référentiel, l'utilisateur s'attend à ce que toutes les nouvelles images soient incluses. La méthode getTraversals d'un ResourceMapping correspondant au modèle de fichier HTML ressemblerait à ceci :

public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Rechercher les ressources supplémentaires sur le serveur
RemoteResourceMappingContext remoteContext = (RemoteResourceMappingContext)context;
IFile file = htmlFile.getFile();
if (remoteContext.hasRemoteChange(file, monitor)) {
IStorage storage = remoteContext.fetchRemoteContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
if (remoteContext.isThreeWay() && remoteContext.hasLocalChange(file, monitor)) {
IStorage storage = remoteContext.fetchBaseContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
}
return new ResourceTraversal[] {
new ResourceTraversal(resources, IResource.DEPTH_ZERO, IResource.NONE)};
}
}

Notez qu'il existe deux ensembles de ressources inclus dans le modèle : celles issues du contenu local du fichier HTML dans l'espace de travail et celles extraites du contenu du fichier distant et du fichier de base. Quel que soit l'ensemble, des ressources peuvent ne pas résider dans l'espace de travail. Par exemple, le fichier HTML local peut contenir un lien relatif à une image qui n'existe pas dans l'espace de travail. Cette ressource doit être incluse afin qu'elle puisse être extraite si elle existe à distance. Comme pour le fichier distant, elle peut contenir une nouvelle copie qui référence les images supplémentaires devant être extraites lorsque le nouveau contenu distant est téléchargé.

Fournisseurs de modèle

Les fournisseurs de modèle permettent de regrouper les mappages de ressources associés. Voici un lien vers la classe ModelProvider. Cette classe a trois objectifs :

  1. A partir d'un fournisseur de modèles, les clients peuvent obtenir des parties d'API supplémentaires qui permettent d'effectuer des opérations sur un ensemble de mappages de ressources à l'aide de la méthode adaptable. Par exemple, l'élément IResourceMappingMerger du modèle est obtenu grâce à l'adaptation du fournisseur de modèles.
  2. En fonction d'un ensemble de ressources de système de fichiers, les clients peuvent demander si un fournisseur de modèles possède des éléments de modèle conservés dans ces ressources et, au quel cas, obtenir l'ensemble de mappage de ressources qui décrit la relation.
  3. Pour les opérations réalisées sur un ensemble de ressources, le valideur de changement de ressource interroge les fournisseurs de modèle afin de déterminer s'il existe des effets secondaires potentiels d'une opération dont les utilisateurs doivent être informés. Ceci est abordé dans une section différente dans Validation des modifications.

L'exemple ci-dessous illustre la définition d'une extension modelProvider.

   <extension
id="modelProvider"
name="Library Example"
point="org.eclipse.core.resources.modelProviders">
<modelProvider
class="org.eclipse.team.examples.library.adapt.LibraryModelProvider"
name="Library Example"/>
<extends-model id="org.eclipse.core.resources.modelProvider"/>
<enablement> <test property="org.eclipse.core.resources.projectNature" value="org.eclipse.team.examples.library.view.nature" />
</enablement>
</extension>

LibraryModelProvider est une sous-classe de ModelProvider. La règle d'activation sert à mettre en correspondance les ressources dans lesquelles le modèle Library conserve son modèle. Dans l'exemple précédent, le fournisseur de modèles met en correspondance toutes les ressources présentes dans un projet qui ont la nature de bibliothèque.

Une fois le fournisseur de modèles fourni, la méthode ResourceMapping#getModelProviderId() doit être remplacée pour renvoyer l'ID du fournisseur de modèles.

   public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}

Pour obtenir le mappage de ressources inverse au mappage des ressources des ressources qui correspondent à la règle d'activation de votre fournisseur, vous devez également remplacer l'une des méthodes getMapping ou les deux. La méthode que vous devez remplacer dépend si le modèle possède des éléments qui contiennent plusieurs ressources ou non. Si les éléments de votre modèle sont associés à une seule ressource, vous pouvez remplacer la méthode qui accepte un seul argument IResource. Dans le cas contraire, vous devez remplacer la méthode qui accepte une grappe de ressources. L'exemple ci-dessous illustre l'utilisation du cas de la ressource unique.

Dans l'exemple suivant, la méthode englobe un fichier de modèle de bibliothèque dans un mappage de ressources. Elle englobe également les dossiers qui contiennent des fichiers utiles pour le fournisseur de modèles.

public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Renvoie un mappage de ressources sur le fichier
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Crée un mappage de ressources profond sur le conteneur
return new LibraryContainerResourceMapping(resource);
}
// La ressource n'est pas utile pour ce fournisseur de modèles
return null;
}
}

Les clients peuvent ensuite accéder au fournisseur de modèles afin de déterminer si celui-ci se préoccupe des ressources sur lesquelles des opérations sont sur le point d'être réalisées. La section suivante décrit l'API qui sera fournie aux opérations d'équipe qui utilisent l'API du fournisseur de modèles pour déterminer l'ensemble complet de mappages de ressources à utiliser lorsqu'une opération d'équipe est réalisée sur un ensemble de ressources sélectionnées ou des éléments de modèle.

Validation des modifications apportées aux ressources

Les opérations effectuées sur les ressources doivent au préalable être validées afin de s'assurer que l'utilisateur est informé des effets secondaires possibles. Ci-dessous figurent les étapes requises pour valider une modification apportée à une ressource.

  1. Elaborez une description de la modification à l'aide de IResourceChangeDescriptionFactory. La fabrique produit un élément IResourceDelta qui duplique l'aspect du delta de la ressource résultante une fois l'opération effectuée.
  2. Validez la modification à l'aide de ResourceChangeValidator. Le valideur consulte tous les fournisseurs de modèle ayant montré un intérêt pour les ressources concernées. Le résultat renvoyé correspond à un ou plusieurs états contenant l'ID du modèle d'origine et une description des effets secondaires potentiels d'une opération sur le modèle.
  3. Informez l'utilisateur sur les effets secondaires possibles des modèles qui sont inconnus de l'auteur de l'opération. Par exemple, si une restructuration Java a reçu un effet secondaire du modèle Java, il peut être ignoré dans la mesure où la restructuration comprend les sémantiques du modèle Java. Toutefois, si un effet secondaire du modèle de bibliothèque est renvoyé, il doit être porté à la connaissance de l'utilisateur car Java ne connaît pas le modèle de bibliothèque.

Fusion basée sur un modèle

Lorsqu'un fournisseur d'équipe tente une fusion en arrière-plan, il effectue les opérations suivantes :

  1. Extraction des mappages de ressources des éléments sélectionnés
  2. Détermination des fournisseurs de modèle impliqués à l'aide de la méthode ResourceMapping#getModelProvider().
  3. Développement de la portée de l'opération pour inclure tous les mappages de ressource nécessaires.
  4. Elaboration d'une description de l'état de synchronisation entre l'état local et distant. Cette description est fournie aux modèles par le biais de l'API IMergeContext.
  5. Adaptation des fournisseurs de modèle à IResourceMappingMerger.
  6. Appel de la méthode validateMerge sur chaque dispositif de fusion, en transmettant la description de la synchronisation, afin de s'assurer qu'aucune condition n'empêche l'exécution d'une fusion.
  7. Délégation de la fusion aux dispositifs de fusion pour effectuer l'opération.
  8. Les fournisseurs de modèle peuvent déléguer la fusion de fichiers au fournisseur d'équipe s'ils souhaitent uniquement contrôler l'ordre de la fusion, ou peuvent effectuer eux-mêmes la fusion et signaler au fournisseur d'équipe lorsque l'opération est terminée.

Contenu de modèle dans les vues d'opération d'équipe

L'affichage des éléments de modèle dans le contexte d'une opération d'équipe est rendu possible grâce à l'infrastructure du navigateur commun.

Les étapes précédentes permettront aux modèles d'apparaître dans les boîtes de dialogue utilisées par les opérations d'équipe. Il existe d'autres étapes obligatoires pour l'intégration dans un aperçu de fusion.

Vue Historique

Les améliorations suivantes ont été apportées dans le domaine de l'historique des fichiers et des éléments de modèle :

Navigation à distance

Les éléments suivants ont été fournis pour prendre en charge la navigation à distance :

Décoration d'éléments de modèle avec un état d'équipe

Les fournisseurs d'équipe peuvent décorer les éléments de modèle en convertissant leurs décorateurs simples de façon à ce qu'ils fonctionnent pour les mappages de ressources exactement comme les contributions d'objets sont converties pour fonctionner pour les mappages de ressources. Toutefois, un aspect de la décoration d'éléments de modèle logique pose problème. Si un élément de modèle ne possède pas un mappage un à un sur une ressource, l'élément de modèle risque de ne pas recevoir de mise à jour de modèle lorsque les ressources sous-jacentes seront modifiées.

Pour résoudre cet incident, l'élément ITeamStateProvider a été introduit afin de permettre aux fournisseurs de modèle d'accéder aux modifications d'état susceptibles d'affecter les décorations d'équipe. Par ailleurs, les vues de modèle peuvent utiliser un élément SynchronizationStateTester pour déterminer lorsque les libellés des éléments de modèle logique doivent être mis à jour. Cette API recourt à l'interface ITeamStateProvider afin de déterminer lorsque l'état d'équipe de la ressource a changé et lorsqu'il peut être transmis à un décorateur d'équipe dans le cadre d'un IDecorationContext.