Partecipazione al salvataggio dello spazio di lavoro

Il processo di salvataggio dello spazio di lavoro viene attivato dall'utente alla chiusura del workbench e periodicamente in altri momenti dalla piattaforma. I plugin possono essere compresi in questo processo in modo che anche i dati importanti dei plugin verranno salvati sul disco al momento del salvataggio degli altri dati persistenti dello spazio di lavoro.

Il processo di salvataggio dello spazio di lavoro può anche essere utilizzato per tracciare le modifiche che si verificano tra le diverse attivazioni del plugin.

Implementazione di un partecipante al salvataggio

Per partecipare all'operazione di salvataggio dello spazio di lavoro, è necessario aggiungere a quest'ultimo un partecipante al salvataggio. Ciò avviene generalmente durante il metodo di avvio del plugin. In questo stesso punto è possibile esaminare lo stato salvato al momento dell'ultima chiusura del plugin.

Di seguito viene illustrato un semplice plugin che descrive il processo di salvataggio.

   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'istanza del plugin deve leggere qualsiasi stato importante dal file.
         File f = getStateLocation().append(location).toFile();
         readStateFrom(f);
      }

      protected void writeImportantState(File target) {
      }
   }

ISaveParticipant definisce il protocollo per un partecipante al salvataggio dello spazio di lavoro. Gli implementatori di questa interfaccia possono fornire la funzionalità per differenti fasi del processo di salvataggio. Di seguito vengono descritte tali fasi e il modo in cui la classe WorkspaceSaveParticipant implementa ciascuna di esse.

      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();
               // salvare lo stato del plugin
               int saveNumber = context.getSaveNumber();
               String saveFileName = "save-" + Integer.toString(saveNumber);
               File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
               // se la scrittura non è corretta, viene attivata un'eccezione e il percorso non verrà aggiornato
               myPluginInstance.writeImportantState(f);
               context.map(new Path("save"), new Path(saveFileName));
               context.needSaveNumber();
               break;
            case ISaveContext.PROJECT_SAVE:
               // richiamare il progetto relativo a questa operazione di salvataggio
               IProject project = context.getProject();
               // salvare le informazioni relative, se necessario
               break;
            case ISaveContext.SNAPSHOT:
               // È necessario che questa operazione sia effettivamente rapida poiché
               // gli snapshot possono essere richiesti con frequenza
               // dallo spazio di lavoro.
               break;
         }
      }

ISaveContext descrive le informazioni relative all'operazione di salvataggio. Sono disponibili tre tipi di operazioni di salvataggio: FULL_SAVE, SNAPSHOT e PROJECT_SAVE. I partecipanti al salvataggio devono prestare attenzione ad eseguire l'elaborazione appropriata al tipo di evento di salvataggio ricevuto. Ad esempio, gli eventi snapshot possono verificarsi piuttosto frequentemente e hanno lo scopo di consentire ai plugin il salvataggio del proprio stato critico. L'impiego di molto tempo per salvare uno stato che può essere ricalcolato in caso di malfunzionamento rallenterà la piattaforma.

Per creare file di salvataggio dati denominati mediante numeri sequenziali (save-1, save-2, ecc.) viene utilizzato un numero di salvataggio. Ogni file di salvataggio è associato a un nome file logico (save) che è indipendente dal numero di salvataggio. I dati dei plugin vengono scritti nel file corrispondente e possono essere richiamati successivamente anche se non si conosce il numero dell'ultima operazione di salvataggio riuscita. Questa tecnica è stata analizzata nel codice di avvio del plugin:

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

Dopo aver salvato i dati e associato il nome file, viene richiamato needSaveNumber per comunicare che l'utente ha partecipato attivamente ad un'operazione di salvataggio dello spazio di lavoro e desidera assegnare un numero a tale attività. I numeri di salvataggio possono essere utilizzati per creare file di dati come descritto in precedenza. 

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

         // Eliminare il vecchio stato salvato dato che non è più necessario
         int previousSaveNumber = context.getPreviousSaveNumber();
         String oldFileName = "save-" + Integer.toString(previousSaveNumber);
         File f = myPluginInstance.getStateLocation().append(oldFileName).toFile();
         f.delete();
      }

In questo codice si eliminano le informazioni relative alla precedente operazione di salvataggio. Si utilizza getPreviousSaveNumber per ottenere il numero di salvataggio assegnato nella precedente operazione di salvataggio (non quella appena completata). Questo numero viene utilizzato per costruire il nome del file da eliminare. Si noti che non viene utilizzata l'associazione del file logico dello stato di salvataggio in quanto il numero del file di salvataggio corrente è stato già associato. 

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

         // poiché l'operazione di salvataggio non è riuscita, eliminare lo stato salvato appena scritto
         int saveNumber = context.getSaveNumber();
         String saveFileName = "save-" + Integer.toString(saveNumber);
         File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
         f.delete();
      }

In questo codice si elimina lo stato appena salvato. Si noti che viene utilizzato il numero di salvataggio corrente per costruire il nome del file appena salvato. Non è importante che questo nome file sia stato associato in ISaveContext. La piattaforma eliminerà il contesto quando un'operazione di salvataggio non riesce.

Se il plugin dell'utente attiva un'eccezione in un qualsiasi momento del ciclo di vita del salvataggio, verrà rimosso dall'operazione di salvataggio corrente e non riceverà nessuno dei restanti metodi del ciclo di vita. Ad esempio, se il metodo di salvataggio non riesce, non si riceverà alcun messaggio di rollback o doneSaving

Utilizzo dello stato precedentemente salvato

Quando si aggiunge un partecipante al salvataggio allo spazio di lavoro, questo restituirà un oggetto ISavedState che descrive ciò che è stato salvato dal plugin durante l'ultima operazione di salvataggio (oppure restituirà null se nessuno stato del plugin è stato salvato in precedenza). Questo oggetto può essere utilizzato per accedere alle informazioni del file di salvataggio precedente (mediante l'associazione tra file e numero di salvataggio) o per elaborare le modifiche apportate tra le varie attivazioni di un plugin.

Accesso ai file di salvataggio

Se è stata utilizzata un'associazione file per salvare i file denominati in modo logico in base al numero di salvataggio, questa stessa associazione può essere utilizzata per richiamare i dati dall'ultimo stato di salvataggio conosciuto.

   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'istanza del plugin deve leggere qualsiasi stato importante dal file.
      myPluginInstance.readStateFrom(f);
   }

Elaborazione dei delta di risorse tra le attivazioni

Ricordare che qualsiasi numero di eventi di modifica delle risorse dovrebbe verificarsi nello spazio di lavoro prima dell'attivazione del plugin. Se si desidera individuare le modifiche che sono state apportate dall'ultima disattivazione del plugin, è possibile utilizzare il meccanismo di salvataggio, anche se non si desidera salvare altri dati.

Il partecipante al salvataggio deve richiedere alla piattaforma di conservare un delta delle risorse. Ciò avviene durante l'operazione di salvataggio.

   public void saving(ISaveContext context) throws CoreException {
      // nessuno stato da salvare mediante il plugin, ma è richiesto un
      // delta delle risorse da utilizzare alla successiva attivazione.
      context.needDelta();
   }

Durante l'avvio del plugin, è possibile accedere allo stato salvato in precedenza. Verranno creati eventi di modifica per tutte le modifiche occorse a partire dall'ultimo salvataggio.

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

La classe fornita deve implementare IResourceChangeListener, come descritto in Traccia delle modifiche delle risorse. Le modifiche apportate in seguito all'ultimo salvataggio vengono segnalate come parte dell'evento di modifica delle risorse POST_AUTO_BUILD.

Nota: le modifiche di indicatori non vengono riportate negli eventi di modifica memorizzati in un ISavedState. È necessario presupporre che, a partire dall'ultimo salvataggio dello stato, siano stati modificati tutti gli indicatori o che non sia stato modificato nessuno di essi.