3030import java .util .Set ;
3131import java .util .concurrent .ArrayBlockingQueue ;
3232import java .util .concurrent .Semaphore ;
33+ import org .apache .maven .model .Resource ;
3334import org .apache .maven .plugin .MojoExecutionException ;
3435import org .apache .maven .plugin .MojoFailureException ;
3536import org .apache .maven .plugins .annotations .Execute ;
5455@ Execute (phase = LifecyclePhase .PROCESS_CLASSES )
5556public 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