All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dreamhead.moco.runner.watcher.WatcherService Maven / Gradle / Ivy

Go to download

Moco is an easy setup stub framework, mainly focusing on testing and integration.

There is a newer version: 1.5.0
Show newest version
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