com.github.dreamhead.moco.runner.watcher.WatcherService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of moco-runner Show documentation
Show all versions of moco-runner Show documentation
Moco is an easy setup stub framework, mainly focusing on testing and integration.
package com.github.dreamhead.moco.runner.watcher;
import com.github.dreamhead.moco.MocoException;
import com.github.dreamhead.moco.util.Files;
import com.github.dreamhead.moco.util.MocoExecutors;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.github.dreamhead.moco.util.Idles.idle;
import static com.google.common.collect.Maps.newHashMap;
import static com.sun.nio.file.SensitivityWatchEventModifier.HIGH;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
public final class WatcherService {
private static Logger logger = LoggerFactory.getLogger(WatcherService.class);
private static final long REGISTER_INTERVAL = 1000;
private ExecutorService executor = MocoExecutors.executor();
private WatchService service;
private boolean running;
private Multimap keys = HashMultimap.create();
private Multimap> listeners = HashMultimap.create();
private Multimap directoryToFiles = HashMultimap.create();
private Map directoryToKey = newHashMap();
private Future> result;
public synchronized void start() throws IOException {
if (running) {
return;
}
doStart();
}
private void doStart() throws IOException {
this.service = FileSystems.getDefault().newWatchService();
this.running = true;
result = executor.submit(() -> {
while (running) {
loop();
}
doStop();
});
}
private void doStop() {
this.listeners.clear();
this.keys.clear();
this.directoryToFiles.clear();
this.directoryToKey.clear();
}
private void loop() {
try {
WatchKey key = service.take();
Collection paths = keys.get(key);
List> events = key.pollEvents().stream()
.filter(e -> e.kind().equals(ENTRY_MODIFY))
.collect(Collectors.toList());
for (WatchEvent> event : events) {
final Path context = (Path) event.context();
List contextPaths = paths.stream()
.filter(p -> p.endsWith(context))
.collect(Collectors.toList());
for (Path path : contextPaths) {
for (Function listener : this.listeners.get(path)) {
listener.apply(path.toFile());
}
break;
}
}
key.reset();
} catch (ClosedWatchServiceException ignored) {
} catch (InterruptedException e) {
logger.error("Error happens", e);
}
}
public synchronized void stop() {
if (this.running) {
try {
this.running = false;
this.service.close();
this.result.get();
} catch (Exception e) {
throw new MocoException(e);
}
}
}
public void register(final File file, final Function listener) {
Path directory = Files.directoryOf(file).toPath();
WatchKey key = registerDirectory(directory);
Path path = file.toPath();
keys.put(key, path);
listeners.put(path, listener);
directoryToFiles.put(directory, path);
idle(REGISTER_INTERVAL, TimeUnit.MILLISECONDS);
}
private WatchKey registerDirectory(final Path directory) {
if (directoryToKey.containsKey(directory)) {
return directoryToKey.get(directory);
}
try {
WatchKey key = directory.register(service, new WatchEvent.Kind[]{ENTRY_MODIFY}, HIGH);
directoryToKey.put(directory, key);
return key;
} catch (IOException e) {
throw new MocoException(e);
}
}
public void unregister(final File file) {
Path directory = Files.directoryOf(file).toPath();
Path path = file.toPath();
if (!directoryToFiles.containsEntry(directory, path)) {
return;
}
directoryToFiles.remove(directory, path);
if (!directoryToFiles.containsKey(directory)) {
WatchKey key = directoryToKey.remove(directory);
if (key != null) {
key.cancel();
}
}
if (directoryToFiles.isEmpty()) {
this.stop();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy