Skip to content

Commit 8a43b87

Browse files
committed
Merge branch 'improved-overflow-support/richer-active-watch' into improved-overflow-support/event-handlers-with-active-watch
2 parents 4fb69dc + 9807fdb commit 8a43b87

File tree

6 files changed

+134
-35
lines changed

6 files changed

+134
-35
lines changed

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

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,30 +36,8 @@
3636
*/
3737
public interface ActiveWatch extends Closeable {
3838

39-
/**
40-
* Handles `event`. The purpose of this method is to trigger the event
41-
* handler of this watch "from the outside" (in addition to having native
42-
* file system libraries trigger the event handler "from the inside"). This
43-
* is useful to report synthetic events (e.g., while handling overflows).
44-
*/
45-
void handleEvent(WatchEvent event);
46-
4739
/**
4840
* Gets the path watched by this watch.
4941
*/
5042
Path getPath();
51-
52-
/**
53-
* Relativizes the full path of `event` against the path watched by this
54-
* watch (as per `getPath()`). Returns a new event whose root path and
55-
* relative path are set in accordance with the relativization.
56-
*/
57-
default WatchEvent relativize(WatchEvent event) {
58-
var fullPath = event.calculateFullPath();
59-
60-
var kind = event.getKind();
61-
var rootPath = getPath();
62-
var relativePath = rootPath.relativize(fullPath);
63-
return new WatchEvent(kind, rootPath, relativePath);
64-
}
6543
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
import java.nio.file.Path;
3030

31+
import org.checkerframework.checker.nullness.qual.Nullable;
32+
3133
/**
3234
* The library publishes these events to all subscribers, they are immutable and safe to share around.
3335
*/
@@ -67,13 +69,13 @@ public enum Kind {
6769
private final Path relativePath;
6870

6971
public WatchEvent(Kind kind, Path rootPath) {
70-
this(kind, rootPath, Path.of(""));
72+
this(kind, rootPath, null);
7173
}
7274

73-
public WatchEvent(Kind kind, Path rootPath, Path relativePath) {
75+
public WatchEvent(Kind kind, Path rootPath, @Nullable Path relativePath) {
7476
this.kind = kind;
7577
this.rootPath = rootPath;
76-
this.relativePath = relativePath;
78+
this.relativePath = relativePath == null ? Path.of("") : relativePath;
7779
}
7880

7981
public Kind getKind() {
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: 5 additions & 8 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;
@@ -90,12 +90,9 @@ protected boolean startIfFirstTime() throws IOException {
9090
}
9191

9292
protected WatchEvent translate(java.nio.file.WatchEvent<?> jdkEvent) {
93-
var jdkKind = jdkEvent.kind();
94-
var context = jdkKind == StandardWatchEventKinds.OVERFLOW ? null : jdkEvent.context();
95-
96-
var kind = translate(jdkKind);
93+
var kind = translate(jdkEvent.kind());
9794
var rootPath = path;
98-
var relativePath = context == null ? Path.of("") : (Path) context;
95+
var relativePath = kind == WatchEvent.Kind.OVERFLOW ? null : (@Nullable Path) jdkEvent.context();
9996

10097
var event = new WatchEvent(kind, rootPath, relativePath);
10198
logger.trace("Translated: {} to {}", jdkEvent, event);
@@ -119,7 +116,7 @@ private WatchEvent.Kind translate(java.nio.file.WatchEvent.Kind<?> jdkKind) {
119116
throw new IllegalArgumentException("Unexpected watch kind: " + jdkKind);
120117
}
121118

122-
// -- ActiveWatch --
119+
// -- EventHandlingWatch --
123120

124121
@Override
125122
public void handleEvent(WatchEvent e) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,8 @@ private void detectedMissingEntries(Path dir, ArrayList<WatchEvent> events, Hash
299299
// -- JDKBaseWatch --
300300

301301
@Override
302-
public void handleEvent(WatchEvent ev) {
303-
processEvents(ev);
302+
public void handleEvent(WatchEvent event) {
303+
processEvents(event);
304304
}
305305

306306
@Override
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)