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

Commit 5d211bd

Browse files
committed
Implement route chain/stack
* introduce filter and route chain * remove route interceptor * simplify programming model in general * a few more unit tests
1 parent 4734f2f commit 5d211bd

38 files changed

Lines changed: 616 additions & 330 deletions

examples/src/main/java/jooby/MyApp.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@
203203
*/
204204
package jooby;
205205

206+
import javax.persistence.EntityManager;
207+
206208
import jooby.jetty.Jetty;
207209

208210
public class MyApp extends Jooby {
@@ -214,11 +216,25 @@ public class MyApp extends Jooby {
214216
use(new Jackson());
215217
use(new Hbs());
216218

217-
get("/", (req, resp) -> {
218-
resp.send(Viewable.of("user", new User()));
219+
get("/default/users", (req, resp) -> {
220+
221+
EntityManager em = req.getInstance(EntityManager.class);
222+
223+
User user1 = new User();
224+
user1.setFirstName("edgar");
225+
user1.setLastName("espina");
226+
user1.setId("1");
227+
em.persist(user1);
228+
229+
resp.send(user1);
219230
});
220231

221-
route(Users.class);
232+
get("/users", (req, resp) -> {
233+
234+
EntityManager em = req.getInstance(EntityManager.class);
235+
236+
resp.send(em.createQuery("from User").getResultList());
237+
});
222238

223239
}
224240

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package jooby;
2+
3+
public interface Filter {
4+
5+
void handle(Request request, Response response, RouteChain chain) throws Exception;
6+
7+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package jooby;
2+
3+
import static java.util.Objects.requireNonNull;
4+
5+
import java.nio.charset.Charset;
6+
import java.util.Optional;
7+
8+
import jooby.Response.ContentNegotiation.Provider;
9+
10+
public class ForwardingResponse implements Response {
11+
12+
private Response response;
13+
14+
public ForwardingResponse(final Response response) {
15+
this.response = requireNonNull(response, "A response is required.");
16+
}
17+
18+
@Override
19+
public HttpHeader header(final String name) {
20+
return response.header(name);
21+
}
22+
23+
@Override
24+
public Charset charset() {
25+
return response.charset();
26+
}
27+
28+
@Override
29+
public Response charset(final Charset charset) {
30+
return response.charset(charset);
31+
}
32+
33+
@Override
34+
public Optional<MediaType> type() {
35+
return response.type();
36+
}
37+
38+
@Override
39+
public Response type(final MediaType type) {
40+
return response.type(type);
41+
}
42+
43+
@Override
44+
public void send(final Object body) throws Exception {
45+
response.send(body);
46+
}
47+
48+
@Override
49+
public void send(final Object body, final BodyConverter converter) throws Exception {
50+
response.send(body, converter);
51+
}
52+
53+
@Override
54+
public ContentNegotiation when(final String type, final Provider provider) {
55+
return response.when(type, provider);
56+
}
57+
58+
@Override
59+
public ContentNegotiation when(final MediaType type, final Provider provider) {
60+
return response.when(type, provider);
61+
}
62+
63+
@Override
64+
public HttpStatus status() {
65+
return response.status();
66+
}
67+
68+
@Override
69+
public Response status(final HttpStatus status) {
70+
return response.status(status);
71+
}
72+
73+
@Override
74+
public boolean committed() {
75+
return response.committed();
76+
}
77+
78+
}

jooby-core/src/main/java/jooby/HttpStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ public String reason() {
562562
*/
563563
@Override
564564
public String toString() {
565-
return Integer.toString(value);
565+
return reason() + " (" + value + ")";
566566
}
567567

568568

jooby-core/src/main/java/jooby/Jooby.java

Lines changed: 26 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* <h1>Starting a new application:</h1>
5050
* <p>
5151
* A new application must extends Jooby, choose a server implementation, register one ore more
52-
* {@link BodyConverter} and defines some {@link Route routes}. It sounds like a lot of work to do,
52+
* {@link BodyConverter} and defines some {@link Router routes}. It sounds like a lot of work to do,
5353
* but it isn't.
5454
* </p>
5555
*
@@ -276,7 +276,7 @@
276276
* @see Request
277277
* @see Response
278278
* @see BodyConverter
279-
* @see Route
279+
* @see Router
280280
* @see RouteInterceptor
281281
* @see RequestModule
282282
*/
@@ -314,6 +314,14 @@ public class Jooby {
314314
/** Keep the global injector instance. */
315315
private Injector injector;
316316

317+
public RouteDefinition use(final Filter filter) {
318+
return use("/**", filter);
319+
}
320+
321+
public RouteDefinition use(final String path, final Filter filter) {
322+
return route(new RouteDefinitionImpl("*", path, filter));
323+
}
324+
317325
/**
318326
* Define an in-line route that supports HTTP GET method:
319327
*
@@ -329,33 +337,12 @@ public class Jooby {
329337
* @param route A route to execute. Required.
330338
* @return A new route definition.
331339
*/
332-
public RouteDefinition get(final String path, final Route route) {
340+
public RouteDefinition get(final String path, final Router route) {
333341
return route(new RouteDefinitionImpl("GET", path, route));
334342
}
335343

336-
/**
337-
* Define an external route that supports HTTP GET method:
338-
*
339-
* <pre>
340-
* get("/", MyRoute.class);
341-
*
342-
* // MyRoute.java
343-
* public class MyRoute implements Route {
344-
* public void handle(Request request, Response response) {
345-
* response.send(something);
346-
* }
347-
* }
348-
* </pre>
349-
*
350-
* An external route is created per-request. They aren't singleton.
351-
*
352-
* @param path A route path. Required.
353-
* @param route A route to execute. Required.
354-
* @return A new route definition.
355-
* @see RequestModule
356-
*/
357-
public RouteDefinition get(final String path, final Class<? extends Route> route) {
358-
return route(new RouteDefinitionImpl("GET", path, wrapRoute(route)));
344+
public RouteDefinition get(final String path, final Filter filter) {
345+
return route(new RouteDefinitionImpl("GET", path, filter));
359346
}
360347

361348
/**
@@ -373,33 +360,12 @@ public RouteDefinition get(final String path, final Class<? extends Route> route
373360
* @param route A route to execute. Required.
374361
* @return A new route definition.
375362
*/
376-
public RouteDefinition post(final String path, final Route route) {
363+
public RouteDefinition post(final String path, final Router route) {
377364
return route(new RouteDefinitionImpl("POST", path, route));
378365
}
379366

380-
/**
381-
* Define an external route that supports HTTP POST method:
382-
*
383-
* <pre>
384-
* post("/", MyRoute.class);
385-
*
386-
* // MyRoute.java
387-
* public class MyRoute implements Route {
388-
* public void handle(Request request, Response response) {
389-
* response.send(something);
390-
* }
391-
* }
392-
* </pre>
393-
*
394-
* An external route is created per-request. They aren't singleton.
395-
*
396-
* @param path A route path. Required.
397-
* @param route A route to execute. Required.
398-
* @return A new route definition.
399-
* @see RequestModule
400-
*/
401-
public RouteDefinition post(final String path, final Class<? extends Route> route) {
402-
return route(new RouteDefinitionImpl("POST", path, wrapRoute(route)));
367+
public RouteDefinition post(final String path, final Filter filter) {
368+
return route(new RouteDefinitionImpl("POST", path, filter));
403369
}
404370

405371
/**
@@ -417,33 +383,12 @@ public RouteDefinition post(final String path, final Class<? extends Route> rout
417383
* @param route A route to execute. Required.
418384
* @return A new route definition.
419385
*/
420-
public RouteDefinition put(final String path, final Route route) {
386+
public RouteDefinition put(final String path, final Router route) {
421387
return route(new RouteDefinitionImpl("PUT", path, route));
422388
}
423389

424-
/**
425-
* Define an external route that supports HTTP PUT method:
426-
*
427-
* <pre>
428-
* put("/", MyRoute.class);
429-
*
430-
* // MyRoute.java
431-
* public class MyRoute implements Route {
432-
* public void handle(Request request, Response response) {
433-
* response.send(something);
434-
* }
435-
* }
436-
* </pre>
437-
*
438-
* An external route is created per-request. They aren't singleton.
439-
*
440-
* @param path A route path. Required.
441-
* @param route A route to execute. Required.
442-
* @return A new route definition.
443-
* @see RequestModule
444-
*/
445-
public RouteDefinition put(final String path, final Class<? extends Route> route) {
446-
return route(new RouteDefinitionImpl("PUT", path, wrapRoute(route)));
390+
public RouteDefinition put(final String path, final Filter filter) {
391+
return route(new RouteDefinitionImpl("PUT", path, filter));
447392
}
448393

449394
/**
@@ -458,36 +403,15 @@ public RouteDefinition put(final String path, final Class<? extends Route> route
458403
* This is a singleton route so make sure you don't share or use global variables.
459404
*
460405
* @param path A route path. Required.
461-
* @param route A route to execute. Required.
406+
* @param router A route to execute. Required.
462407
* @return A new route definition.
463408
*/
464-
public RouteDefinition delete(final String path, final Route route) {
465-
return route(new RouteDefinitionImpl("DELETE", path, route));
409+
public RouteDefinition delete(final String path, final Router router) {
410+
return route(new RouteDefinitionImpl("DELETE", path, router));
466411
}
467412

468-
/**
469-
* Define an external route that supports HTTP DELETE method:
470-
*
471-
* <pre>
472-
* delete("/", MyRoute.class);
473-
*
474-
* // MyRoute.java
475-
* public class MyRoute implements Route {
476-
* public void handle(Request request, Response response) {
477-
* response.send(something);
478-
* }
479-
* }
480-
* </pre>
481-
*
482-
* An external route is created per-request. They aren't singleton.
483-
*
484-
* @param path A route path. Required.
485-
* @param route A route to execute. Required.
486-
* @return A new route definition.
487-
* @see RequestModule
488-
*/
489-
public RouteDefinition delete(final String path, final Class<? extends Route> route) {
490-
return route(new RouteDefinitionImpl("DELETE", path, wrapRoute(route)));
413+
public RouteDefinition delete(final String path, final Filter filter) {
414+
return route(new RouteDefinitionImpl("DELETE", path, filter));
491415
}
492416

493417
/**
@@ -496,7 +420,7 @@ public RouteDefinition delete(final String path, final Class<? extends Route> ro
496420
* @param route The external route class.
497421
* @return A new inline route.
498422
*/
499-
private static Route wrapRoute(final Class<? extends Route> route) {
423+
private static Router wrapRouter(final Class<? extends Router> route) {
500424
return (req, resp) -> req.getInstance(route).handle(req, resp);
501425
}
502426

@@ -514,7 +438,7 @@ private static Route wrapRoute(final Class<? extends Route> route) {
514438
* @return A new route definition.
515439
*/
516440
public RouteDefinition assets(final String path) {
517-
return get(path, AssetRoute.class);
441+
return get(path, wrapRouter(AssetRoute.class));
518442
}
519443

520444
/**
@@ -669,9 +593,6 @@ public void configure(final Binder binder) {
669593
requestModule.addBinding().toInstance(
670594
rm -> protoRoutes.forEach(routeClass -> rm.bind(routeClass)));
671595

672-
// Route Interceptors
673-
Multibinder.newSetBinder(binder, RouteInterceptor.class);
674-
675596
// tmp dir
676597
binder.bind(File.class).annotatedWith(Names.named("java.io.tmpdir"))
677598
.toInstance(new File(config.getString("java.io.tmpdir")));

jooby-core/src/main/java/jooby/JoobyModule.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import com.typesafe.config.ConfigFactory;
99

1010
/**
11-
* A module can publish or produces: {@link Route routes}, {@link BodyConverter converters},
11+
* A module can publish or produces: {@link Router routes}, {@link BodyConverter converters},
1212
* {@link RequestModule request modules}, {@link RouteInterceptor interceptors} and any other
1313
* application specific service or contract of your choice.
1414
* <p>
@@ -30,13 +30,13 @@
3030
* @see Jooby#use(JoobyModule)
3131
*/
3232
@Beta
33-
public interface JoobyModule {
33+
public abstract class JoobyModule {
3434

3535
/**
3636
* @return Produces a module config object (when need it). By default a module doesn't produce
3737
* any configuration object.
3838
*/
39-
default @Nonnull Config config() {
39+
public @Nonnull Config config() {
4040
return ConfigFactory.empty();
4141
}
4242

@@ -46,7 +46,7 @@ public interface JoobyModule {
4646
*
4747
* @throws Exception If something goes wrong.
4848
*/
49-
default void start() throws Exception {
49+
public void start() throws Exception {
5050
}
5151

5252
/**
@@ -55,7 +55,7 @@ default void start() throws Exception {
5555
*
5656
* @throws Exception If something goes wrong.
5757
*/
58-
default void stop() throws Exception {
58+
public void stop() throws Exception {
5959
}
6060

6161
/**
@@ -68,6 +68,6 @@ default void stop() throws Exception {
6868
* @param binder A guice binder. Not null.
6969
* @throws Exception If the module fails during configuration.
7070
*/
71-
void configure(@Nonnull Mode mode, @Nonnull Config config, @Nonnull Binder binder)
71+
public abstract void configure(@Nonnull Mode mode, @Nonnull Config config, @Nonnull Binder binder)
7272
throws Exception;
7373
}

0 commit comments

Comments
 (0)