package com.example.services.impl; import com.example.utils.FileUtils; import com.example.utils.NBS3SyncThreadFactory; import com.example.config.Config; import com.example.services.DirectoryWatcher; import com.example.services.FileOperation; import com.example.services.Publisher; import java.io.File; import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import static java.nio.file.LinkOption.*; import static java.nio.file.StandardWatchEventKinds.*; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; public class S3DirectoryWatcher implements DirectoryWatcher { private WatchService watcher; private static final Logger logger = Logger.getLogger(S3DirectoryWatcher.class.getName()); private Publisher publisher; private Map<WatchKey,Path> keys = new HashMap<WatchKey, Path>(); private final Config config; public S3DirectoryWatcher(Config config, Publisher publisher) { this.publisher = publisher; this.config = config; } private WatchService getWatcher() throws IOException { if (watcher == null) { watcher = FileSystems.getDefault().newWatchService(); } return watcher; } /** * Register the given directory with the WatchService */ private void register(Path dir) throws IOException { WatchKey key = dir.register(getWatcher(), ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); Path prev = keys.get(key); if (prev == null) { logger.info("Watching " + dir); } else { if (!dir.equals(prev)) { logger.info("Update " + prev + " -> " + dir); } } keys.put(key, dir); } /** * Register the given directory, and all its sub-directories, with the * WatchService. */ private void registerAll(final Path start) throws IOException { // register directory and sub-directories Files.walkFileTree(start, new SimpleFileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { register(dir); return FileVisitResult.CONTINUE; } }); } @Override public void registerDirectory(final Path p) { try { registerAll(p); } catch (IOException e) { logger.severe("Error when registering directory: " + e.getMessage()); } startWatching(); } private void startWatching() { try { NBS3SyncThreadFactory.newThread("Directory watcher", new Runnable() { @Override public void run() { while (true) { WatchKey key; try { key = watcher.take(); } catch (InterruptedException x) { return; } Path dir = keys.get(key); if (dir == null) { logger.warning("Watchkey not recognized"); continue; } for (WatchEvent<?> event : key.pollEvents()) { WatchEvent.Kind kind = event.kind(); if (kind == OVERFLOW) { continue; } WatchEvent<Path> ev = (WatchEvent<Path>) event; // TODO: fix unchecked cast Path path = dir.resolve(ev.context()); FileOperation op = S3FileEvent.getFileOperation(kind); logger.finest(kind.name() + ": " + path.toString()); if (kind == ENTRY_CREATE) { try { if (Files.isDirectory(path, NOFOLLOW_LINKS)) { registerAll(path); } } catch (IOException e) { logger.warning("Could not read directory " + path.toString()); } } File f = dir.resolve(path).toFile(); if (!FileUtils.shouldIgnore(f)) { publisher.publish(new S3FileEvent(op, f, config.getQueueName())); } } boolean valid = key.reset(); if (!valid) { keys.remove(key); if (keys.isEmpty()) { //TODO: Do something useful here } } } } }).start(); } catch (Exception e) { logger.severe("Something bad happened " + e.getMessage()); } } }