Skip to content

Commit

Permalink
Merge pull request #30266 from gsmet/2.15.3-backports-2
Browse files Browse the repository at this point in the history
2.15.3 backports 2
  • Loading branch information
gsmet authored Jan 10, 2023
2 parents bb63690 + 8ed5f79 commit 2707f6a
Show file tree
Hide file tree
Showing 30 changed files with 367 additions and 62 deletions.
2 changes: 1 addition & 1 deletion bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<smallrye-health.version>3.3.1</smallrye-health.version>
<smallrye-metrics.version>3.0.5</smallrye-metrics.version>
<smallrye-open-api.version>2.3.1</smallrye-open-api.version>
<smallrye-graphql.version>1.9.0</smallrye-graphql.version>
<smallrye-graphql.version>1.9.1</smallrye-graphql.version>
<smallrye-opentracing.version>2.1.1</smallrye-opentracing.version>
<smallrye-fault-tolerance.version>5.6.0</smallrye-fault-tolerance.version>
<smallrye-jwt.version>3.5.4</smallrye-jwt.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,25 +418,15 @@ public MainClassBuildItem mainClassBuildStep(BuildProducer<GeneratedClassBuildIt
}

private static String sanitizeMainClassName(ClassInfo mainClass, IndexView index) {
String className = mainClass.name().toString();
DotName mainClassDotName = mainClass.name();
String className = mainClassDotName.toString();
if (isKotlinClass(mainClass)) {
MethodInfo mainMethod = mainClass.method("main",
ArrayType.create(Type.create(DotName.createSimple(String.class.getName()), Type.Kind.CLASS), 1));
if (mainMethod == null) {
ClassInfo classToCheck = mainClass;
boolean hasQuarkusApplicationSuperClass = false;
while (classToCheck != null) {
DotName superName = classToCheck.superName();
if (superName.equals(QUARKUS_APPLICATION)) {
hasQuarkusApplicationSuperClass = true;
break;
}
if (superName.equals(OBJECT)) {
break;
}
classToCheck = index.getClassByName(superName);
}
if (!hasQuarkusApplicationSuperClass) {
boolean hasQuarkusApplicationInterface = index.getAllKnownImplementors(QUARKUS_APPLICATION).stream().map(
ClassInfo::name).anyMatch(d -> d.equals(mainClassDotName));
if (!hasQuarkusApplicationInterface) {
className += "Kt";
}
}
Expand Down
12 changes: 11 additions & 1 deletion devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,15 @@ public class DevMojo extends AbstractMojo {
private Pty pty;
private boolean windowsColorSupport;

/**
* Indicates for which launch mode the dependencies should be resolved.
*
* @return launch mode for which the dependencies should be resolved
*/
protected LaunchMode getLaunchModeClasspath() {
return LaunchMode.DEVELOPMENT;
}

@Override
public void setLog(Log log) {
super.setLog(log);
Expand Down Expand Up @@ -1089,7 +1098,7 @@ private QuarkusDevModeLauncher newLauncher(Boolean debugPortOk) throws Exception
final Path appModelLocation = resolveSerializedModelLocation();

ApplicationModel appModel = bootstrapProvider
.getResolvedApplicationModel(QuarkusBootstrapProvider.getProjectId(project), LaunchMode.DEVELOPMENT);
.getResolvedApplicationModel(QuarkusBootstrapProvider.getProjectId(project), getLaunchModeClasspath());
if (appModel != null) {
bootstrapProvider.close();
} else {
Expand Down Expand Up @@ -1118,6 +1127,7 @@ private QuarkusDevModeLauncher newLauncher(Boolean debugPortOk) throws Exception
final BootstrapMavenContext mvnCtx = new BootstrapMavenContext(mvnConfig);
appModel = new BootstrapAppModelResolver(new MavenArtifactResolver(mvnCtx))
.setDevMode(true)
.setTest(LaunchMode.TEST.equals(getLaunchModeClasspath()))
.setCollectReloadableDependencies(!noDeps)
.resolveModel(mvnCtx.getCurrentProject().getAppArtifact());
}
Expand Down
7 changes: 7 additions & 0 deletions devtools/maven/src/main/java/io/quarkus/maven/TestMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@
import io.quarkus.bootstrap.app.QuarkusBootstrap;
import io.quarkus.deployment.dev.DevModeContext;
import io.quarkus.deployment.dev.IsolatedTestModeMain;
import io.quarkus.runtime.LaunchMode;

/**
* The test mojo, that starts continuous testing outside of dev mode
*/
@Mojo(name = "test", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true)
public class TestMojo extends DevMojo {

@Override
protected LaunchMode getLaunchModeClasspath() {
return LaunchMode.TEST;
}

@Override
protected void modifyDevModeContext(MavenDevModeLauncher.Builder builder) {
builder.entryPointCustomizer(new Consumer<DevModeContext>() {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/security-openid-connect-client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public class ProtectedResource {

As you can see `ProtectedResource` returns a name from both `userName()` and `adminName()` methods. The name is extracted from the current `JsonWebToken`.

Next let's add a REST Client with `OpenID Connect Client Reactive Filter` and another REST Client with `OpenID Connect Token Propagation Filter`. `FrontendResource` will use these two clients to call `ProtectedResource`:
Next let's add a REST Client with `OidcClientRequestReactiveFilter` and another REST Client with `AccessTokenRequestReactiveFilter`. `FrontendResource` will use these two clients to call `ProtectedResource`:

[source,java]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,15 +447,16 @@ quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app
quarkus.oidc.logout.path=/logout
# Logged-out users should be returned to the /welcome.html site which will offer an option to re-login:
quarkus.oidc.logout.post-logout-path=/welcome.html
# Only the authenticated users can initiate a logout:
quarkus.http.auth.permission.authenticated.paths=/logout
quarkus.http.auth.permission.authenticated.policy=authenticated
# Logged-out users should be returned to the /welcome.html site which will offer an option to re-login:
quarkus.http.auth.permission.authenticated.paths=/welcome.html
quarkus.http.auth.permission.authenticated.policy=permit
# All users can see the welcome page:
quarkus.http.auth.permission.public.paths=/welcome.html
quarkus.http.auth.permission.public.policy=permit
----

You may also need to set `quarkus.oidc.authentication.cookie-path` to a path value common to all the application resources which is `/` in this example.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class QuarkusNettyConnectionCache implements ConnectionCache {

volatile FastThreadLocal<Acquirable> connectionCache = new FastThreadLocal<>();
final FastThreadLocal<Acquirable> connectionCache = new FastThreadLocal<>();

@Override
public Acquirable get() {
Expand All @@ -36,6 +36,21 @@ public void put(Acquirable acquirable) {

@Override
public void reset() {
connectionCache = new FastThreadLocal<>();
// Do our best to release memory. In fact `io.agroal.pool.ConnectionPool` calls
// this method in `housingkeepingExecutor` thread only, so business threads still
// hold references to `ConnectionHandler` objects.
connectionCache.remove();

// `FastThreadLocalThread` uses an array and increasing index for `FastThreadLocal`, the thread
// local variables will *never* be expunged until the thread exits, so `FastThreadLocal` instance
// musn't be created again.
//
// For other non-`FastThreadLocalThread` threads, `FastThreadLocal` actually uses static
// `java.lang.ThreadLocal`, it's useless to create fresh `FastThreadLocal` instance.
//
// In summary, this connection cache always holds `ConnectionHandler` instances in thread local
// variables even after the underlying JDBC connections close, this does leak some memory.

//connectionCache = new FastThreadLocal<>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
import io.dekorate.kubernetes.decorator.RemoveAnnotationDecorator;
import io.dekorate.kubernetes.decorator.RemoveFromMatchingLabelsDecorator;
import io.dekorate.kubernetes.decorator.RemoveFromSelectorDecorator;
import io.dekorate.kubernetes.decorator.RemoveLabelDecorator;
import io.dekorate.project.BuildInfo;
import io.dekorate.project.FileProjectFactory;
import io.dekorate.project.Project;
Expand Down Expand Up @@ -208,13 +207,11 @@ private static Collection<DecoratorBuildItem> createLabelDecorators(Optional<Pro
});

if (!config.isAddVersionToLabelSelectors()) {
result.add(new DecoratorBuildItem(target, new RemoveLabelDecorator(name, Labels.VERSION)));
result.add(new DecoratorBuildItem(target, new RemoveFromSelectorDecorator(name, Labels.VERSION)));
result.add(new DecoratorBuildItem(target, new RemoveFromMatchingLabelsDecorator(name, Labels.VERSION)));
}

if (!config.isAddNameToLabelSelectors()) {
result.add(new DecoratorBuildItem(target, new RemoveLabelDecorator(name, Labels.NAME)));
result.add(new DecoratorBuildItem(target, new RemoveFromSelectorDecorator(name, Labels.NAME)));
result.add(new DecoratorBuildItem(target, new RemoveFromMatchingLabelsDecorator(name, Labels.NAME)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,28 @@ public void accept(EndpointIndexer.ResourceMethodCallbackData entry) {
QuarkusResteasyReactiveDotNames.IGNORE_METHOD_FOR_REFLECTION_PREDICATE)
.source(source)
.build());

// if there is a body parameter type, register it for reflection
ResourceMethod resourceMethod = entry.getResourceMethod();
MethodParameter[] methodParameters = resourceMethod.getParameters();
if (methodParameters != null) {
for (int i = 0; i < methodParameters.length; i++) {
MethodParameter methodParameter = methodParameters[i];
if (methodParameter.getParameterType() == ParameterType.BODY) {
reflectiveHierarchyBuildItemBuildProducer.produce(new ReflectiveHierarchyBuildItem.Builder()
.type(method.parameterType(i))
.index(index)
.ignoreTypePredicate(
QuarkusResteasyReactiveDotNames.IGNORE_TYPE_FOR_REFLECTION_PREDICATE)
.ignoreFieldPredicate(
QuarkusResteasyReactiveDotNames.IGNORE_FIELD_FOR_REFLECTION_PREDICATE)
.ignoreMethodPredicate(
QuarkusResteasyReactiveDotNames.IGNORE_METHOD_FOR_REFLECTION_PREDICATE)
.source(source)
.build());
}
}
}
}
})
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.resteasy.reactive.jackson.deployment.test.sse;
package io.quarkus.resteasy.reactive.jackson.deployment.test.streams;

public class Message {
public String name;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package io.quarkus.resteasy.reactive.jackson.deployment.test.sse;
package io.quarkus.resteasy.reactive.jackson.deployment.test.streams;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
Expand All @@ -16,8 +19,8 @@
import io.smallrye.common.annotation.Blocking;
import io.smallrye.mutiny.Multi;

@Path("sse")
public class SseResource {
@Path("streams")
public class StreamResource {

@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
Expand Down Expand Up @@ -120,4 +123,21 @@ public Multi<Message> multiStreamJson() {
return Multi.createFrom().items(new Message("hello"), new Message("stef"));
}

/**
* Reproduce <a href="https://github.com/quarkusio/quarkus/issues/30044">#30044</a>.
*/
@Path("stream-json/multi/fast")
@GET
@Produces(RestMediaType.APPLICATION_STREAM_JSON)
@RestStreamElementType(MediaType.APPLICATION_JSON)
public Multi<Message> multiStreamJsonFast() {
List<UUID> ids = new ArrayList<>(5000);
for (int i = 0; i < 5000; i++) {
ids.add(UUID.randomUUID());
}
return Multi.createFrom().items(ids::stream)
.onItem().transform(id -> new Message(id.toString()))
.onOverflow().buffer(81920);
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.resteasy.reactive.jackson.deployment.test.sse;
package io.quarkus.resteasy.reactive.jackson.deployment.test.streams;

import static io.restassured.RestAssured.when;
import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -33,24 +33,24 @@
import io.quarkus.test.common.http.TestHTTPResource;
import io.smallrye.mutiny.Multi;

public class SseTestCase {
public class StreamTestCase {

@TestHTTPResource
URI uri;

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(SseResource.class, Message.class));
.addClasses(StreamResource.class, Message.class));

@Test
public void testSseFromSse() throws Exception {
testSse("sse");
testSse("streams");
}

@Test
public void testSseFromMulti() throws Exception {
testSse("sse/multi");
testSse("streams/multi");
}

private void testSse(String path) throws Exception {
Expand Down Expand Up @@ -81,12 +81,12 @@ public void accept(Throwable throwable) {

@Test
public void testMultiFromSse() {
testMulti("sse");
testMulti("streams");
}

@Test
public void testMultiFromMulti() {
testMulti("sse/multi");
testMulti("streams/multi");
}

private void testMulti(String path) {
Expand All @@ -99,24 +99,24 @@ private void testMulti(String path) {

@Test
public void testJsonMultiFromSse() {
testJsonMulti("sse/json");
testJsonMulti("sse/json2");
testJsonMulti("sse/blocking/json");
testJsonMulti("streams/json");
testJsonMulti("streams/json2");
testJsonMulti("streams/blocking/json");
}

@Test
public void testJsonMultiFromMulti() {
testJsonMulti("sse/json/multi");
testJsonMulti("streams/json/multi");
}

@Test
public void testJsonMultiFromMultiWithDefaultElementType() {
testJsonMulti("sse/json/multi2");
testJsonMulti("streams/json/multi2");
}

@Test
public void testNdJsonMultiFromMulti() {
when().get(uri.toString() + "sse/ndjson/multi")
when().get(uri.toString() + "streams/ndjson/multi")
.then().statusCode(HttpStatus.SC_OK)
// @formatter:off
.body(is("{\"name\":\"hello\"}\n"
Expand All @@ -127,7 +127,7 @@ public void testNdJsonMultiFromMulti() {

@Test
public void testStreamJsonMultiFromMulti() {
when().get(uri.toString() + "sse/stream-json/multi")
when().get(uri.toString() + "streams/stream-json/multi")
.then().statusCode(HttpStatus.SC_OK)
// @formatter:off
.body(is("{\"name\":\"hello\"}\n"
Expand All @@ -143,4 +143,19 @@ private void testJsonMulti(String path) {
List<Message> list = multi.collect().asList().await().atMost(Duration.ofSeconds(30));
assertThat(list).extracting("name").containsExactly("hello", "stef");
}

/**
* Reproduce <a href="https://github.com/quarkusio/quarkus/issues/30044">#30044</a>.
*/
@Test
public void testStreamJsonMultiFromMultiFast() {
String payload = when().get(uri.toString() + "streams/stream-json/multi/fast")
.then().statusCode(HttpStatus.SC_OK)
.header(HttpHeaders.CONTENT_TYPE, containsString(RestMediaType.APPLICATION_STREAM_JSON))
.extract().response().asString();

// the payload include 5000 json objects
assertThat(payload.lines()).hasSize(5000)
.allSatisfy(s -> assertThat(s).matches("\\{\"name\":\".*\"}"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public void testParser() {

// all fields
testParser("data:DATA\nid:ID\n:COMMENT\nretry:23\nevent:NAME\n\n", "DATA", "COMMENT", "ID", "NAME", 23);
// all fields and no data: no event
testParser("id:ID\n:COMMENT\nretry:23\nevent:NAME\n\n", null, null, null, null, SseEvent.RECONNECT_NOT_SET);
// all fields and no data
testParser("id:ID\n:COMMENT\nretry:23\nevent:NAME\n\n", null, "COMMENT", "ID", "NAME", 23);

// optional space after colon
testParser("data:foo\n\n", "foo", null, null, null, SseEvent.RECONNECT_NOT_SET);
Expand Down Expand Up @@ -147,6 +147,13 @@ private void testParser(String event, String data, String comment, String lastId
.setId(lastId)
.setName(name)
.setReconnectDelay(reconnectDelay)));
} else if (comment != null) {
testParser(Collections.singletonList(event), Collections.singletonList(new InboundSseEventImpl(null, null)
.setData(null)
.setComment(comment)
.setId(lastId)
.setName(name)
.setReconnectDelay(reconnectDelay)));
} else {
testParser(Collections.singletonList(event), Collections.emptyList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ public Multi<String> sseThrows() {
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public Multi<OutboundSseEvent> sseRaw(@Context Sse sse) {
return Multi.createFrom().items(sse.newEventBuilder().id("one").data("uno").name("eins").build(),
return Multi.createFrom().items(sse.newEventBuilder().comment("dummy").build(),
sse.newEventBuilder().id("one").data("uno").name("eins").build(),
sse.newEventBuilder().id("two").data("dos").name("zwei").build(),
sse.newEventBuilder().id("three").data("tres").name("drei").build());
}
Expand Down
Loading

0 comments on commit 2707f6a

Please sign in to comment.