Logo Search packages:      
Sourcecode: eclipse-pydev version File versions  Download package

DeltaSaver.java

/*
 * Created on 12/10/2005
 */
package org.python.pydev.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.python.pydev.core.log.Log;

/**
 * This class can be used to work on deltas. It is able to save and restore data on a 'delta' fashion.
 * 
 * It is supposed to be used in the following way:
 * 
 * When a class needs to save a lot of data in the disk and this data is gathered in deltas, it only does the first large
 * processing and then uses this class to keep track of other changes (and from time to time, reorganizes all the data and
 * erases the deltas).
 * 
 * This object is supposed to be used by another that knows what is the data being added and how to restore that data.
 * Also, the order in which the deltas are generated is important.
 * 
 * @author Fabio
 */
00036 public class DeltaSaver<X> {
    
    /**
     * Superclass of all commands
     * 
     * @author Fabio
     */
00043     public abstract static class DeltaCommand implements Serializable{

        public transient Object data;

        public DeltaCommand(Object o) {
            this.data = o;
        }

        public abstract void processWith(IDeltaProcessor deltaProcessor);
        
        public void readData(ICallback<Object, ObjectInputStream> readFromFileMethod, ObjectInputStream in) {
            this.data = readFromFileMethod.call(in);
        }

    }

    /**
     * Delete command
     * 
     * @author Fabio
     */
00064     public static class DeltaDeleteCommand extends DeltaCommand {

        private static final long serialVersionUID = 1;

        public DeltaDeleteCommand(Object o) {
            super(o);
        }

        @SuppressWarnings("unchecked")
        public void processWith(IDeltaProcessor deltaProcessor){
            deltaProcessor.processDelete(data);
        }

    }

    
    /**
     * Insert command
     * 
     * @author Fabio
     */
00085     public static class DeltaInsertCommand extends DeltaCommand{

        private static final long serialVersionUID = 1;

        public DeltaInsertCommand(Object o) {
            super(o);
        }
        
        @SuppressWarnings("unchecked")
        public void processWith(IDeltaProcessor deltaProcessor){
            deltaProcessor.processInsert(data);
        }
    }
    
    
    /**
     * Update command
     * 
     * @author Fabio
     */
00105     public static class DeltaUpdateCommand extends DeltaCommand{
        
        private static final long serialVersionUID = 1;
        
        public DeltaUpdateCommand(Object o) {
            super(o);
        }
        
        @SuppressWarnings("unchecked")
        public void processWith(IDeltaProcessor deltaProcessor){
            deltaProcessor.processUpdate(data);
        }
    }

    /**
     * Directory where the deltas should be saved / restored.
     */
00122     private File dirToSaveDeltas;
    
    /**
     * This is equal to '.'+extension
     */
00127     private String suffix;

    /**
     * List of commands
     */
00132     private List<DeltaCommand> commands;
    
    /**
     * Used to keep track of a number to use to save the command
     */
00137     private int nCommands;

    /**
     * This is the method that should read the data in the delta from a file... This is because of the &*(^%EO way eclipse handles this kind of stuff,
     * so, we can't just serialize it from another plugin.
     */
00143     private ICallback<Object, ObjectInputStream> readFromFileMethod;
    
    /**
     * @param dirToSaveDeltas this is the directory where the deltas should be saved
     * @param extension this is the extension that should be given to the deltas
     */
00149     public DeltaSaver(File dirToSaveDeltas, String extension, ICallback<Object, ObjectInputStream> readFromFileMethod) {
        this.dirToSaveDeltas = dirToSaveDeltas;
        this.suffix = "."+extension;
        this.commands = Collections.synchronizedList(new ArrayList<DeltaCommand>());
        this.readFromFileMethod = readFromFileMethod;
        validateDir();
        loadDeltas();
    }


    /**
     * Checks if the dir is correct
     */
00162     private void validateDir() {
        if(this.dirToSaveDeltas.exists() == false){
            throw new RuntimeException("The path passed to save / restore deltas does not exist ("+dirToSaveDeltas+")");
        }
        if(this.dirToSaveDeltas.isDirectory() == false){
            throw new RuntimeException("The path passed to save / restore deltas is not actually a directory ("+dirToSaveDeltas+")");
        }
    }

    /**
     * Gets existing deltas in the disk
     */
00174     private void loadDeltas() {
      synchronized(this.commands){
              ArrayList<File> deltasFound = findDeltas();
              for (File file : deltasFound) {
                  try {
                      DeltaCommand cmd = (DeltaCommand) IOUtils.readFromFile(file, this.readFromFileMethod);
                      if(cmd != null && cmd.data != null){
                        addRestoredCommand(cmd);
                      }
                  } catch (Exception e) {
                      Log.log(e);
                  }
              }
      }
        
    }

    /**
     * @return a list of files with all the deltas in the dir we are acting upon
     */
00194     private ArrayList<File> findDeltas() {
        ArrayList<File> deltasFound = new ArrayList<File>();
        File[] files = this.dirToSaveDeltas.listFiles();
        for (File file : files) {
            if(file.exists() && file.isFile() && file.getName().endsWith(suffix)){
                deltasFound.add(file);
            }
        }
        //also, sort by the name (which must be an integer)
        Collections.sort(deltasFound, new Comparator<File>(){

            public int compare(File o1, File o2) {
                String i = FullRepIterable.headAndTail(o1.getName())[0];
                String j = FullRepIterable.headAndTail(o2.getName())[0];
                return new Integer(i).compareTo(new Integer(j));
            }}
        );
        return deltasFound;
    }

    /**
     * Adds some command (adds to list and NOT to the disk)
     * 
     * @param command the command found in the disk
     */
00219     private void addRestoredCommand(DeltaCommand command) {
        this.commands.add(command);
    }
    
    /**
     * Adds some command (adds to list and to the disk)
     * 
     * @param command the command to be added
     */
00228     public void addCommand(DeltaCommand command) {
      synchronized(this.commands){
              File file = new File(this.dirToSaveDeltas, nCommands+suffix);
              nCommands++;
              try {
                  file.createNewFile();
              } catch (IOException e) {
                  throw new RuntimeException(e);
              }
              //always write the command and its data separately
              IOUtils.writeToFile(command, command.data, file);
              this.commands.add(command);
      }
    }

    /**
     * @return the number of available deltas
     */
00246     public int availableDeltas() {
      synchronized(this.commands){
            return this.commands.size();
      }
    }

    /**
     * Clears all deltas in the disk (and in memory... also restarts numbering the deltas)
     */
00255     public void clearAll() {
        ArrayList<File> deltas = findDeltas();
        for (File file : deltas) {
            if(file.exists()){
                  file.delete();
            }
        }
        this.commands.clear();
        nCommands = 0;
    }

    public void addInsertCommand(X o) {
        addCommand(new DeltaInsertCommand(o));
    }

    public void addDeleteCommand(X o) {
        addCommand(new DeltaDeleteCommand(o));
    }

    public void addUpdateCommand(X o) {
        addCommand(new DeltaUpdateCommand(o));
    }

    /**
     * Passes the current deltas to the delta processor.
     */
00281     public void processDeltas(IDeltaProcessor<X> deltaProcessor) {
      synchronized(this.commands){
                  boolean processed = false;
              for (DeltaCommand cmd : this.commands) {
                  try {
                              cmd.processWith(deltaProcessor);
                              processed = false;
                        } catch (Exception e) {
                              Log.log(e);
                        }
              }
              if(processed){
                  //if nothing happened, we don't end the processing (no need to do it)
                  deltaProcessor.endProcessing();
              }
              this.clearAll();
      }
    }

}



class IOUtils {
    public static void writeToFile(Object o1, Object o2, File file) {
        try {
            OutputStream out = new FileOutputStream(file);
            try {
                ObjectOutputStream stream = new ObjectOutputStream(out);
                stream.writeObject(o1);
                stream.writeObject(o2);
                stream.close();
            } catch (Exception e) {
                Log.log(e);
                throw new RuntimeException(e);
            } finally{
                out.close();
            }
        } catch (Exception e) {
            Log.log(e);
        }
    }

    /**
     * @param astOutputFile
     * @param readFromFileMethod 
     * @return
     */
    public static Object readFromFile(File astOutputFile, ICallback<Object, ObjectInputStream> readFromFileMethod) {
        try {
            boolean deletFile = false;
            //the file is not even there
            if(!astOutputFile.exists()){
                  return null;
            }
            InputStream input = new FileInputStream(astOutputFile);
            ObjectInputStream in = new ObjectInputStream(input);
            DeltaSaver.DeltaCommand o = null;
            try {
                        o = (DeltaSaver.DeltaCommand) in.readObject();
                        o.readData(readFromFileMethod, in);
            } catch (Exception e) {
                  //the format has changed (no real problem here... just erase the file)
                  deletFile = true;
                  o = null;
                  } finally {
                        in.close();
                        input.close();
                  }
                  if(deletFile){
                        if(astOutputFile.exists()){
                              astOutputFile.delete();
                        }
                  }
            return o;
        } catch (Exception e) {
            Log.log(e); 
            return null;
        }
    }

}

Generated by  Doxygen 1.6.0   Back to index