Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit 63d004f

Browse files
committed
after/complete handler must work when going async fix jooby-project#423
1 parent dbaac5a commit 63d004f

File tree

11 files changed

+228
-63
lines changed

11 files changed

+228
-63
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.jooby.issues;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import java.util.concurrent.ExecutorService;
6+
import java.util.concurrent.Executors;
7+
import java.util.concurrent.atomic.AtomicReference;
8+
9+
import org.jooby.Results;
10+
import org.jooby.test.OnServer;
11+
import org.jooby.test.ServerFeature;
12+
import org.jooby.undertow.Undertow;
13+
import org.junit.After;
14+
import org.junit.Test;
15+
16+
@OnServer(Undertow.class)
17+
public class Issue423 extends ServerFeature {
18+
19+
private static final AtomicReference<String> T = new AtomicReference<>(null);
20+
{
21+
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
22+
Thread t = new Thread(r, "deferred");
23+
t.setDaemon(true);
24+
return t;
25+
});
26+
27+
after((req, rsp, result) -> {
28+
return Results.ok("async:" + result.get());
29+
});
30+
31+
after((req, rsp, result) -> {
32+
Thread thread = Thread.currentThread();
33+
return Results.ok(thread.getName() + ":" + result.get());
34+
});
35+
36+
complete((req, rsp, err) -> {
37+
Thread thread = Thread.currentThread();
38+
T.set(thread.getName());
39+
});
40+
41+
get("/423", promise(deferred -> {
42+
executor.execute(() -> {
43+
deferred.resolve("foo");
44+
});
45+
}));
46+
}
47+
48+
@Test
49+
public void afterCompleteCallbacksShouldRunInAsyncMode() throws Exception {
50+
request()
51+
.get("/423")
52+
.expect("async:deferred:foo");
53+
}
54+
55+
@After
56+
public void after() {
57+
assertEquals("deferred", T.getAndSet(null));
58+
}
59+
60+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.jooby.issues;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import java.util.concurrent.ExecutorService;
6+
import java.util.concurrent.Executors;
7+
import java.util.concurrent.atomic.AtomicReference;
8+
9+
import org.jooby.test.OnServer;
10+
import org.jooby.test.ServerFeature;
11+
import org.jooby.undertow.Undertow;
12+
import org.junit.After;
13+
import org.junit.Test;
14+
15+
@OnServer(Undertow.class)
16+
public class Issue423b extends ServerFeature {
17+
18+
private static final AtomicReference<String> T = new AtomicReference<>(null);
19+
{
20+
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
21+
Thread t = new Thread(r, "deferred");
22+
t.setDaemon(true);
23+
return t;
24+
});
25+
26+
renderer((v, ctx) -> {
27+
throw new IllegalStateException("renderer-err");
28+
});
29+
complete((req, rsp, err) -> {
30+
Thread thread = Thread.currentThread();
31+
T.set(thread.getName() + ":" + err.get().getMessage());
32+
});
33+
34+
get("/423", promise(deferred -> {
35+
executor.execute(() -> {
36+
deferred.resolve("foo");
37+
});
38+
}));
39+
}
40+
41+
@Test
42+
public void shouldImportStartStopCallback() throws Exception {
43+
request()
44+
.get("/423")
45+
.expect(500);
46+
}
47+
48+
@After
49+
public void after() {
50+
assertEquals("deferred:renderer-err", T.getAndSet(null));
51+
}
52+
53+
}

jooby-couchbase/src/test/java/org/jooby/couchbase/CouchbaseTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,10 @@ public void envproperty() throws Exception {
149149
Config conf = ConfigFactory.empty()
150150
.withValue("couchbase.env.kvEndpoints", ConfigValueFactory.fromAnyRef(5));
151151
new MockUnit(Env.class, Config.class, Binder.class)
152-
.expect(setProperty(bucket))
153152
.expect(unit -> {
154153
Config mock = unit.get(Config.class);
155154
expect(mock.hasPath("couchbase.env")).andReturn(true);
156155
expect(mock.getConfig("couchbase.env")).andReturn(conf.getConfig("couchbase.env"));
157-
158-
expect(System.setProperty("com.couchbase.kvEndpoints", "5")).andReturn(null);
159156
})
160157
.expect(createEnv)
161158
.expect(bindEnv)
@@ -194,6 +191,7 @@ public void envproperty() throws Exception {
194191
.run(unit -> {
195192
new Couchbase("couchbase://localhost/" + bucket)
196193
.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
194+
assertEquals("5", System.getProperty("com.couchbase.kvEndpoints"));
197195
});
198196
}
199197

jooby-couchbase/src/test/java/org/jooby/couchbase/N1QTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class N1QTest {
99
@Test
1010
public void from() {
1111
new N1Q();
12+
System.getProperties().remove(N1Q.COUCHBASE_DEFBUCKET);
1213
assertEquals("SELECT N.* FROM `default` N WHERE N._class = \"org.jooby.couchbase.N1QTest\"",
1314
N1Q.from(N1QTest.class).toString());
1415
}

jooby-pac4j/src/main/java/org/jooby/internal/pac4j/AuthCallback.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public AuthCallback(final Clients clients, final AuthStore store,
6464

6565
@SuppressWarnings("unchecked")
6666
@Override
67-
public void handle(final Request req, final Response rsp, final Chain chain) throws Exception {
67+
public void handle(final Request req, final Response rsp, final Chain chain) throws Throwable {
6868
WebContext ctx = req.require(WebContext.class);
6969

7070
List<Client> clientList = clients.findAllClients();

jooby-pac4j/src/main/java/org/jooby/internal/pac4j/AuthLogout.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public AuthLogout(final String redirectTo) {
4545

4646
@SuppressWarnings("unchecked")
4747
@Override
48-
public void handle(final Request req, final Response rsp) throws Exception {
48+
public void handle(final Request req, final Response rsp) throws Throwable {
4949
// DON'T create a session for JWT/param/header auth (a.k.a stateless)
5050
Optional<Session> ifSession = req.ifSession();
5151
if (ifSession.isPresent()) {

jooby/src/main/java/org/jooby/Response.java

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,27 @@ public Forwarding(final Response response) {
5959
}
6060

6161
@Override
62-
public void download(final String filename, final InputStream stream) throws Exception {
62+
public void download(final String filename, final InputStream stream) throws Throwable {
6363
rsp.download(filename, stream);
6464
}
6565

6666
@Override
67-
public void download(final File file) throws Exception {
67+
public void download(final File file) throws Throwable {
6868
rsp.download(file);
6969
}
7070

7171
@Override
72-
public void download(final String filename, final File file) throws Exception {
72+
public void download(final String filename, final File file) throws Throwable {
7373
rsp.download(filename, file);
7474
}
7575

7676
@Override
77-
public void download(final String filename) throws Exception {
77+
public void download(final String filename) throws Throwable {
7878
rsp.download(filename);
7979
}
8080

8181
@Override
82-
public void download(final String filename, final String location) throws Exception {
82+
public void download(final String filename, final String location) throws Throwable {
8383
rsp.download(filename, location);
8484
}
8585

@@ -182,12 +182,12 @@ public void end() {
182182
}
183183

184184
@Override
185-
public void redirect(final String location) throws Exception {
185+
public void redirect(final String location) throws Throwable {
186186
rsp.redirect(location);
187187
}
188188

189189
@Override
190-
public void redirect(final Status status, final String location) throws Exception {
190+
public void redirect(final Status status, final String location) throws Throwable {
191191
rsp.redirect(status, location);
192192
}
193193

@@ -213,6 +213,16 @@ public boolean committed() {
213213
return rsp.committed();
214214
}
215215

216+
@Override
217+
public void push(final Route.After handler) {
218+
rsp.push(handler);
219+
}
220+
221+
@Override
222+
public void push(final Route.Complete handler) {
223+
rsp.push(handler);
224+
}
225+
216226
@Override
217227
public String toString() {
218228
return rsp.toString();
@@ -243,7 +253,7 @@ public static Response unwrap(final Response rsp) {
243253
* @param stream A stream to attach.
244254
* @throws Exception If something goes wrong.
245255
*/
246-
void download(String filename, InputStream stream) throws Exception;
256+
void download(String filename, InputStream stream) throws Throwable;
247257

248258
/**
249259
* Transfer the file at path as an "attachment". Typically, browsers will prompt the user for
@@ -253,7 +263,7 @@ public static Response unwrap(final Response rsp) {
253263
* @param location Classpath location of the file.
254264
* @throws Exception If something goes wrong.
255265
*/
256-
default void download(final String location) throws Exception {
266+
default void download(final String location) throws Throwable {
257267
download(location, location);
258268
}
259269

@@ -266,7 +276,7 @@ default void download(final String location) throws Exception {
266276
* @param location classpath location of the file.
267277
* @throws Exception If something goes wrong.
268278
*/
269-
void download(final String filename, final String location) throws Exception;
279+
void download(final String filename, final String location) throws Throwable;
270280

271281
/**
272282
* Transfer the file at path as an "attachment". Typically, browsers will prompt the user for
@@ -276,7 +286,7 @@ default void download(final String location) throws Exception {
276286
* @param file A file to use.
277287
* @throws Exception If something goes wrong.
278288
*/
279-
default void download(final File file) throws Exception {
289+
default void download(final File file) throws Throwable {
280290
download(file.getName(), file);
281291
}
282292

@@ -289,7 +299,7 @@ default void download(final File file) throws Exception {
289299
* @param file A file to use.
290300
* @throws Exception If something goes wrong.
291301
*/
292-
default void download(final String filename, final File file) throws Exception {
302+
default void download(final String filename, final File file) throws Throwable {
293303
length(file.length());
294304
download(filename, new FileInputStream(file));
295305
}
@@ -504,9 +514,9 @@ default void send(final Object result) throws Throwable {
504514
* </pre>
505515
*
506516
* @param location Either a relative or absolute location.
507-
* @throws Exception If redirection fails.
517+
* @throws Throwable If redirection fails.
508518
*/
509-
default void redirect(final String location) throws Exception {
519+
default void redirect(final String location) throws Throwable {
510520
redirect(Status.FOUND, location);
511521
}
512522

@@ -567,9 +577,9 @@ default void redirect(final String location) throws Exception {
567577
*
568578
* @param status A redirect status.
569579
* @param location Either a relative or absolute location.
570-
* @throws Exception If redirection fails.
580+
* @throws Throwable If redirection fails.
571581
*/
572-
void redirect(Status status, String location) throws Exception;
582+
void redirect(Status status, String location) throws Throwable;
573583

574584
/**
575585
* @return A HTTP status or empty if status was not set yet.
@@ -620,4 +630,7 @@ default Response status(final int status) {
620630
*/
621631
void end();
622632

633+
void push(Route.After handler);
634+
635+
void push(Route.Complete handler);
623636
}

jooby/src/main/java/org/jooby/Route.java

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import java.util.function.Function;
3939
import java.util.stream.Collectors;
4040

41-
import org.jooby.internal.DeferredExecution;
4241
import org.jooby.internal.RouteImpl;
4342
import org.jooby.internal.RouteMatcher;
4443
import org.jooby.internal.RoutePattern;
@@ -1906,13 +1905,8 @@ default void handle(final Request req, final Response rsp, final Chain chain) th
19061905
interface After extends Filter {
19071906
@Override
19081907
default void handle(final Request req, final Response rsp, final Chain chain) throws Throwable {
1909-
chain.next(req, new Response.Forwarding(rsp) {
1910-
1911-
@Override
1912-
public void send(final Result result) throws Throwable {
1913-
super.send(handle(req, rsp, result));
1914-
}
1915-
});
1908+
rsp.push(this);
1909+
chain.next(req, rsp);
19161910
}
19171911

19181912
/**
@@ -2034,18 +2028,8 @@ interface Complete extends Filter {
20342028

20352029
@Override
20362030
default void handle(final Request req, final Response rsp, final Chain chain) throws Throwable {
2037-
Optional<Throwable> err = Optional.empty();
2038-
try {
2039-
chain.next(req, rsp);
2040-
} catch (DeferredExecution ex) {
2041-
// try it as success
2042-
throw ex;
2043-
} catch (Throwable cause) {
2044-
err = Optional.of(cause);
2045-
throw cause;
2046-
} finally {
2047-
handle(req, rsp, err);
2048-
}
2031+
rsp.push(this);
2032+
chain.next(req, rsp);
20492033
}
20502034

20512035
/**

0 commit comments

Comments
 (0)