Skip to content

Commit 762439b

Browse files
committed
Add resource watching
1 parent 00f2dc6 commit 762439b

File tree

4 files changed

+114
-31
lines changed

4 files changed

+114
-31
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Version 2.7.1 (2017-12-15)
2+
3+
* [new] In watch goal, trigger a LiveReload (without app refresh) when a resource change.
4+
15
# Version 2.7.0 (2017-11-31)
26

37
* [new] Add watch goal which automatically refreshes the application when a source file change.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
<groupId>org.seedstack</groupId>
2121
<artifactId>seedstack-maven-plugin</artifactId>
22-
<version>2.7.0-SNAPSHOT</version>
22+
<version>2.7.1-SNAPSHOT</version>
2323
<packaging>maven-plugin</packaging>
2424

2525
<properties>

src/license/THIRD-PARTY.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# Please fill the missing licenses for dependencies :
1414
#
1515
#
16-
#Thu Nov 30 15:58:46 CET 2017
16+
#Sat Dec 09 19:25:38 CET 2017
1717
classworlds--classworlds--1.1-alpha-2=
1818
dom4j--dom4j--1.6.1=
1919
jdom--jdom--1.0=

src/main/java/org/seedstack/maven/WatchMojo.java

Lines changed: 108 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.Set;
3131
import java.util.concurrent.ArrayBlockingQueue;
3232
import java.util.concurrent.Semaphore;
33+
import org.apache.maven.model.Resource;
3334
import org.apache.maven.plugin.MojoExecutionException;
3435
import org.apache.maven.plugin.MojoFailureException;
3536
import org.apache.maven.plugins.annotations.Execute;
@@ -54,8 +55,10 @@
5455
@Execute(phase = LifecyclePhase.PROCESS_CLASSES)
5556
public class WatchMojo extends AbstractExecutableMojo {
5657
private static final int LIVE_RELOAD_PORT = 35729;
57-
private DirectoryWatcher directoryWatcher;
58-
private Thread watcherThread;
58+
private DirectoryWatcher sourceWatcher;
59+
private DirectoryWatcher resourceWatcher;
60+
private Thread sourceWatcherThread;
61+
private Thread resourceWatcherThread;
5962
private List<String> compileSourceRoots;
6063
private ReloadingClassLoader reloadingClassLoader;
6164
private DefaultLauncherRunnable launcherRunnable;
@@ -64,8 +67,10 @@ public class WatchMojo extends AbstractExecutableMojo {
6467
@Override
6568
public void execute() throws MojoExecutionException, MojoFailureException {
6669
this.compileSourceRoots = Collections.unmodifiableList(getProject().getCompileSourceRoots());
70+
6771
try {
68-
this.directoryWatcher = new DirectoryWatcher(getLog(), new WatchFileChangeListener());
72+
this.sourceWatcher = new DirectoryWatcher(getLog(), new SourceChangeListener());
73+
this.resourceWatcher = new DirectoryWatcher(getLog(), new ResourceChangeListener());
6974
} catch (IOException e) {
7075
throw new MojoExecutionException("Unable to create directory watcher", e);
7176
}
@@ -75,31 +80,63 @@ public void execute() throws MojoExecutionException, MojoFailureException {
7580
if (file.isDirectory()) {
7681
getLog().info("Will watch source directory " + file.getPath());
7782
try {
78-
this.directoryWatcher.watchRecursively(file.toPath());
83+
this.sourceWatcher.watchRecursively(file.toPath());
84+
} catch (IOException e) {
85+
throw new MojoExecutionException("Unable to watch source directory " + file.getAbsolutePath(), e);
86+
}
87+
}
88+
}
89+
90+
for (Resource resource : getProject().getResources()) {
91+
File file = new File(resource.getDirectory());
92+
if (file.isDirectory()) {
93+
getLog().info("Will watch resource directory " + file.getPath());
94+
try {
95+
this.resourceWatcher.watchRecursively(file.toPath());
7996
} catch (IOException e) {
80-
throw new MojoExecutionException("Unable to watch directory " + file.getAbsolutePath(), e);
97+
throw new MojoExecutionException("Unable to watch resource directory "
98+
+ file.getAbsolutePath(), e);
8199
}
82100
}
83101
}
84102

85-
this.watcherThread = new Thread(this.directoryWatcher, "watcher");
103+
this.sourceWatcherThread = new Thread(this.sourceWatcher, "source-watcher");
104+
this.resourceWatcherThread = new Thread(this.resourceWatcher, "resource-watcher");
105+
System.setProperty("seedstack.config.config.watchPeriod", "1");
106+
86107
this.launcherRunnable = new DefaultLauncherRunnable(getArgs(), getMonitor(), getLog());
87108
execute(launcherRunnable, false);
88109

89-
Runtime.getRuntime().addShutdownHook(new Thread("watcher") {
110+
Runtime.getRuntime().addShutdownHook(new Thread("watch") {
90111
@Override
91112
public void run() {
92-
directoryWatcher.stop();
93-
watcherThread.interrupt();
113+
if (lrServer != null) {
114+
try {
115+
lrServer.stop();
116+
} catch (Exception e) {
117+
getLog().error("Unable to stop LiveReload server", e);
118+
}
119+
}
120+
121+
sourceWatcher.stop();
122+
sourceWatcherThread.interrupt();
123+
try {
124+
sourceWatcherThread.join(1000);
125+
} catch (InterruptedException e) {
126+
// ignore
127+
}
128+
129+
resourceWatcher.stop();
130+
resourceWatcherThread.interrupt();
94131
try {
95-
watcherThread.join(1000);
132+
resourceWatcherThread.join(1000);
96133
} catch (InterruptedException e) {
97134
// ignore
98135
}
99136
}
100137
});
101138

102-
// Start live reload server
139+
// Start LiveReload server
103140
try {
104141
getLog().info("Starting LiveReload server on port " + LIVE_RELOAD_PORT);
105142
lrServer = new LRServer(LIVE_RELOAD_PORT);
@@ -108,18 +145,12 @@ public void run() {
108145
getLog().error("Unable to start LiveReload server", e);
109146
}
110147

111-
// Start watching sources
112-
watcherThread.start();
148+
// Start watching sources and resources
149+
sourceWatcherThread.start();
150+
resourceWatcherThread.start();
113151

152+
// Wait for the app to end
114153
waitForShutdown();
115-
116-
if (lrServer != null) {
117-
try {
118-
lrServer.stop();
119-
} catch (Exception e) {
120-
getLog().error("Unable to stop LiveReload server", e);
121-
}
122-
}
123154
}
124155

125156
@Override
@@ -132,7 +163,48 @@ public ReloadingClassLoader run() {
132163
return reloadingClassLoader;
133164
}
134165

135-
private class WatchFileChangeListener implements FileChangeListener {
166+
private class ResourceChangeListener implements FileChangeListener {
167+
@Override
168+
public void onChange(Set<FileEvent> fileEvents) {
169+
getLog().info("Resource changes detected");
170+
171+
for (FileEvent fileEvent : fileEvents) {
172+
if (fileEvent.getKind() == FileEvent.Kind.CREATE) {
173+
getLog().debug("NEW: " + fileEvent.getFile().getPath());
174+
} else if (fileEvent.getKind() == FileEvent.Kind.MODIFY) {
175+
getLog().debug("MODIFIED: " + fileEvent.getFile().getPath());
176+
} else if (fileEvent.getKind() == FileEvent.Kind.DELETE) {
177+
getLog().debug("DELETED: " + fileEvent.getFile().getPath());
178+
}
179+
180+
if (isConfigFile(fileEvent.getFile())) {
181+
getLog().info("A configuration file has changed, waiting for the application to notice the change");
182+
// Wait for the application to notice the change
183+
try {
184+
Thread.sleep(2000);
185+
} catch (InterruptedException e) {
186+
// ignore
187+
}
188+
break;
189+
}
190+
}
191+
192+
triggerLiveReload();
193+
}
194+
195+
private boolean isConfigFile(File file) {
196+
String fileName = file.getName();
197+
return fileName.equals("application.yaml")
198+
|| fileName.equals("application.override.yaml")
199+
|| fileName.equals("application.json")
200+
|| fileName.equals("application.override.json")
201+
|| fileName.equals("application.properties")
202+
|| fileName.equals("application.override.properties")
203+
|| file.getParentFile().getPath().endsWith("META-INF" + File.separator + "configuration");
204+
}
205+
}
206+
207+
private class SourceChangeListener implements FileChangeListener {
136208
private static final String COMPILATION_FAILURE_EXCEPTION = "org.apache.maven.plugin.compiler" +
137209
".CompilationFailureException";
138210

@@ -200,10 +272,7 @@ private void refresh(Set<FileEvent> fileEvents) {
200272
launcherRunnable.refresh();
201273

202274
// Trigger LiveReload
203-
if (lrServer != null) {
204-
getLog().info("Triggering LiveReload");
205-
lrServer.notifyChange("/");
206-
}
275+
triggerLiveReload();
207276

208277
getLog().info("Refresh complete");
209278
}
@@ -228,15 +297,15 @@ private void analyzeEvents(Set<FileEvent> fileEvents, Set<File> compiledFilesToR
228297
if (canonicalChangedFile.startsWith(sourceRootPath + File.separator)
229298
&& canonicalChangedFile.endsWith(".java")) {
230299
if (fileEvent.getKind() == FileEvent.Kind.CREATE) {
231-
getLog().debug("NEW: " + canonicalChangedFile);
300+
getLog().debug("NEW: " + changedFile.getPath());
232301
compiledFilesToUpdate.add(resolveCompiledFile(sourceRootPath,
233302
canonicalChangedFile));
234303
} else if (fileEvent.getKind() == FileEvent.Kind.MODIFY) {
235-
getLog().debug("MODIFIED: " + canonicalChangedFile);
304+
getLog().debug("MODIFIED: " + changedFile.getPath());
236305
compiledFilesToUpdate.add(resolveCompiledFile(sourceRootPath,
237306
canonicalChangedFile));
238307
} else if (fileEvent.getKind() == FileEvent.Kind.DELETE) {
239-
getLog().debug("DELETED: " + canonicalChangedFile);
308+
getLog().debug("DELETED: " + changedFile.getPath());
240309
compiledFilesToRemove.add(resolveCompiledFile(sourceRootPath,
241310
canonicalChangedFile));
242311
}
@@ -318,4 +387,14 @@ public void visitInnerClass(String name, String outerName, String innerName, int
318387
}
319388
}
320389

390+
private void triggerLiveReload() {
391+
if (lrServer != null) {
392+
getLog().info("Triggering LiveReload");
393+
try {
394+
lrServer.notifyChange("/");
395+
} catch (Exception e) {
396+
getLog().warn("Error triggering LiveReload", e);
397+
}
398+
}
399+
}
321400
}

0 commit comments

Comments
 (0)