Die Verarbeitung für das Speichern des Arbeitsbereichs wird ausgelöst, wenn die Workbench durch den Benutzer beendet wird. Außerdem wird diese Verarbeitung in regelmäßigen Abständen durch die Plattform ausgelöst. Plug-ins können in den Prozess für die Speicherung des Arbeitsbereichs einbezogen werden, damit kritische Plug-in-Daten ebenfalls auf Platte geschrieben werden, wenn die übrigen permanenten Daten des Arbeitsbereichs gespeichert werden.
Mit dem Prozess für die Speicherung des Arbeitsbereichs können außerdem Änderungen protokolliert werden, die zwischen Aktivierungen von Plug-ins erfolgt sind.
Damit ein Element bei der Speicherung des Arbeitsbereichs berücksichtigt wird, müssen Sie einen Speicherungsteilnehmer zum Arbeitsbereich hinzufügen. Dies erfolgt normalerweise in der Startmethode des Plug-ins. Hier werden außerdem alle Statuswerte gelesen, die bei der letzten Beendigung des Plug-ins möglicherweise gespeichert wurden.
Das folgende Beispiel veranschaulicht, wie ein einfaches Plug-in den Speicherprozess integriert:
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; // Das Plug-in-Exemplar sollte alle wichtigen Statuswerte aus der Datei lesen. File f = getStateLocation().append(location).toFile(); readStateFrom(f); } protected void writeImportantState(File target) { } }
ISaveParticipant definiert das Protokoll für einen Teilnehmer an der Arbeitsbereichssicherung. Implementierungselemente dieser Schnittstelle können ein Verhalten für die unterschiedlichen Phasen des Sicherungsprozesses bereitstellen. Die einzelnen Phasen und die Implementierung dieser Schritte durch die Klasse WorkspaceSaveParticipant werden im Folgenden erläutert.
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(); // save the plug-in state int saveNumber = context.getSaveNumber(); String saveFileName = "save-" + Integer.toString(saveNumber); File f = myPluginInstance.getStateLocation().append(saveFileName).toFile(); // Falls das Schreiben fehlschlägt, wird eine Ausnahmebedingung ausgegeben und der Pfad nicht aktualisiert myPluginInstance.writeImportantState(f); context.map(new Path("save"), new Path(saveFileName)); context.needSaveNumber(); break; case ISaveContext.PROJECT_SAVE: // Projekt für diese Sicherungsoperation abrufen IProject project = context.getProject(); // Seine Informationen ggf. speichern break; case ISaveContext.SNAPSHOT: // Diese Operation muss sehr schnell sein, da durch // den Arbeitsbereich häufig Momentaufnahmen // angefordert werden. break; } }
ISaveContext beschreibt Informationen über die Sicherungsoperation. Es gibt drei Arten von Sicherungsoperationen: FULL_SAVE, SNAPSHOT und PROJECT_SAVE. Die Sicherungsteilnehmer sollten die entsprechende Verarbeitung für die empfangene Art des Sicherungsereignisses sorgfältig ausführen. Ereignisse für Momentaufnahmen können relativ häufig eintreten und sollten Plug-ins die Sicherung des kritischen Status ermöglichen. Wenn das Sichern eines Status, der im Falle eines Systemabsturzes neue berechnet werden kann, sehr lange dauert, wirkt sich dies negativ auf die Leistung der Plattform aus.
Über eine Sicherungsnummer werden Sicherungsdateien für die Daten erstellt, die mit fortlaufenden Zahlen (save-1, save-2 usw.) benannt werden. Jeder Sicherungsdatei ist ein logischer Dateiname (save) zugeordnet, der von der Sicherungsnummer unabhängig ist. Die Plug-in-Daten werden in die entsprechende Datei geschrieben und können später abgerufen werden, ohne dass hierbei die spezifische Sicherungsnummer der letzten erfolgreichen Sicherungsoperation bekannt sein muss. Diese Methode kennen Sie bereits aus dem Startcode des Plug-ins:
IPath location = lastState.lookup(new Path("save"));Nachdem die Daten gesichert wurden und der Dateiname zugeordnet worden ist, wird durch einen Aufruf von needSaveNumber angegeben, dass eine Teilnahme an der Arbeitsbereichssicherung vorlag und der Sicherungsaktivität eine Nummer zugeordnet werden soll. Anhand der Sicherungsnummer können wie oben beschrieben Datendateien erstellt werden.
public void doneSaving(ISaveContext context) { MyPlugin myPluginInstance = MyPlugin.getDefault(); // Alten Sicherungsstatus löschen, da er nicht mehr benötigt wird int previousSaveNumber = context.getPreviousSaveNumber(); String oldFileName = "save-" + Integer.toString(previousSaveNumber); File f = myPluginInstance.getStateLocation().append(oldFileName).toFile(); f.delete(); }
An dieser Stelle können die Sicherungsdaten aus der letzten Sicherungsoperation bereinigt werden. Mit getPreviousSaveNumber wird die Sicherungsnummer abgerufen, die der vorherigen (nicht der soeben abgeschlossenen!) Sicherungsoperation zugeordnet war. Anhand dieser Nummer wird der Name der Datei konstruiert, die gelöscht werden muss. Die Zuordnung der logischen Datei für den Sicherungsstatus wird hierbei nicht verwendet, da die aktuelle Nummer der Sicherungsdatei bereits zugeordnet wurde.
public void rollback(ISaveContext context) { MyPlugin myPluginInstance = MyPlugin.getDefault(); // Soeben geschriebenen Sicherungsstatus löschen, weil die Sicherungsoperation fehlgeschlagen ist int saveNumber = context.getSaveNumber(); String saveFileName = "save-" + Integer.toString(saveNumber); File f = myPluginInstance.getStateLocation().append(saveFileName).toFile(); f.delete(); }
An dieser Stelle wird der gerade gesicherte Status gelöscht. Hierbei wird die aktuelle Sicherungsnummer verwendet, um den Namen der soeben gesicherten Datei zu konstruieren. Die Tatsache, dass dieser Dateiname in ISaveContext zugeordnet wurde, ist nicht von Bedeutung. Die Plattform löscht den Kontext, wenn eine Sicherungsoperation fehlschlägt.
Falls Ihr Plug-in während des Sicherungslebenszyklus eine Ausnahmebedingung ausgibt, wird es aus der aktuellen Sicherungsoperation entfernt und erhält keine der verbleibenden Lebenszyklusmethoden. Wenn das Fehlschlagen beispielsweise während der Methode saving erfolgt, wird die Nachricht für rollback oder doneSaving nicht empfangen.
Wenn Sie einen Sicherungsteilnehmer zum Arbeitsbereich hinzufügen, gibt dieser ein Objekt ISavedState zurück. Dieses Objekt beschreibt, was während der letzten Sicherungsoperation durch das Plug-in gesichert wurde bzw. gibt null an, wenn das Plug-in noch keinen Status gesichert hat. Über dieses Objekt können Sie auf Informationen aus der vorherigen Sicherungsdatei zugreifen (mit Sicherungsnummer und Dateimaske) oder Änderungen verarbeiten, die zwischen Aktivierungen eines Plug-ins vorgenommen wurden.
Wenn eine Dateimaske verwendet wurde, um logisch benannte Dateien gemäß der Sicherungsnummer zu sichern, können Sie mit derselben Maske die Daten aus dem letzten bekannten Sicherungsstatus abrufen.
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(); // Das Plug-in-Exemplar sollte alle wichtigen Statuswerte aus der Datei lesen. myPluginInstance.readStateFrom(f); }
Wie Sie bereits wissen, können im Arbeitsbereich beliebig viele Ressourcenänderungen stattgefunden haben, bevor das Plug-in zum ersten Mal aktiviert wird. Wenn Sie wissen wollen, welche Änderungen seit der Inaktivierung des Plug-ins vorgenommen wurden, können Sie dies über den Sicherungsmechanismus ermitteln, und zwar auch dann, wenn keine anderen Daten sichern müssen.
Der Sicherungsteilnehmer muss die Anforderung ausgeben, dass die Plattform für ihn ein Ressourcendelta aufbewahrt. Dies erfolgt im Rahmen der Sicherungsoperation.
public void saving(ISaveContext context) throws CoreException { // Es soll kein Status im Plug-in gesichert, aber ein // Ressourcendelta für die nächste Aktivierung angefordert werden. context.needDelta(); }
Während des Plug-in-Starts ist ein Zugriff auf die früheren Sicherungsstatus möglich, und für alle Änderungen, die seit der letzten Sicherung vorgenommen wurden, werden Änderungsereignisse erstellt.
ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant(); ISavedState lastState = ResourcesPlugin.getWorkspace().addSaveParticipant(myPluginInstance, saveParticipant); if (lastState != null) { lastState.processResourceChangeEvents(new MyResourceChangeReporter()); }
Die zur Verfügung gestellte Klasse muss IResourceChangeListener wie in Ressourcenänderungen verfolgen beschrieben, implementieren. Die Änderungen seit der letzten Sicherung werden im Rahmen des Ereignisses POST_AUTO_BUILD für Ressourcenänderungen gemeldet.
Hinweise: Markierungsänderungen werden in den Änderungsereignissen, die in einem Objekt ISavedState gespeichert werden, nicht gemeldet. Sie müssen davon ausgehen, dass die Markierungen ganz oder teilweise seit der letzten Statussicherung geändert wurden.