org.keedio.flume.source.watchdir.WatchDirObserver Maven / Gradle / Ivy
package org.keedio.flume.source.watchdir;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import name.pachler.nio.file.FileSystems;
import name.pachler.nio.file.Path;
import name.pachler.nio.file.Paths;
import name.pachler.nio.file.StandardWatchEventKind;
import name.pachler.nio.file.WatchEvent;
import name.pachler.nio.file.WatchKey;
import name.pachler.nio.file.WatchService;
import name.pachler.nio.file.ext.ExtendedWatchEventKind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
/**
*
* This thread monitors the directory indicated in the constructor recursively.
* At the time believed a new file to all
* registered listeners are notified.
*
* Events deleted or modified files are not managed.
*
*/
public class WatchDirObserver implements Runnable {
private WatchService watcherSvc;
private List listeners;
private static final Logger LOGGER= LoggerFactory
.getLogger(WatchDirObserver.class);
private final Map keys;
private WatchDirFileSet set;
public synchronized List getListeners() {
return listeners;
}
public WatchDirObserver(WatchDirFileSet set) {
this.set = set;
keys = new HashMap();
listeners = new ArrayList();
try {
Path directotyToWatch = Paths.get(set.getPath());
watcherSvc = FileSystems.getDefault().newWatchService();
registerAll(java.nio.file.Paths.get(directotyToWatch.toString()));
} catch (IOException e){
LOGGER.info("No se puede monitorizar el directorio: " + set.getPath(), e);
}
}
static WatchEvent castEvent(WatchEvent> event) {
return (WatchEvent)event;
}
/**
* Method used to record listeners. There must be at least one.
* @param listener Must implement WhatchDirListerner. See listeners implementations for more information
*/
public void addWatchDirListener(WatchDirListener listener) {
listeners.add(listener);
}
protected void update(WatchDirEvent event) {
for (WatchDirListener listener:getListeners()) {
try{
listener.process(event);
} catch (WatchDirException e) {
LOGGER.info("Error procesando el listener", e);
}
}
}
@SuppressWarnings("unchecked")
static WatchEvent cast(WatchEvent> event) {
return (WatchEvent) event;
}
/**
* Register the given directory, and all its sub-directories, with the WatchService.
* @param start The initial path to monitor.
*
*/
private void registerAll(final java.nio.file.Path start) throws IOException {
EnumSet opts;
if (set.isFollowLinks())
opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
else
opts = EnumSet.noneOf(FileVisitOption.class);
// register directory and sub-directories
java.nio.file.Files.walkFileTree(start, opts, Integer.MAX_VALUE, new SimpleFileVisitor() {
@Override
public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs)
throws IOException {
register(Paths.get(dir.toString()));
return FileVisitResult.CONTINUE;
}
});
}
private void register(Path dir) throws IOException {
LOGGER.trace("WatchDir: register");
// Solo nos preocupamos por los ficheros de nueva creacion
WatchKey key = null;
try {
key = dir.register(watcherSvc, StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_MODIFY, StandardWatchEventKind.ENTRY_DELETE, ExtendedWatchEventKind.ENTRY_RENAME_FROM, ExtendedWatchEventKind.ENTRY_RENAME_TO);
} catch (UnsupportedOperationException e) {
LOGGER.debug("Eventos no soportados. Registramos solo CREATE, DELETED, MODIFY");
key = dir.register(watcherSvc, StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_MODIFY, StandardWatchEventKind.ENTRY_DELETE);
}
Path prev = keys.get(key);
LOGGER.info("Previous directory: " + prev);
if (prev == null) {
LOGGER.info("Registering directory: " + dir);
} else {
if (!dir.equals(prev)) {
LOGGER.info("Updating previous directory: " + "-> " + prev + " to " + dir);
}
}
keys.put(key, dir);
}
@Override
public void run() {
if (listeners.isEmpty()) {
LOGGER.error("No existen listeners. Finalizando");
} else {
try {
boolean fin = false;
// En primer lugar procesamos todos los ficheros pre-existentes
if (set.isReadOnStartup()) {
for(String file:set.getExistingFiles()) {
WatchDirEvent event = new WatchDirEvent(file, "ENTRY_CREATE", set);
update(event);
LOGGER.debug("Fichero existente anteriormente:" + file + " .Se procesa");
}
}
while (!fin) {
// wait for key to be signaled
WatchKey key;
key = watcherSvc.take();
Path dir = keys.get(key);
for (WatchEvent> event : key.pollEvents()) {
WatchEvent ev = cast(event);
Path name = ev.context();
Path path = dir.resolve(name);
// Si se crea un nuevo directorio es necesario registrarlo de nuevo
if (java.nio.file.Files.isDirectory(java.nio.file.Paths.get(path.toString()), NOFOLLOW_LINKS))
registerAll(java.nio.file.Paths.get(path.toString()));
else {
if (set.haveToProccess(path.toString())) {
update(new WatchDirEvent(path.toString(), event.kind().name(), set));
}
}
}
// reset key and remove from set if directory no longer
// accessible
key.reset();
Thread.sleep(1000);
}
} catch (InterruptedException e) {
LOGGER.info(e.getMessage(), e);
} catch (Exception e) {
LOGGER.info(e.getMessage(), e);
}
}
}
public static boolean match(String patterns, String string) {
String[] splitPat = patterns.split(",");
boolean match = false;
for (String pattern:splitPat) {
Pattern pat = Pattern.compile(pattern + "$");
Matcher mat = pat.matcher(string);
match = match || mat.find();
if (match) break;
}
return match;
}
}