Skip to content

Commit 378f29a

Browse files
authored
Merge pull request #1 from SWAT-engineering/initial-implementation
Initial pure JDK implementation
2 parents 4d4fedd + d1b6e9e commit 378f29a

28 files changed

+3351
-1
lines changed

.editorconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Editor configuration, see http://editorconfig.org
2+
root = true
3+
4+
[*]
5+
charset = utf-8
6+
indent_style = space
7+
indent_size = 2
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
max_line_length = 80
11+
12+
[*.sh]
13+
end_of_line = lf
14+
15+
[*.java]
16+
indent_size = 4
17+
max_line_length = 120

.github/workflows/build.yaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Build and Test
2+
on:
3+
push:
4+
branches:
5+
- main
6+
tags:
7+
- 'v[0-9]+.*'
8+
pull_request:
9+
branches:
10+
- main
11+
12+
jobs:
13+
test:
14+
strategy:
15+
matrix:
16+
os: [ubuntu-latest, macos-latest, windows-latest]
17+
jdk: [11, 17, 21]
18+
fail-fast: false
19+
runs-on: ${{ matrix.os }}
20+
steps:
21+
- uses: actions/checkout@v4
22+
- name: Set up JDK
23+
uses: actions/setup-java@v4
24+
with:
25+
java-version: ${{ matrix.jdk }}
26+
distribution: 'temurin'
27+
cache: 'maven'
28+
29+
- name: test
30+
run: mvn -B clean test
31+
env:
32+
DELAY_FACTOR: 3
33+
34+
checker-framework:
35+
runs-on: ubuntu-latest
36+
steps:
37+
- uses: actions/checkout@v4
38+
- name: Set up JDK 11
39+
uses: actions/setup-java@v4
40+
with:
41+
java-version: 11
42+
distribution: 'temurin'
43+
cache: 'maven'
44+
45+
- run: mvn -B -Pchecker-framework clean compile

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@
2222
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
2323
hs_err_pid*
2424
replay_pid*
25+
26+
/target

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"java.configuration.updateBuildConfiguration": "automatic"
3+
}

README.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,59 @@
11
# java-watch
2-
a java file watcher that works across platforms and supports recursion and single file watches
2+
a java file watcher that works across platforms and supports recursion, single file watches, and tries to make sure no events are missed.
33

4+
## Features
5+
6+
Currently working features in java-watch:
7+
8+
- Recursive watches, even if platform doesn't support it natively.
9+
- Recursive watches also work inside directories created after the watch started
10+
- Even in case of overflow you will get notifications of **new** directories (and it's recursive files), modification events will however not be simulated
11+
- Single file watches
12+
- Multiple watches for the same directory are merged to avoid overloading the kernel
13+
- Events are process on a worker pool, which you can customize.
14+
15+
Future features:
16+
17+
- Avoid poll based watcher in macOS/OSX that only detects changes every 2 seconds
18+
- Support file watches natively in linux
19+
- Monitor only specific events (such as only CREATES)
20+
21+
## Usage
22+
23+
Import dependency in pom.xml:
24+
25+
```xml
26+
<dependency>
27+
<groupId>engineering.swat</groupId>
28+
<artifactId>java-watch</artifactId>
29+
<version>${java-watch-version}</version>
30+
</dependency>
31+
```
32+
33+
Start using java-watch:
34+
35+
```java
36+
var directory = Path.of("tmp", "test-dir");
37+
var watcherSetup = Watcher.watch(directory, WatchScope.PATH_AND_CHILDREN)
38+
.withExecutor(Executors.newCachedThreadPool()) // optionally configure a custom thread pool
39+
.onEvent(watchEvent -> {
40+
System.err.println(watchEvent);
41+
});
42+
43+
try(var active = watcherSetup.start()) {
44+
System.out.println("Monitoring files, press any key to stop");
45+
System.in.read();
46+
}
47+
// after active.close(), the watch is stopped and
48+
// no new events will be scheduled on the threadpool
49+
```
450

551
## Related work
52+
53+
Before starting this library, we wanted to use existing libraries, but they all lacked proper support for recursive file watches or lacked configurability. This library now has a growing collection of tests and a small API that should allow for future improvements without breaking compatibility.
54+
55+
The following section describes the related work research on the libraries and underlying limitations.
56+
657
After reading the documentation of the following discussion on file system watches:
758

859
- [Paul Millr's nodejs chokidar](https://github.com/paulmillr/chokidar)

pom.xml

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>engineering.swat</groupId>
7+
<artifactId>java-watch</artifactId>
8+
<version>0.0.1-SNAPSHOT</version>
9+
<packaging>jar</packaging>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<checkerframework.version>3.42.0</checkerframework.version>
14+
<junit.version>5.10.2</junit.version>
15+
<log4j.version>2.23.0</log4j.version>
16+
<maven.compiler.source>11</maven.compiler.source>
17+
<maven.compiler.target>11</maven.compiler.target>
18+
</properties>
19+
20+
<build>
21+
<plugins>
22+
<plugin>
23+
<groupId>org.apache.maven.plugins</groupId>
24+
<artifactId>maven-compiler-plugin</artifactId>
25+
<version>3.10.1</version>
26+
<configuration>
27+
<release>11</release>
28+
<compilerArgument>-parameters</compilerArgument>
29+
</configuration>
30+
</plugin>
31+
<plugin>
32+
<groupId>org.apache.maven.plugins</groupId>
33+
<artifactId>maven-source-plugin</artifactId>
34+
<version>3.2.1</version>
35+
<executions>
36+
<execution>
37+
<id>attach-sources</id>
38+
<goals>
39+
<goal>jar</goal>
40+
</goals>
41+
</execution>
42+
</executions>
43+
</plugin>
44+
<plugin>
45+
<groupId>org.apache.maven.plugins</groupId>
46+
<artifactId>maven-release-plugin</artifactId>
47+
<configuration>
48+
<tagNameFormat>v@{project.version}</tagNameFormat>
49+
</configuration>
50+
</plugin>
51+
<plugin>
52+
<groupId>org.apache.maven.plugins</groupId>
53+
<artifactId>maven-javadoc-plugin</artifactId>
54+
<version>3.4.0</version>
55+
<configuration>
56+
<additionalparam>-Xdoclint:none</additionalparam>
57+
</configuration>
58+
</plugin>
59+
<plugin>
60+
<groupId>org.apache.maven.plugins</groupId>
61+
<artifactId>maven-surefire-plugin</artifactId>
62+
<version>2.22.2</version>
63+
</plugin>
64+
<plugin>
65+
<groupId>org.jacoco</groupId>
66+
<artifactId>jacoco-maven-plugin</artifactId>
67+
<version>0.8.8</version>
68+
<executions>
69+
<execution>
70+
<goals>
71+
<goal>prepare-agent</goal>
72+
</goals>
73+
</execution>
74+
<execution>
75+
<id>report</id>
76+
<phase>test</phase>
77+
<goals>
78+
<goal>report</goal>
79+
</goals>
80+
</execution>
81+
</executions>
82+
</plugin>
83+
</plugins>
84+
</build>
85+
86+
<dependencies>
87+
<dependency>
88+
<groupId>org.junit.jupiter</groupId>
89+
<artifactId>junit-jupiter-engine</artifactId>
90+
<version>${junit.version}</version>
91+
<scope>test</scope>
92+
</dependency>
93+
<dependency>
94+
<groupId>org.junit.jupiter</groupId>
95+
<artifactId>junit-jupiter-params</artifactId>
96+
<version>${junit.version}</version>
97+
<scope>test</scope>
98+
</dependency>
99+
<dependency>
100+
<groupId>org.awaitility</groupId>
101+
<artifactId>awaitility</artifactId>
102+
<version>4.2.2</version>
103+
<scope>test</scope>
104+
</dependency>
105+
<dependency>
106+
<groupId>org.checkerframework</groupId>
107+
<artifactId>checker-qual</artifactId>
108+
<version>${checkerframework.version}</version>
109+
</dependency>
110+
<dependency>
111+
<groupId>org.apache.logging.log4j</groupId>
112+
<artifactId>log4j-api</artifactId>
113+
<version>${log4j.version}</version>
114+
</dependency>
115+
<dependency>
116+
<groupId>org.apache.logging.log4j</groupId>
117+
<artifactId>log4j-core</artifactId>
118+
<version>${log4j.version}</version>
119+
</dependency>
120+
</dependencies>
121+
122+
<profiles>
123+
<profile> <!-- run with: mvn clean compile -P checker-framework -->
124+
<id>checker-framework</id>
125+
<build>
126+
<plugins>
127+
<plugin>
128+
<!-- This plugin will set properties values using dependency information -->
129+
<groupId>org.apache.maven.plugins</groupId>
130+
<artifactId>maven-dependency-plugin</artifactId>
131+
<executions>
132+
<execution>
133+
<goals>
134+
<goal>properties</goal>
135+
</goals>
136+
</execution>
137+
</executions>
138+
</plugin>
139+
<plugin>
140+
<groupId>org.apache.maven.plugins</groupId>
141+
<artifactId>maven-compiler-plugin</artifactId>
142+
<version>3.10.1</version>
143+
<configuration>
144+
<fork>true</fork>
145+
<release>11</release>
146+
<compilerArgs>
147+
<arg>-Xmaxerrs</arg>
148+
<arg>10000</arg>
149+
<arg>-Xmaxwarns</arg>
150+
<arg>10000</arg>
151+
<!-- we have to open up the jdk modules for checker framework to work. note if we get a modules.java this has to change-->
152+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
153+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
154+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
155+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
156+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
157+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
158+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
159+
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
160+
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
161+
<arg>-Astubs=src/main/checkerframework</arg>
162+
</compilerArgs>
163+
<annotationProcessorPaths>
164+
<path>
165+
<groupId>org.checkerframework</groupId>
166+
<artifactId>checker</artifactId>
167+
<version>${checkerframework.version}</version>
168+
</path>
169+
</annotationProcessorPaths>
170+
<annotationProcessors>
171+
<!-- Add all the checkers you want to enable here -->
172+
<annotationProcessor>
173+
org.checkerframework.checker.nullness.NullnessChecker
174+
</annotationProcessor>
175+
</annotationProcessors>
176+
</configuration>
177+
</plugin>
178+
</plugins>
179+
</build>
180+
181+
<dependencies>
182+
<dependency>
183+
<groupId>org.checkerframework</groupId>
184+
<artifactId>checker</artifactId>
185+
<version>${checkerframework.version}</version>
186+
<scope>provided</scope>
187+
</dependency>
188+
</dependencies>
189+
190+
</profile>
191+
</profiles>
192+
</project>

0 commit comments

Comments
 (0)