All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.duracloud.sync.mgmt.ChangedList Maven / Gradle / Ivy

There is a newer version: 8.1.0
Show newest version
/*
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 *     http://duracloud.org/license/
 */
package org.duracloud.sync.mgmt;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.lang3.event.EventListenerSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The list of files which have been changed.
 *
 * @author: Bill Branan
 * Date: Mar 15, 2010
 */
public class ChangedList {

    private static final Logger log = LoggerFactory.getLogger(ChangedList.class);
    private LinkedHashMap fileList;
    private LinkedHashMap reservedFiles;
    private ExecutorService executorService;
    private long listVersion;
    private boolean shutdown = false;

    private static ChangedList instance;

    private EventListenerSupport listeners;

    public static synchronized ChangedList getInstance() {
        if(instance == null) {
            instance = new ChangedList();
        }
        return instance;
    }

    private ChangedList() {
        fileList = new LinkedHashMap();
        reservedFiles = new LinkedHashMap();
        listVersion = 0;
        listeners =
            new EventListenerSupport(ChangedListListener.class);
        this.executorService = Executors.newSingleThreadExecutor();
    }

    /**
     * Adds a changed file to the list of items to be processed.
     * Note that only the most current update to any given file is
     * provided to the change processor.
     *
     * @param changedFile a file which has changed on the file system
     */
    public void addChangedFile(final File changedFile) {
        if(null != changedFile){
            addChangedFile(new ChangedFile(changedFile));
        }else{
            log.warn("The changedFile parameter was unexpectedly null. Ignored.");
        }
    }

    /**
     * Gets the current size of the changed list
     * @return the size of the list
     */
    public int getListSize() {
        return fileList.size();
    }
    
    /**
     * Gets the current size of the changed list included the files that have been reserved
     * @return the size of the list
     */
    public int getListSizeIncludingReservedFiles() {
        return fileList.size() + reservedFiles.size();
    }

    protected synchronized void addChangedFile(ChangedFile changedFile) {
        fileList.put(changedFile.getFile().getAbsolutePath(), changedFile);
        incrementVersion();
        fireChangedEvent();
    }

    protected void fireChangedEvent() {
        listeners.fire().listChanged(this);
    }

    protected void fireChangedEventAsync() {
        this.executorService.execute(new Runnable(){
            @Override
            public void run() {
                fireChangedEvent();
            }
        });
    }

    public void addListener(ChangedListListener listener){
        this.listeners.addListener(listener);
    }

    public void removeListener(ChangedListListener listener){
        this.listeners.removeListener(listener);
    }

    /**
     * Removes all files from the changed list.
     */
    public synchronized void clear(){
        fileList.clear();
        reservedFiles.clear();
        fireChangedEvent();
    }

    /**
     * Retrieves a changed file for processing and removes it from the list of unreserved
     * files.  
     * Returns null if there are no changed files in the list.
     *
     * @return a file which has changed on the file system
     */
    public synchronized ChangedFile reserve() {
        if(fileList.isEmpty() || shutdown) {
            return null;
        }

        String key = fileList.keySet().iterator().next();
        ChangedFile changedFile = fileList.remove(key);
        reservedFiles.put(key, changedFile);
        incrementVersion();
        fireChangedEventAsync();
        return changedFile;
    }

    private void incrementVersion() {
        if(listVersion < Long.MAX_VALUE) {
            listVersion++;
        } else {
            listVersion = 0;
        }
    }

    public long getVersion() {
        return listVersion;
    }

    /**
     * Writes out the current state of the ChangeList to the given file.
     *
     * @param persistFile file to write state to
     * @return the version ID of the ChangedList which was persisted
     */
    public  long persist(File persistFile) {
        try {
            FileOutputStream fileStream = new FileOutputStream(persistFile);
            ObjectOutputStream oStream = new ObjectOutputStream((fileStream));

            long persistVersion;
            Map fileListCopy;
            synchronized(this) {
                fileListCopy = (Map)fileList.clone();
                fileListCopy.putAll(reservedFiles);
                persistVersion = listVersion;
            }

            oStream.writeObject(fileListCopy);
            oStream.close();
            return persistVersion;
        } catch(IOException e) {
            throw new RuntimeException("Unable to persist File Changed List:" +
                e.getMessage(), e);
        }
    }

    /**
     * Restores the state of the ChangedList using the given backup file
     *
     * @param persistFile file containing previous state
     * @param contentDirs content directories currently configured.
     */
    public synchronized void restore(File persistFile, List contentDirs) {
        try {
            FileInputStream fileStream = new FileInputStream(persistFile);
            ObjectInputStream oStream = new ObjectInputStream(fileStream);

            synchronized(this) {
                fileList = (LinkedHashMap) oStream.readObject();

                //remove files in change list that are not in the content dir list.
                if (contentDirs != null && !contentDirs.isEmpty()) {

                    Iterator> entries =
                        fileList.entrySet().iterator();
                    while (entries.hasNext()) {
                        Entry entry = entries.next();
                        ChangedFile file = entry.getValue();
                        boolean watched = false;
                        for (File contentDir : contentDirs) {
                            if (file.getFile()
                                    .getAbsolutePath()
                                    .startsWith(contentDir.getAbsolutePath())) {
                                watched = true;
                                break;
                            }
                        }

                        if (!watched) {
                            entries.remove();
                        }
                    }
                }
            }
            oStream.close();
        } catch(Exception e) {
            throw new RuntimeException("Unable to restore File Changed List:" +
                e.getMessage(), e);
        }
    }
    

    public synchronized List peek(int maxFiles){
        List files = new LinkedList();
        Iterator> it = this.fileList.entrySet().iterator();
        int count = 0;
        while(it.hasNext() && count < maxFiles) {
            files.add(it.next().getValue().getFile());
            count++;
        }
        return files;
    }

    synchronized void  remove(ChangedFile changedFile) {
       this.reservedFiles.remove(getKey(changedFile));
    }
    
    synchronized void  unreserve(ChangedFile changedFile){
        ChangedFile removedFile = this.reservedFiles.remove(getKey(changedFile));
        if(removedFile != null){
            addChangedFile(removedFile);
        }
    }

    private String getKey(ChangedFile changedFile) {
        return changedFile.getFile().getAbsolutePath();
    }

    public void shutdown() {
        executorService.shutdown();
        shutdown = true;
        ChangedList.instance = null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy