Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/main/java/engineering/swat/watch/ActiveWatch.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,17 @@
package engineering.swat.watch;

import java.io.Closeable;
import java.nio.file.Path;

/**
* <p>Marker interface for an active watch, in the future might get properties you can inspect.</p>
* <p>Marker interface for an active watch, in the future might get more properties you can inspect.</p>
*
* <p>For now, make sure to close the watch when not interested in new events</p>
* <p>For now, make sure to close the watch when not interested in new events.</p>
*/
public interface ActiveWatch extends Closeable {

/**
* Gets the path watched by this watch.
*/
Path getPath();
}
55 changes: 55 additions & 0 deletions src/main/java/engineering/swat/watch/impl/EventHandlingWatch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* BSD 2-Clause License
*
* Copyright (c) 2023, Swat.engineering
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package engineering.swat.watch.impl;

import engineering.swat.watch.ActiveWatch;
import engineering.swat.watch.WatchEvent;

public interface EventHandlingWatch extends ActiveWatch {

/**
* Handles `event`. The purpose of this method is to trigger the event
* handler of this watch "from the outside" (in addition to having native
* file system libraries trigger the event handler "from the inside"). This
* is useful to report synthetic events (e.g., while handling overflows).
*/
void handleEvent(WatchEvent event);

/**
* Relativizes the full path of `event` against the path watched by this
* watch (as per `getPath()`). Returns a new event whose root path and
* relative path are set in accordance with the relativization.
*/
default WatchEvent relativize(WatchEvent event) {
var fullPath = event.calculateFullPath();

var kind = event.getKind();
var rootPath = getPath();
var relativePath = rootPath.relativize(fullPath);
return new WatchEvent(kind, rootPath, relativePath);
}
}
16 changes: 14 additions & 2 deletions src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;

import engineering.swat.watch.ActiveWatch;
import engineering.swat.watch.WatchEvent;
import engineering.swat.watch.impl.EventHandlingWatch;

public abstract class JDKBaseWatch implements ActiveWatch {
public abstract class JDKBaseWatch implements EventHandlingWatch {
private final Logger logger = LogManager.getLogger();

protected final Path path;
Expand Down Expand Up @@ -115,4 +115,16 @@

throw new IllegalArgumentException("Unexpected watch kind: " + jdkKind);
}

// -- EventHandlingWatch --

@Override
public void handleEvent(WatchEvent e) {
eventHandler.accept(e);
}

@Override
public Path getPath() {
return path;

Check warning on line 128 in src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/engineering/swat/watch/impl/jdk/JDKBaseWatch.java#L128

Added line #L128 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private void handleJDKEvents(List<java.nio.file.WatchEvent<?>> events) {
exec.execute(() -> {
for (var ev : events) {
try {
eventHandler.accept(translate(ev));
handleEvent(translate(ev));
}
catch (Throwable ignored) {
logger.error("Ignoring downstream exception:", ignored);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@

// -- JDKBaseWatch --

@Override
public void handleEvent(WatchEvent event) {
internal.handleEvent(event);
}

Check warning on line 78 in src/main/java/engineering/swat/watch/impl/jdk/JDKFileWatch.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/engineering/swat/watch/impl/jdk/JDKFileWatch.java#L77-L78

Added lines #L77 - L78 were not covered by tests

@Override
public synchronized void close() throws IOException {
internal.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@
}
}


private List<WatchEvent> syncAfterOverflow(Path dir) {
var events = new ArrayList<WatchEvent>();
var seenFiles = new HashSet<Path>();
Expand Down Expand Up @@ -299,6 +298,11 @@

// -- JDKBaseWatch --

@Override
public void handleEvent(WatchEvent event) {
processEvents(event);
}

Check warning on line 304 in src/main/java/engineering/swat/watch/impl/jdk/JDKRecursiveDirectoryWatch.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/engineering/swat/watch/impl/jdk/JDKRecursiveDirectoryWatch.java#L303-L304

Added lines #L303 - L304 were not covered by tests

@Override
public void close() throws IOException {
IOException firstFail = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* BSD 2-Clause License
*
* Copyright (c) 2023, Swat.engineering
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package engineering.swat.watch.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;
import java.nio.file.Path;

import org.junit.jupiter.api.Test;

import engineering.swat.watch.WatchEvent;

class EventHandlingWatchTests {

private static EventHandlingWatch emptyWatch(Path path) {
return new EventHandlingWatch() {
@Override
public void handleEvent(WatchEvent event) {
// Nothing to handle
}

@Override
public void close() throws IOException {
// Nothing to close
}

@Override
public Path getPath() {
return path;
}
};
}

@Test
void relativizeTest() {
var e1 = new WatchEvent(WatchEvent.Kind.OVERFLOW, Path.of("foo"), Path.of("bar", "baz.txt"));
var e2 = new WatchEvent(WatchEvent.Kind.OVERFLOW, Path.of("foo", "bar", "baz.txt"));
var e3 = emptyWatch(Path.of("foo")).relativize(e2);
assertEquals(e1.getRootPath(), e3.getRootPath());
assertEquals(e1.getRelativePath(), e3.getRelativePath());
}
}