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.
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.
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.
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); }
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.