Skip to content

Commit c275d19

Browse files
SentryManrbygrave
andauthored
Use ScopedValue to retrieve the Request Context (#316)
* scoped value get * workflow * test and autocloseble * Update CtxHolder.java * Revert "autocloseble" This reverts commit 775d9c8. * test * Make CtxHolder final and runWith() package private in java 25 - CtxHolder can be final - Change runWith() visibility to match (package private) in both places --------- Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
1 parent 5a0c5f6 commit c275d19

File tree

9 files changed

+126
-10
lines changed

9 files changed

+126
-10
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
java_version: [21]
16+
java_version: [25]
1717
os: [ubuntu-latest]
1818

1919
steps:

.github/workflows/jetty.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
java_version: [21]
18+
java_version: [25]
1919
os: [ubuntu-latest]
2020

2121
steps:

.github/workflows/robaho.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
java_version: [21]
18+
java_version: [25]
1919
os: [ubuntu-latest]
2020

2121
steps:

avaje-jex/pom.xml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,41 @@
7272
<scope>test</scope>
7373
</dependency>
7474
</dependencies>
75+
76+
<build>
77+
<plugins>
78+
<plugin>
79+
<groupId>org.apache.maven.plugins</groupId>
80+
<artifactId>maven-compiler-plugin</artifactId>
81+
<executions>
82+
<execution>
83+
<id>compile-java-25</id>
84+
<phase>compile</phase>
85+
<goals>
86+
<goal>compile</goal>
87+
</goals>
88+
<configuration>
89+
<release>25</release>
90+
<compileSourceRoots>
91+
<compileSourceRoot>
92+
${project.basedir}/src/main/java25</compileSourceRoot>
93+
</compileSourceRoots>
94+
<multiReleaseOutput>true</multiReleaseOutput>
95+
</configuration>
96+
</execution>
97+
</executions>
98+
</plugin>
99+
<plugin>
100+
<groupId>org.apache.maven.plugins</groupId>
101+
<artifactId>maven-jar-plugin</artifactId>
102+
<configuration>
103+
<archive>
104+
<manifestEntries>
105+
<Multi-Release>true</Multi-Release>
106+
</manifestEntries>
107+
</archive>
108+
</configuration>
109+
</plugin>
110+
</plugins>
111+
</build>
75112
</project>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.avaje.jex.core;
2+
import java.util.Optional;
3+
4+
import io.avaje.jex.http.Context;
5+
6+
public final class CtxHolder {
7+
private static final ThreadLocal<Context> CTX = new ThreadLocal<>();
8+
9+
private CtxHolder() {}
10+
11+
static void runWith(Context ctx, Runnable task) {
12+
CTX.set(ctx);
13+
try {
14+
task.run();
15+
} finally {
16+
CTX.remove();
17+
}
18+
}
19+
20+
public static Context ctx() {
21+
return Optional.ofNullable(CTX.get()).orElseThrow();
22+
}
23+
}

avaje-jex/src/main/java/io/avaje/jex/core/RoutingHandler.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,16 @@ public void handle(HttpExchange exchange) {
4545
try {
4646
final Map<String, String> params = route.pathParams(uri);
4747
JdkContext ctx = new JdkContext(mgr, exchange, route.matchPath(), params, route.roles());
48-
try {
49-
ctx.setMode(Mode.BEFORE);
50-
new BaseFilterChain(filters.iterator(), route.handler(), ctx, mgr).proceed();
51-
handleNoResponse(exchange);
52-
} catch (Exception e) {
53-
mgr.handleException(ctx, e);
54-
}
48+
CtxHolder.runWith(ctx,
49+
() -> {
50+
try {
51+
ctx.setMode(Mode.BEFORE);
52+
new BaseFilterChain(filters.iterator(), route.handler(), ctx, mgr).proceed();
53+
handleNoResponse(exchange);
54+
} catch (Exception e) {
55+
mgr.handleException(ctx, e);
56+
}
57+
});
5558
} finally {
5659
route.dec();
5760
exchange.close();

avaje-jex/src/main/java/io/avaje/jex/http/Context.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.sun.net.httpserver.HttpExchange;
2424

2525
import io.avaje.jex.core.Constants;
26+
import io.avaje.jex.core.CtxHolder;
2627
import io.avaje.jex.core.json.JsonbOutput;
2728
import io.avaje.jex.security.BasicAuthCredentials;
2829
import io.avaje.jex.security.Role;
@@ -189,6 +190,11 @@ default Context contentType(ContentType contentType) {
189190
*/
190191
Map<String, String> cookieMap();
191192

193+
/** Retrieve the context associated with the current http request. */
194+
static Context currentRequest() {
195+
return CtxHolder.ctx();
196+
}
197+
192198
/** Return the underlying JDK {@link HttpExchange} object backing the context */
193199
HttpExchange exchange();
194200

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.avaje.jex.core;
2+
3+
import io.avaje.jex.http.Context;
4+
5+
public final class CtxHolder {
6+
7+
private static final ScopedValue<Context> SV = ScopedValue.newInstance();
8+
9+
private CtxHolder() {}
10+
11+
static void runWith(Context ctx, Runnable task) {
12+
ScopedValue.where(SV, ctx).run(task);
13+
}
14+
15+
public static Context ctx() {
16+
return SV.get();
17+
}
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.avaje.jex.http;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import java.util.NoSuchElementException;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
import io.avaje.jex.Jex;
11+
import io.avaje.jex.core.TestPair;
12+
13+
class CtxHolderTest {
14+
static TestPair init() {
15+
final Jex app = Jex.create().get("/", __ -> Context.currentRequest().text("dummy"));
16+
return TestPair.create(app);
17+
}
18+
19+
@Test
20+
void get() {
21+
var pair = init();
22+
assertEquals(200, pair.request().GET().asDiscarding().statusCode());
23+
}
24+
25+
@Test
26+
void notSet() {
27+
assertThrows(NoSuchElementException.class, Context::currentRequest);
28+
}
29+
}

0 commit comments

Comments
 (0)