/** * License Agreement for OpenSearchServer * * Copyright (C) 2015 Emmanuel Keller / Jaeksoft * * http://www.open-search-server.com * * This file is part of OpenSearchServer. * * OpenSearchServer is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenSearchServer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenSearchServer. * If not, see <http://www.gnu.org/licenses/>. **/ package com.jaeksoft.searchlib.crawler.file; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchEvent.Kind; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.nio.file.attribute.BasicFileAttributes; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import com.jaeksoft.searchlib.util.ReadWriteLock; public class Event implements Runnable { static Logger log = Logger.getLogger("LogTest"); private final Path rootPath; private final WatchService watcher; private final HashMap<WatchKey, Path> keys; private class PathFifoMap { private final ReadWriteLock rwl; private final LinkedHashMap<Path, Long> hashMap; private PathFifoMap() { rwl = new ReadWriteLock(); hashMap = new LinkedHashMap<Path, Long>() { private static final long serialVersionUID = 2288939087853531613L; @Override protected boolean removeEldestEntry(Map.Entry<Path, Long> eldest) { long t = System.currentTimeMillis(); return t - t % 60000 != eldest.getValue(); } }; } public Long get(Path dirPath) { rwl.r.lock(); try { return hashMap.get(dirPath); } finally { rwl.r.unlock(); } } public void put(Path dirPath, long now) { rwl.w.lock(); try { hashMap.put(dirPath, now); } finally { rwl.w.unlock(); } } } private final PathFifoMap history; /** * An Event class is running thread listening for events in the file system. * * @param filePath * The path of the monitored directory * @throws IOException */ public Event(String filePath) throws IOException { rootPath = FileSystems.getDefault().getPath(filePath); watcher = FileSystems.getDefault().newWatchService(); keys = new HashMap<WatchKey, Path>(); history = new PathFifoMap(); new Register(rootPath); System.out.println("Watch " + rootPath + " " + keys.size()); new Thread(this).start(); } private class Register extends SimpleFileVisitor<Path> { private Register(Path path) { try { Files.walkFileTree(path, this); } catch (IOException e) { e.printStackTrace(); } } @Override final public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException { if (attrs.isDirectory()) { keys.put(file.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY), file); } return FileVisitResult.CONTINUE; } } @Override public void run() { try { // Infinite loop. for (;;) { WatchKey key = watcher.take(); Path dir = keys.get(key); if (dir != null) { for (WatchEvent<?> watchEvent : key.pollEvents()) { Kind<?> kind = watchEvent.kind(); if (kind == StandardWatchEventKinds.OVERFLOW) continue; Object o = watchEvent.context(); Path file = (o instanceof Path) ? (Path) o : null; if (file == null) continue; Path child = dir.resolve(file); // If this is a new directory, we have to register it if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) if (kind == StandardWatchEventKinds.ENTRY_CREATE) new Register(child); } long t = System.currentTimeMillis(); long now = t - t % 60000; Path dirPath = dir.toAbsolutePath(); Long time = history.get(dirPath); if (time == null || time != now) { log.info(dirPath); history.put(dirPath, now); } } if (!key.reset()) { keys.remove(key); if (keys.isEmpty()) break; } } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Unwatch " + rootPath); } public static void main(String[] args) throws IOException, InterruptedException { PropertyConfigurator.configure("log4j.properties"); for (String arg : args) { new Event(arg); } } }