Participation à la sauvegarde de l'espace de travail

Le traitement de sauvegarde de l'espace de travail est déclenché lorsque ce dernier est arrêté par l'utilisateur et à d'autres moments, périodiquement par la plate-forme. Les plug-ins peuvent participer au processus de sauvegarde de l'espace de travail de telle sorte que les données de plug-in sensibles sont sauvegardées sur le disque chaque fois que le reste des données persistantes de l'espace de travail est sauvegardé.

Le processus de sauvegarde de l'espace de travail peut être également utilisé pour effectuer le suivi des modifications qui surviennent entre les activations de votre plug-in.

Implémentation d'un participant à la sauvegarde

Pour participer à la sauvegarde de l'espace de travail, vous devez ajouter un participant de sauvegarde à l'espace de travail. Ceci s'effectue généralement au cours de la méthode startup du plug-in. C'est là également que vous lisez l'état éventuellement enregistré lors du dernier arrêt de votre plug-in.

Examinons un plug-in simple illustrant le processus d'enregistrement.

   package com.example.saveparticipant;

   import org.eclipse.core.runtime.*;
   import org.eclipse.core.resources.*;
   import java.io.File;
   import java.util.*;

   public class MyPlugin extends Plugin {
      private static MyPlugin plugin;

      public MyPlugin(IPluginDescriptor descriptor) {
         super(descriptor);
         plugin = this;
      }

      public static MyPlugin getDefault() {
         return plugin;
      }

      protected void readStateFrom(File target) {
      }

      public void startup() throws CoreException {
         super.startup();
         ISaveParticipant saveParticipant = new
MyWorkspaceSaveParticipant();
         ISavedState lastState =
            ResourcesPlugin.getWorkspace().addSaveParticipant(this, saveParticipant);
         if (lastState == null)
            return;
         IPath location = lastState.lookup(new Path("save"));
         if (location == null)
            return;
         // l'instance du plug-in doit lire tout état important dans le fichier.
         File f = getStateLocation().append(location).toFile();
         readStateFrom(f);
      }

      protected void writeImportantState(File target) {
      }
   }

ISaveParticipant définit le protocole pour un participant à la sauvegarde de l'espace de travail. Les classes d'implémentation de cette interface peuvent fournir le comportement de différents niveaux du processus de sauvegarde. Examinons ces niveaux et voyons comment la classe WorkspaceSaveParticipant implémente chacune de ces étapes.

      public void prepareToSave(ISaveContext context) throws CoreException {
      }
      public void saving(ISaveContext context) throws CoreException {
         switch (context.getKind()) {
            case ISaveContext.FULL_SAVE:
               MyPlugin myPluginInstance = MyPlugin.getDefault();
               // enregistre l'état du plug-in
               int saveNumber = context.getSaveNumber();
               String saveFileName = "save-" + Integer.toString(saveNumber);
               File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
               // si l'écriture échoue, une exception est lancée
et le chemin n'est pas mis à jour.
               myPluginInstance.writeImportantState(f);
               context.map(new Path("save"), new Path(saveFileName));
               context.needSaveNumber();
               break;
            case ISaveContext.PROJECT_SAVE:
               // extraction du projet relatif à cette opération d'enregistrement
               IProject project = context.getProject();
               // enregistrement des informations, si besoin est
               break;
            case ISaveContext.SNAPSHOT:
               // Cette opération doit être rapide car des
               // l'espace de travail peut demander fréquemment
               // des captures d'écran.
               break;
         }
      }

ISaveContext décrit les informations relatives à l'opération de sauvegarde. Il existe trois types d'opérations de sauvegarde : FULL_SAVE, SNAPSHOT et PROJECT_SAVE. Les participants à la sauvegarde doivent être attentifs à l'exécution du traitement approprié au type d'événement de sauvegarde qu'ils ont reçus. Par exemple, des événements instantanés peuvent se produire assez fréquemment et sont destinés à permettre aux plug-ins de sauvegarder leur état critique. Si la sauvegarde d'un état pouvant être recalculé dans l'éventualité d'une panne dure longtemps, la plate-forme s'en trouve ralentie.

Un numéro de sauvegarde est utilisé pour créer des fichiers de sauvegarde des données, désignés à l'aide de numéros séquentiels (save-1, save-2, etc.).Chaque fichier de sauvegarde est mappé sur un nom de fichier logique (save), indépendant du numéro de sauvegarde. Les données du plug-in sont écrites dans le fichier correspondant et peuvent être extraites ultérieurement sans savoir le numéro de sauvegarde spécifique de la dernière opération de sauvegarde réussie. N'oubliez pas que nous avons vu cette technique dans le code de démarrage de notre plug-in.

IPath location = lastState.lookup(new Path("save"));

Une fois les données sauvegardées et le nom de fichier mappé, nous appelons needSaveNumber pour indiquer que nous avons activement participé à la sauvegarde de l'espace de travail et souhaitons assigner un numéro à l'activité de sauvegarde. Les numéros de sauvegarde peuvent être utilisés pour créer des fichiers de données comme ci-dessus.

      public void doneSaving(ISaveContext context) {
         MyPlugin myPluginInstance = MyPlugin.getDefault();

         // supprime l'état précédent car il est devenu inutile
         int previousSaveNumber = context.getPreviousSaveNumber();
         String oldFileName = "save-" + Integer.toString(previousSaveNumber);
         File f = myPluginInstance.getStateLocation().append(oldFileName).toFile();
         f.delete();
      }

A ce point, nous nettoyons les informations de sauvegarde. Nous utilisons getPreviousSaveNumber pour extraire le numéro de sauvegarde attribué au cours de l'opération de sauvegarde précédente (pas celle que nous venons de terminer). Nous utilisons ce numéro pour élaborer le nom du fichier à supprimer. Il est à noter que nous n'utilisons pas la mappe du fichier logique de l'état de sauvegarde du fait que nous avons déjà mappé notre numéro de fichier de sauvegarde courant.

      public void rollback(ISaveContext context) {
         MyPlugin myPluginInstance = MyPlugin.getDefault();

         // l'opération d'enregistrement ayant échoué, supprime
l'état sauvegardé qui vient d'être écrit.
         int saveNumber = context.getSaveNumber();
         String saveFileName = "save-" + Integer.toString(saveNumber);
         File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
         f.delete();
      }

A ce point, nous supprimons l'état que nous venons de sauvegarder. Il est à noter que nous utilisons le numéro de sauvegarde courant pour élaborer le nom du fichier que nous venons de sauvegarder. Il n'est pas nécessaire de s'inquiéter sur le fait que nous avons mappé ce nom de fichier dans ISaveContext. La plate-forme supprime le contexte lorsqu'une opération de sauvegarde échoue.

Si votre plug-in lance une exception à n'importe quel moment du cycle de vie de sauvegarde, il sera supprimé de l'opération de sauvegarde courante et ne recevra aucune des méthodes du cycle de vie restantes. Par exemple, si votre méthode de sauvegarde échoue, vous ne recevrez pas de message d'annulation ou de succès de sauvegarde (doneSaving).

Utilisation du précédent état sauvegardé

Lorsque vous ajoutez un participant de sauvegarde à l'espace de travail, il renvoie un objet ISavedState qui décrit ce que votre plug-in a sauvegardé au cours de sa dernière opération de sauvegarde (ou null si votre plug-in n'a pas enregistré de précédent état). Cet objet peut être utilisé pour accéder aux informations à partir du fichier de sauvegarde précédent (à l'aide du numéro de sauvegarde et de la mappe du fichier) ou pour traiter les changements qui se sont produits entre les activations d'un plug-in.

Accès aux fichiers sauvegardés

Si une mappe de fichier a été utilisée pour sauvegarder des fichiers désignés logiquement en fonction du numéro de sauvegarde, cette même mappe peut être utilisée pour extraire les données du dernier état de sauvegarde connu.

   ISaveParticipant saveParticipant = new
MyWorkspaceSaveParticipant();
   ISavedState lastState =
      ResourcesPlugin.getWorkspace().addSaveParticipant(myPluginInstance, saveParticipant);

   if (lastState != null) {
      String saveFileName = lastState.lookup(new Path("save")).toString();
      File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
      // l'instance du plug-in doit lire tout état important dans le fichier.
      myPluginInstance.readStateFrom(f);
   }

Traitement des deltas de ressources entre les activations

N'oubliez pas qu'un certain nombre d'événements de changement de ressources peut se produire dans l'espace de travail avant que votre plug-in ne soit activé. Si vous souhaitez connaître les changements qui ont eu lieu depuis la désactivation de votre plug-in, vous pouvez utiliser le mécanisme de sauvegarde, même si vous n'avez pas besoin de sauvegarder d'autres données.

Le participant à la sauvegarde doit demander que la plate-forme conserve un delta des ressources en son nom. Ceci fait partie de l'opération de sauvegarde.

   public void saving(ISaveContext context) throws CoreException {
      // aucun état à enregistrer par le plug-in, mais demande d'un
      // delta de ressources pour la prochaine activation.
      context.needDelta();
   }

Au cours du démarrage du plug-in, il est possible d'accéder au précédent état sauvegardé et des événements sont créés pour tous les changements qui se sont produits depuis la dernière sauvegarde.

   ISaveParticipant saveParticipant = new
MyWorkspaceSaveParticipant();
   ISavedState lastState =
      ResourcesPlugin.getWorkspace().addSaveParticipant(myPluginInstance, saveParticipant);
   if (lastState != null) {
      lastState.processResourceChangeEvents(new MyResourceChangeReporter());
   }

La classe fournie doit implémenter IResourceChangeListener, comme décrit à la section Suivi des modifications des ressources. Les changements survenus depuis la dernière sauvegarde sont rapportés comme faisant partie de l'événement de modification des ressources POST_AUTO_BUILD.

Remarque :  Les modifications de marqueur ne sont pas rapportées dans les événements de modification stockés dans un ISavedState. Vous devez présumer que certains marqueurs ou leur totalité ont changé depuis la dernière sauvegarde de votre état.