Skip to content

Commit 027b865

Browse files
committed
Ability to access the current context via the service registry.
See #1937
1 parent e300477 commit 027b865

9 files changed

Lines changed: 279 additions & 84 deletions

File tree

docs/asciidoc/context.adoc

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,46 @@
11
== Context
22

3-
A javadoc:Context[Context] allows you to interact with the HTTP Request and manipulate the HTTP Response
3+
A javadoc:Context[Context] allows you to interact with the HTTP Request and manipulate the HTTP Response.
4+
5+
In most of the cases you can access the context object as a parameter of your route handler:
6+
7+
.Java
8+
[source, java, role="primary"]
9+
----
10+
{
11+
get("/", ctx -> { /* do important stuff with variable 'ctx'. */ });
12+
}
13+
----
14+
15+
.Kotlin
16+
[source, kotlin, role="secondary"]
17+
----
18+
{
19+
get("/") { /* variable 'it' holds the context now. */ }
20+
}
21+
----
22+
23+
If you need to access the context via the service registry or dependency injection, you need to
24+
explicitly request the registration of it as a service with the following invocation:
25+
26+
.Java
27+
[source, java, role="primary"]
28+
----
29+
{
30+
setContextAsService(true);
31+
}
32+
----
33+
34+
.Kotlin
35+
[source, kotlin, role="secondary"]
36+
----
37+
{
38+
setContextAsService(true)
39+
}
40+
----
41+
42+
Important to note that the context is a *request scoped* object, it's only available through the service
43+
registry while the request it belongs to is being processed.
444

545
=== Parameters
646

@@ -35,14 +75,14 @@ response.
3575
[source, kotlin, role="secondary"]
3676
----
3777
{
38-
get("/") {
78+
get("/") { ctx ->
3979
val token = ctx.header("token").value() // <1>
4080
4181
val headers = ctx.headers() // <2>
4282
43-
val = ctx.headerMap(); // <3>
83+
val headerMap = ctx.headerMap(); // <3>
4484
...
45-
});
85+
}
4686
4787
}
4888
----
@@ -74,12 +114,12 @@ Request cookies are send to the server using the `Cookie` header, but we do prov
74114
[source, kotlin, role="secondary"]
75115
----
76116
{
77-
get("/") {
117+
get("/") { ctx ->
78118
val token = ctx.cookie("token").value() // <1>
79119
80-
val = ctx.cookieMap(); // <2>
120+
val cookieMap = ctx.cookieMap() // <2>
81121
...
82-
});
122+
}
83123
84124
}
85125
----
@@ -111,15 +151,15 @@ Path parameter are part of the `URI`. To define a path variable you need to use
111151
[source,kotlin,role="secondary"]
112152
----
113153
{
114-
get("/{id}") { ctx.path("id").value() } // <1>
154+
get("/{id}") { ctx -> ctx.path("id").value() } // <1>
115155
116-
get("/@{id}") { ctx.path("id").value() } // <2>
156+
get("/@{id}") { ctx -> ctx.path("id").value() } // <2>
117157
118-
get("/file/{name}.{ext}") { cxt.path("name") + "." + ctx.path("ext") } // <3>
158+
get("/file/{name}.{ext}") { ctx -> cxt.path("name") + "." + ctx.path("ext") } // <3>
119159
120-
get("/file/*") { ctx.path("*") } // <4>
160+
get("/file/*") { ctx -> ctx.path("*") } // <4>
121161
122-
get("/{id:[0-9]+}") { ctx.path("id) } // <5>
162+
get("/{id:[0-9]+}") { ctx -> ctx.path("id) } // <5>
123163
}
124164
----
125165

@@ -151,7 +191,7 @@ Path parameter are part of the `URI`. To define a path variable you need to use
151191
[source, kotlin, role="secondary"]
152192
----
153193
{
154-
get("/{name}") {
194+
get("/{name}") { ctx ->
155195
val pathString = ctx.getRequestPath() // <1>
156196
157197
val path = ctx.path() // <2>
@@ -161,7 +201,7 @@ Path parameter are part of the `URI`. To define a path variable you need to use
161201
val name = ctx.path("name").value() // <4>
162202
163203
...
164-
});
204+
}
165205
}
166206
----
167207

@@ -226,7 +266,7 @@ class SearchQuery {
226266
[source, kotlin, role="secondary"]
227267
----
228268
{
229-
get("/search") {
269+
get("/search") { ctx ->
230270
val queryString = ctx.queryString() // <1>
231271
232272
val query = ctx.query() // <2>
@@ -238,7 +278,7 @@ class SearchQuery {
238278
val searchQuery = ctx.query<SearchQuery>() // <5>
239279
240280
...
241-
});
281+
}
242282
}
243283
244284
data class SearchQuery (val q: String)
@@ -316,7 +356,7 @@ class User {
316356
[source, kotlin, role="secondary"]
317357
----
318358
{
319-
post("/user") {
359+
post("/user") { ctx ->
320360
val form = ctx.form() // <1>
321361
322362
val formMap = ctx.formMultimap() // <2>
@@ -328,7 +368,7 @@ class User {
328368
val user = ctx.form<User>() // <5>
329369
330370
...
331-
});
371+
}
332372
}
333373
334374
data class User (val id: String, val pass: String)
@@ -390,7 +430,7 @@ class User {
390430
[source, kotlin, role="secondary"]
391431
----
392432
{
393-
post("/user") {
433+
post("/user") { ctx ->
394434
val multipart = ctx.multipart() // <1>
395435
396436
val multipartMap = ctx.multipartMultimap() // <2>
@@ -404,7 +444,7 @@ class User {
404444
val user = ctx.multipart<User>() // <6>
405445
406446
...
407-
});
447+
}
408448
}
409449
410450
data class User (val id: String, val pass: String, val pic: FileUpload)
@@ -499,7 +539,7 @@ a javadoc:Session[] but the lifecycle is shorter: *data is kept for only one req
499539
.Kotlin
500540
[source,kotlin,role="secondary"]
501541
----
502-
get("/") {
542+
get("/") { ctx ->
503543
ctx.flash("success").value("Welcome!") <3>
504544
}
505545

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,11 @@ public Jooby errorCode(@Nonnull Class<? extends Throwable> type,
629629
return this;
630630
}
631631

632+
@Nonnull @Override public Jooby setContextAsService(boolean contextAsService) {
633+
router.setContextAsService(contextAsService);
634+
return this;
635+
}
636+
632637
@Nonnull @Override public Jooby setHiddenMethod(@Nonnull String parameterName) {
633638
router.setHiddenMethod(parameterName);
634639
return this;

jooby/src/main/java/io/jooby/Router.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ interface Match {
242242
*/
243243
@Nonnull Router setCurrentUser(@Nullable Function<Context, Object> provider);
244244

245+
/**
246+
* If enabled, allows to retrieve the {@link Context} object associated with the current
247+
* request via the service registry while the request is being processed.
248+
*
249+
* @param contextAsService whether to enable or disable this feature
250+
* @return This router.
251+
*/
252+
@Nonnull Router setContextAsService(boolean contextAsService);
253+
245254
/* ***********************************************************************************************
246255
* use(Router)
247256
* ***********************************************************************************************
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.internal;
7+
8+
import io.jooby.Context;
9+
import io.jooby.RequestScope;
10+
11+
import javax.inject.Provider;
12+
13+
import static io.jooby.RequestScope.bind;
14+
import static io.jooby.RequestScope.unbind;
15+
16+
public class ContextAsServiceInitializer implements ContextInitializer, Provider<Context> {
17+
18+
public static final ContextAsServiceInitializer INSTANCE = new ContextAsServiceInitializer();
19+
20+
private ContextAsServiceInitializer() {}
21+
22+
@Override
23+
public void apply(Context ctx) {
24+
bind(this, ctx);
25+
ctx.onComplete(context -> unbind(this));
26+
}
27+
28+
@Override
29+
public Context get() {
30+
return RequestScope.get(this);
31+
}
32+
}

0 commit comments

Comments
 (0)