/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.root1.kad.utils.folderwatch;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author achristian
*/
public class FolderWatch implements Runnable {
private final Logger log = LoggerFactory.getLogger(getClass());
class FolderContainer {
private final File folder;
private final FolderWatchListener listener;
private final Map<File, Long> fileMap = new HashMap<>();
private final FileFilter fileFilter;
public FolderContainer(File folder, FileFilter ff, FolderWatchListener listener) throws TooMuchFilesException {
this.folder = folder;
this.listener = listener;
this.fileFilter = ff;
for (File file : getFiles(folder, fileFilter)) {
fileMap.put(file, file.lastModified());
}
log.info("Starting on {} with {} files to observe", folder.getAbsolutePath(), fileMap.size());
}
public FolderContainer(File folder, FolderWatchListener listener) throws TooMuchFilesException {
this(folder, null, listener);
}
public FolderWatchListener getListener() {
return listener;
}
public File getFolder() {
return folder;
}
public Map<File, Long> getFileMap() {
return fileMap;
}
private FileFilter getFileFilter() {
return fileFilter;
}
}
private final int POLL_DELAY = 1000;
private final Thread pollThread = new Thread(this, "FolderWatch");
private Map<File, FolderContainer> dirContainerMap = new HashMap<>();
private boolean running;
public FolderWatch(String name) {
running = true;
pollThread.setName(pollThread.getName() + "#" + name);
pollThread.start();
}
public void addListener(File folder, FolderWatchListener listener) throws TooMuchFilesException {
if (!folder.isDirectory()) {
throw new IllegalArgumentException("Only directories allowed, no files.");
}
dirContainerMap.put(folder, new FolderContainer(folder, listener));
}
public void addListener(File folder, FileFilter ff, FolderWatchListener listener) throws TooMuchFilesException {
if (!folder.isDirectory()) {
throw new IllegalArgumentException("Only directories allowed, no files.");
}
dirContainerMap.put(folder, new FolderContainer(folder, ff, listener));
}
public List<File> getFiles(File folder, FileFilter ff) throws TooMuchFilesException {
List<File> files = new ArrayList<>();
Stack<File> stack = new Stack();
// initial push
File[] listFiles = ff!=null?folder.listFiles(ff):folder.listFiles();
if (listFiles != null) {
for (File f : listFiles) {
stack.push(f);
}
}
while (!stack.isEmpty()) {
File pop = stack.pop();
if (pop.isFile()) {
// add file to list
files.add(pop);
if (files.size() > 1000) {
throw new TooMuchFilesException("Too much files....");
}
} else {
// add childs
File[] listChilds = ff!=null?pop.listFiles(ff):pop.listFiles();
if (listChilds != null) {
for (File f : listChilds) {
stack.push(f);
}
}
}
}
return files;
}
@Override
public void run() {
while (running) {
Set<File> folders = dirContainerMap.keySet();
for (File folder : folders) {
FolderContainer fc = dirContainerMap.get(folder);
Map<File, Long> fileMap = fc.getFileMap();
try {
List<File> files = getFiles(folder, fc.getFileFilter());
for (File file : files) {
if (fileMap.containsKey(file)) {
// existing file
if (file.lastModified() != fileMap.get(file)) {
// changed
log.info("Changed: {}", file.getAbsolutePath());
fc.getListener().modified(file);
// save lastmodified for next check
fileMap.put(file, file.lastModified());
} else {
// no change --> no event
}
} else {
// new file
log.info("Created: {}", file.getAbsolutePath());
fc.getListener().created(file);
fileMap.put(file, file.lastModified());
}
}
Iterator<File> knownFilesIter = fileMap.keySet().iterator();
while (knownFilesIter.hasNext()) {
File knownFile = knownFilesIter.next();
if (!files.contains(knownFile)) {
log.info("Deleted: {}", knownFile.getAbsolutePath());
fc.getListener().deleted(knownFile);
knownFilesIter.remove();
}
}
} catch (TooMuchFilesException ex) {
log.warn("Too much files to observe... skipping {}", fc.getFolder().getAbsolutePath());
}
}
try {
Thread.sleep(POLL_DELAY);
} catch (InterruptedException ex) {
// nothing to do
}
}
}
public static void main(String[] args) throws TooMuchFilesException {
FolderWatch dw = new FolderWatch("Test");
// dw.addListener(new File("/media/bigdisk/Programming/Java/KnxAutomationDaemon/KnxAutomationDaemon"), new DefaultFolderWatchListener());
dw.addListener(new File("/media/bigdisk/Programming/Java/KnxAutomationDaemon/KnxAutomationDaemon"), new FileFilter() {
@Override
public boolean accept(File f) {
return f.getName().endsWith(".jar") || f.isDirectory();
}
}, new DefaultFolderWatchListener());
}
}