4545import java .io .IOException ;
4646import java .io .InputStreamReader ;
4747import java .net .URI ;
48+ import java .nio .file .FileSystems ;
49+ import java .nio .file .Path ;
50+ import java .nio .file .Paths ;
51+ import java .nio .file .StandardWatchEventKinds ;
52+ import java .nio .file .WatchEvent ;
53+ import java .nio .file .WatchKey ;
54+ import java .nio .file .WatchService ;
55+ import java .util .LinkedList ;
56+ import java .util .List ;
4857import java .util .Timer ;
4958import java .util .TimerTask ;
5059import java .util .logging .Level ;
5160import java .util .logging .Logger ;
5261
62+ import org .glassfish .jersey .examples .reload .compiler .AppClassLoader ;
63+ import org .glassfish .jersey .examples .reload .compiler .Compiler ;
64+ import org .glassfish .jersey .examples .reload .compiler .JavaFile ;
5365import org .glassfish .jersey .grizzly2 .httpserver .GrizzlyHttpServerFactory ;
5466import org .glassfish .jersey .server .ResourceConfig ;
5567import org .glassfish .jersey .server .spi .Container ;
5668import org .glassfish .jersey .server .spi .ContainerLifecycleListener ;
5769
5870import org .glassfish .grizzly .http .server .HttpServer ;
5971
72+ import com .sun .nio .file .SensitivityWatchEventModifier ;
73+
6074/**
6175 * Reload example application.
6276 * <p/>
@@ -75,80 +89,126 @@ public class App {
7589 private static final URI BASE_URI = URI .create ("http://localhost:8080/flights/" );
7690 public static final String ROOT_PATH = "arrivals" ;
7791 public static final String CONFIG_FILENAME = "resources" ;
78- public static final long REFRESH_PERIOD_MS = 2000 ;
92+ public static final String SRC_MAIN_JAVA = "src/main/java" ;
7993
8094 static Container container ;
8195
82- // @todo Java SE 7 - use java.nio.file.WatchService
8396 static class FileCheckTask extends TimerTask {
8497
85- long lastModified ;
86-
87- FileCheckTask (final long lastModified ) {
88- this .lastModified = lastModified ;
89- }
90-
9198 @ Override
9299 public void run () {
93- final File configFile = new File (CONFIG_FILENAME );
94- final long actualLastModified = configFile .lastModified ();
95- if (lastModified < actualLastModified ) {
96- lastModified = actualLastModified ;
97- reloadApp (configFile );
98- }
99- }
100100
101- private void reloadApp (final File configFile ) {
102- LOGGER .info ("Reloading resource classes:" );
103- final ResourceConfig rc = new ResourceConfig ();
101+ WatchService watcher ;
104102
105103 try {
106- try (BufferedReader r = new BufferedReader (new InputStreamReader (new FileInputStream (configFile ), "UTF-8" ))) {
107- while (r .ready ()) {
108- final String className = r .readLine ();
109- if (!className .startsWith ("#" )) {
110- try {
111- rc .registerClasses (Class .forName (className ));
112- LOGGER .info (String .format (" + loaded class %s.\n " , className ));
113- } catch (final ClassNotFoundException ex ) {
114- LOGGER .info (String .format (" ! class %s not found.\n " , className ));
104+ watcher = FileSystems .getDefault ().newWatchService ();
105+
106+ Path srcDir = Paths .get ("src/main/java/org/glassfish/jersey/examples/reload" );
107+ registerWatcher (watcher , srcDir );
108+
109+ Path configFilePath = Paths .get ("." );
110+ registerWatcher (watcher , configFilePath );
111+
112+ } catch (IOException e ) {
113+ e .printStackTrace ();
114+ throw new RuntimeException ("Could not initialize watcher service!" );
115+ }
116+
117+ for (;;) {
118+
119+ try {
120+ final WatchKey watchKey = watcher .take ();
121+
122+ try {
123+ for (WatchEvent <?> event : watchKey .pollEvents ()) {
124+ final WatchEvent .Kind <?> kind = event .kind ();
125+ if (kind == StandardWatchEventKinds .ENTRY_MODIFY ) {
126+ WatchEvent <Path > pathEvent = (WatchEvent <Path >) event ;
127+ Path modifiedFile = pathEvent .context ();
128+ System .out .printf ("FILE MODIFIED: %s\n " , modifiedFile );
115129 }
116- } else {
117- LOGGER .info (String .format (" - ignored class %s\n " , className .substring (1 )));
118130 }
131+ } finally {
132+ watchKey .reset (); // so that consecutive events could be processed
119133 }
134+
135+ final File configFile = new File (CONFIG_FILENAME );
136+ reloadApp (configFile );
137+ } catch (InterruptedException e ) {
138+ Thread .currentThread ().interrupt ();
120139 }
121- } catch (final Exception ex ) {
122- Logger .getLogger (App .class .getName ()).log (Level .SEVERE , null , ex );
123140 }
141+ }
142+
143+ private void registerWatcher (WatchService watcher , Path directory ) throws IOException {
144+ directory .register (watcher ,
145+ new WatchEvent .Kind []{
146+ StandardWatchEventKinds .ENTRY_MODIFY
147+ },
148+ SensitivityWatchEventModifier .HIGH );
149+ }
150+
151+ private void reloadApp (final File configFile ) {
152+ LOGGER .info ("Reloading resource classes:" );
153+ final ResourceConfig rc = createResourceConfig (configFile );
124154 App .container .reload (rc );
125155 }
126156
127157 }
128158
129- public static void main (final String [] args ) {
159+ private static ResourceConfig createResourceConfig (File configFile ) {
160+ final ResourceConfig rc = new ResourceConfig ();
161+
130162 try {
131- LOGGER .info ("Resource Config Reload Jersey Example App" );
163+ final AppClassLoader appClassLoader = new AppClassLoader (Thread .currentThread ().getContextClassLoader ());
164+ final List <JavaFile > javaFiles = getJavaFiles (configFile );
132165
133- final ResourceConfig resourceConfig = new ResourceConfig ( ArrivalsResource . class );
134- resourceConfig . registerInstances ( new ContainerLifecycleListener () {
135- @ Override
136- public void onStartup ( final Container container ) {
137- App . container = container ;
138- final Timer t = new Timer ( true );
139- t . scheduleAtFixedRate ( new FileCheckTask ( 0 ), 0 , REFRESH_PERIOD_MS );
166+ Compiler . compile ( appClassLoader , javaFiles );
167+
168+ for ( JavaFile javaFile : javaFiles ) {
169+ try {
170+ rc . registerClasses ( appClassLoader . loadClass ( javaFile . getClassName ())) ;
171+ } catch ( final ClassNotFoundException ex ) {
172+ LOGGER . info ( String . format ( " ! class %s not found. \n " , javaFile . getClassName ()) );
140173 }
174+ }
175+ } catch (final Exception ex ) {
176+ Logger .getLogger (App .class .getName ()).log (Level .SEVERE , null , ex );
177+ }
141178
142- @ Override
143- public void onReload (final Container container ) {
144- System .out .println ("Application has been reloaded!" );
179+ return rc ;
180+ }
181+
182+ private static List <JavaFile > getJavaFiles (File configFile ) throws Exception {
183+
184+ final List <JavaFile > javaFiles = new LinkedList <>();
185+
186+ try (BufferedReader r = new BufferedReader (new InputStreamReader (new FileInputStream (configFile ), "UTF-8" ))) {
187+ while (r .ready ()) {
188+ final String className = r .readLine ();
189+ if (!className .startsWith ("#" )) {
190+ javaFiles .add (new JavaFile (className , SRC_MAIN_JAVA ));
191+ LOGGER .info (String .format (" + included class %s.\n " , className ));
192+ } else {
193+ LOGGER .info (String .format (" - ignored class %s\n " , className .substring (1 )));
145194 }
195+ }
196+ }
197+ return javaFiles ;
198+ }
146199
147- @ Override
148- public void onShutdown (final Container container ) {
149- // ignore
200+ public static void main (final String [] args ) throws Exception {
201+ try {
202+ LOGGER .info ("Resource Config Reload Jersey Example App" );
203+
204+ for (String s : args ) {
205+ if (s .startsWith ("-cp=" )) {
206+ Compiler .classpath = s .substring (4 );
150207 }
151- });
208+ }
209+
210+ final ResourceConfig resourceConfig = createResourceConfig (new File (CONFIG_FILENAME ));
211+ registerReloader (resourceConfig );
152212
153213 final HttpServer server = GrizzlyHttpServerFactory .createHttpServer (BASE_URI , resourceConfig , true );
154214 Runtime .getRuntime ().addShutdownHook (new Thread (new Runnable () {
@@ -167,4 +227,30 @@ public void run() {
167227 Logger .getLogger (App .class .getName ()).log (Level .SEVERE , null , ex );
168228 }
169229 }
230+
231+ private static Class <?> loadClass (String className ) throws Exception {
232+ final JavaFile javaFile = new JavaFile (className , SRC_MAIN_JAVA );
233+ return Compiler .compile (className , javaFile );
234+ }
235+
236+ private static void registerReloader (ResourceConfig resourceConfig ) {
237+ resourceConfig .registerInstances (new ContainerLifecycleListener () {
238+ @ Override
239+ public void onStartup (final Container container ) {
240+ App .container = container ;
241+ final Timer t = new Timer (true );
242+ t .schedule (new FileCheckTask (), 0 );
243+ }
244+
245+ @ Override
246+ public void onReload (final Container container ) {
247+ System .out .println ("Application has been reloaded!" );
248+ }
249+
250+ @ Override
251+ public void onShutdown (final Container container ) {
252+ // ignore
253+ }
254+ });
255+ }
170256}
0 commit comments