/* * 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()); } }