flyway;
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .withApplicationRoot((jar) -> jar
+ .addAsResource("db/migration/V1.0.0__Quarkus.sql")
+ .addAsResource("disabled-config.properties", "application.properties"));
+
+ @Test
+ @DisplayName("No Flyway instance available if disabled")
+ public void testFlywayConfigInjection() {
+ assertTrue(flyway.isUnsatisfied());
+ }
+}
diff --git a/extensions/flyway/deployment/src/test/resources/baseline-on-migrate-named-datasources-inactive.properties b/extensions/flyway/deployment/src/test/resources/baseline-on-migrate-named-datasources-inactive.properties
new file mode 100644
index 0000000000000..d816d7b5a8451
--- /dev/null
+++ b/extensions/flyway/deployment/src/test/resources/baseline-on-migrate-named-datasources-inactive.properties
@@ -0,0 +1,24 @@
+quarkus.datasource.users.db-kind=h2
+quarkus.datasource.users.username=sa
+quarkus.datasource.users.password=sa
+quarkus.datasource.users.jdbc.url=jdbc:h2:tcp://localhost:11302/mem:quarkus-flyway-baseline-on-named-ds-users
+
+# Flyway config properties
+quarkus.flyway.users.migrate-at-start=true
+quarkus.flyway.users.table=test_flyway_history
+quarkus.flyway.users.baseline-on-migrate=true
+quarkus.flyway.users.baseline-version=0.0.1
+quarkus.flyway.users.baseline-description=Initial description for test
+
+quarkus.datasource.laptops.db-kind=h2
+quarkus.datasource.laptops.username=sa
+quarkus.datasource.laptops.password=sa
+quarkus.datasource.laptops.jdbc.url=jdbc:h2:tcp://localhost:11302/mem:quarkus-flyway-baseline-on-named-ds-laptops
+
+# Flyway config properties
+quarkus.flyway.laptops.active=false
+quarkus.flyway.laptops.migrate-at-start=true
+quarkus.flyway.laptops.table=test_flyway_history
+quarkus.flyway.laptops.baseline-on-migrate=true
+quarkus.flyway.laptops.baseline-version=0.0.1
+quarkus.flyway.laptops.baseline-description=Initial description for test
diff --git a/extensions/flyway/deployment/src/test/resources/disabled-config.properties b/extensions/flyway/deployment/src/test/resources/disabled-config.properties
new file mode 100644
index 0000000000000..7bf03c9db53df
--- /dev/null
+++ b/extensions/flyway/deployment/src/test/resources/disabled-config.properties
@@ -0,0 +1,8 @@
+quarkus.datasource.db-kind=h2
+quarkus.datasource.username=sa
+quarkus.datasource.password=sa
+quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1
+
+# Flyway config properties
+quarkus.flyway.enabled=false
+quarkus.flyway.migrate-at-start=true
diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java
index 47e7a4878c7f4..5560e96941cc4 100644
--- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java
+++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayBuildTimeConfig.java
@@ -21,6 +21,16 @@ public FlywayDataSourceBuildTimeConfig getConfigForDataSourceName(String dataSou
return namedDataSources.getOrDefault(dataSourceName, FlywayDataSourceBuildTimeConfig.defaultConfig());
}
+ /**
+ * Whether Flyway is enabled *during the build*.
+ *
+ * If Flyway is disabled, the Flyway beans won't be created and Flyway won't be usable.
+ *
+ * @asciidoclet
+ */
+ @ConfigItem(defaultValue = "true")
+ public boolean enabled;
+
/**
* Flyway configuration for the default datasource.
*/
diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java
index 79f4c961a0e5a..726ada0de89fd 100644
--- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java
+++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java
@@ -22,6 +22,12 @@ public static FlywayDataSourceRuntimeConfig defaultConfig() {
return new FlywayDataSourceRuntimeConfig();
}
+ /**
+ * Flag to activate/deactivate Flyway for a specific datasource at runtime.
+ */
+ @ConfigItem(defaultValue = "true")
+ public boolean active = true;
+
/**
* The maximum number of retries when attempting to connect to the database.
*
diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java
index 2bb0fffb51c72..f8df08e4e7825 100644
--- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java
+++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java
@@ -8,7 +8,6 @@
import javax.sql.DataSource;
import jakarta.enterprise.inject.Default;
-import jakarta.enterprise.inject.UnsatisfiedResolutionException;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.FlywayExecutor;
@@ -67,7 +66,7 @@ public Function, FlywayContainer> fl
public FlywayContainer apply(SyntheticCreationalContext context) {
DataSource dataSource = context.getInjectedReference(DataSources.class).getDataSource(dataSourceName);
if (dataSource instanceof UnconfiguredDataSource) {
- throw new UnsatisfiedResolutionException("No datasource present");
+ return new UnconfiguredDataSourceFlywayContainer(dataSourceName);
}
FlywayContainerProducer flywayProducer = context.getInjectedReference(FlywayContainerProducer.class);
@@ -82,44 +81,58 @@ public Function, Flyway> flywayFunction(Strin
return new Function<>() {
@Override
public Flyway apply(SyntheticCreationalContext context) {
- Annotation flywayContainerQualifier;
- if (DataSourceUtil.isDefault(dataSourceName)) {
- flywayContainerQualifier = Default.Literal.INSTANCE;
- } else {
- flywayContainerQualifier = FlywayDataSourceLiteral.of(dataSourceName);
- }
-
- FlywayContainer flywayContainer = context.getInjectedReference(FlywayContainer.class, flywayContainerQualifier);
+ FlywayContainer flywayContainer = context.getInjectedReference(FlywayContainer.class,
+ getFlywayContainerQualifier(dataSourceName));
return flywayContainer.getFlyway();
}
};
}
- public void doStartActions() {
- if (!config.getValue().enabled) {
+ public void doStartActions(String dataSourceName) {
+ FlywayDataSourceRuntimeConfig flywayDataSourceRuntimeConfig = config.getValue()
+ .getConfigForDataSourceName(dataSourceName);
+
+ if (!config.getValue().getConfigForDataSourceName(dataSourceName).active) {
return;
}
- for (InstanceHandle flywayContainerHandle : Arc.container().listAll(FlywayContainer.class)) {
- FlywayContainer flywayContainer = flywayContainerHandle.get();
+ InstanceHandle flywayContainerInstanceHandle = Arc.container().instance(FlywayContainer.class,
+ getFlywayContainerQualifier(dataSourceName));
- if (flywayContainer.isCleanAtStart()) {
- flywayContainer.getFlyway().clean();
- }
- if (flywayContainer.isValidateAtStart()) {
- flywayContainer.getFlyway().validate();
- }
- if (flywayContainer.isBaselineAtStart()) {
- new FlywayExecutor(flywayContainer.getFlyway().getConfiguration())
- .execute(new BaselineCommand(flywayContainer.getFlyway()), true, null);
- }
- if (flywayContainer.isRepairAtStart()) {
- flywayContainer.getFlyway().repair();
- }
- if (flywayContainer.isMigrateAtStart()) {
- flywayContainer.getFlyway().migrate();
- }
+ if (!flywayContainerInstanceHandle.isAvailable()) {
+ return;
}
+
+ FlywayContainer flywayContainer = flywayContainerInstanceHandle.get();
+
+ if (flywayContainer instanceof UnconfiguredDataSourceFlywayContainer) {
+ return;
+ }
+
+ if (flywayContainer.isCleanAtStart()) {
+ flywayContainer.getFlyway().clean();
+ }
+ if (flywayContainer.isValidateAtStart()) {
+ flywayContainer.getFlyway().validate();
+ }
+ if (flywayContainer.isBaselineAtStart()) {
+ new FlywayExecutor(flywayContainer.getFlyway().getConfiguration())
+ .execute(new BaselineCommand(flywayContainer.getFlyway()), true, null);
+ }
+ if (flywayContainer.isRepairAtStart()) {
+ flywayContainer.getFlyway().repair();
+ }
+ if (flywayContainer.isMigrateAtStart()) {
+ flywayContainer.getFlyway().migrate();
+ }
+ }
+
+ private static Annotation getFlywayContainerQualifier(String dataSourceName) {
+ if (DataSourceUtil.isDefault(dataSourceName)) {
+ return Default.Literal.INSTANCE;
+ }
+
+ return FlywayDataSourceLiteral.of(dataSourceName);
}
static class BaselineCommand implements FlywayExecutor.Command {
diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java
index 481ee6e821539..703e3cd0b00a1 100644
--- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java
+++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRuntimeConfig.java
@@ -21,13 +21,6 @@ public FlywayDataSourceRuntimeConfig getConfigForDataSourceName(String dataSourc
return namedDataSources.getOrDefault(dataSourceName, FlywayDataSourceRuntimeConfig.defaultConfig());
}
- /**
- * Flag to enable / disable Flyway.
- *
- */
- @ConfigItem(defaultValue = "true")
- public boolean enabled;
-
/**
* Flyway configuration for the default datasource.
*/
diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/UnconfiguredDataSourceFlywayContainer.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/UnconfiguredDataSourceFlywayContainer.java
new file mode 100644
index 0000000000000..a3206cd8141ae
--- /dev/null
+++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/UnconfiguredDataSourceFlywayContainer.java
@@ -0,0 +1,16 @@
+package io.quarkus.flyway.runtime;
+
+import org.flywaydb.core.Flyway;
+
+public class UnconfiguredDataSourceFlywayContainer extends FlywayContainer {
+
+ public UnconfiguredDataSourceFlywayContainer(String dataSourceName) {
+ super(null, false, false, false, false, false, dataSourceName, false, false);
+ }
+
+ @Override
+ public Flyway getFlyway() {
+ throw new UnsupportedOperationException(
+ "Cannot get a Flyway instance for unconfigured datasource " + getDataSourceName());
+ }
+}
diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java
index 18bfe47e63283..7315ade3084a6 100644
--- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java
+++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java
@@ -13,7 +13,7 @@
final class Substitute_JandexBehavior {
@Substitute
- public static T doWithJandex(JandexBehavior.JandexOperation operation) {
+ public static void doWithJandex(JandexBehavior.JandexOperation operation) {
throw new IllegalStateException("Jandex should not be used at runtime.");
}
diff --git a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java
index abd5fa3db6d43..fa7831fb6e266 100644
--- a/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java
+++ b/extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/KeycloakPolicyEnforcerAuthorizer.java
@@ -44,7 +44,8 @@ public Uni checkPermission(RoutingContext request, Uni apply(Throwable t) {
t.getCause())));
}
// Token has expired, try to refresh
+ if (isRpInitiatedLogout(context, configContext)) {
+ LOG.debug("Session has expired, performing an RP initiated logout");
+ fireEvent(SecurityEvent.Type.OIDC_LOGOUT_RP_INITIATED_SESSION_EXPIRED,
+ Map.of(SecurityEvent.SESSION_TOKENS_PROPERTY, session));
+ return Uni.createFrom().item((SecurityIdentity) null)
+ .call(() -> buildLogoutRedirectUriUni(context, configContext,
+ currentIdToken));
+ }
if (session.getRefreshToken() == null) {
LOG.debug(
"Token has expired, token refresh is not possible because the refresh token is null");
@@ -981,6 +989,12 @@ private void fireEvent(SecurityEvent.Type eventType, SecurityIdentity securityId
}
}
+ private void fireEvent(SecurityEvent.Type eventType, Map properties) {
+ if (resolver.isSecurityEventObserved()) {
+ resolver.getSecurityEvent().fire(new SecurityEvent(eventType, properties));
+ }
+ }
+
private String getRedirectPath(OidcTenantConfig oidcConfig, RoutingContext context) {
Authentication auth = oidcConfig.getAuthentication();
return auth.getRedirectPath().isPresent() ? auth.getRedirectPath().get() : context.request().path();
diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcJsonWebTokenProducer.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcJsonWebTokenProducer.java
index 7c4c540ebeb6f..c9a66cf76f5d9 100644
--- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcJsonWebTokenProducer.java
+++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcJsonWebTokenProducer.java
@@ -79,7 +79,9 @@ private JsonWebToken getTokenCredential(Class extends TokenCredential> type) {
return new OidcJwtCallerPrincipal(jwtClaims, credential);
}
String tokenType = type == AccessTokenCredential.class ? "access" : "ID";
- LOG.tracef("Current identity is not associated with an %s token", tokenType);
+ LOG.warnf(
+ "Identity is not associated with an %s token. Access 'JsonWebToken' with '@IdToken' qualifier if ID token is required and 'JsonWebToken' without this qualifier when JWT access token is required. Inject either 'io.quarkus.security.identity.SecurityIdentity' or 'io.quarkus.oidc.UserInfo' if you need to have the same endpoint code working for both authorization code and bearer token authentication flows.",
+ tokenType);
return new NullJsonWebToken();
}
}
diff --git a/extensions/opentelemetry/runtime/pom.xml b/extensions/opentelemetry/runtime/pom.xml
index 57677019dddab..7befd1be1b261 100644
--- a/extensions/opentelemetry/runtime/pom.xml
+++ b/extensions/opentelemetry/runtime/pom.xml
@@ -177,6 +177,11 @@
assertj-core
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java
index 6ab6ffac43112..de8326f931aeb 100644
--- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java
+++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java
@@ -1,9 +1,12 @@
package io.quarkus.opentelemetry.runtime;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
@@ -16,6 +19,7 @@ public final class OpenTelemetryUtil {
public static final String SPAN_ID = "spanId";
public static final String SAMPLED = "sampled";
public static final String PARENT_ID = "parentId";
+ private static final Set SPAN_DATA_KEYS = Set.of(TRACE_ID, SPAN_ID, SAMPLED, PARENT_ID);
private OpenTelemetryUtil() {
}
@@ -54,22 +58,45 @@ public static Map convertKeyValueListToMap(List headers)
* @param vertxContext vertx context
*/
public static void setMDCData(Context context, io.vertx.core.Context vertxContext) {
+ setMDCData(getSpanData(context), vertxContext);
+ }
+
+ public static void setMDCData(Map spanData, io.vertx.core.Context vertxContext) {
+ if (spanData == null) {
+ return;
+ }
+
+ for (Entry entry : spanData.entrySet()) {
+ if (SPAN_DATA_KEYS.contains(entry.getKey())) {
+ VertxMDC.INSTANCE.put(entry.getKey(), entry.getValue(), vertxContext);
+ }
+ }
+ }
+
+ /**
+ * Gets current span data from the MDC context.
+ *
+ * @param context opentelemetry context
+ */
+ public static Map getSpanData(Context context) {
+ if (context == null) {
+ return Collections.emptyMap();
+ }
Span span = Span.fromContextOrNull(context);
+ Map spanData = new HashMap<>();
if (span != null) {
SpanContext spanContext = span.getSpanContext();
- VertxMDC vertxMDC = VertxMDC.INSTANCE;
- vertxMDC.put(SPAN_ID, spanContext.getSpanId(), vertxContext);
- vertxMDC.put(TRACE_ID, spanContext.getTraceId(), vertxContext);
- vertxMDC.put(SAMPLED, Boolean.toString(spanContext.isSampled()), vertxContext);
+ spanData.put(SPAN_ID, spanContext.getSpanId());
+ spanData.put(TRACE_ID, spanContext.getTraceId());
+ spanData.put(SAMPLED, Boolean.toString(spanContext.isSampled()));
if (span instanceof ReadableSpan) {
SpanContext parentSpanContext = ((ReadableSpan) span).getParentSpanContext();
- if (parentSpanContext.isValid()) {
- vertxMDC.put(PARENT_ID, parentSpanContext.getSpanId(), vertxContext);
- } else {
- vertxMDC.remove(PARENT_ID, vertxContext);
+ if (parentSpanContext != null && parentSpanContext.isValid()) {
+ spanData.put(PARENT_ID, parentSpanContext.getSpanId());
}
}
}
+ return spanData;
}
/**
diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java
index 7a30e5bcdae2d..ebba2e69aee64 100644
--- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java
+++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java
@@ -3,6 +3,8 @@
import static io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle.setContextSafe;
import static io.smallrye.common.vertx.VertxContext.isDuplicatedContext;
+import java.util.Map;
+
import org.jboss.logging.Logger;
import io.opentelemetry.context.Context;
@@ -64,14 +66,18 @@ public Scope attach(io.vertx.core.Context vertxContext, Context toAttach) {
return Scope.noop();
}
vertxContext.putLocal(OTEL_CONTEXT, toAttach);
- OpenTelemetryUtil.setMDCData(toAttach, vertxContext);
+ final Map spanDataToAttach = OpenTelemetryUtil.getSpanData(toAttach);
+ OpenTelemetryUtil.setMDCData(spanDataToAttach, vertxContext);
return new Scope() {
@Override
public void close() {
- if (getContext(vertxContext) != toAttach) {
- log.warn("Context in storage not the expected context, Scope.close was not called correctly");
+ final Context before = getContext(vertxContext);
+ if (before != toAttach) {
+ log.warn("Context in storage not the expected context, Scope.close was not called correctly. Details:" +
+ " OTel context before: " + OpenTelemetryUtil.getSpanData(before) +
+ ". OTel context toAttach: " + spanDataToAttach);
}
if (beforeAttach == null) {
diff --git a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java
index f1842ccc980a5..eebe37eee8a85 100644
--- a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java
+++ b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java
@@ -1,5 +1,8 @@
package io.quarkus.opentelemetry.runtime;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collections;
@@ -8,6 +11,13 @@
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanBuilder;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import io.opentelemetry.sdk.trace.SpanProcessor;
+
public class OpenTelemetryUtilTest {
@Test
@@ -58,4 +68,54 @@ public void testConvertKeyValueListToMap_empty_value() {
.convertKeyValueListToMap(Collections.emptyList());
Assertions.assertThat(actual).containsExactly();
}
+
+ @Test
+ public void testGetSpanData() {
+ SpanProcessor mockedSpanProcessor = mock(SpanProcessor.class);
+
+ SdkTracerProvider tracerSdkFactory = SdkTracerProvider.builder()
+ .addSpanProcessor(mockedSpanProcessor)
+ .build();
+ Tracer spanBuilderSdkTest = tracerSdkFactory.get("SpanBuilderSdkTest");
+ SpanBuilder spanBuilder = spanBuilderSdkTest.spanBuilder("SpanName");
+
+ Span parent = spanBuilder.startSpan();
+ Context contextParent = Context.current().with(parent);
+
+ Span child = spanBuilder.setParent(contextParent).startSpan();
+ Context contextChild = Context.current().with(child);
+
+ Map actual = OpenTelemetryUtil.getSpanData(contextChild);
+ assertEquals(4, actual.size());
+ assertEquals(child.getSpanContext().getSpanId(), actual.get("spanId"));
+ assertEquals(child.getSpanContext().getTraceId(), actual.get("traceId"));
+ assertEquals("true", actual.get("sampled"));
+ assertEquals(parent.getSpanContext().getSpanId(), actual.get("parentId"));
+ }
+
+ @Test
+ public void testGetSpanData_noParent() {
+ SpanProcessor mockedSpanProcessor = mock(SpanProcessor.class);
+ SdkTracerProvider tracerSdkFactory = SdkTracerProvider.builder()
+ .addSpanProcessor(mockedSpanProcessor)
+ .build();
+ Tracer spanBuilderSdkTest = tracerSdkFactory.get("SpanBuilderSdkTest");
+
+ SpanBuilder spanBuilder = spanBuilderSdkTest.spanBuilder("SpanName");
+
+ Span child = spanBuilder.startSpan();
+ Context contextChild = Context.current().with(child);
+
+ Map actual = OpenTelemetryUtil.getSpanData(contextChild);
+ assertEquals(3, actual.size());
+ assertEquals(child.getSpanContext().getSpanId(), actual.get("spanId"));
+ assertEquals(child.getSpanContext().getTraceId(), actual.get("traceId"));
+ assertEquals("true", actual.get("sampled"));
+ }
+
+ @Test
+ public void testGetSpanData_nullValue() {
+ Map actual = OpenTelemetryUtil.getSpanData(null);
+ assertEquals(0, actual.size());
+ }
}
diff --git a/extensions/reactive-datasource/deployment/src/main/java/io/quarkus/reactive/datasource/deployment/VertxPoolBuildItem.java b/extensions/reactive-datasource/deployment/src/main/java/io/quarkus/reactive/datasource/deployment/VertxPoolBuildItem.java
index 01e475b64c66f..ced3f83275f99 100644
--- a/extensions/reactive-datasource/deployment/src/main/java/io/quarkus/reactive/datasource/deployment/VertxPoolBuildItem.java
+++ b/extensions/reactive-datasource/deployment/src/main/java/io/quarkus/reactive/datasource/deployment/VertxPoolBuildItem.java
@@ -10,28 +10,26 @@
* If you inject this build item when recording runtime init template calls, you are guaranteed the Pool configuration
* has been injected and Pools can be created.
*/
+@Deprecated(forRemoval = true)
public final class VertxPoolBuildItem extends MultiBuildItem {
- private final RuntimeValue extends Pool> vertxPool;
- private final String dbKind;
- private final boolean isDefault;
+ public VertxPoolBuildItem() {
+ }
public VertxPoolBuildItem(RuntimeValue extends Pool> vertxPool, String dbKind, boolean isDefault) {
- this.vertxPool = vertxPool;
- this.dbKind = dbKind;
- this.isDefault = isDefault;
+
}
public RuntimeValue extends Pool> getPool() {
- return vertxPool;
+ throw new IllegalStateException("should never be called");
}
public String getDbKind() {
- return dbKind;
+ throw new IllegalStateException("should never be called");
}
public boolean isDefault() {
- return isDefault;
+ throw new IllegalStateException("should never be called");
}
}
diff --git a/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/DB2PoolBuildItem.java b/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/DB2PoolBuildItem.java
index 95b5c18a89872..a63b88b6c2796 100644
--- a/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/DB2PoolBuildItem.java
+++ b/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/DB2PoolBuildItem.java
@@ -1,17 +1,19 @@
package io.quarkus.reactive.db2.client.deployment;
+import java.util.function.Function;
+
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
-import io.quarkus.runtime.RuntimeValue;
import io.vertx.db2client.DB2Pool;
public final class DB2PoolBuildItem extends MultiBuildItem {
private final String dataSourceName;
- private final RuntimeValue db2Pool;
+ private final Function, DB2Pool> db2Pool;
- public DB2PoolBuildItem(String dataSourceName, RuntimeValue db2Pool) {
+ public DB2PoolBuildItem(String dataSourceName, Function, DB2Pool> db2Pool) {
this.dataSourceName = dataSourceName;
this.db2Pool = db2Pool;
}
@@ -20,7 +22,7 @@ public String getDataSourceName() {
return dataSourceName;
}
- public RuntimeValue getDB2Pool() {
+ public Function, DB2Pool> getDB2Pool() {
return db2Pool;
}
diff --git a/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java b/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java
index d20b951f8d517..d21106cfd1baf 100644
--- a/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java
+++ b/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java
@@ -6,15 +6,20 @@
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Instance;
import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
+import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem.ExtendedBeanConfigurator;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
@@ -51,7 +56,6 @@
import io.quarkus.reactive.db2.client.runtime.DB2PoolRecorder;
import io.quarkus.reactive.db2.client.runtime.DB2ServiceBindingConverter;
import io.quarkus.reactive.db2.client.runtime.DataSourcesReactiveDB2Config;
-import io.quarkus.runtime.RuntimeValue;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
import io.quarkus.vertx.core.deployment.EventLoopCountBuildItem;
import io.quarkus.vertx.deployment.VertxBuildItem;
@@ -60,6 +64,12 @@
class ReactiveDB2ClientProcessor {
+ private static final ParameterizedType POOL_INJECTION_TYPE = ParameterizedType.create(DotName.createSimple(Instance.class),
+ new Type[] { ClassType.create(DotName.createSimple(DB2PoolCreator.class.getName())) }, null);
+ private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0];
+
+ private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class);
+
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
ServiceStartBuildItem build(BuildProducer feature,
@@ -81,7 +91,7 @@ ServiceStartBuildItem build(BuildProducer feature,
feature.produce(new FeatureBuildItem(Feature.REACTIVE_DB2_CLIENT));
for (String dataSourceName : dataSourcesBuildTimeConfig.dataSources().keySet()) {
- createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, db2Pool, vertxPool, syntheticBeans, dataSourceName,
+ createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, db2Pool, syntheticBeans, dataSourceName,
dataSourcesBuildTimeConfig, dataSourcesRuntimeConfig, dataSourcesReactiveBuildTimeConfig,
dataSourcesReactiveRuntimeConfig, dataSourcesReactiveDB2Config, defaultDataSourceDbKindBuildItems,
curateOutcomeBuildItem);
@@ -90,6 +100,7 @@ ServiceStartBuildItem build(BuildProducer feature,
// Enable SSL support by default
sslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.REACTIVE_DB2_CLIENT));
+ vertxPool.produce(new VertxPoolBuildItem());
return new ServiceStartBuildItem("reactive-db2-client");
}
@@ -168,7 +179,6 @@ private void createPoolIfDefined(DB2PoolRecorder recorder,
EventLoopCountBuildItem eventLoopCount,
ShutdownContextBuildItem shutdown,
BuildProducer db2Pool,
- BuildProducer vertxPool,
BuildProducer syntheticBeans,
String dataSourceName,
DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
@@ -184,20 +194,21 @@ private void createPoolIfDefined(DB2PoolRecorder recorder,
return;
}
- RuntimeValue pool = recorder.configureDB2Pool(vertx.getVertx(),
+ Function, DB2Pool> poolFunction = recorder.configureDB2Pool(vertx.getVertx(),
eventLoopCount.getEventLoopCount(),
dataSourceName,
dataSourcesRuntimeConfig,
dataSourcesReactiveRuntimeConfig,
dataSourcesReactiveDB2Config,
shutdown);
- db2Pool.produce(new DB2PoolBuildItem(dataSourceName, pool));
+ db2Pool.produce(new DB2PoolBuildItem(dataSourceName, poolFunction));
ExtendedBeanConfigurator db2PoolBeanConfigurator = SyntheticBeanBuildItem.configure(DB2Pool.class)
.defaultBean()
.addType(Pool.class)
.scope(ApplicationScoped.class)
- .runtimeValue(pool)
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(poolFunction)
.unremovable()
.setRuntimeInit();
@@ -209,14 +220,21 @@ private void createPoolIfDefined(DB2PoolRecorder recorder,
.configure(io.vertx.mutiny.db2client.DB2Pool.class)
.defaultBean()
.scope(ApplicationScoped.class)
- .runtimeValue(recorder.mutinyDB2Pool(pool))
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(recorder.mutinyDB2Pool(poolFunction))
.setRuntimeInit();
addQualifiers(mutinyDB2PoolConfigurator, dataSourceName);
syntheticBeans.produce(mutinyDB2PoolConfigurator.done());
+ }
- vertxPool.produce(new VertxPoolBuildItem(pool, DatabaseKind.DB2, DataSourceUtil.isDefault(dataSourceName)));
+ private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) {
+ if (DataSourceUtil.isDefault(dataSourceName)) {
+ return EMPTY_ANNOTATIONS;
+ }
+ return new AnnotationInstance[] {
+ AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() };
}
private static boolean isReactiveDB2PoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
diff --git a/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java b/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java
index 90681e5e63bde..d5e372b88779b 100644
--- a/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java
+++ b/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java
@@ -12,13 +12,15 @@
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.enterprise.inject.Instance;
+import jakarta.enterprise.util.TypeLiteral;
import org.jboss.logging.Logger;
-import io.quarkus.arc.Arc;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.credentials.CredentialsProvider;
import io.quarkus.credentials.runtime.CredentialsProviderFinder;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
@@ -44,28 +46,42 @@
public class DB2PoolRecorder {
private static final Logger log = Logger.getLogger(DB2PoolRecorder.class);
+ private static final TypeLiteral> TYPE_LITERAL = new TypeLiteral<>() {
+ };
- public RuntimeValue configureDB2Pool(RuntimeValue vertx,
+ public Function, DB2Pool> configureDB2Pool(RuntimeValue vertx,
Supplier eventLoopCount,
String dataSourceName,
DataSourcesRuntimeConfig dataSourcesRuntimeConfig,
DataSourcesReactiveRuntimeConfig dataSourcesReactiveRuntimeConfig,
DataSourcesReactiveDB2Config dataSourcesReactiveDB2Config,
ShutdownContext shutdown) {
-
- DB2Pool db2Pool = initialize((VertxInternal) vertx.getValue(),
- eventLoopCount.get(),
- dataSourceName,
- dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
- dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
- dataSourcesReactiveDB2Config.dataSources().get(dataSourceName).reactive().db2());
-
- shutdown.addShutdownTask(db2Pool::close);
- return new RuntimeValue<>(db2Pool);
+ return new Function<>() {
+ @Override
+ public DB2Pool apply(SyntheticCreationalContext context) {
+ DB2Pool db2Pool = initialize((VertxInternal) vertx.getValue(),
+ eventLoopCount.get(),
+ dataSourceName,
+ dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
+ dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
+ dataSourcesReactiveDB2Config.dataSources().get(dataSourceName).reactive().db2(),
+ context);
+
+ shutdown.addShutdownTask(db2Pool::close);
+ return db2Pool;
+ }
+ };
}
- public RuntimeValue mutinyDB2Pool(RuntimeValue db2Pool) {
- return new RuntimeValue<>(io.vertx.mutiny.db2client.DB2Pool.newInstance(db2Pool.getValue()));
+ public Function, io.vertx.mutiny.db2client.DB2Pool> mutinyDB2Pool(
+ Function, DB2Pool> function) {
+ return new Function<>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public io.vertx.mutiny.db2client.DB2Pool apply(SyntheticCreationalContext context) {
+ return io.vertx.mutiny.db2client.DB2Pool.newInstance(function.apply(context));
+ }
+ };
}
private DB2Pool initialize(VertxInternal vertx,
@@ -73,14 +89,15 @@ private DB2Pool initialize(VertxInternal vertx,
String dataSourceName,
DataSourceRuntimeConfig dataSourceRuntimeConfig,
DataSourceReactiveRuntimeConfig dataSourceReactiveRuntimeConfig,
- DataSourceReactiveDB2Config dataSourceReactiveDB2Config) {
+ DataSourceReactiveDB2Config dataSourceReactiveDB2Config,
+ SyntheticCreationalContext context) {
PoolOptions poolOptions = toPoolOptions(eventLoopCount, dataSourceRuntimeConfig, dataSourceReactiveRuntimeConfig,
dataSourceReactiveDB2Config);
DB2ConnectOptions db2ConnectOptions = toConnectOptions(dataSourceName, dataSourceRuntimeConfig,
dataSourceReactiveRuntimeConfig, dataSourceReactiveDB2Config);
Supplier> databasesSupplier = toDatabasesSupplier(vertx, List.of(db2ConnectOptions),
dataSourceRuntimeConfig);
- return createPool(vertx, poolOptions, db2ConnectOptions, dataSourceName, databasesSupplier);
+ return createPool(vertx, poolOptions, db2ConnectOptions, dataSourceName, databasesSupplier, context);
}
private Supplier> toDatabasesSupplier(Vertx vertx, List db2ConnectOptionsList,
@@ -213,12 +230,13 @@ private DB2ConnectOptions toConnectOptions(String dataSourceName, DataSourceRunt
}
private DB2Pool createPool(Vertx vertx, PoolOptions poolOptions, DB2ConnectOptions dB2ConnectOptions,
- String dataSourceName, Supplier> databases) {
+ String dataSourceName, Supplier> databases,
+ SyntheticCreationalContext context) {
Instance instance;
if (DataSourceUtil.isDefault(dataSourceName)) {
- instance = Arc.container().select(DB2PoolCreator.class);
+ instance = context.getInjectedReference(TYPE_LITERAL);
} else {
- instance = Arc.container().select(DB2PoolCreator.class,
+ instance = context.getInjectedReference(TYPE_LITERAL,
new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName));
}
if (instance.isResolvable()) {
diff --git a/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/MSSQLPoolBuildItem.java b/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/MSSQLPoolBuildItem.java
index 0eb56a6071d9d..639f59dac3e25 100644
--- a/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/MSSQLPoolBuildItem.java
+++ b/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/MSSQLPoolBuildItem.java
@@ -1,17 +1,19 @@
package io.quarkus.reactive.mssql.client.deployment;
+import java.util.function.Function;
+
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
-import io.quarkus.runtime.RuntimeValue;
import io.vertx.mssqlclient.MSSQLPool;
public final class MSSQLPoolBuildItem extends MultiBuildItem {
private final String dataSourceName;
- private final RuntimeValue mssqlPool;
+ private final Function, MSSQLPool> mssqlPool;
- public MSSQLPoolBuildItem(String dataSourceName, RuntimeValue mssqlPool) {
+ public MSSQLPoolBuildItem(String dataSourceName, Function, MSSQLPool> mssqlPool) {
this.dataSourceName = dataSourceName;
this.mssqlPool = mssqlPool;
}
@@ -20,7 +22,7 @@ public String getDataSourceName() {
return dataSourceName;
}
- public RuntimeValue getMSSQLPool() {
+ public Function, MSSQLPool> getMSSQLPool() {
return mssqlPool;
}
diff --git a/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java b/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java
index 5e5d06baf8bdd..fc29eb683d158 100644
--- a/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java
+++ b/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java
@@ -6,15 +6,20 @@
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Instance;
import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
+import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem.ExtendedBeanConfigurator;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
@@ -51,7 +56,6 @@
import io.quarkus.reactive.mssql.client.runtime.DataSourcesReactiveMSSQLConfig;
import io.quarkus.reactive.mssql.client.runtime.MSSQLPoolRecorder;
import io.quarkus.reactive.mssql.client.runtime.MsSQLServiceBindingConverter;
-import io.quarkus.runtime.RuntimeValue;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
import io.quarkus.vertx.core.deployment.EventLoopCountBuildItem;
import io.quarkus.vertx.deployment.VertxBuildItem;
@@ -60,6 +64,11 @@
class ReactiveMSSQLClientProcessor {
+ private static final ParameterizedType POOL_INJECTION_TYPE = ParameterizedType.create(DotName.createSimple(Instance.class),
+ new Type[] { ClassType.create(DotName.createSimple(MSSQLPoolCreator.class.getName())) }, null);
+ private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0];
+ private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class);
+
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
ServiceStartBuildItem build(BuildProducer feature,
@@ -81,7 +90,7 @@ ServiceStartBuildItem build(BuildProducer feature,
feature.produce(new FeatureBuildItem(Feature.REACTIVE_MSSQL_CLIENT));
for (String dataSourceName : dataSourcesBuildTimeConfig.dataSources().keySet()) {
- createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, msSQLPool, vertxPool, syntheticBeans, dataSourceName,
+ createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, msSQLPool, syntheticBeans, dataSourceName,
dataSourcesBuildTimeConfig, dataSourcesRuntimeConfig, dataSourcesReactiveBuildTimeConfig,
dataSourcesReactiveRuntimeConfig, dataSourcesReactiveMSSQLConfig, defaultDataSourceDbKindBuildItems,
curateOutcomeBuildItem);
@@ -90,6 +99,7 @@ ServiceStartBuildItem build(BuildProducer feature,
// Enable SSL support by default
sslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.REACTIVE_MSSQL_CLIENT));
+ vertxPool.produce(new VertxPoolBuildItem());
return new ServiceStartBuildItem("reactive-mssql-client");
}
@@ -168,7 +178,6 @@ private void createPoolIfDefined(MSSQLPoolRecorder recorder,
EventLoopCountBuildItem eventLoopCount,
ShutdownContextBuildItem shutdown,
BuildProducer msSQLPool,
- BuildProducer vertxPool,
BuildProducer syntheticBeans,
String dataSourceName,
DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
@@ -184,20 +193,21 @@ private void createPoolIfDefined(MSSQLPoolRecorder recorder,
return;
}
- RuntimeValue pool = recorder.configureMSSQLPool(vertx.getVertx(),
+ Function, MSSQLPool> poolFunction = recorder.configureMSSQLPool(vertx.getVertx(),
eventLoopCount.getEventLoopCount(),
dataSourceName,
dataSourcesRuntimeConfig,
dataSourcesReactiveRuntimeConfig,
dataSourcesReactiveMSSQLConfig,
shutdown);
- msSQLPool.produce(new MSSQLPoolBuildItem(dataSourceName, pool));
+ msSQLPool.produce(new MSSQLPoolBuildItem(dataSourceName, poolFunction));
ExtendedBeanConfigurator msSQLPoolBeanConfigurator = SyntheticBeanBuildItem.configure(MSSQLPool.class)
.defaultBean()
.addType(Pool.class)
.scope(ApplicationScoped.class)
- .runtimeValue(pool)
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(poolFunction)
.unremovable()
.setRuntimeInit();
@@ -209,14 +219,21 @@ private void createPoolIfDefined(MSSQLPoolRecorder recorder,
.configure(io.vertx.mutiny.mssqlclient.MSSQLPool.class)
.defaultBean()
.scope(ApplicationScoped.class)
- .runtimeValue(recorder.mutinyMSSQLPool(pool))
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(recorder.mutinyMSSQLPool(poolFunction))
.setRuntimeInit();
addQualifiers(mutinyMSSQLPoolConfigurator, dataSourceName);
syntheticBeans.produce(mutinyMSSQLPoolConfigurator.done());
+ }
- vertxPool.produce(new VertxPoolBuildItem(pool, DatabaseKind.MSSQL, DataSourceUtil.isDefault(dataSourceName)));
+ private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) {
+ if (DataSourceUtil.isDefault(dataSourceName)) {
+ return EMPTY_ANNOTATIONS;
+ }
+ return new AnnotationInstance[] {
+ AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() };
}
private static boolean isReactiveMSSQLPoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
diff --git a/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java b/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java
index 3c9dc91c63deb..dad7ed85e5f86 100644
--- a/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java
+++ b/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java
@@ -12,13 +12,15 @@
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.enterprise.inject.Instance;
+import jakarta.enterprise.util.TypeLiteral;
import org.jboss.logging.Logger;
-import io.quarkus.arc.Arc;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.credentials.CredentialsProvider;
import io.quarkus.credentials.runtime.CredentialsProviderFinder;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
@@ -43,9 +45,12 @@
@Recorder
public class MSSQLPoolRecorder {
+ private static final TypeLiteral> TYPE_LITERAL = new TypeLiteral<>() {
+ };
+
private static final Logger log = Logger.getLogger(MSSQLPoolRecorder.class);
- public RuntimeValue configureMSSQLPool(RuntimeValue vertx,
+ public Function, MSSQLPool> configureMSSQLPool(RuntimeValue vertx,
Supplier eventLoopCount,
String dataSourceName,
DataSourcesRuntimeConfig dataSourcesRuntimeConfig,
@@ -53,33 +58,47 @@ public RuntimeValue configureMSSQLPool(RuntimeValue vertx,
DataSourcesReactiveMSSQLConfig dataSourcesReactiveMSSQLConfig,
ShutdownContext shutdown) {
- MSSQLPool mssqlPool = initialize((VertxInternal) vertx.getValue(),
- eventLoopCount.get(),
- dataSourceName,
- dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
- dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
- dataSourcesReactiveMSSQLConfig.dataSources().get(dataSourceName).reactive().mssql());
-
- shutdown.addShutdownTask(mssqlPool::close);
- return new RuntimeValue<>(mssqlPool);
+ return new Function<>() {
+ @Override
+ public MSSQLPool apply(SyntheticCreationalContext context) {
+ MSSQLPool pool = initialize((VertxInternal) vertx.getValue(),
+ eventLoopCount.get(),
+ dataSourceName,
+ dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
+ dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
+ dataSourcesReactiveMSSQLConfig.dataSources().get(dataSourceName).reactive().mssql(),
+ context);
+
+ shutdown.addShutdownTask(pool::close);
+ return pool;
+ }
+ };
}
- public RuntimeValue mutinyMSSQLPool(RuntimeValue mssqlPool) {
- return new RuntimeValue<>(io.vertx.mutiny.mssqlclient.MSSQLPool.newInstance(mssqlPool.getValue()));
+ public Function, io.vertx.mutiny.mssqlclient.MSSQLPool> mutinyMSSQLPool(
+ Function, MSSQLPool> function) {
+ return new Function, io.vertx.mutiny.mssqlclient.MSSQLPool>() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public io.vertx.mutiny.mssqlclient.MSSQLPool apply(SyntheticCreationalContext context) {
+ return io.vertx.mutiny.mssqlclient.MSSQLPool.newInstance(function.apply(context));
+ }
+ };
}
private MSSQLPool initialize(VertxInternal vertx,
Integer eventLoopCount,
String dataSourceName, DataSourceRuntimeConfig dataSourceRuntimeConfig,
DataSourceReactiveRuntimeConfig dataSourceReactiveRuntimeConfig,
- DataSourceReactiveMSSQLConfig dataSourceReactiveMSSQLConfig) {
+ DataSourceReactiveMSSQLConfig dataSourceReactiveMSSQLConfig,
+ SyntheticCreationalContext context) {
PoolOptions poolOptions = toPoolOptions(eventLoopCount, dataSourceRuntimeConfig, dataSourceReactiveRuntimeConfig,
dataSourceReactiveMSSQLConfig);
MSSQLConnectOptions mssqlConnectOptions = toMSSQLConnectOptions(dataSourceName, dataSourceRuntimeConfig,
dataSourceReactiveRuntimeConfig, dataSourceReactiveMSSQLConfig);
Supplier> databasesSupplier = toDatabasesSupplier(vertx, List.of(mssqlConnectOptions),
dataSourceRuntimeConfig);
- return createPool(vertx, poolOptions, mssqlConnectOptions, dataSourceName, databasesSupplier);
+ return createPool(vertx, poolOptions, mssqlConnectOptions, dataSourceName, databasesSupplier, context);
}
private Supplier> toDatabasesSupplier(Vertx vertx,
@@ -214,12 +233,13 @@ private MSSQLConnectOptions toMSSQLConnectOptions(String dataSourceName, DataSou
}
private MSSQLPool createPool(Vertx vertx, PoolOptions poolOptions, MSSQLConnectOptions mSSQLConnectOptions,
- String dataSourceName, Supplier> databases) {
+ String dataSourceName, Supplier> databases,
+ SyntheticCreationalContext context) {
Instance instance;
if (DataSourceUtil.isDefault(dataSourceName)) {
- instance = Arc.container().select(MSSQLPoolCreator.class);
+ instance = context.getInjectedReference(TYPE_LITERAL);
} else {
- instance = Arc.container().select(MSSQLPoolCreator.class,
+ instance = context.getInjectedReference(TYPE_LITERAL,
new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName));
}
if (instance.isResolvable()) {
diff --git a/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/MySQLPoolBuildItem.java b/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/MySQLPoolBuildItem.java
index b8c40a65cef57..0b64cbf31d0c5 100644
--- a/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/MySQLPoolBuildItem.java
+++ b/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/MySQLPoolBuildItem.java
@@ -1,17 +1,19 @@
package io.quarkus.reactive.mysql.client.deployment;
+import java.util.function.Function;
+
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
-import io.quarkus.runtime.RuntimeValue;
import io.vertx.mysqlclient.MySQLPool;
public final class MySQLPoolBuildItem extends MultiBuildItem {
private final String dataSourceName;
- private final RuntimeValue mysqlPool;
+ private final Function, MySQLPool> mysqlPool;
- public MySQLPoolBuildItem(String dataSourceName, RuntimeValue mysqlPool) {
+ public MySQLPoolBuildItem(String dataSourceName, Function, MySQLPool> mysqlPool) {
this.dataSourceName = dataSourceName;
this.mysqlPool = mysqlPool;
}
@@ -20,7 +22,7 @@ public String getDataSourceName() {
return dataSourceName;
}
- public RuntimeValue getMySQLPool() {
+ public Function, MySQLPool> getMySQLPool() {
return mysqlPool;
}
diff --git a/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java b/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java
index b512986ade9ee..7f61ab1eb9231 100644
--- a/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java
+++ b/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java
@@ -6,15 +6,20 @@
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Instance;
import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
+import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem.ExtendedBeanConfigurator;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
@@ -51,7 +56,6 @@
import io.quarkus.reactive.mysql.client.runtime.DataSourcesReactiveMySQLConfig;
import io.quarkus.reactive.mysql.client.runtime.MySQLPoolRecorder;
import io.quarkus.reactive.mysql.client.runtime.MySQLServiceBindingConverter;
-import io.quarkus.runtime.RuntimeValue;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
import io.quarkus.vertx.core.deployment.EventLoopCountBuildItem;
import io.quarkus.vertx.deployment.VertxBuildItem;
@@ -60,6 +64,11 @@
class ReactiveMySQLClientProcessor {
+ private static final ParameterizedType POOL_INJECTION_TYPE = ParameterizedType.create(DotName.createSimple(Instance.class),
+ new Type[] { ClassType.create(DotName.createSimple(MySQLPoolCreator.class.getName())) }, null);
+ private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0];
+ private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class);
+
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
ServiceStartBuildItem build(BuildProducer feature,
@@ -81,7 +90,7 @@ ServiceStartBuildItem build(BuildProducer feature,
feature.produce(new FeatureBuildItem(Feature.REACTIVE_MYSQL_CLIENT));
for (String dataSourceName : dataSourcesBuildTimeConfig.dataSources().keySet()) {
- createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, mySQLPool, vertxPool, syntheticBeans, dataSourceName,
+ createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, mySQLPool, syntheticBeans, dataSourceName,
dataSourcesBuildTimeConfig, dataSourcesRuntimeConfig, dataSourcesReactiveBuildTimeConfig,
dataSourcesReactiveRuntimeConfig, dataSourcesReactiveMySQLConfig, defaultDataSourceDbKindBuildItems,
curateOutcomeBuildItem);
@@ -90,6 +99,7 @@ ServiceStartBuildItem build(BuildProducer feature,
// Enable SSL support by default
sslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.REACTIVE_MYSQL_CLIENT));
+ vertxPool.produce(new VertxPoolBuildItem());
return new ServiceStartBuildItem("reactive-mysql-client");
}
@@ -169,7 +179,6 @@ private void createPoolIfDefined(MySQLPoolRecorder recorder,
EventLoopCountBuildItem eventLoopCount,
ShutdownContextBuildItem shutdown,
BuildProducer mySQLPool,
- BuildProducer vertxPool,
BuildProducer syntheticBeans,
String dataSourceName,
DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
@@ -185,20 +194,21 @@ private void createPoolIfDefined(MySQLPoolRecorder recorder,
return;
}
- RuntimeValue pool = recorder.configureMySQLPool(vertx.getVertx(),
+ Function, MySQLPool> poolFunction = recorder.configureMySQLPool(vertx.getVertx(),
eventLoopCount.getEventLoopCount(),
dataSourceName,
dataSourcesRuntimeConfig,
dataSourcesReactiveRuntimeConfig,
dataSourcesReactiveMySQLConfig,
shutdown);
- mySQLPool.produce(new MySQLPoolBuildItem(dataSourceName, pool));
+ mySQLPool.produce(new MySQLPoolBuildItem(dataSourceName, poolFunction));
ExtendedBeanConfigurator mySQLPoolBeanConfigurator = SyntheticBeanBuildItem.configure(MySQLPool.class)
.defaultBean()
.addType(Pool.class)
.scope(ApplicationScoped.class)
- .runtimeValue(pool)
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(poolFunction)
.unremovable()
.setRuntimeInit();
@@ -210,14 +220,21 @@ private void createPoolIfDefined(MySQLPoolRecorder recorder,
.configure(io.vertx.mutiny.mysqlclient.MySQLPool.class)
.defaultBean()
.scope(ApplicationScoped.class)
- .runtimeValue(recorder.mutinyMySQLPool(pool))
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(recorder.mutinyMySQLPool(poolFunction))
.setRuntimeInit();
addQualifiers(mutinyMySQLPoolConfigurator, dataSourceName);
syntheticBeans.produce(mutinyMySQLPoolConfigurator.done());
+ }
- vertxPool.produce(new VertxPoolBuildItem(pool, DatabaseKind.MYSQL, DataSourceUtil.isDefault(dataSourceName)));
+ private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) {
+ if (DataSourceUtil.isDefault(dataSourceName)) {
+ return EMPTY_ANNOTATIONS;
+ }
+ return new AnnotationInstance[] {
+ AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() };
}
private static boolean isReactiveMySQLPoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
diff --git a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java
index b3db354d08583..8b0d101285326 100644
--- a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java
+++ b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java
@@ -14,11 +14,13 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.enterprise.inject.Instance;
+import jakarta.enterprise.util.TypeLiteral;
-import io.quarkus.arc.Arc;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.credentials.CredentialsProvider;
import io.quarkus.credentials.runtime.CredentialsProviderFinder;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
@@ -44,27 +46,42 @@
@Recorder
public class MySQLPoolRecorder {
- public RuntimeValue configureMySQLPool(RuntimeValue vertx,
+ private static final TypeLiteral> TYPE_LITERAL = new TypeLiteral<>() {
+ };
+
+ public Function, MySQLPool> configureMySQLPool(RuntimeValue vertx,
Supplier eventLoopCount,
String dataSourceName,
DataSourcesRuntimeConfig dataSourcesRuntimeConfig,
DataSourcesReactiveRuntimeConfig dataSourcesReactiveRuntimeConfig,
DataSourcesReactiveMySQLConfig dataSourcesReactiveMySQLConfig,
ShutdownContext shutdown) {
-
- MySQLPool mysqlPool = initialize((VertxInternal) vertx.getValue(),
- eventLoopCount.get(),
- dataSourceName,
- dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
- dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
- dataSourcesReactiveMySQLConfig.dataSources().get(dataSourceName).reactive().mysql());
-
- shutdown.addShutdownTask(mysqlPool::close);
- return new RuntimeValue<>(mysqlPool);
+ return new Function<>() {
+ @Override
+ public MySQLPool apply(SyntheticCreationalContext context) {
+ MySQLPool pool = initialize((VertxInternal) vertx.getValue(),
+ eventLoopCount.get(),
+ dataSourceName,
+ dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
+ dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
+ dataSourcesReactiveMySQLConfig.dataSources().get(dataSourceName).reactive().mysql(),
+ context);
+
+ shutdown.addShutdownTask(pool::close);
+ return pool;
+ }
+ };
}
- public RuntimeValue mutinyMySQLPool(RuntimeValue mysqlPool) {
- return new RuntimeValue<>(io.vertx.mutiny.mysqlclient.MySQLPool.newInstance(mysqlPool.getValue()));
+ public Function, io.vertx.mutiny.mysqlclient.MySQLPool> mutinyMySQLPool(
+ Function, MySQLPool> function) {
+ return new Function<>() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public io.vertx.mutiny.mysqlclient.MySQLPool apply(SyntheticCreationalContext context) {
+ return io.vertx.mutiny.mysqlclient.MySQLPool.newInstance(function.apply(context));
+ }
+ };
}
private MySQLPool initialize(VertxInternal vertx,
@@ -72,14 +89,15 @@ private MySQLPool initialize(VertxInternal vertx,
String dataSourceName,
DataSourceRuntimeConfig dataSourceRuntimeConfig,
DataSourceReactiveRuntimeConfig dataSourceReactiveRuntimeConfig,
- DataSourceReactiveMySQLConfig dataSourceReactiveMySQLConfig) {
+ DataSourceReactiveMySQLConfig dataSourceReactiveMySQLConfig,
+ SyntheticCreationalContext context) {
PoolOptions poolOptions = toPoolOptions(eventLoopCount, dataSourceRuntimeConfig, dataSourceReactiveRuntimeConfig,
dataSourceReactiveMySQLConfig);
List mySQLConnectOptions = toMySQLConnectOptions(dataSourceName, dataSourceRuntimeConfig,
dataSourceReactiveRuntimeConfig, dataSourceReactiveMySQLConfig);
Supplier> databasesSupplier = toDatabasesSupplier(vertx, mySQLConnectOptions,
dataSourceRuntimeConfig);
- return createPool(vertx, poolOptions, mySQLConnectOptions, dataSourceName, databasesSupplier);
+ return createPool(vertx, poolOptions, mySQLConnectOptions, dataSourceName, databasesSupplier, context);
}
private Supplier> toDatabasesSupplier(Vertx vertx,
@@ -232,12 +250,13 @@ private List toMySQLConnectOptions(String dataSourceName,
}
private MySQLPool createPool(Vertx vertx, PoolOptions poolOptions, List mySQLConnectOptionsList,
- String dataSourceName, Supplier> databases) {
+ String dataSourceName, Supplier> databases,
+ SyntheticCreationalContext context) {
Instance instance;
if (DataSourceUtil.isDefault(dataSourceName)) {
- instance = Arc.container().select(MySQLPoolCreator.class);
+ instance = context.getInjectedReference(TYPE_LITERAL);
} else {
- instance = Arc.container().select(MySQLPoolCreator.class,
+ instance = context.getInjectedReference(TYPE_LITERAL,
new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName));
}
if (instance.isResolvable()) {
diff --git a/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/OraclePoolBuildItem.java b/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/OraclePoolBuildItem.java
index 4a8a264324cfe..a7bba6abd8c71 100644
--- a/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/OraclePoolBuildItem.java
+++ b/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/OraclePoolBuildItem.java
@@ -1,17 +1,19 @@
package io.quarkus.reactive.oracle.client.deployment;
+import java.util.function.Function;
+
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
-import io.quarkus.runtime.RuntimeValue;
import io.vertx.oracleclient.OraclePool;
public final class OraclePoolBuildItem extends MultiBuildItem {
private final String dataSourceName;
- private final RuntimeValue oraclePool;
+ private final Function, OraclePool> oraclePool;
- public OraclePoolBuildItem(String dataSourceName, RuntimeValue oraclePool) {
+ public OraclePoolBuildItem(String dataSourceName, Function, OraclePool> oraclePool) {
this.dataSourceName = dataSourceName;
this.oraclePool = oraclePool;
}
@@ -20,7 +22,7 @@ public String getDataSourceName() {
return dataSourceName;
}
- public RuntimeValue getOraclePool() {
+ public Function, OraclePool> getOraclePool() {
return oraclePool;
}
diff --git a/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java b/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java
index 25918da0fca34..a82812d3d8409 100644
--- a/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java
+++ b/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java
@@ -6,15 +6,20 @@
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Instance;
import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
+import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem.ExtendedBeanConfigurator;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
@@ -51,7 +56,6 @@
import io.quarkus.reactive.oracle.client.runtime.DataSourcesReactiveOracleConfig;
import io.quarkus.reactive.oracle.client.runtime.OraclePoolRecorder;
import io.quarkus.reactive.oracle.client.runtime.OracleServiceBindingConverter;
-import io.quarkus.runtime.RuntimeValue;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
import io.quarkus.vertx.core.deployment.EventLoopCountBuildItem;
import io.quarkus.vertx.deployment.VertxBuildItem;
@@ -60,6 +64,11 @@
class ReactiveOracleClientProcessor {
+ private static final ParameterizedType POOL_INJECTION_TYPE = ParameterizedType.create(DotName.createSimple(Instance.class),
+ new Type[] { ClassType.create(DotName.createSimple(OraclePoolCreator.class.getName())) }, null);
+ private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0];
+ private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class);
+
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
ServiceStartBuildItem build(BuildProducer feature,
@@ -81,7 +90,7 @@ ServiceStartBuildItem build(BuildProducer feature,
feature.produce(new FeatureBuildItem(Feature.REACTIVE_ORACLE_CLIENT));
for (String dataSourceName : dataSourcesBuildTimeConfig.dataSources().keySet()) {
- createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, oraclePool, vertxPool, syntheticBeans,
+ createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, oraclePool, syntheticBeans,
dataSourceName,
dataSourcesBuildTimeConfig, dataSourcesRuntimeConfig, dataSourcesReactiveBuildTimeConfig,
dataSourcesReactiveRuntimeConfig, dataSourcesReactiveOracleConfig, defaultDataSourceDbKindBuildItems,
@@ -91,6 +100,7 @@ ServiceStartBuildItem build(BuildProducer feature,
// Enable SSL support by default
sslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.REACTIVE_ORACLE_CLIENT));
+ vertxPool.produce(new VertxPoolBuildItem());
return new ServiceStartBuildItem("reactive-oracle-client");
}
@@ -169,7 +179,6 @@ private void createPoolIfDefined(OraclePoolRecorder recorder,
EventLoopCountBuildItem eventLoopCount,
ShutdownContextBuildItem shutdown,
BuildProducer oraclePool,
- BuildProducer vertxPool,
BuildProducer syntheticBeans,
String dataSourceName,
DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
@@ -185,20 +194,22 @@ private void createPoolIfDefined(OraclePoolRecorder recorder,
return;
}
- RuntimeValue pool = recorder.configureOraclePool(vertx.getVertx(),
+ Function, OraclePool> poolFunction = recorder.configureOraclePool(
+ vertx.getVertx(),
eventLoopCount.getEventLoopCount(),
dataSourceName,
dataSourcesRuntimeConfig,
dataSourcesReactiveRuntimeConfig,
dataSourcesReactiveOracleConfig,
shutdown);
- oraclePool.produce(new OraclePoolBuildItem(dataSourceName, pool));
+ oraclePool.produce(new OraclePoolBuildItem(dataSourceName, poolFunction));
ExtendedBeanConfigurator oraclePoolBeanConfigurator = SyntheticBeanBuildItem.configure(OraclePool.class)
.defaultBean()
.addType(Pool.class)
.scope(ApplicationScoped.class)
- .runtimeValue(pool)
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(poolFunction)
.unremovable()
.setRuntimeInit();
@@ -210,14 +221,21 @@ private void createPoolIfDefined(OraclePoolRecorder recorder,
.configure(io.vertx.mutiny.oracleclient.OraclePool.class)
.defaultBean()
.scope(ApplicationScoped.class)
- .runtimeValue(recorder.mutinyOraclePool(pool))
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(recorder.mutinyOraclePool(poolFunction))
.setRuntimeInit();
addQualifiers(mutinyOraclePoolConfigurator, dataSourceName);
syntheticBeans.produce(mutinyOraclePoolConfigurator.done());
+ }
- vertxPool.produce(new VertxPoolBuildItem(pool, DatabaseKind.ORACLE, DataSourceUtil.isDefault(dataSourceName)));
+ private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) {
+ if (DataSourceUtil.isDefault(dataSourceName)) {
+ return EMPTY_ANNOTATIONS;
+ }
+ return new AnnotationInstance[] {
+ AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() };
}
private static boolean isReactiveOraclePoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
diff --git a/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java b/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java
index e217cc1a818af..dc49a6eafd261 100644
--- a/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java
+++ b/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java
@@ -6,13 +6,15 @@
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.enterprise.inject.Instance;
+import jakarta.enterprise.util.TypeLiteral;
import org.jboss.logging.Logger;
-import io.quarkus.arc.Arc;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.credentials.CredentialsProvider;
import io.quarkus.credentials.runtime.CredentialsProviderFinder;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
@@ -38,29 +40,44 @@
@Recorder
public class OraclePoolRecorder {
+ private static final TypeLiteral> TYPE_LITERAL = new TypeLiteral<>() {
+ };
+
private static final Logger log = Logger.getLogger(OraclePoolRecorder.class);
- public RuntimeValue configureOraclePool(RuntimeValue vertx,
+ public Function, OraclePool> configureOraclePool(RuntimeValue vertx,
Supplier eventLoopCount,
String dataSourceName,
DataSourcesRuntimeConfig dataSourcesRuntimeConfig,
DataSourcesReactiveRuntimeConfig dataSourcesReactiveRuntimeConfig,
DataSourcesReactiveOracleConfig dataSourcesReactiveOracleConfig,
ShutdownContext shutdown) {
-
- OraclePool oraclePool = initialize((VertxInternal) vertx.getValue(),
- eventLoopCount.get(),
- dataSourceName,
- dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
- dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
- dataSourcesReactiveOracleConfig.dataSources().get(dataSourceName).reactive().oracle());
-
- shutdown.addShutdownTask(oraclePool::close);
- return new RuntimeValue<>(oraclePool);
+ return new Function, OraclePool>() {
+ @Override
+ public OraclePool apply(SyntheticCreationalContext context) {
+ OraclePool pool = initialize((VertxInternal) vertx.getValue(),
+ eventLoopCount.get(),
+ dataSourceName,
+ dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
+ dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
+ dataSourcesReactiveOracleConfig.dataSources().get(dataSourceName).reactive().oracle(),
+ context);
+
+ shutdown.addShutdownTask(pool::close);
+ return pool;
+ }
+ };
}
- public RuntimeValue mutinyOraclePool(RuntimeValue oraclePool) {
- return new RuntimeValue<>(io.vertx.mutiny.oracleclient.OraclePool.newInstance(oraclePool.getValue()));
+ public Function, io.vertx.mutiny.oracleclient.OraclePool> mutinyOraclePool(
+ Function, OraclePool> function) {
+ return new Function<>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public io.vertx.mutiny.oracleclient.OraclePool apply(SyntheticCreationalContext context) {
+ return io.vertx.mutiny.oracleclient.OraclePool.newInstance(function.apply(context));
+ }
+ };
}
private OraclePool initialize(VertxInternal vertx,
@@ -68,14 +85,15 @@ private OraclePool initialize(VertxInternal vertx,
String dataSourceName,
DataSourceRuntimeConfig dataSourceRuntimeConfig,
DataSourceReactiveRuntimeConfig dataSourceReactiveRuntimeConfig,
- DataSourceReactiveOracleConfig dataSourceReactiveOracleConfig) {
+ DataSourceReactiveOracleConfig dataSourceReactiveOracleConfig,
+ SyntheticCreationalContext context) {
PoolOptions poolOptions = toPoolOptions(eventLoopCount, dataSourceRuntimeConfig, dataSourceReactiveRuntimeConfig,
dataSourceReactiveOracleConfig);
OracleConnectOptions oracleConnectOptions = toOracleConnectOptions(dataSourceName, dataSourceRuntimeConfig,
dataSourceReactiveRuntimeConfig, dataSourceReactiveOracleConfig);
Supplier> databasesSupplier = toDatabasesSupplier(vertx, List.of(oracleConnectOptions),
dataSourceRuntimeConfig);
- return createPool(vertx, poolOptions, oracleConnectOptions, dataSourceName, databasesSupplier);
+ return createPool(vertx, poolOptions, oracleConnectOptions, dataSourceName, databasesSupplier, context);
}
private Supplier> toDatabasesSupplier(Vertx vertx,
@@ -185,12 +203,13 @@ private OracleConnectOptions toOracleConnectOptions(String dataSourceName, DataS
}
private OraclePool createPool(Vertx vertx, PoolOptions poolOptions, OracleConnectOptions oracleConnectOptions,
- String dataSourceName, Supplier> databases) {
+ String dataSourceName, Supplier> databases,
+ SyntheticCreationalContext context) {
Instance instance;
if (DataSourceUtil.isDefault(dataSourceName)) {
- instance = Arc.container().select(OraclePoolCreator.class);
+ instance = context.getInjectedReference(TYPE_LITERAL);
} else {
- instance = Arc.container().select(OraclePoolCreator.class,
+ instance = context.getInjectedReference(TYPE_LITERAL,
new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName));
}
if (instance.isResolvable()) {
diff --git a/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/PgPoolBuildItem.java b/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/PgPoolBuildItem.java
index 518bf7df817a8..0d19c802ead05 100644
--- a/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/PgPoolBuildItem.java
+++ b/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/PgPoolBuildItem.java
@@ -1,17 +1,19 @@
package io.quarkus.reactive.pg.client.deployment;
+import java.util.function.Function;
+
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
-import io.quarkus.runtime.RuntimeValue;
import io.vertx.pgclient.PgPool;
public final class PgPoolBuildItem extends MultiBuildItem {
private final String dataSourceName;
- private final RuntimeValue pgPool;
+ private final Function, PgPool> pgPool;
- public PgPoolBuildItem(String dataSourceName, RuntimeValue pgPool) {
+ public PgPoolBuildItem(String dataSourceName, Function, PgPool> pgPool) {
this.dataSourceName = dataSourceName;
this.pgPool = pgPool;
}
@@ -20,7 +22,7 @@ public String getDataSourceName() {
return dataSourceName;
}
- public RuntimeValue getPgPool() {
+ public Function, PgPool> getPgPool() {
return pgPool;
}
diff --git a/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java b/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java
index 77690e5430e3d..e1db7a21692b0 100644
--- a/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java
+++ b/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java
@@ -6,15 +6,20 @@
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Instance;
import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
+import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem.ExtendedBeanConfigurator;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
@@ -52,7 +57,6 @@
import io.quarkus.reactive.pg.client.runtime.DataSourcesReactivePostgreSQLConfig;
import io.quarkus.reactive.pg.client.runtime.PgPoolRecorder;
import io.quarkus.reactive.pg.client.runtime.PostgreSQLServiceBindingConverter;
-import io.quarkus.runtime.RuntimeValue;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
import io.quarkus.vertx.core.deployment.EventLoopCountBuildItem;
import io.quarkus.vertx.deployment.VertxBuildItem;
@@ -61,6 +65,11 @@
class ReactivePgClientProcessor {
+ private static final ParameterizedType POOL_INJECTION_TYPE = ParameterizedType.create(DotName.createSimple(Instance.class),
+ new Type[] { ClassType.create(DotName.createSimple(PgPoolCreator.class.getName())) }, null);
+ private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0];
+ private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class);
+
@BuildStep
NativeImageConfigBuildItem config() {
return NativeImageConfigBuildItem.builder().addRuntimeInitializedClass("io.vertx.pgclient.impl.codec.StartupMessage")
@@ -93,7 +102,7 @@ ServiceStartBuildItem build(BuildProducer feature,
feature.produce(new FeatureBuildItem(Feature.REACTIVE_PG_CLIENT));
for (String dataSourceName : dataSourcesBuildTimeConfig.dataSources().keySet()) {
- createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, pgPool, vertxPool, syntheticBeans, dataSourceName,
+ createPoolIfDefined(recorder, vertx, eventLoopCount, shutdown, pgPool, syntheticBeans, dataSourceName,
dataSourcesBuildTimeConfig, dataSourcesRuntimeConfig, dataSourcesReactiveBuildTimeConfig,
dataSourcesReactiveRuntimeConfig, dataSourcesReactivePostgreSQLConfig, defaultDataSourceDbKindBuildItems,
curateOutcomeBuildItem);
@@ -102,6 +111,7 @@ ServiceStartBuildItem build(BuildProducer feature,
// Enable SSL support by default
sslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.REACTIVE_PG_CLIENT));
+ vertxPool.produce(new VertxPoolBuildItem());
return new ServiceStartBuildItem("reactive-pg-client");
}
@@ -174,7 +184,6 @@ private void createPoolIfDefined(PgPoolRecorder recorder,
EventLoopCountBuildItem eventLoopCount,
ShutdownContextBuildItem shutdown,
BuildProducer pgPool,
- BuildProducer vertxPool,
BuildProducer syntheticBeans,
String dataSourceName,
DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
@@ -190,20 +199,21 @@ private void createPoolIfDefined(PgPoolRecorder recorder,
return;
}
- RuntimeValue pool = recorder.configurePgPool(vertx.getVertx(),
+ Function, PgPool> poolFunction = recorder.configurePgPool(vertx.getVertx(),
eventLoopCount.getEventLoopCount(),
dataSourceName,
dataSourcesRuntimeConfig,
dataSourcesReactiveRuntimeConfig,
dataSourcesReactivePostgreSQLConfig,
shutdown);
- pgPool.produce(new PgPoolBuildItem(dataSourceName, pool));
+ pgPool.produce(new PgPoolBuildItem(dataSourceName, poolFunction));
ExtendedBeanConfigurator pgPoolBeanConfigurator = SyntheticBeanBuildItem.configure(PgPool.class)
.defaultBean()
.addType(Pool.class)
.scope(ApplicationScoped.class)
- .runtimeValue(pool)
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(poolFunction)
.unremovable()
.setRuntimeInit();
@@ -215,14 +225,21 @@ private void createPoolIfDefined(PgPoolRecorder recorder,
.configure(io.vertx.mutiny.pgclient.PgPool.class)
.defaultBean()
.scope(ApplicationScoped.class)
- .runtimeValue(recorder.mutinyPgPool(pool))
+ .addInjectionPoint(POOL_INJECTION_TYPE, injectionPointAnnotations(dataSourceName))
+ .createWith(recorder.mutinyPgPool(poolFunction))
.setRuntimeInit();
addQualifiers(mutinyPgPoolConfigurator, dataSourceName);
syntheticBeans.produce(mutinyPgPoolConfigurator.done());
+ }
- vertxPool.produce(new VertxPoolBuildItem(pool, DatabaseKind.POSTGRESQL, DataSourceUtil.isDefault(dataSourceName)));
+ private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) {
+ if (DataSourceUtil.isDefault(dataSourceName)) {
+ return EMPTY_ANNOTATIONS;
+ }
+ return new AnnotationInstance[] {
+ AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() };
}
private static boolean isReactivePostgreSQLPoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
diff --git a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java
index 7988a6f86afa7..053c68a56708f 100644
--- a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java
+++ b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java
@@ -13,11 +13,13 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.enterprise.inject.Instance;
+import jakarta.enterprise.util.TypeLiteral;
-import io.quarkus.arc.Arc;
+import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.credentials.CredentialsProvider;
import io.quarkus.credentials.runtime.CredentialsProviderFinder;
import io.quarkus.datasource.common.runtime.DataSourceUtil;
@@ -43,27 +45,42 @@
@Recorder
public class PgPoolRecorder {
- public RuntimeValue configurePgPool(RuntimeValue vertx,
+ private static final TypeLiteral> TYPE_LITERAL = new TypeLiteral<>() {
+ };
+
+ public Function, PgPool> configurePgPool(RuntimeValue vertx,
Supplier eventLoopCount,
String dataSourceName,
DataSourcesRuntimeConfig dataSourcesRuntimeConfig,
DataSourcesReactiveRuntimeConfig dataSourcesReactiveRuntimeConfig,
DataSourcesReactivePostgreSQLConfig dataSourcesReactivePostgreSQLConfig,
ShutdownContext shutdown) {
-
- PgPool pgPool = initialize((VertxInternal) vertx.getValue(),
- eventLoopCount.get(),
- dataSourceName,
- dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
- dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
- dataSourcesReactivePostgreSQLConfig.dataSources().get(dataSourceName).reactive().postgresql());
-
- shutdown.addShutdownTask(pgPool::close);
- return new RuntimeValue<>(pgPool);
+ return new Function<>() {
+ @Override
+ public PgPool apply(SyntheticCreationalContext context) {
+ PgPool pgPool = initialize((VertxInternal) vertx.getValue(),
+ eventLoopCount.get(),
+ dataSourceName,
+ dataSourcesRuntimeConfig.dataSources().get(dataSourceName),
+ dataSourcesReactiveRuntimeConfig.getDataSourceReactiveRuntimeConfig(dataSourceName),
+ dataSourcesReactivePostgreSQLConfig.dataSources().get(dataSourceName).reactive().postgresql(),
+ context);
+
+ shutdown.addShutdownTask(pgPool::close);
+ return pgPool;
+ }
+ };
}
- public RuntimeValue mutinyPgPool(RuntimeValue pgPool) {
- return new RuntimeValue<>(io.vertx.mutiny.pgclient.PgPool.newInstance(pgPool.getValue()));
+ public Function, io.vertx.mutiny.pgclient.PgPool> mutinyPgPool(
+ Function, PgPool> function) {
+ return new Function<>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public io.vertx.mutiny.pgclient.PgPool apply(SyntheticCreationalContext context) {
+ return io.vertx.mutiny.pgclient.PgPool.newInstance(function.apply(context));
+ }
+ };
}
private PgPool initialize(VertxInternal vertx,
@@ -71,14 +88,15 @@ private PgPool initialize(VertxInternal vertx,
String dataSourceName,
DataSourceRuntimeConfig dataSourceRuntimeConfig,
DataSourceReactiveRuntimeConfig dataSourceReactiveRuntimeConfig,
- DataSourceReactivePostgreSQLConfig dataSourceReactivePostgreSQLConfig) {
+ DataSourceReactivePostgreSQLConfig dataSourceReactivePostgreSQLConfig,
+ SyntheticCreationalContext context) {
PoolOptions poolOptions = toPoolOptions(eventLoopCount, dataSourceRuntimeConfig, dataSourceReactiveRuntimeConfig,
dataSourceReactivePostgreSQLConfig);
List pgConnectOptionsList = toPgConnectOptions(dataSourceName, dataSourceRuntimeConfig,
dataSourceReactiveRuntimeConfig, dataSourceReactivePostgreSQLConfig);
Supplier> databasesSupplier = toDatabasesSupplier(vertx, pgConnectOptionsList,
dataSourceRuntimeConfig);
- return createPool(vertx, poolOptions, pgConnectOptionsList, dataSourceName, databasesSupplier);
+ return createPool(vertx, poolOptions, pgConnectOptionsList, dataSourceName, databasesSupplier, context);
}
private Supplier> toDatabasesSupplier(Vertx vertx, List pgConnectOptionsList,
@@ -220,12 +238,13 @@ private List toPgConnectOptions(String dataSourceName, DataSou
}
private PgPool createPool(Vertx vertx, PoolOptions poolOptions, List pgConnectOptionsList,
- String dataSourceName, Supplier> databases) {
+ String dataSourceName, Supplier> databases,
+ SyntheticCreationalContext context) {
Instance instance;
if (DataSourceUtil.isDefault(dataSourceName)) {
- instance = Arc.container().select(PgPoolCreator.class);
+ instance = context.getInjectedReference(TYPE_LITERAL);
} else {
- instance = Arc.container().select(PgPoolCreator.class,
+ instance = context.getInjectedReference(TYPE_LITERAL,
new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName));
}
if (instance.isResolvable()) {
diff --git a/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java b/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java
index 7ba1c30da0eed..2a60256424809 100644
--- a/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java
+++ b/extensions/redis-cache/runtime/src/main/java/io/quarkus/cache/redis/runtime/RedisCacheImpl.java
@@ -1,5 +1,6 @@
package io.quarkus.cache.redis.runtime;
+import java.net.ConnectException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.List;
@@ -10,6 +11,8 @@
import java.util.function.Predicate;
import java.util.function.Supplier;
+import org.jboss.logging.Logger;
+
import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.cache.CacheException;
@@ -35,6 +38,8 @@
*/
public class RedisCacheImpl extends AbstractCache implements RedisCache {
+ private static final Logger log = Logger.getLogger(RedisCacheImpl.class);
+
private static final Map> PRIMITIVE_TO_CLASS_MAPPING = Map.of(
"int", Integer.class,
"byte", Byte.class,
@@ -123,6 +128,19 @@ private String encodeKey(K key) {
return new String(marshaller.encode(key), StandardCharsets.UTF_8);
}
+ private Uni computeValue(K key, Function valueLoader, boolean isWorkerThread) {
+ if (isWorkerThread) {
+ return Uni.createFrom().item(new Supplier() {
+ @Override
+ public V get() {
+ return valueLoader.apply(key);
+ }
+ }).runSubscriptionOn(MutinyHelper.blockingExecutor(vertx.getDelegate()));
+ } else {
+ return Uni.createFrom().item(valueLoader.apply(key));
+ }
+ }
+
@Override
public Uni get(K key, Class clazz, Function valueLoader) {
// With optimistic locking:
@@ -148,17 +166,7 @@ public Uni apply(V cached) throws Exception {
if (cached != null) {
return Uni.createFrom().item(new StaticSupplier<>(cached));
} else {
- Uni uni;
- if (isWorkerThread) {
- uni = Uni.createFrom().item(new Supplier() {
- @Override
- public V get() {
- return valueLoader.apply(key);
- }
- }).runSubscriptionOn(MutinyHelper.blockingExecutor(vertx.getDelegate()));
- } else {
- uni = Uni.createFrom().item(valueLoader.apply(key));
- }
+ Uni uni = computeValue(key, valueLoader, isWorkerThread);
return uni.onItem().call(new Function>() {
@Override
@@ -185,7 +193,15 @@ public Uni> apply(V value) {
}
}));
}
- });
+ })
+
+ .onFailure(ConnectException.class).recoverWithUni(new Function>() {
+ @Override
+ public Uni extends V> apply(Throwable e) {
+ log.warn("Unable to connect to Redis, recomputing cached value", e);
+ return computeValue(key, valueLoader, isWorkerThread);
+ }
+ });
}
@Override
@@ -215,7 +231,11 @@ public Uni apply(RedisConnection connection) {
}
});
}
- });
+ })
+ .onFailure(ConnectException.class).recoverWithUni(e -> {
+ log.warn("Unable to connect to Redis, recomputing cached value", e);
+ return valueLoader.apply(key);
+ });
}
@Override
diff --git a/extensions/redis-cache/runtime/src/test/java/io/quarkus/cache/redis/runtime/RedisCacheImplTest.java b/extensions/redis-cache/runtime/src/test/java/io/quarkus/cache/redis/runtime/RedisCacheImplTest.java
index c69a50ff13796..c1e7466a4ffbe 100644
--- a/extensions/redis-cache/runtime/src/test/java/io/quarkus/cache/redis/runtime/RedisCacheImplTest.java
+++ b/extensions/redis-cache/runtime/src/test/java/io/quarkus/cache/redis/runtime/RedisCacheImplTest.java
@@ -29,7 +29,12 @@ class RedisCacheImplTest extends RedisCacheTestBase {
@AfterEach
void clear() {
- redis.send(Request.cmd(Command.FLUSHALL).arg("SYNC")).await().atMost(Duration.ofSeconds(10));
+ try {
+ redis.send(Request.cmd(Command.FLUSHALL).arg("SYNC")).await()
+ .atMost(Duration.ofSeconds(10));
+ } catch (Exception ignored) {
+ // ignored.
+ }
}
@Test
@@ -45,6 +50,18 @@ public void testPutInTheCache() {
assertThat(r).isNotNull();
}
+ @Test
+ public void testPutInTheCacheWithoutRedis() {
+ String k = UUID.randomUUID().toString();
+ RedisCacheInfo info = new RedisCacheInfo();
+ info.name = "foo";
+ info.valueType = String.class.getName();
+ info.expireAfterWrite = Optional.of(Duration.ofSeconds(2));
+ RedisCacheImpl cache = new RedisCacheImpl(info, vertx, redis, BLOCKING_ALLOWED);
+ server.close();
+ assertThat(cache.get(k, s -> "hello").await().indefinitely()).isEqualTo("hello");
+ }
+
@Test
public void testPutInTheCacheWithOptimisticLocking() {
String k = UUID.randomUUID().toString();
@@ -355,6 +372,32 @@ void testAsyncGetWithDefaultType() {
}));
}
+ @Test
+ void testAsyncGetWithDefaultTypeWithoutRedis() {
+ RedisCacheInfo info = new RedisCacheInfo();
+ info.name = "star-wars";
+ info.expireAfterWrite = Optional.of(Duration.ofSeconds(2));
+ info.valueType = Person.class.getName();
+ RedisCacheImpl cache = new RedisCacheImpl(info, vertx, redis, BLOCKING_ALLOWED);
+
+ server.close();
+
+ assertThat(cache
+ .getAsync("test",
+ x -> Uni.createFrom().item(new Person("luke", "skywalker"))
+ .runSubscriptionOn(Infrastructure.getDefaultExecutor()))
+ .await().indefinitely()).satisfies(p -> {
+ assertThat(p.firstName).isEqualTo("luke");
+ assertThat(p.lastName).isEqualTo("skywalker");
+ });
+
+ assertThat(cache.getAsync("test", x -> Uni.createFrom().item(new Person("leia", "organa")))
+ .await().indefinitely()).satisfies(p -> {
+ assertThat(p.firstName).isEqualTo("leia");
+ assertThat(p.lastName).isEqualTo("organa");
+ });
+ }
+
@Test
void testAsyncGetWithDefaultTypeWithOptimisticLocking() {
RedisCacheInfo info = new RedisCacheInfo();
diff --git a/extensions/resteasy-classic/rest-client/runtime/pom.xml b/extensions/resteasy-classic/rest-client/runtime/pom.xml
index b0095161d1a09..2ec750c3592c3 100644
--- a/extensions/resteasy-classic/rest-client/runtime/pom.xml
+++ b/extensions/resteasy-classic/rest-client/runtime/pom.xml
@@ -25,12 +25,6 @@
io.quarkus
quarkus-resteasy-common
-
-
- org.jboss.resteasy
- resteasy-cdi
-
-
io.quarkus
diff --git a/extensions/resteasy-classic/resteasy-common/runtime/pom.xml b/extensions/resteasy-classic/resteasy-common/runtime/pom.xml
index dc485b199d7e1..51726a0e168ab 100644
--- a/extensions/resteasy-classic/resteasy-common/runtime/pom.xml
+++ b/extensions/resteasy-classic/resteasy-common/runtime/pom.xml
@@ -81,10 +81,6 @@
jakarta.ws.rs
jakarta.ws.rs-api
-
- org.jboss.resteasy
- resteasy-cdi
-
org.jboss.resteasy
resteasy-json-binding-provider
diff --git a/extensions/resteasy-classic/resteasy-server-common/runtime/pom.xml b/extensions/resteasy-classic/resteasy-server-common/runtime/pom.xml
index 9175af66fa019..00b5a3bebcd99 100644
--- a/extensions/resteasy-classic/resteasy-server-common/runtime/pom.xml
+++ b/extensions/resteasy-classic/resteasy-server-common/runtime/pom.xml
@@ -25,6 +25,10 @@
io.quarkus
quarkus-resteasy-common
+
+ org.jboss.resteasy
+ resteasy-cdi
+
jakarta.validation
jakarta.validation-api
diff --git a/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/JakartaRestResourceHttpPermissionTest.java b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/JakartaRestResourceHttpPermissionTest.java
new file mode 100644
index 0000000000000..ed21f896dc164
--- /dev/null
+++ b/extensions/resteasy-classic/resteasy/deployment/src/test/java/io/quarkus/resteasy/test/security/JakartaRestResourceHttpPermissionTest.java
@@ -0,0 +1,230 @@
+package io.quarkus.resteasy.test.security;
+
+import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.net.URL;
+import java.time.Duration;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import io.quarkus.security.test.utils.TestIdentityController;
+import io.quarkus.security.test.utils.TestIdentityProvider;
+import io.quarkus.test.QuarkusUnitTest;
+import io.quarkus.test.common.http.TestHTTPResource;
+import io.smallrye.mutiny.Uni;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.mutiny.core.Vertx;
+import io.vertx.mutiny.core.http.HttpClientRequest;
+
+public class JakartaRestResourceHttpPermissionTest {
+ private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(20);
+ private static final String APP_PROPS = "quarkus.http.auth.permission.foo.paths=/api/foo,/api/foo/\n" +
+ "quarkus.http.auth.permission.foo.policy=authenticated\n" +
+ "quarkus.http.auth.permission.bar.paths=api/bar*\n" +
+ "quarkus.http.auth.permission.bar.policy=authenticated\n" +
+ "quarkus.http.auth.permission.baz-fum-pub.paths=/api/baz/fum\n" +
+ "quarkus.http.auth.permission.baz-fum-pub.policy=permit\n" +
+ "quarkus.http.auth.permission.baz-fum.paths=/api/baz/fum*\n" +
+ "quarkus.http.auth.permission.baz-fum.policy=authenticated\n" +
+ "quarkus.http.auth.permission.root.paths=/\n" +
+ "quarkus.http.auth.permission.root.policy=authenticated\n" +
+ "quarkus.http.auth.permission.dot.paths=dot,dot/\n" +
+ "quarkus.http.auth.permission.dot.policy=authenticated\n";
+
+ @RegisterExtension
+ static QuarkusUnitTest runner = new QuarkusUnitTest()
+ .withApplicationRoot((jar) -> jar
+ .addClasses(TestIdentityProvider.class, TestIdentityController.class, ApiResource.class,
+ RootResource.class, PublicResource.class)
+ .addAsResource(new StringAsset(APP_PROPS), "application.properties"));
+
+ @BeforeAll
+ public static void setup() {
+ TestIdentityController.resetRoles().add("test", "test", "test");
+ }
+
+ @TestHTTPResource
+ URL url;
+
+ @Inject
+ Vertx vertx;
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ // path without wildcard, with leading slashes in both policy and @Path
+ "/api/foo/", "/api/foo",
+ // path with wildcard, without leading slashes in both policy and @Path
+ "/api/bar", "/api/bar/", "/api/bar/irish",
+ // combination of permit and authenticated policies, paths are resolved to /api/baz/fum/ and auth required
+ "/api/baz/fum/"
+ })
+ public void testEmptyPathSegments(String path) {
+ assurePath(path, 401);
+ assurePathAuthenticated(path, getLastNonEmptySegmentContent(path));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "/", "///", "/?stuff", "" })
+ public void testRootPath(String path) {
+ assurePath(path, 401);
+ assurePathAuthenticated(path);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "/one/", "/three?stuff" })
+ public void testNotSecuredPaths(String path) {
+ // negative testing - all paths are public unless auth policy is applied
+ assurePath(path, 200);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "/api/foo///", "////api/foo", "/api//foo", "/api/bar///irish", "/api/bar///irish/",
+ "/api//baz/fum//",
+ "/api///foo", "////api/bar", "/api///bar", "/api//bar" })
+ public void testSecuredNotFound(String path) {
+ assurePath(path, 401);
+ assurePathAuthenticated(path, 404);
+ }
+
+ private static String getLastNonEmptySegmentContent(String path) {
+ while (path.endsWith("/") || path.endsWith(".")) {
+ path = path.substring(0, path.length() - 1);
+ }
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+
+ @Path("/api")
+ public static class ApiResource {
+
+ @GET
+ @Path("/foo")
+ public String foo() {
+ return "foo";
+ }
+
+ @GET
+ @Path("/bar")
+ public String bar() {
+ return "bar";
+ }
+
+ @GET
+ @Path("/bar/irish")
+ public String irishBar() {
+ return "irish";
+ }
+
+ @GET
+ @Path("/baz/fum")
+ public String bazFum() {
+ return "fum";
+ }
+
+ }
+
+ @Path("/")
+ public static class RootResource {
+
+ @GET
+ public String get() {
+ return "root";
+ }
+
+ }
+
+ @Path("/")
+ public static class PublicResource {
+
+ @Path("one")
+ @GET
+ public String one() {
+ return "one";
+ }
+
+ @Path("/two")
+ @GET
+ public String two() {
+ return "two";
+ }
+
+ @Path("/three")
+ @GET
+ public String three() {
+ return "three";
+ }
+
+ @Path("four")
+ @GET
+ public String four() {
+ return "four";
+ }
+
+ @Path("/four#stuff")
+ @GET
+ public String fourWitFragment() {
+ return "four#stuff";
+ }
+
+ @Path("five")
+ @GET
+ public String five() {
+ return "five";
+ }
+
+ }
+
+ private void assurePath(String path, int expectedStatusCode) {
+ assurePath(path, expectedStatusCode, null, false);
+ }
+
+ private void assurePathAuthenticated(String path) {
+ assurePath(path, 200, null, true);
+ }
+
+ private void assurePathAuthenticated(String path, int statusCode) {
+ assurePath(path, statusCode, null, true);
+ }
+
+ private void assurePathAuthenticated(String path, String body) {
+ assurePath(path, 200, body, true);
+ }
+
+ private void assurePath(String path, int expectedStatusCode, String body, boolean auth) {
+ var httpClient = vertx.createHttpClient();
+ try {
+ httpClient
+ .request(HttpMethod.GET, url.getPort(), url.getHost(), path)
+ .map(r -> {
+ if (auth) {
+ r.putHeader("Authorization", "Basic " + encodeBase64URLSafeString("test:test".getBytes()));
+ }
+ return r;
+ })
+ .flatMap(HttpClientRequest::send)
+ .invoke(r -> assertEquals(expectedStatusCode, r.statusCode(), path))
+ .flatMap(r -> {
+ if (body != null) {
+ return r.body().invoke(b -> assertEquals(b.toString(), body, path));
+ } else {
+ return Uni.createFrom().nullItem();
+ }
+ })
+ .await()
+ .atMost(REQUEST_TIMEOUT);
+ } finally {
+ httpClient
+ .close()
+ .await()
+ .atMost(REQUEST_TIMEOUT);
+ }
+ }
+}
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/test/java/io/quarkus/resteasy/reactive/jsonb/deployment/test/sse/SseParserTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/test/java/io/quarkus/resteasy/reactive/jsonb/deployment/test/sse/SseParserTest.java
index 6b55e2a725a56..7f8bd584a0244 100644
--- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/test/java/io/quarkus/resteasy/reactive/jsonb/deployment/test/sse/SseParserTest.java
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jsonb/deployment/src/test/java/io/quarkus/resteasy/reactive/jsonb/deployment/test/sse/SseParserTest.java
@@ -140,23 +140,12 @@ public void testParser() {
}
private void testParser(String event, String data, String comment, String lastId, String name, long reconnectDelay) {
- if (data != null) {
- testParser(Collections.singletonList(event), Collections.singletonList(new InboundSseEventImpl(null, null)
- .setData(data)
- .setComment(comment)
- .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());
- }
+ testParser(Collections.singletonList(event), Collections.singletonList(new InboundSseEventImpl(null, null)
+ .setData(data)
+ .setComment(comment)
+ .setId(lastId)
+ .setName(name)
+ .setReconnectDelay(reconnectDelay)));
}
private void testParser(List events, List expectedEvents) {
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/JakartaRestResourceHttpPermissionTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/JakartaRestResourceHttpPermissionTest.java
new file mode 100644
index 0000000000000..ee706eae57662
--- /dev/null
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/JakartaRestResourceHttpPermissionTest.java
@@ -0,0 +1,224 @@
+package io.quarkus.resteasy.reactive.server.test.security;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.net.URL;
+import java.time.Duration;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import io.quarkus.security.test.utils.TestIdentityController;
+import io.quarkus.security.test.utils.TestIdentityProvider;
+import io.quarkus.test.QuarkusUnitTest;
+import io.quarkus.test.common.http.TestHTTPResource;
+import io.vertx.core.Vertx;
+import io.vertx.ext.web.client.WebClient;
+
+public class JakartaRestResourceHttpPermissionTest {
+ private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(20);
+ private static final String APP_PROPS = "quarkus.http.auth.permission.foo.paths=/api/foo,/api/foo/\n" +
+ "quarkus.http.auth.permission.foo.policy=authenticated\n" +
+ "quarkus.http.auth.permission.bar.paths=api/bar*\n" +
+ "quarkus.http.auth.permission.bar.policy=authenticated\n" +
+ "quarkus.http.auth.permission.baz-fum-pub.paths=/api/baz/fum\n" +
+ "quarkus.http.auth.permission.baz-fum-pub.policy=permit\n" +
+ "quarkus.http.auth.permission.baz-fum.paths=/api/baz/fum*\n" +
+ "quarkus.http.auth.permission.baz-fum.policy=authenticated\n" +
+ "quarkus.http.auth.permission.root.paths=/\n" +
+ "quarkus.http.auth.permission.root.policy=authenticated\n" +
+ "quarkus.http.auth.permission.fragment.paths=/#stuff,/#stuff/\n" +
+ "quarkus.http.auth.permission.fragment.policy=authenticated\n";
+ private static WebClient client;
+
+ @RegisterExtension
+ static QuarkusUnitTest runner = new QuarkusUnitTest()
+ .withApplicationRoot((jar) -> jar
+ .addClasses(TestIdentityProvider.class, TestIdentityController.class, ApiResource.class,
+ RootResource.class, PublicResource.class)
+ .addAsResource(new StringAsset(APP_PROPS), "application.properties"));
+
+ @BeforeAll
+ public static void setup() {
+ TestIdentityController.resetRoles().add("test", "test", "test");
+ }
+
+ @AfterAll
+ public static void cleanup() {
+ if (client != null) {
+ client.close();
+ }
+ }
+
+ @Inject
+ Vertx vertx;
+
+ @TestHTTPResource
+ URL url;
+
+ private WebClient getClient() {
+ if (client == null) {
+ client = WebClient.create(vertx);
+ }
+ return client;
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ // path without wildcard, with leading slashes in both policy and @Path
+ "////api/foo", "/api/foo", "/api//foo", "/api//foo", "/api///foo", "/api/foo/", "/api/foo///",
+ "/api/foo///.", "/api/foo/./",
+ // path with wildcard, without leading slashes in both policy and @Path
+ "////api/bar", "/api///bar", "/api//bar", "/api/bar", "/api/bar/", "/api/bar/irish",
+ "/api/bar///irish", "/api/bar///irish/.", "/../api/bar///irish/.",
+ // combination of permit and authenticated policies, paths are resolved to /api/baz/fum/ and auth required
+ "/api/baz/fum/", "/api//baz/fum//", "/api//baz/fum/."
+ })
+ public void testEmptyPathSegments(String path) {
+ assurePath(path, 401);
+
+ assurePathAuthenticated(path, getLastNonEmptySegmentContent(path));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "/", "///", "/?stuff", "/#stuff/", "" })
+ public void testRootPath(String path) {
+ assurePath(path, 401);
+ assurePathAuthenticated(path);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "/one/", "///two", "/three?stuff", "/four#stuff", "/.////five" })
+ public void testNotSecuredPaths(String path) {
+ // negative testing - all paths are public unless auth policy is applied
+ assurePathAuthenticated(path);
+ }
+
+ private static String getLastNonEmptySegmentContent(String path) {
+ while (path.endsWith("/") || path.endsWith(".")) {
+ path = path.substring(0, path.length() - 1);
+ }
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+
+ @Path("/api")
+ public static class ApiResource {
+
+ @GET
+ @Path("/foo")
+ public String foo() {
+ return "foo";
+ }
+
+ @GET
+ @Path("bar")
+ public String bar() {
+ return "bar";
+ }
+
+ @GET
+ @Path("bar/irish")
+ public String irishBar() {
+ return "irish";
+ }
+
+ @GET
+ @Path("baz/fum")
+ public String bazFum() {
+ return "fum";
+ }
+
+ }
+
+ @Path("/")
+ public static class RootResource {
+
+ @GET
+ public String get() {
+ return "root";
+ }
+
+ @Path("#stuff")
+ @GET
+ public String fragment() {
+ return "#stuff";
+ }
+
+ }
+
+ @Path("/")
+ public static class PublicResource {
+
+ @Path("one")
+ @GET
+ public String one() {
+ return "one";
+ }
+
+ @Path("/two")
+ @GET
+ public String two() {
+ return "two";
+ }
+
+ @Path("/three")
+ @GET
+ public String three() {
+ return "three";
+ }
+
+ @Path("four")
+ @GET
+ public String four() {
+ return "four";
+ }
+
+ @Path("four#stuff")
+ @GET
+ public String fourFragment() {
+ return "four#stuff";
+ }
+
+ @Path("five")
+ @GET
+ public String five() {
+ return "five";
+ }
+
+ }
+
+ private void assurePath(String path, int expectedStatusCode) {
+ assurePath(path, expectedStatusCode, null, false);
+ }
+
+ private void assurePathAuthenticated(String path) {
+ assurePath(path, 200, null, true);
+ }
+
+ private void assurePathAuthenticated(String path, String body) {
+ assurePath(path, 200, body, true);
+ }
+
+ private void assurePath(String path, int expectedStatusCode, String body, boolean auth) {
+ var req = getClient().get(url.getPort(), url.getHost(), path);
+ if (auth) {
+ req.basicAuthentication("test", "test");
+ }
+ var result = req.send();
+ await().atMost(REQUEST_TIMEOUT).until(result::isComplete);
+ assertEquals(expectedStatusCode, result.result().statusCode(), path);
+ if (body != null) {
+ Assertions.assertTrue(result.result().bodyAsString().contains(body), path);
+ }
+ }
+}
diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java
index e4483f6586bb7..04fd0a2d54494 100644
--- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java
+++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java
@@ -39,6 +39,7 @@
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.RuntimeType;
import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
@@ -60,6 +61,7 @@
import org.jboss.resteasy.reactive.client.spi.MissingMessageBodyReaderErrorMessageContextualizer;
import org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames;
import org.jboss.resteasy.reactive.common.processor.transformation.AnnotationStore;
+import org.jboss.resteasy.reactive.common.util.QuarkusMultivaluedHashMap;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.CustomScopeAnnotationsBuildItem;
@@ -331,12 +333,15 @@ void registerProvidersFromAnnotations(CombinedIndexBuildItem indexBuildItem,
}
}
- Map generatedProviders = new HashMap<>();
- populateClientExceptionMapperFromAnnotations(generatedClasses, reflectiveClasses, index, generatedProviders);
- populateClientRedirectHandlerFromAnnotations(generatedClasses, reflectiveClasses, index, generatedProviders);
+ MultivaluedMap generatedProviders = new QuarkusMultivaluedHashMap<>();
+ populateClientExceptionMapperFromAnnotations(generatedClasses, reflectiveClasses, index)
+ .forEach(generatedProviders::add);
+ populateClientRedirectHandlerFromAnnotations(generatedClasses, reflectiveClasses, index)
+ .forEach(generatedProviders::add);
for (AnnotationToRegisterIntoClientContextBuildItem annotation : annotationsToRegisterIntoClientContext) {
- populateClientProviderFromAnnotations(annotation, generatedClasses, reflectiveClasses,
- index, generatedProviders);
+ populateClientProviderFromAnnotations(annotation, generatedClasses, reflectiveClasses, index)
+ .forEach(generatedProviders::add);
+
}
addGeneratedProviders(index, constructor, annotationsByClassName, generatedProviders);
@@ -551,77 +556,83 @@ && isImplementorOf(index, target.asClass(), RESPONSE_EXCEPTION_MAPPER, Set.of(AP
}
}
- private void populateClientExceptionMapperFromAnnotations(BuildProducer generatedClasses,
- BuildProducer reflectiveClasses, IndexView index,
- Map