/*******************************************************************************
* Copyright (c) 2010- Association for Decentralized Information Management in
* Industry THTH ry.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
*******************************************************************************/
package org.simantics.databoard.accessor.impl;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* DirectoryWatch monitors a directory for file additions / removals.
*
* DirectoryWatch is used in the long wait for WatchService.
*
* @author Toni Kalajainen
*/
public class DirectoryWatch {
public static final long POLL_INTERVAL = 10000; // seconds
Timer timer;
FileFilter filter;
File directory;
List knownFiles;
CopyOnWriteArrayList listeners = new CopyOnWriteArrayList();
TimerTask task = new TimerTask() {
public void run() {
poll();
}
};
public DirectoryWatch(File directory, FileFilter filter) {
this.directory = directory;
this.filter = filter;
knownFiles = readFiles();
timer = new Timer(directory.toString()+" watcher", true);
timer.schedule(task, 1, POLL_INTERVAL);
}
/**
* Close the timer.
* This method does one last poll.
*/
public void close() {
timer.cancel();
poll();
}
public static class DirectoryEvent {
public Set filesAdded = new HashSet();
public Set filesRemoved = new HashSet();
}
public interface DirectoryListener {
void onWatchEvent(DirectoryEvent e);
}
public void addListener(DirectoryListener listener) {
listeners.add(listener);
}
public void removeListener(DirectoryListener listener) {
listeners.remove(listener);
}
/**
* Get a snapshot of currently known files
*
* @return a snapshot of files
*/
public List files() {
return knownFiles;
}
/**
* Reload the directory
*/
public void refresh() {
poll();
}
/**
* Add file to the known list without reading the disk.
* The modification is void after next timer refresh.
*
* @param f
*/
public synchronized void add(File f) {
ArrayList newList = new ArrayList( knownFiles );
newList.add(f);
knownFiles = newList;
}
/**
* Remove file from the known list without reading the disk.
* The modification is void after next timer refresh.
*
* @param f
*/
public synchronized void remove(File f) {
ArrayList newList = new ArrayList( knownFiles );
newList.remove(f);
knownFiles = newList;
}
/**
* Read files
* @return a list of absolute files
*/
private List readFiles() {
File[] files = directory.listFiles(filter);
List newFiles = new ArrayList( files.length );
for (File f : files) {
// System.out.println(f);
// f = f.getAbsoluteFile();
// System.out.println(f);
newFiles.add(f);
}
return newFiles;
}
/**
* Read files and spawn events
*/
private synchronized void poll() {
DirectoryEvent e = read();
if (e.filesAdded.isEmpty() && e.filesRemoved.isEmpty()) return;
// Spawn an event
for (DirectoryListener l : listeners)
l.onWatchEvent(e);
}
private DirectoryEvent read() {
List oldFiles = knownFiles;
List newFiles = readFiles();
knownFiles = newFiles;
DirectoryEvent result = new DirectoryEvent();
result.filesAdded.addAll(newFiles);
result.filesAdded.removeAll(oldFiles);
result.filesRemoved.addAll(oldFiles);
result.filesRemoved.removeAll(newFiles);
return result;
}
}