O processo de salvamento do espaço de trabalho é acionado quando o workbench é encerrado pelo usuário e às vezes periodicamente pela plataforma. Os plug-ins podem participar do processo de salvamento do espaço de trabalho para que dados críticos do plug-in sejam salvos em disco toda vez que os demais dados persistentes do espaço de trabalho forem salvos.
O processo de salvamento na área de trabalho também pode ser utilizado para controlar as alterações que ocorrem entre as ativações do plug-in.
Para participar do salvamento na área de trabalho, você deve nela incluir um participante do salvamento. Geralmente, isso é feito durante o método de inicialização do plug-in. É também o local onde você lê qualquer estado que possa ter salvo durante a última vez que o plug-in foi encerrado.
Observemos um plug-in simples que demonstrará o processo de salvamento.
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; // a instância do plug-in deve ler qualquer estado importante no arquivo. File f = getStateLocation().append(location).toFile(); readStateFrom(f); } protected void writeImportantState(File target) { } }
ISaveParticipant define o protocolo de um participante do salvamento na área de trabalho. Os implementadores dessa interface podem fornecer comportamento para diferentes estágios do processo de salvamento. Observemos os estágios e como a nossa classe WorkspaceSaveParticipant implementa cada uma dessas etapas.
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(); // salvar o estado do plug-in int saveNumber = context.getSaveNumber(); String saveFileName = "save-" + Integer.toString(saveNumber); File f = myPluginInstance.getStateLocation().append(saveFileName).toFile(); // se falharmos ao gravar, uma exceção será emitida e não atualizaremos o caminho myPluginInstance.writeImportantState(f); context.map(new Path("save"), new Path(saveFileName)); context.needSaveNumber(); break; case ISaveContext.PROJECT_SAVE: // obter o projeto relacionado a esta operação de gravação IProject project = context.getProject(); // salvar suas informações, se necessário break; case ISaveContext.SNAPSHOT: // Esta operação precisa ser realmente rápida, porque // os instantâneos podem ser solicitados com freqüência pela // área de trabalho. break; } }
O ISaveContext descreve informações sobre a operação de gravação. Há três tipos de operações de gravação: FULL_SAVE, SNAPSHOT e PROJECT_SAVE. Os participantes de salvamento devem ser cautelosos para executar o processamento apropriado para o tipo de evento de gravação que eles receberam. Por exemplo, os eventos instantâneos podem ocorrer com certa freqüência e devem permitir que os plug-ins salvem seu estado crítico. Levar um grande tempo para salvar o estado que pode ser calculado novamente no caso de uma falha fará a plataforma ficar mais lenta.
Um número do salvamento é utilizado para criar arquivos de salvamento de dados que são nomeados utilizando os números seqüenciais salvamento-1, salvamento-2, etc.) Cada arquivo salvo é mapeado para um nome de arquivo lógico (salvamento), o qual não depende do número do salvamento. Os dados do plug-in são gravados no arquivo correspondente e podem ser recuperados posteriormente, sem que se saiba o número do salvamento específico da última operação de gravação bem-sucedida. Lembre-se de que vimos essa técnica no código de inicialização do nosso plug-in:
IPath location = lastState.lookup(new Path("save"));Após salvarmos nossos dados e mapearmos o nome do arquivo, chamamos needSaveNumber para indicar que participamos ativamente em um salvamento da área de trabalho e que desejamos atribuir um número à atividade de salvamento. Os números do salvamento podem ser utilizados para criar arquivos de dados, como acima.
public void doneSaving(ISaveContext context) { MyPlugin myPluginInstance = MyPlugin.getDefault(); // excluir o estado salvo anteriormente, pois ele não será mais necessário int previousSaveNumber = context.getPreviousSaveNumber(); String oldFileName = "save-" + Integer.toString(previousSaveNumber); File f = myPluginInstance.getStateLocation().append(oldFileName).toFile(); f.delete(); }
Aqui, limpamos as informações de salvamento da operação de gravação anterior. Utilizamos getPreviousSaveNumber para obter o número de salvamento que estava associado na operação de gravação anterior (não aquela que acabamos de concluir). Utilizamos esse número para construir o nome do arquivo que precisamos excluir. Observe que não utilizamos o mapa de arquivo lógico do estado de salvamento porque já mapeamos o número de nosso arquivo de salvamento atual.
public void rollback(ISaveContext context) { MyPlugin myPluginInstance = MyPlugin.getDefault(); // como a operação de gravação falhou, exclua o estado salvo que acabamos de gravar int saveNumber = context.getSaveNumber(); String saveFileName = "save-" + Integer.toString(saveNumber); File f = myPluginInstance.getStateLocation().append(saveFileName).toFile(); f.delete(); }
Aqui, excluímos o estado que acabamos de salvar. Observe que utilizamos o número do salvamento atual para formar o nome do arquivo que acabamos de salvar. Não precisamos nos preocupar com o fato de que mapeamos o nome desse arquivo para ISaveContext. A plataforma descartará o contexto quando uma operação de gravação falhar.
Se o plug-in lançar uma exceção em qualquer momento do ciclo de vida do salvamento, ele será removido da operação de gravação atual e não obterá qualquer um dos métodos restantes do ciclo de vida. Por exemplo, se você falhar durante o método saving não receberá uma mensagem de rollback ou doneSaving.
Quando incluímos um participante do salvamento na área de trabalho, ele retornará um objeto ISavedState, o qual descreve o que o plug-in salvou durante sua última operação de gravação (ou null se o plug-in não salvou nenhum estado anteriormente). Esse objeto pode ser utilizado para acessar informações do arquivo de salvamento anterior (utilizando o número do salvamento e o mapeamento do arquivo) ou para processar alterações que ocorreram entre as ativações de um plug-in.
Se o mapeamento de um arquivo foi utilizado para salvar arquivos nomeados logicamente, de acordo com o número do salvamento, esse mesmo mapeamento pode ser utilizado para recuperar os dados do último estado de salvamento conhecido.
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(); // a instância do plug-in deve ler qualquer estado importante no arquivo. myPluginInstance.readStateFrom(f); }
Lembre-se de que qualquer número de eventos de alteração de recurso poderia ocorrer na área de trabalho antes do plug-in ser ativado. Para saber quais alterações ocorreram desde a desativação do plug-in, utilize o mecanismo de salvamento, mesmo que não seja necessário salvar qualquer outro dado.
O participante do salvamento deve solicitar que a plataforma mantenha um delta de recursos em seu benefício. Isso é feito como parte da operação de gravação.
public void saving(ISaveContext context) throws CoreException { // nenhum estado a ser salvo pelo plug-in, mas solicite um // delta de recurso a ser utilizado na próxima ativação. context.needDelta(); }
Durante a inicialização do plug-in, o estado salvo anteriormente pode ser acessado e os eventos de alteração serão criados para todas as alterações ocorridas desde o último salvamento.
ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant(); ISavedState lastState = ResourcesPlugin.getWorkspace().addSaveParticipant(myPluginInstance, saveParticipant); if (lastState != null) { lastState.processResourceChangeEvents(new MyResourceChangeReporter()); }
A classe fornecida deve implementar IResourceChangeListener, conforme descrito em Monitorando alterações do recurso. As alterações desde o último salvamento são relatadas como parte do evento de alteração de recurso POST_AUTO_BUILD.
Nota: As alterações do marcador não são relatadas nos eventos de alteração armazenados em um ISavedState. Você deve assumir que todo e qualquer marcador foi alterado quando seu último estado foi salvo.