2525import java .nio .file .Files ;
2626import java .nio .file .Path ;
2727import java .nio .file .Paths ;
28+ import java .util .ArrayList ;
29+ import java .util .Iterator ;
30+ import java .util .LinkedList ;
2831import java .util .List ;
2932import java .util .ServiceLoader ;
3033import java .util .concurrent .Executor ;
3538
3639public class Jooby implements Router {
3740
38- private final RouterImpl router ;
41+ private RouterImpl router ;
3942
4043 private ExecutionMode mode = ExecutionMode .DEFAULT ;
4144
4245 private Consumer <Server > serverConfigurer ;
4346
4447 private Path tmpdir ;
4548
49+ private List <Throwing .Runnable > startCallbacks ;
50+
51+ private List <Throwing .Runnable > readyCallbacks ;
52+
53+ private LinkedList <Throwing .Runnable > stopCallbacks ;
54+
4655 /**
4756 * Not ideal but useful. We want to have access to environment properties from instance
4857 * initializer. So external method before creating a new Jooby instance does a call to
@@ -64,12 +73,36 @@ public Env environment() {
6473 return environment ;
6574 }
6675
67- public Jooby environment (Env environment ) {
76+ public Jooby environment (@ Nonnull Env environment ) {
6877 this .environment = environment ;
6978 return this ;
7079 }
7180
72- @ Nonnull @ Override public Jooby basePath (String basePath ) {
81+ public Jooby onStart (@ Nonnull Throwing .Runnable task ) {
82+ if (startCallbacks == null ) {
83+ startCallbacks = new ArrayList <>();
84+ }
85+ startCallbacks .add (task );
86+ return this ;
87+ }
88+
89+ public Jooby onStarted (@ Nonnull Throwing .Runnable task ) {
90+ if (readyCallbacks == null ) {
91+ readyCallbacks = new ArrayList <>();
92+ }
93+ readyCallbacks .add (task );
94+ return this ;
95+ }
96+
97+ public Jooby onStop (@ Nonnull Throwing .Runnable task ) {
98+ if (stopCallbacks == null ) {
99+ stopCallbacks = new LinkedList <>();
100+ }
101+ stopCallbacks .addFirst (task );
102+ return this ;
103+ }
104+
105+ @ Nonnull @ Override public Jooby basePath (@ Nonnull String basePath ) {
73106 router .basePath (basePath );
74107 return this ;
75108 }
@@ -247,7 +280,19 @@ public Jooby start(Server server) {
247280 ensureTmpdir (tmpdir );
248281 Logger log = log ();
249282 log .debug ("environment:\n {}" , environment );
283+
250284 router .start (this );
285+
286+ fireStart ();
287+
288+ return this ;
289+ }
290+
291+ public Jooby ready (Server server ) {
292+ Logger log = log ();
293+
294+ fireStarted ();
295+
251296 log .info ("{} [{}@{}]\n \n {}\n \n listening on:\n http://localhost:{}{}\n " ,
252297 getClass ().getSimpleName (),
253298 server .getClass ().getSimpleName ().toLowerCase (), mode .name ().toLowerCase (), router ,
@@ -256,7 +301,17 @@ public Jooby start(Server server) {
256301 }
257302
258303 public Jooby stop () {
259- router .destroy ();
304+ if (router != null ) {
305+ router .destroy ();
306+ router = null ;
307+ }
308+
309+ fireStop ();
310+ return this ;
311+ }
312+
313+ public Jooby configureServer (Consumer <Server > configurer ) {
314+ this .serverConfigurer = configurer ;
260315 return this ;
261316 }
262317
@@ -298,8 +353,43 @@ private static String appname(Class<?> clazz) {
298353 return segments .length == 1 ? segments [0 ] : segments [segments .length - 2 ];
299354 }
300355
301- public Jooby configureServer (Consumer <Server > configurer ) {
302- this .serverConfigurer = configurer ;
303- return this ;
356+ private void fireStart () {
357+ if (startCallbacks != null ) {
358+ fire (startCallbacks );
359+ startCallbacks = null ;
360+ }
361+ }
362+
363+ private void fireStarted () {
364+ if (readyCallbacks != null ) {
365+ fire (readyCallbacks );
366+ readyCallbacks = null ;
367+ }
368+ }
369+
370+ private void fire (List <Throwing .Runnable > tasks ) {
371+ Iterator <Throwing .Runnable > iterator = tasks .iterator ();
372+ while (iterator .hasNext ()) {
373+ Throwing .Runnable task = iterator .next ();
374+ task .run ();
375+ iterator .remove ();
376+ }
377+ }
378+
379+ private void fireStop () {
380+ if (stopCallbacks != null ) {
381+ List <Throwing .Runnable > tasks = stopCallbacks ;
382+ stopCallbacks = null ;
383+ Iterator <Throwing .Runnable > iterator = tasks .iterator ();
384+ while (iterator .hasNext ()) {
385+ Throwing .Runnable task = iterator .next ();
386+ try {
387+ task .run ();
388+ } catch (Exception x ) {
389+ log ().info ("exception found while executing onStop:" , x );
390+ }
391+ iterator .remove ();
392+ }
393+ }
304394 }
305395}
0 commit comments