Skip to content

Commit 912ee1a

Browse files
authored
Merge pull request #41133 from gsmet/3.11.2-backports-2
[3.11] 3.11.2 backports 2
2 parents 8ea5fff + bf5418d commit 912ee1a

File tree

12 files changed

+194
-35
lines changed

12 files changed

+194
-35
lines changed

bom/application/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<smallrye-graphql.version>2.8.4</smallrye-graphql.version>
5959
<smallrye-fault-tolerance.version>6.3.0</smallrye-fault-tolerance.version>
6060
<smallrye-jwt.version>4.5.2</smallrye-jwt.version>
61-
<smallrye-context-propagation.version>2.1.0</smallrye-context-propagation.version>
61+
<smallrye-context-propagation.version>2.1.2</smallrye-context-propagation.version>
6262
<smallrye-reactive-streams-operators.version>1.0.13</smallrye-reactive-streams-operators.version>
6363
<smallrye-reactive-types-converter.version>3.0.1</smallrye-reactive-types-converter.version>
6464
<smallrye-mutiny-vertx-binding.version>3.12.0</smallrye-mutiny-vertx-binding.version>

core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownRecorder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ public void setListeners(List<ShutdownListener> listeners, boolean delayEnabled)
2828
}
2929

3030
public static void runShutdown() {
31+
if (shutdownListeners == null) { // when QUARKUS_INIT_AND_EXIT is used, ShutdownRecorder#setListeners has not been called
32+
return;
33+
}
3134
log.debug("Attempting to gracefully shutdown.");
3235
try {
3336
executePreShutdown();

docs/src/main/asciidoc/gradle-tooling.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ Before you start Quarkus on the remote host set the environment variable `QUARKU
294294
on bare metal you can set it via the `export QUARKUS_LAUNCH_DEVMODE=true` command and then run the application with the proper `java -jar ...` command to run the application.
295295

296296
If you plan on running the application via Docker, then you'll need to add `-e QUARKUS_LAUNCH_DEVMODE=true` to the `docker run` command.
297-
When the application starts you should now see the following line in the logs: `Profile dev activated. Live Coding activated`.
297+
When the application starts you should now see the following line in the logs: `Profile dev activated. Live Coding activated`. You will also need to give the application the rights to update the deployment resources by adding `RUN chmod o+rw -R /deployments` after the `COPY` commands into your Dockerfile. For security reasons, this option should not be added to the production Dockerfile.
298298

299299

300300
NOTE: The remote side does not need to include Maven or any other development tools. The normal `fast-jar` Dockerfile

docs/src/main/asciidoc/maven-tooling.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ include::{includes}/devtools/build.adoc[]
238238
Before you start Quarkus on the remote host set the environment variable `QUARKUS_LAUNCH_DEVMODE=true`. If you are
239239
on bare metal you can set it via the `export QUARKUS_LAUNCH_DEVMODE=true` command and then run the application with the proper `java -jar ...` command to run the application.
240240

241-
If you plan on running the application via Docker, then you'll need to add `-e QUARKUS_LAUNCH_DEVMODE=true` to the `docker run` command.
242-
When the application starts you should now see the following line in the logs: `Profile dev activated. Live Coding activated`.
241+
If you plan on running the application via Docker, then you'll need to add `-e QUARKUS_LAUNCH_DEVMODE=true` to the `docker run` command.
242+
When the application starts you should now see the following line in the logs: `Profile dev activated. Live Coding activated`. You will also need to give the application the rights to update the deployment resources by adding `RUN chmod o+rw -R /deployments` after the `COPY` commands into your Dockerfile. For security reasons, this option should not be added to the production Dockerfile.
243243

244244
NOTE: The remote side does not need to include Maven or any other development tools. The normal `fast-jar` Dockerfile
245245
that is generated with a new Quarkus application is all you need. If you are using bare metal launch the Quarkus runner

extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/session/TransactionScopedStatelessSession.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ public void refresh(String s, Object o, LockMode lockMode) {
360360
public void fetch(Object o) {
361361
checkBlocking();
362362
try (SessionResult emr = acquireSession()) {
363-
emr.statelessSession.refresh(o);
363+
emr.statelessSession.fetch(o);
364364
}
365365
}
366366

extensions/vertx/deployment/src/test/java/io/quarkus/vertx/deployment/MessageConsumerFailureTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ public void testFailure() throws InterruptedException {
4646
verifyFailure("foo-completion-stage", "java.lang.NullPointerException: Something is null", false);
4747
verifyFailure("foo-completion-stage-failure", "boom", true);
4848
verifyFailure("foo-uni", "java.lang.NullPointerException: Something is null", false);
49-
verifyFailure("foo-uni-failure", "boom", true);
49+
verifyFailure("foo-uni-failure", "java.io.IOException: boom", true);
5050

5151
verifyFailure("foo-blocking", "java.lang.IllegalStateException: Red is dead", false);
5252
verifyFailure("foo-message-blocking", "java.lang.NullPointerException", false);
5353
verifyFailure("foo-completion-stage-blocking", "java.lang.NullPointerException: Something is null", false);
5454
verifyFailure("foo-completion-stage-failure-blocking", "boom", true);
5555
verifyFailure("foo-uni-blocking", "java.lang.NullPointerException: Something is null", false);
56-
verifyFailure("foo-uni-failure-blocking", "boom", true);
56+
verifyFailure("foo-uni-failure-blocking", "java.io.IOException: boom", true);
5757
}
5858

5959
@Test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package io.quarkus.websockets.next.test.errors;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import java.net.URI;
7+
import java.time.Duration;
8+
import java.util.List;
9+
import java.util.concurrent.CopyOnWriteArrayList;
10+
import java.util.concurrent.CountDownLatch;
11+
import java.util.concurrent.TimeUnit;
12+
13+
import jakarta.inject.Inject;
14+
15+
import org.junit.jupiter.api.Test;
16+
import org.junit.jupiter.api.extension.RegisterExtension;
17+
18+
import io.quarkus.logging.Log;
19+
import io.quarkus.test.QuarkusUnitTest;
20+
import io.quarkus.test.common.http.TestHTTPResource;
21+
import io.quarkus.websockets.next.OnError;
22+
import io.quarkus.websockets.next.OnOpen;
23+
import io.quarkus.websockets.next.WebSocket;
24+
import io.quarkus.websockets.next.WebSocketConnection;
25+
import io.quarkus.websockets.next.test.utils.WSClient;
26+
import io.smallrye.mutiny.Multi;
27+
import io.vertx.core.Vertx;
28+
import io.vertx.core.impl.NoStackTraceThrowable;
29+
30+
public class MultiClosedConnectionTest {
31+
32+
@RegisterExtension
33+
public static final QuarkusUnitTest test = new QuarkusUnitTest()
34+
.withApplicationRoot(root -> {
35+
root.addClasses(Echo.class, WSClient.class);
36+
});
37+
38+
@Inject
39+
Vertx vertx;
40+
41+
@TestHTTPResource("echo")
42+
URI testUri;
43+
44+
@Test
45+
void testError() throws InterruptedException {
46+
WSClient client = WSClient.create(vertx).connect(testUri);
47+
client.waitForMessages(1);
48+
client.close();
49+
assertTrue(Echo.TERMINATION_LATCH.await(5, TimeUnit.SECONDS));
50+
assertTrue(Echo.ERROR_LATCH.await(5, TimeUnit.SECONDS));
51+
// Connection is closed and the returned Multi should be cancelled
52+
int numOfMessages = Echo.MESSAGES.size();
53+
Thread.sleep(600);
54+
// No more ticks are emitted
55+
assertEquals(numOfMessages, Echo.MESSAGES.size());
56+
}
57+
58+
@WebSocket(path = "/echo")
59+
public static class Echo {
60+
61+
static final CountDownLatch TERMINATION_LATCH = new CountDownLatch(1);
62+
static final CountDownLatch ERROR_LATCH = new CountDownLatch(1);
63+
64+
static final List<String> MESSAGES = new CopyOnWriteArrayList<>();
65+
66+
@OnOpen
67+
Multi<String> onOpen() {
68+
return Multi.createFrom()
69+
.ticks()
70+
.every(Duration.ofMillis(300))
71+
.map(tick -> tick + "")
72+
.invoke(s -> {
73+
Log.infof("Next tick: %s", s);
74+
MESSAGES.add(s);
75+
})
76+
.onTermination()
77+
.invoke(() -> {
78+
Log.info("Terminated!");
79+
TERMINATION_LATCH.countDown();
80+
});
81+
}
82+
83+
@OnError
84+
void onConnectionClosedError(NoStackTraceThrowable t, WebSocketConnection conn) {
85+
Log.info("Error callback!");
86+
if (conn.isClosed()) {
87+
String message = t.getMessage();
88+
if (message != null && message.contains("WebSocket is closed")) {
89+
ERROR_LATCH.countDown();
90+
}
91+
}
92+
}
93+
94+
}
95+
96+
}

extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketEndpointBase.java

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -319,41 +319,31 @@ public Uni<Void> sendText(String message, boolean broadcast) {
319319
return broadcast ? connection.broadcast().sendText(message) : connection.sendText(message);
320320
}
321321

322-
public Uni<Void> multiText(Multi<Object> multi, Function<Object, Uni<Void>> action) {
323-
multi.onFailure().recoverWithMulti(t -> doOnError(t).toMulti())
322+
public Uni<Void> multiText(Multi<Object> multi, Function<? super Object, Uni<?>> action) {
323+
multi
324+
// Encode and send message
325+
.onItem().call(action)
326+
.onFailure().recoverWithMulti(t -> {
327+
return doOnError(t).toMulti();
328+
})
324329
.subscribe().with(
325-
m -> {
326-
// Encode and send message
327-
action.apply(m)
328-
.onFailure().recoverWithUni(this::doOnError)
329-
.subscribe()
330-
.with(v -> LOG.debugf("Multi >> text message: %s", connection),
331-
t -> LOG.errorf(t, "Unable to send text message from Multi: %s", connection));
332-
},
333-
t -> {
334-
LOG.errorf(t, "Unable to send text message from Multi: %s ", connection);
335-
});
330+
m -> LOG.debugf("Multi >> text message: %s", connection),
331+
t -> LOG.errorf(t, "Unable to send text message from Multi: %s ", connection));
336332
return Uni.createFrom().voidItem();
337333
}
338334

339335
public Uni<Void> sendBinary(Buffer message, boolean broadcast) {
340336
return broadcast ? connection.broadcast().sendBinary(message) : connection.sendBinary(message);
341337
}
342338

343-
public Uni<Void> multiBinary(Multi<Object> multi, Function<Object, Uni<Void>> action) {
344-
multi.onFailure().recoverWithMulti(t -> doOnError(t).toMulti())
339+
public Uni<Void> multiBinary(Multi<Object> multi, Function<? super Object, Uni<?>> action) {
340+
multi
341+
// Encode and send message
342+
.onItem().call(action)
343+
.onFailure().recoverWithMulti(t -> doOnError(t).toMulti())
345344
.subscribe().with(
346-
m -> {
347-
// Encode and send message
348-
action.apply(m)
349-
.onFailure().recoverWithUni(this::doOnError)
350-
.subscribe()
351-
.with(v -> LOG.debugf("Multi >> binary message: %s", connection),
352-
t -> LOG.errorf(t, "Unable to send binary message from Multi: %s", connection));
353-
},
354-
t -> {
355-
LOG.errorf(t, "Unable to send text message from Multi: %s ", connection);
356-
});
345+
m -> LOG.debugf("Multi >> binary message: %s", connection),
346+
t -> LOG.errorf(t, "Unable to send binary message from Multi: %s ", connection));
357347
return Uni.createFrom().voidItem();
358348
}
359349
}

independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/serialization/DynamicEntityWriter.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,15 @@ public void write(ResteasyReactiveRequestContext context, Object entity) throws
4141
ServerHttpRequest vertxRequest = context.serverRequest();
4242
// first check and see if the resource method defined a media type and try to use it
4343
if ((context.getTarget() != null) && (context.getTarget().getProduces() != null)) {
44-
MediaType negotiatedMediaType = context.getTarget().getProduces()
45-
.negotiateProduces(vertxRequest.getRequestHeader(HttpHeaders.ACCEPT)).getKey();
44+
MediaType negotiatedMediaType = null;
45+
List<String> accepts = context.getHttpHeaders().getRequestHeader(HttpHeaders.ACCEPT);
46+
for (String accept : accepts) {
47+
negotiatedMediaType = context.getTarget().getProduces().negotiateProduces(accept).getKey();
48+
if (negotiatedMediaType != null) {
49+
break;
50+
}
51+
}
52+
4653
List<MessageBodyWriter<?>> writersList = serialisers.findWriters(null, entity.getClass(), negotiatedMediaType,
4754
RuntimeType.SERVER);
4855
if (!writersList.isEmpty()) {

independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeaderTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import jakarta.ws.rs.core.HttpHeaders;
2121
import jakarta.ws.rs.core.MediaType;
2222
import jakarta.ws.rs.core.MultivaluedMap;
23+
import jakarta.ws.rs.core.Response;
2324
import jakarta.ws.rs.ext.Provider;
2425

2526
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo;
@@ -123,6 +124,37 @@ void entityTextWithAcceptToTextInFilter() {
123124
.body(equalTo("text"));
124125
}
125126

127+
@Test
128+
void responseEntityJsonWithoutAcceptToTextInFilter() {
129+
given().accept("application/json")
130+
.when()
131+
.get("test/response")
132+
.then()
133+
.statusCode(200)
134+
.body(containsString("\"text\""));
135+
}
136+
137+
@Test
138+
void responseEntityTextWithoutAcceptToTextInFilter() {
139+
given().accept("text/plain")
140+
.when()
141+
.get("test/response")
142+
.then()
143+
.statusCode(200)
144+
.body(equalTo("text"));
145+
}
146+
147+
@Test
148+
void responseEntityTextWithAcceptToTextInFilter() {
149+
given().accept("application/json")
150+
.header("x-set-accept-to-text", "true")
151+
.when()
152+
.get("test/response")
153+
.then()
154+
.statusCode(200)
155+
.body(equalTo("text"));
156+
}
157+
126158
@Path("/test")
127159
public static class Resource {
128160

@@ -152,6 +184,13 @@ public String html() {
152184
public Entity entity() {
153185
return new Entity("text");
154186
}
187+
188+
@GET
189+
@Path("response")
190+
@Produces({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON })
191+
public Response response() {
192+
return Response.ok(new Entity("text")).build();
193+
}
155194
}
156195

157196
public record Entity(String value) {

0 commit comments

Comments
 (0)