Συστατικό στοιχείο συμμετοχής αποθήκευσης χώρου εργασίας

Η επεξεργασία αποθήκευσης χώρου εργασίας ενεργοποιείται αυτόματα κατά τον τερματισμό λειτουργίας του πάγκου εργασίας από το χρήστη και περιοδικά από την πλατφόρμα.  Οι πρόσθετες λειτουργίες μπορούν να συμμετέχουν στη διεργασία αποθήκευσης χώρου εργασίας έτσι ώστε τα κρίσιμα δεδομένα πρόσθετης λειτουργίας να αποθηκεύονται στο δίσκο όταν αποθηκεύονται τα υπόλοιπα μόνιμα δεδομένα του χώρου εργασίας.

Η διεργασία αποθήκευσης χώρου εργασίας μπορεί επίσης να χρησιμοποιηθεί για την παρακολούθηση αλλαγών οι οποίες προκύπτουν ανάμεσα στις ενεργοποιήσεις της πρόσθετης λειτουργίας σας.

Υλοποίηση ενός συστατικού στοιχείου συμμετοχής αποθήκευσης

Για να συμμετέχετε στην αποθήκευση του χώρου εργασίας, πρέπει να προσθέσετε ένα συστατικό στοιχείο συμμετοχής αποθήκευσης στο χώρο εργασίας. Αυτό γίνεται συνήθως κατά τη διάρκεια της μεθόδου εκκίνησης της πρόσθετης λειτουργίας σας.Επίσης σε αυτό το σημείο ενημερώνεστε για οποιαδήποτε κατάσταση ενδεχομένως έχετε αποθηκεύσει κατά τον τελευταίο τερματισμό της πρόσθετης λειτουργίας σας.

Ας ρίξουμε μια ματιά σε μια απλή πρόσθετη λειτουργία η οποία παρουσιάζει τη διεργασία αποθήκευσης.

   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;
      // the plugin instance should read any important state from the file.
         File f = getStateLocation().append(location).toFile();
         readStateFrom(f);
      }

      protected void writeImportantState(File target) {
      }
   }

η διασύνδεση ISaveParticipant ορίζει το πρωτόκολλο για το συστατικό στοιχείο συμμετοχής αποθήκευσης. Οι υλοποιητές αυτής της διασύνδεσης μπορούν να παρέχουν συμπεριφορά για διαφορετικά στάδια της διεργασίας αποθήκευσης.  Ας δούμε όμως τα στάδια αυτά και τον τρόπο με τον οποίο η κλάση WorkspaceSaveParticipant υλοποιεί κάθε ένα από αυτά τα βήματα.

      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();
               // if we fail to write, an exception is thrown and we do not update the path
               myPluginInstance.writeImportantState(f);
               context.map(new Path("save"), new Path(saveFileName));
               context.needSaveNumber();
      break;
            case ISaveContext.PROJECT_SAVE:
               // get the project related to this save operation
               IProject project = context.getProject();
               // save its information, if necessary
      break;
            case ISaveContext.SNAPSHOT:
               // This operation needs to be really fast because
               // snapshots can be requested frequently by the
               // workspace.
      break;
         }
      }

Η διασύνδεση ISaveContext περιγράφει πληροφορίες σχετικά με τη λειτουργία αποθήκευσης.   Υπάρχουν τρια είδη λειτουργιών αποθήκευσης:  FULL_SAVE, SNAPSHOT, και PROJECT_SAVE.  Τα συστατικά στοιχεία συμμετοχής αποθήκευσης θα πρέπει να μεριμνούν ώστε να εκτελούν την κατάλληλη επεξεργασία για το είδος του συμβάντος αποθήκευσης που λαμβάνουν.  Για παράδειγμα, αρκετά συχνά ενδέχεται να προκύπτουν συμβάντα τμημάτων κώδικα τα οποία προορίζονται να επιτρέπουν στις πρόσθετες λειτουργίες την αποθήκευση της κρίσιμης κατάστασής τους.  Μια μεγάλης διάρκειας αποθήκευση κατάστασης, που μπορεί να υπολογιστεί εκ νέου σε περίπτωση τερματισμού λειτουργίας, επιβραδύνει την πλατφόρμα.

Ένας αριθμός αποθήκευσης χρησιμοποιείται για τη δημιουργία αρχείων αποθήκευσης δεδομένων τα οποία ονομάζονται με χρήση διαδοχικών αριθμών (save-1, save-2, κλπ.)  Κάθε αρχείο αποθήκευσης αντιστοιχίζεται με ένα λογικό όνομα αρχείου (save) το οποίο είναι ανεξάρτητο από τον αριθμό αποθήκευσης. Τα δεδομένα πρόσθετης λειτουργίας εγγράφονται στο αντίστοιχο αρχείο και μπορεί να ανακτηθούν αργότερα χωρίς να γνωρίζετε απαραίτητα τον ειδικό αριθμό αποθήκευσης της τελευταίας επιτυχημένης αποθήκευσης.  Να θυμάστε ότι είδαμε τη συγκεκριμένη τεχνική στον κώδικα εκκίνησης πρόσθετης λειτουργίας:

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

Αφού αποθηκεύσουμε τα δεδομένα μας και αντιστοιχίσουμε το όνομα αρχείου, καλούμε το needSaveNumber για να υποδηλώσει ότι έχουμε συμμετάσχει ενεργά στην αποθήκευση του χώρου εργασίας και επιθυμούμε να αναθέσουμε έναν αριθμό στη δραστηριότητα αποθήκευσης. Οι αριθμοί αποθήκευσης μπορούν να χρησιμοποιηθούν για τη δημιουργία αρχείων δεδομένων όπως είδαμε παραπάνω. 

      public void doneSaving(ISaveContext context) {
         MyPlugin myPluginInstance = MyPlugin.getDefault();

         // delete the old saved state since it is not necessary anymore
         int previousSaveNumber = context.getPreviousSaveNumber();
         String oldFileName = "save-" + Integer.toString(previousSaveNumber);
         File f = myPluginInstance.getStateLocation().append(oldFileName).toFile();
         f.delete();
      }

Εδώ, κάνουμε εκκαθάριση των πληροφοριών αποθήκευσης από την προηγούμενη λειτουργία αποθήκευσης.  Χρησιμοποιούμε το getPreviousSaveNumber για να λάβουμε τον αριθμό αποθήκευσης που ανατέθηκε στην προηγούμενη λειτουργία αποθήκευσης (όχι αυτόν που μόλις συμπληρώσαμε).  Χρησιμοποιούμε αυτόν τον αριθμό για να κατασκευάσουμε το όνομα του αρχείου που θέλουμε να διαγράψουμε.  Σημειώστε ότι δεν θα πρέπει να χρησιμοποιούμε το χάρτη αντιστοίχισης λογικού αρχείου της κατάστασης αποθήκευσης αφού έχουμε ήδη αντιστοιχίσει τον τρέχοντα αριθμό αρχείου αποθήκευσης. 

      public void rollback(ISaveContext context) {
         MyPlugin myPluginInstance = MyPlugin.getDefault();

         // since the save operation has failed, delete the saved state we have just written
         int saveNumber = context.getSaveNumber();
         String saveFileName = "save-" + Integer.toString(saveNumber);
      File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
         f.delete();
      }

Στο σημείο αυτό, διαγράφουμε την κατάσταση που μόλις αποθηκεύσαμε.  Σημειώστε ότι χρησιμοποιούμε τον τρέχοντα αριθμό αποθήκευσης προκειμένου να κατασκευάσουμε το όνομα αρχείου που μόλις αποθηκεύσαμε.  Δεν θα πρέπει να μας ανησυχεί το γεγονός ότι αντιστοιχίσαμε αυτό το όνομα αρχείου μέσα στη διασύνδεση ISaveContext. Η πλατφόρμα απορρίπτει το περιεχόμενο όταν η λειτουργία αποθήκευσης αποτυγχάνει.

Αν η πρόσθετη λειτουργία σας προκαλέσει ανά πάσα στιγμή μια εξαίρεση κατά τη διάρκεια του κύκλου ζωής αποθήκευσης, αυτή θα αφαιρεθεί από την τρέχουσα λειτουργία αποθήκευσης και δεν θα λάβει καμία από τις εναπομείνουσες μεθόδους κύκλου ζωής.  Για παράδειγμα, αν αποτύχετε κατά τη διάρκεια της μεθόδου saving, δεν θα λάβετε το μήνυμα rollback ή doneSaving

Χρήση μιας κατάστασης που αποθηκεύτηκε προηγουμένως

Όταν προσθέτετε ένα συστατικό στοιχείο συμμετοχής στο χώρο εργασίας, αυτό επιστρέφει ένα αντικείμενο ISavedState, το οποίο περιγράφει τι αποθηκεύτηκε από την πρόσθετη λειτουργίας σας κατά την τελευταία λειτουργία αποθήκευσης (ή null αν η πρόσθετη λειτουργία σας δεν έχει προηγουμένως αποθηκεύσει κάποια κατάσταση). Το αντικείμενο αυτό μπορεί να χρησιμοποιηθεί για την πρόσβαση σε πληροφορίες από το προηγούμενο αρχείο αποθήκευσης (με χρήση του αριθμού αποθήκευσης και της αντιστοίχισης αρχείου) ή την πρόσβαση σε αλλαγές που προέκυψαν μεταξύ των ενεργοποιήσεων μιας πρόσθετης λειτουργίας.

Πρόσβαση στα αρχεία αποθήκευσης

Αν η αντιστοίχιση αρχείου χρησιμοποιήθηκε για την αποθήκευση των λογικά ονομασμένων αρχείων με βάση τον αριθμό αποθήκευσης, μπορείτε να χρησιμοποιήσετε την ίδια αντιστοίχιση προκειμένου να ανακτήσετε τα δεδομένα από την τελευταία γνωστή κατάσταση αποθήκευσης.

   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();
      // the plugin instance should read any important state from the file.
      myPluginInstance.readStateFrom(f);
   }

Επεξεργασία τροποποιημένων στοιχείων πόρου μεταξύ ενεργοποιήσεων

Θυμηθείτε ότι, πριν από την ενεργοποίηση της πρόσθετης λειτουργίας σας, στο χώρο εργασίας μπορεί να προκύψει ένας οποιοσδήποτε αριθμός συμβάντων αλλαγής πόρου. Αν θέλετε να γνωρίζετε ποιές αλλαγές έχουν προκύψει από την απενεργοποίηση της πρόσθετης λειτουργίας σας, μπορείτε να χρησιμοποιήσετε για αυτό το λόγο το μηχανισμό αποθήκευσης, ακόμα και εάν δεν χρειάζεται να αποθηκεύσετε οποιαδήποτε άλλα δεδομένα.

Το συστατικό στοιχείο συμμετοχής αποθήκευσης πρέπει να ζητήσει από την πλατφόρμα τη διατήρηση των τροποιημένων στοιχείων πόρου για λογαριασμό του. Αυτό γίνεται ως τμήμα της λειτουργίας αποθήκευσης.

   public void saving(ISaveContext context) throws CoreException {
      // no state to be saved by the plug-in, but request a
      // resource delta to be used on next activation.
      context.needDelta();
   }

Κατά την εκκίνηση της πρόσθετης λειτουργίας, μπορείτε να αποκτήσετε πρόσβαση στην προηγούμενη αποθηκευμένη κατάσταση οπότε και θα δημιουργηθούν συμβάντα αλλαγής για όλες τις αλλαγές που προέκυψαν από την τελευταία αποθήκευση.

   ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant();
   ISavedState lastState =
      ResourcesPlugin.getWorkspace().addSaveParticipant(myPluginInstance, saveParticipant);
   if (lastState != null) {
      lastState.processResourceChangeEvents(new MyResourceChangeReporter());
   }

Η παρεχόμενη κλάση πρέπει να υλοποιεί τη διασύνδεση IResourceChangeListener, όπως περιγράφεται στην ενότητα Παρακολούθηση αλλαγών πόρου.  Οι αλλαγές που πραγματοποιήθηκαν από την τελευταία αποθήκευση αναφέρονται ως τμήμα του συμβάντος αλλαγής πόρου POST_AUTO_BUILD.

Σημείωση:  Οι αλλαγές δείκτη δεν αναφέρονται σε όσα συμβάντα αλλαγής αποθηκεύονται σε ένα ISavedState. Πρέπει να υποθέσετε ότι οποιοσδήποτε ή όλοι οι δείκτες έχουν αλλάξει από την αποθήκευση της τελευταίας σας κατάστασης.