Skip to content

Commit 2ba4497

Browse files
committed
lifce cycle callbacks: onStart/onStarted/onStop
1 parent 16b85aa commit 2ba4497

9 files changed

Lines changed: 248 additions & 152 deletions

File tree

examples/src/main/java/examples/HelloApp.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import io.jooby.FileUpload;
2121
import io.jooby.json.Jackson;
2222

23+
import java.util.concurrent.Executors;
24+
2325
public class HelloApp extends Jooby {
2426

2527
public static class User {
@@ -109,6 +111,15 @@ public Message(String message) {
109111
ctx.statusCode(statusCode)
110112
.sendText(statusCode.reason());
111113
});
114+
115+
new Thread(() -> {
116+
try {
117+
Thread.sleep(5000);
118+
System.exit(0);
119+
} catch (InterruptedException e) {
120+
e.printStackTrace();
121+
}
122+
}).start();
112123
}
113124

114125
public static void main(String[] args) {

jooby/src/main/java/io/jooby/Functions.java

Lines changed: 0 additions & 61 deletions
This file was deleted.

jooby/src/main/java/io/jooby/Jooby.java

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import java.nio.file.Files;
2626
import java.nio.file.Path;
2727
import java.nio.file.Paths;
28+
import java.util.ArrayList;
29+
import java.util.Iterator;
30+
import java.util.LinkedList;
2831
import java.util.List;
2932
import java.util.ServiceLoader;
3033
import java.util.concurrent.Executor;
@@ -35,14 +38,20 @@
3538

3639
public 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\nlistening 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
}

jooby/src/main/java/io/jooby/Server.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,53 @@
1616
package io.jooby;
1717

1818
import javax.annotation.Nonnull;
19+
import java.util.List;
20+
import java.util.concurrent.Executor;
21+
import java.util.concurrent.atomic.AtomicBoolean;
22+
import java.util.function.Supplier;
1923

2024
public interface Server {
2125

26+
abstract class Base implements Server {
27+
28+
private AtomicBoolean stopping = new AtomicBoolean();
29+
30+
protected void fireStart(List<Jooby> applications, Supplier<Executor> workerProvider) {
31+
Executor serverWorker = null;
32+
for (Jooby app : applications) {
33+
Executor worker = app.worker();
34+
if (worker == null) {
35+
if (serverWorker == null) {
36+
// server worker is shared between app
37+
serverWorker = workerProvider.get();
38+
}
39+
app.worker(serverWorker);
40+
}
41+
app.start(this);
42+
}
43+
}
44+
45+
protected void fireReady(List<Jooby> applications) {
46+
for (Jooby app : applications) {
47+
app.ready(this);
48+
}
49+
}
50+
51+
protected void fireStop(List<Jooby> applications) {
52+
if (stopping.compareAndSet(false, true)) {
53+
if (applications != null) {
54+
for (Jooby app : applications) {
55+
app.stop();
56+
}
57+
}
58+
}
59+
}
60+
61+
protected void addShutdownHook() {
62+
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
63+
}
64+
}
65+
2266
/** 16KB constant. */
2367
int _16KB = 0x4000;
2468

@@ -41,4 +85,5 @@ public interface Server {
4185
@Nonnull Server stop();
4286

4387
@Nonnull Server gzip(boolean enabled);
88+
4489
}

jooby/src/test/java/io/jooby/FunctionsTest.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)