Participação na salvaguarda do espaço de trabalho

O processamento de salvaguarda do espaço de trabalho é desencadeado quando a área de trabalho é encerrada pelo utilizador e noutras alturas periodicamente pela plataforma.  Os plug-ins podem participar no processo de salvaguarda do espaço de trabalho de modo a que os dados críticos de plug-in sejam guardados em disco sempre que forem guardados os restantes dados persistentes do espaço de trabalho.

O processamento de salvaguarda do espaço de trabalho também pode ser usado para acompanhar alterações que ocorram entre activações do plug-in.

Implementar um participante na salvaguarda

Para participar na salvaguarda do espaço de trabalho, é necessário adicionar um participante na salvaguarda ao espaço de trabalho. Tal realiza-se geralmente durante o método de arranque do plug-in.   É também aqui que se lêem estados que se podem ter guardado aquando do último encerramento do plug-in.

Vejamos um simples plug-in para demonstrar o processo de salvaguarda.

   package com.exemplo.participantesalvaguarda;

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

   public class oMeuPlugin extends Plugin {
      private static oMeuPlugin plugin;

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

      public static oMeuPlugin 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;
         // a instância de plug-in deve ler qualquer estado importante do ficheiro.
         File f = getStateLocation().append(location).toFile();
         readStateFrom(f);
      }

      protected void writeImportantState(File target) {
      }
   }

O ISaveParticipant define o protocolo para um participante na salvaguarda do espaço de trabalho. Os implementadores desta interface podem facultar comportamento para diferentes fases do processo de salvaguarda.   Vejamos as fases e como a classe WorkspaceSaveParticipant implementa cada um destes passos.

      public void prepareToSave(ISaveContext context) throws CoreException {
      }
   public void saving(ISaveContext context) throws CoreException {
         switch (context.getKind()) {
            case ISaveContext.FULL_SAVE:
         oMeuPlugin aMinhaInstânciaPlugin =  oMeuPlugin.getDefault();
               // guardar o estado do plug-in
               int saveNumber = context.getSaveNumber();
         String saveFileName = "save-" + Integer.toString(saveNumber);
               File f = aMinhaInstânciaPlugin.getStateLocation().append(saveFileName).toFile();
               // se a escrita falhar, é devolvida uma excepção e não actualizamos o caminho
               aMinhaInstânciaPlugin.writeImportantState(f);
               context.map(new Path("save"), new Path(saveFileName));
               context.needSaveNumber();
      break;
            case ISaveContext.PROJECT_SAVE:
               // obter o projecto relacionado com esta operação de salvaguarda
               IProject project = context.getProject();
               // guardar as suas informações, se necessário
      break;
            case ISaveContext.SNAPSHOT:
               // Esta operação precisa de ser muito rápida porque
               // podem ser frequentemente pedidos instantâneos pelo
               // espaço de trabalho.
      break;
         }
      }

O ISaveContext descreve informações sobre a operação de salvaguarda.   Há três tipos de operações de salvaguarda:   FULL_SAVE, SNAPSHOT e PROJECT_SAVE. Os participantes na salvaguarda devem ter cuidado ao realizar o processamento apropriado ao tipo de evento de salvaguarda que receberam.  Por exemplo, podem ocorrer eventos de instantâneo com frequência e destinam-se a permitir aos plug-ins guardarem o seu estado crítico  Demorar muito tempo a guardar estado que pode ser recalculado em caso de avaria irá atrasar a plataforma.

É utilizado um número de salvaguarda para criar ficheiros de salvaguarda de dados que são denominados save-1, save-2, etc.) Cada ficheiro de salvaguarda é correlacionado com um nome de ficheiro lógico (save) que é independente do número de salvaguarda. Os dados de plug-in são escritos no ficheiro correspondente e podem ser obtidos mais tarde sem conhecimento do número de salvaguarda específico da última operação de salvaguarda bem sucedida.   Lembre-se que vimos esta técnica no   código de arranque do nosso plug-in:

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

Depois de guardar os dados e correlacionar o nome do ficheiro, chamamos needSaveNumber para indicar que participámos activamente numa salvaguarda de espaço de trabalho e queremos atribuir um número à actividade de salvaguarda. Os números de salvaguarda podem ser utilizados para criar ficheiros de dados como se descreve supra.  

      public void doneSaving(ISaveContext context) {
         oMeuPlugin aMinhaInstânciaPlugin =  oMeuPlugin.getDefault();

         // eliminar o antigo estado guardado dado que já não é necessário
         int previousSaveNumber = context.getPreviousSaveNumber();
         String oldFileName = "save-" + Integer.toString(previousSaveNumber);
         File f = aMinhaInstânciaPlugin.getStateLocation().append(oldFileName).toFile();
         f.delete();
      }

Aqui limpamos as informações de salvaguarda da anterior operação de salvaguarda.  Utilizamos getPreviousSaveNumber para obter o número da salvaguarda que foi atribuído na operação de salvaguarda anterior (e não daquela que acabámos de concluir).  Utilizamos este número para construir o nome do ficheiro que temos de eliminar.  Repare que não utilizamos a correlação com o ficheiro lógico do estado de salvaguarda dado que já correlacionámos o nosso actual número de ficheiro de salvaguarda.  

      public void rollback(ISaveContext context) {
         oMeuPlugin aMinhaInstânciaPlugin =  oMeuPlugin.getDefault();

         // dado que a operação de salvaguarda falhou, eliminar o estado guardado que acabámos de escrever
         int saveNumber = context.getSaveNumber();
         String saveFileName = "save-" + Integer.toString(saveNumber);
               File f = aMinhaInstânciaPlugin.getStateLocation().append(saveFileName).toFile();
         f.delete();
      }

Aqui eliminamos o estado que acabámos de guardar.  Repare que utilizamos o actual número de salvaguarda para construir o nome do ficheiro que acabámos de guardar.   Não temos de nos preocupar com o facto de que correlacionámos este nome de ficheiro com ISaveContext. A plataforma irá descartar o contexto quando uma operação de salvaguarda falhar.

Se o plug-in devolver uma excepção em qualquer altura durante o ciclo de vida da salvaguarda, será removido da actual operação de salvaguarda e não poderá obter nenhum dos métodos do ciclo de vida restante.  Por exemplo, se falhar durante o método saving, não receberá nenhuma mensagem de rollback nem doneSaving.  

Utilizar estado guardado anteriormente

Ao adicionar um participante de salvaguarda ao espaço de trabalho, este devolve um objecto ISavedState, o qual descrebe o que o plug-in guardou durante a última operação de salvaguarda (ou null se o plug-in não tiver guardado estado algum). Este objecto pode ser usado para aceder a informações do anterior ficheiro de salvaguarda (através do número de salvaguarda e da correlação de ficheiros) ou para processar alterações que tenham ocorrido entre activações de um plug-in.

Aceder a ficheiros de salvaguarda

Se tiver sido usada uma correlação de ficheiros para guardar ficheiros denominados logicamente segundo o número de salvaguarda, esta mesma correlação poderá ser usada para obter os dados do último estado de salvaguarda conhecido.

   ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant();
   ISavedState lastState =
      ResourcesPlugin.getWorkspace().addSaveParticipant(aMinhaInstânciaPlugin, saveParticipant);

   if (lastState != null) {
      String saveFileName = lastState.lookup(new Path("save")).toString();
               File f = aMinhaInstânciaPlugin.getStateLocation().append(saveFileName).toFile();
         // a instância de plug-in deve ler qualquer estado importante do ficheiro.
      aMinhaInstânciaPlugin.readStateFrom(f);
   }

Processar deltas de recursos entre activações

Recorde que podem ocorrer quaisquer eventos de alteração a recursos no espaço de trabalho antes de o plug-in começar por ser activado. Se quiser saber que alterações ocorreram desde que o plug-in foi desactivado, poderá utilizar o mecanismo de salvaguarda para o fazer, mesmo que não precise de guardar mais dados nenhuns.

O participante na salvaguarda deve pedir que a plataforma mantenha um delta de recursos em seu nome. Tal realiza-se como parte da operação de salvaguarda.

   public void saving(ISaveContext context) throws CoreException {
      // não há estado para guardar com o plug-in, mas pede-se um
      // delta de recursos para utilizar na próxima activação.
      context.needDelta();
   }

Durante o arranque do plug-in, o anterior estado guardado pode ser acedido e serão criados eventos de alteração para todas as alterações que tenham ocorrido desde a última salvaguarda.

   ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant();
   ISavedState lastState =
      ResourcesPlugin.getWorkspace().addSaveParticipant(aMinhaInstânciaPlugin, saveParticipant);
   if (lastState != null) {
      lastState.processResourceChangeEvents(new oMeuRelatorAlteraçãoRecurso());
   }

A classe facultada deve implementar IResourceChangeListener, como se descreve em Acompanhar alterações a recursos. As alterações desde a última salvaguarda sãom reportadas como parte do evento de alteração a recursos POST_AUTO_BUILD.

Nota:  As alterações a marcadores não são reportadas nos eventos de alteração armazenados em ISavedState. Terá de partir do princípio de que alguns ou todos os marcadores foram alterados desde a última salvaguarda de estado.