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

org.rx.io.FileWatcher Maven / Gradle / Ivy

package org.rx.io;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.rx.beans.NEnum;
import org.rx.beans.Tuple;
import org.rx.core.Disposable;
import org.rx.core.Tasks;
import org.rx.util.function.TripleAction;

import java.nio.file.*;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.function.Predicate;

import static org.rx.core.Contract.catchCall;
import static org.rx.core.Contract.require;

@Slf4j
public class FileWatcher extends Disposable {
    @RequiredArgsConstructor
    public enum ChangeKind implements NEnum {
        Create(1), Modify(2), Delete(3);

        @Getter
        private final int value;
    }

    @Getter
    private String directoryPath;
    private WatchService service;
    private volatile boolean keepHandle;
    private Future future;
    private final List, Predicate>> callback;

    @SneakyThrows
    public FileWatcher(String directoryPath) {
        this.directoryPath = directoryPath;
        callback = new CopyOnWriteArrayList<>();

        Files.createDirectory(Files.path(directoryPath));
        service = FileSystems.getDefault().newWatchService();
        Paths.get(directoryPath).register(service, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
    }

    @SneakyThrows
    @Override
    protected void freeObjects() {
        stop();
        service.close();
        service = null;
    }

    public boolean tryPeek(TripleAction onChange) {
        require(onChange);

        WatchKey key = service.poll();
        if (key == null) {
            return false;
        }
        for (WatchEvent event : key.pollEvents()) {
            raiseEvent(event, Tuple.of(onChange, null));
        }
        key.reset();
        return true;
    }

    public synchronized FileWatcher start() {
        if (future != null) {
            return this;
        }

        keepHandle = true;
        future = Tasks.run(() -> {
            while (keepHandle) {
                catchCall(() -> {
                    WatchKey key = service.take();
                    for (WatchEvent event : key.pollEvents()) {
                        for (Tuple, Predicate> tuple : callback) {
                            catchCall(() -> raiseEvent(event, tuple));
                        }
                    }
                    key.reset();
                });
            }
            return null;
        });
        return this;
    }

    public FileWatcher callback(TripleAction onChange) {
        return callback(onChange, null);
    }

    public FileWatcher callback(TripleAction onChange, Predicate filter) {
        require(keepHandle, onChange);

        callback.add(Tuple.of(onChange, filter));
        return this;
    }

    @SneakyThrows
    private void raiseEvent(WatchEvent event, Tuple, Predicate> tuple) {
        WatchEvent $event = (WatchEvent) event;
        Path absolutePath = Paths.get(directoryPath, $event.context().toString());
        if (tuple.right != null && !tuple.right.test(absolutePath)) {
            return;
        }
        ChangeKind changeKind;
        if ($event.kind().equals(StandardWatchEventKinds.ENTRY_CREATE)) {
            changeKind = ChangeKind.Create;
        } else if ($event.kind().equals(StandardWatchEventKinds.ENTRY_MODIFY)) {
            changeKind = ChangeKind.Modify;
        } else {
            changeKind = ChangeKind.Delete;
        }
        tuple.left.invoke(changeKind, absolutePath);
    }

    @SneakyThrows
    protected void raiseCallback(ChangeKind kind, Path changedPath) {
        for (Tuple, Predicate> tuple : callback) {
            tuple.left.invoke(kind, changedPath);
        }
    }

    public synchronized void stop() {
        if (future == null) {
            return;
        }

        future.cancel(false);
        future = null;
        keepHandle = false;
        callback.clear();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy