Skip to content

Commit 8d4dd06

Browse files
authored
Merge pull request #19 from SWAT-engineering/improved-overflow-support/richer-active-watch
Improved overflow support: Internal `EventHandlingWatch` interface
2 parents 53f3038 + 9807fdb commit 8d4dd06

File tree

7 files changed

+154
-6
lines changed

7 files changed

+154
-6
lines changed

src/main/java/engineering/swat/watch/ActiveWatch.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,17 @@
2727
package engineering.swat.watch;
2828

2929
import java.io.Closeable;
30+
import java.nio.file.Path;
3031

3132
/**
32-
* <p>Marker interface for an active watch, in the future might get properties you can inspect.</p>
33+
* <p>Marker interface for an active watch, in the future might get more properties you can inspect.</p>
3334
*
34-
* <p>For now, make sure to close the watch when not interested in new events</p>
35+
* <p>For now, make sure to close the watch when not interested in new events.</p>
3536
*/
3637
public interface ActiveWatch extends Closeable {
3738

39+
/**
40+
* Gets the path watched by this watch.
41+
*/
42+
Path getPath();
3843
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* BSD 2-Clause License
3+
*
4+
* Copyright (c) 2023, Swat.engineering
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice, this
10+
* list of conditions and the following disclaimer.
11+
*
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*/
27+
package engineering.swat.watch.impl;
28+
29+
import engineering.swat.watch.ActiveWatch;
30+
import engineering.swat.watch.WatchEvent;
31+
32+
public interface EventHandlingWatch extends ActiveWatch {
33+
34+
/**
35+
* Handles `event`. The purpose of this method is to trigger the event
36+
* handler of this watch "from the outside" (in addition to having native
37+
* file system libraries trigger the event handler "from the inside"). This
38+
* is useful to report synthetic events (e.g., while handling overflows).
39+
*/
40+
void handleEvent(WatchEvent event);
41+
42+
/**
43+
* Relativizes the full path of `event` against the path watched by this
44+
* watch (as per `getPath()`). Returns a new event whose root path and
45+
* relative path are set in accordance with the relativization.
46+
*/
47+
default WatchEvent relativize(WatchEvent event) {
48+
var fullPath = event.calculateFullPath();
49+
50+
var kind = event.getKind();
51+
var rootPath = getPath();
52+
var relativePath = rootPath.relativize(fullPath);
53+
return new WatchEvent(kind, rootPath, relativePath);
54+
}
55+
}

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@
3737
import org.apache.logging.log4j.Logger;
3838
import org.checkerframework.checker.nullness.qual.Nullable;
3939

40-
import engineering.swat.watch.ActiveWatch;
4140
import engineering.swat.watch.WatchEvent;
41+
import engineering.swat.watch.impl.EventHandlingWatch;
4242

43-
public abstract class JDKBaseWatch implements ActiveWatch {
43+
public abstract class JDKBaseWatch implements EventHandlingWatch {
4444
private final Logger logger = LogManager.getLogger();
4545

4646
protected final Path path;
@@ -115,4 +115,16 @@ private WatchEvent.Kind translate(java.nio.file.WatchEvent.Kind<?> jdkKind) {
115115

116116
throw new IllegalArgumentException("Unexpected watch kind: " + jdkKind);
117117
}
118+
119+
// -- EventHandlingWatch --
120+
121+
@Override
122+
public void handleEvent(WatchEvent e) {
123+
eventHandler.accept(e);
124+
}
125+
126+
@Override
127+
public Path getPath() {
128+
return path;
129+
}
118130
}

src/main/java/engineering/swat/watch/impl/jdk/JDKDirectoryWatch.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private void handleJDKEvents(List<java.nio.file.WatchEvent<?>> events) {
6262
exec.execute(() -> {
6363
for (var ev : events) {
6464
try {
65-
eventHandler.accept(translate(ev));
65+
handleEvent(translate(ev));
6666
}
6767
catch (Throwable ignored) {
6868
logger.error("Ignoring downstream exception:", ignored);

src/main/java/engineering/swat/watch/impl/jdk/JDKFileWatch.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ private static Path requireNonNull(@Nullable Path p, String message) {
7272

7373
// -- JDKBaseWatch --
7474

75+
@Override
76+
public void handleEvent(WatchEvent event) {
77+
internal.handleEvent(event);
78+
}
79+
7580
@Override
7681
public synchronized void close() throws IOException {
7782
internal.close();

src/main/java/engineering/swat/watch/impl/jdk/JDKRecursiveDirectoryWatch.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,6 @@ private List<WatchEvent> registerForNewDirectory(Path dir) {
270270
}
271271
}
272272

273-
274273
private List<WatchEvent> syncAfterOverflow(Path dir) {
275274
var events = new ArrayList<WatchEvent>();
276275
var seenFiles = new HashSet<Path>();
@@ -299,6 +298,11 @@ private void detectedMissingEntries(Path dir, ArrayList<WatchEvent> events, Hash
299298

300299
// -- JDKBaseWatch --
301300

301+
@Override
302+
public void handleEvent(WatchEvent event) {
303+
processEvents(event);
304+
}
305+
302306
@Override
303307
public void close() throws IOException {
304308
IOException firstFail = null;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* BSD 2-Clause License
3+
*
4+
* Copyright (c) 2023, Swat.engineering
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice, this
10+
* list of conditions and the following disclaimer.
11+
*
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*/
27+
package engineering.swat.watch.impl;
28+
29+
import static org.junit.jupiter.api.Assertions.assertEquals;
30+
31+
import java.io.IOException;
32+
import java.nio.file.Path;
33+
34+
import org.junit.jupiter.api.Test;
35+
36+
import engineering.swat.watch.WatchEvent;
37+
38+
class EventHandlingWatchTests {
39+
40+
private static EventHandlingWatch emptyWatch(Path path) {
41+
return new EventHandlingWatch() {
42+
@Override
43+
public void handleEvent(WatchEvent event) {
44+
// Nothing to handle
45+
}
46+
47+
@Override
48+
public void close() throws IOException {
49+
// Nothing to close
50+
}
51+
52+
@Override
53+
public Path getPath() {
54+
return path;
55+
}
56+
};
57+
}
58+
59+
@Test
60+
void relativizeTest() {
61+
var e1 = new WatchEvent(WatchEvent.Kind.OVERFLOW, Path.of("foo"), Path.of("bar", "baz.txt"));
62+
var e2 = new WatchEvent(WatchEvent.Kind.OVERFLOW, Path.of("foo", "bar", "baz.txt"));
63+
var e3 = emptyWatch(Path.of("foo")).relativize(e2);
64+
assertEquals(e1.getRootPath(), e3.getRootPath());
65+
assertEquals(e1.getRelativePath(), e3.getRelativePath());
66+
}
67+
}

0 commit comments

Comments
 (0)