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.