From c792dcf3856cb0a765dd7cd5218123c3f804173b Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Thu, 22 Jun 2023 18:16:13 +0200 Subject: [PATCH 01/11] Various fixes regarding GraalVM/Mandrel flavor (cherry picked from commit b2c2435b498deb5b16f042957f55a3b2e44ca37d) --- .../quarkus/deployment/pkg/NativeConfig.java | 4 +- docs/pom.xml | 2 +- docs/src/main/asciidoc/_attributes.adoc | 4 +- .../main/asciidoc/building-native-image.adoc | 48 +++++++++++-------- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java index 1e4913748af07..e966f9a1aca3b 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/NativeConfig.java @@ -461,8 +461,8 @@ interface Debug { interface Compression { /** * The compression level in [1, 10]. - * 10 means best - * + * 10 means best. + *

* Higher compression level requires more time to compress the executable. */ OptionalInt level(); diff --git a/docs/pom.xml b/docs/pom.xml index 087c3f2a89c19..94f59c856cd95 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -17,7 +17,7 @@ - jdk-17.0.7 + jdk-17 jdk-17 3.5.0 diff --git a/docs/src/main/asciidoc/_attributes.adoc b/docs/src/main/asciidoc/_attributes.adoc index 2028b41225096..16ea1b43215d8 100644 --- a/docs/src/main/asciidoc/_attributes.adoc +++ b/docs/src/main/asciidoc/_attributes.adoc @@ -6,9 +6,9 @@ // . :maven-version: ${proposed-maven-version} :graalvm-version: ${graal-community.version-for-documentation} -:graalvm-flavor: ${graal-community.version-for-documentation}-java17 +:graalvm-flavor: ${graal-community.version-for-documentation} :mandrel-version: ${mandrel.version-for-documentation} -:mandrel-flavor: ${mandrel.version-for-documentation}-java17 +:mandrel-flavor: ${mandrel.version-for-documentation} :surefire-version: ${version.surefire.plugin} :gradle-version: ${gradle-wrapper.version} :elasticsearch-version: ${elasticsearch-server.version} diff --git a/docs/src/main/asciidoc/building-native-image.adoc b/docs/src/main/asciidoc/building-native-image.adoc index e94113b02fe33..102fe53c583ec 100644 --- a/docs/src/main/asciidoc/building-native-image.adoc +++ b/docs/src/main/asciidoc/building-native-image.adoc @@ -122,36 +122,28 @@ On Windows, you will have to go through the Control Panel to set your environmen ==== Installing via scoop will do this for you. ==== -3. (Only for GraalVM CE/EE) Install the `native-image` tool using `gu install`: -+ -[source,bash] ----- -${GRAALVM_HOME}/bin/gu install native-image ----- -+ -Some previous releases of GraalVM included the `native-image` tool by default. This is no longer the case; it must be installed as a second step after GraalVM itself is installed. Note: there is an outstanding issue xref:graal-and-catalina[using GraalVM with macOS Catalina]. -4. (Optional) Set the `JAVA_HOME` environment variable to the GraalVM installation directory. +3. (Optional) Set the `JAVA_HOME` environment variable to the GraalVM installation directory. + [source,bash] ---- export JAVA_HOME=${GRAALVM_HOME} ---- -5. (Optional) Add the GraalVM `bin` directory to the path +4. (Optional) Add the GraalVM `bin` directory to the path + [source,bash] ---- export PATH=${GRAALVM_HOME}/bin:$PATH ---- -[[graal-and-catalina]] -.Issues using GraalVM with macOS Catalina +[[graal-and-macos]] +.Issues using GraalVM with macOS [NOTE] ==== -GraalVM binaries are not (yet) notarized for macOS Catalina as reported in this https://github.com/oracle/graal/issues/1724[GraalVM issue]. This means that you may see the following error when using `gu`: +GraalVM binaries are not (yet) notarized for macOS as reported in this https://github.com/oracle/graal/issues/1724[GraalVM issue]. This means that you may see the following error when using `native-image`: [source,bash] ---- -“gu” cannot be opened because the developer cannot be verified +“native-image” cannot be opened because the developer cannot be verified ---- Use the following command to recursively delete the `com.apple.quarantine` extended attribute on the GraalVM install directory as a workaround: @@ -214,7 +206,7 @@ include::{includes}/devtools/build-native.adoc[] ==== The Microsoft Native Tools for Visual Studio must first be initialized before packaging. You can do this by starting the `x64 Native Tools Command Prompt` that was installed with the Visual Studio Build Tools. At -`x64 Native Tools Command Prompt` you can navigate to your project folder and run `mvnw package -Dnative`. +`x64 Native Tools Command Prompt` you can navigate to your project folder and run `./mvnw package -Dnative`. Another solution is to write a script to do this for you: @@ -323,7 +315,9 @@ using the default, `prod` profile. Alternatively, if you need to specify specific properties when running tests against the native executable built using the `prod` profile, an option is to put those properties in file `src/test/resources/application-nativeit.yaml`, and refer to it from the `failsafe` plugin configuration using the `QUARKUS_CONFIG_LOCATIONS` environment variable. For instance: -``` + +[source,xml] +---- maven-failsafe-plugin ${surefire-plugin.version} @@ -346,7 +340,7 @@ built using the `prod` profile, an option is to put those properties in file `sr -``` +---- ==== === Java preview features @@ -432,6 +426,17 @@ In this case, use the parameter `-Dquarkus.native.remote-container-build=true` i The reason for this is that the local build driver invoked through `-Dquarkus.native.container-build=true` uses volume mounts to make the JAR available in the build container, but volume mounts do not work with remote daemons. The remote container build driver copies the necessary files instead of mounting them. Note that even though the remote driver also works with local daemons, the local driver should be preferred in the local case because mounting is usually more performant than copying. ==== +[TIP] +==== +The builder image used by default supports Java 17 as it is the latest LTS version. + +If your application uses Java 18 or later, you need to specify a builder image supporting Java 20: + +:build-additional-parameters: -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-20 +include::{includes}/devtools/build-native-container-parameters.adoc[] +:!build-additional-parameters: +==== + [TIP] ==== Building with GraalVM instead of Mandrel requires a custom builder image parameter to be passed additionally: @@ -538,9 +543,14 @@ The project generation has also provided a `Dockerfile.native` in the `src/main/ ---- FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6 WORKDIR /work/ -COPY target/*-runner /work/application -RUN chmod 775 /work +RUN chown 1001 /work \ + && chmod "g+rwX" /work \ + && chown 1001:root /work +COPY --chown=1001:root target/*-runner /work/application + EXPOSE 8080 +USER 1001 + CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] ---- From 5b7480e4c29947fc5d8438aaf2403a46b0ada784 Mon Sep 17 00:00:00 2001 From: Michelle Purcell Date: Tue, 27 Jun 2023 14:23:39 +0100 Subject: [PATCH 02/11] Styling edits to proactive auth content tweak (cherry picked from commit 126cfee0f3eeda156623bbce745f296f88c5be4e) --- .../security-proactive-authentication.adoc | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/docs/src/main/asciidoc/security-proactive-authentication.adoc b/docs/src/main/asciidoc/security-proactive-authentication.adoc index 1630b7e662557..b924a493021d5 100644 --- a/docs/src/main/asciidoc/security-proactive-authentication.adoc +++ b/docs/src/main/asciidoc/security-proactive-authentication.adoc @@ -13,36 +13,44 @@ Proactive authentication is enabled in Quarkus by default. This means that if an [[proactive-authentication]] -Requests with an invalid credential will always be rejected, even when the page is public. +Requests with an invalid credential will always be rejected, even when the page is public. -You can change the default behavior if you only want to authenticate when the target page requires authentication. +If you only want to authenticate when the target page requires authentication, you can change the default behavior. -To disable proactive authentication in Quarkus, set the following attribute in the `application.properties` configuration file: +To disable proactive authentication in Quarkus, set the following attribute in the `application.properties` configuration file: [source,xml,options="nowrap",role="white-space-pre"] ---- -`quarkus.http.auth.proactive=false` +`quarkus.http.auth.proactive=false` ---- -If you disable proactive authentication, the authentication process runs only when an identity is requested. An identity can be requested because of security rules that require the user to authenticate or because programmatic access to the current identity is required. +If you disable proactive authentication, the authentication process runs only when an identity is requested. +An identity can be requested because of security rules that require the user to authenticate or because programmatic access to the current identity is required. -If proactive authentication is in use, accessing the `SecurityIdentity` is a blocking operation. -This is because authentication may have yet to happen, and accessing it may require calls to external systems, such as databases that may block. -For blocking applications, this is no problem. However, if you have disabled authentication in a reactive application, this will fail (as you cannot do blocking operations on the IO thread). +If proactive authentication is in use, accessing `SecurityIdentity` is a blocking operation. +This is because authentication might have yet to happen and accessing `SecurityIdentity` might require calls to external systems, such as databases, that might block the operation. +For blocking applications, this is not an issue. +However, if you have disabled authentication in a reactive application, this will fail because you cannot do blocking operations on the I/O thread. To work around this, you need to `@Inject` an instance of `io.quarkus.security.identity.CurrentIdentityAssociation` and call the `Uni getDeferredIdentity();` method. -You can then subscribe to the resulting `Uni` and will be notified when authentication is complete and the identity is available. +Then, you can subscribe to the resulting `Uni` and will be notified when authentication is complete and the identity is available. -NOTE: It's still possible to access the `SecurityIdentity` synchronously with `public SecurityIdentity getIdentity()` in the xref:resteasy-reactive.adoc[RESTEasy Reactive] from endpoints annotated with `@RolesAllowed`, `@Authenticated`, or with respective configuration authorization checks as authentication has already happened. -The same is also valid for the xref:reactive-routes.adoc[Reactive routes] if a route response is synchronous. +[NOTE] +==== +You can still access `SecurityIdentity` synchronously with `public SecurityIdentity getIdentity()` in xref:resteasy-reactive.adoc[RESTEasy Reactive] from endpoints that are annotated with `@RolesAllowed`, `@Authenticated`, or with respective configuration authorization checks because authentication has already happened. +The same is also valid for xref:reactive-routes.adoc[Reactive routes] if a route response is synchronous. +==== -xref:security-authorization.adoc#standard-security-annotations[Standard security annotations] on CDI beans are not supported on IO thread if a non-void secured method returns a value synchronously and proactive authentication is disabled, as they need to access the `SecurityIdentity`. -In the example below, we have defined `HelloResource` and `HelloService`. It's easy to see that any GET request to `/hello` will run on IO thread and throw `BlockingOperationNotAllowedException` exception. +xref:security-authorization.adoc#standard-security-annotations[Standard security annotations] on CDI beans are not supported on an I/O thread if a non-void secured method returns a value synchronously and proactive authentication is disabled because they need to access `SecurityIdentity`. + +In the following example, `HelloResource` and `HelloService` are defined. +Any GET request to `/hello` will run on the I/O thread and throw a `BlockingOperationNotAllowedException` exception. There is more than one way to fix the example: -* switch to a worker thread (annotate `hello` endpoint with `@Blocking`) -* change `sayHello` method return type (use reactive or asynchronous data type) -* arguably the safest way is to move `@RolesAllowed` annotation to the endpoint, as accessing `SecurityIdentity` from endpoint methods is never the blocking operation +* Switch to a worker thread by annotating the `hello` endpoint with `@Blocking`. +* Change the `sayHello` method return type by using a reactive or asynchronous data type. +* Move `@RolesAllowed` annotation to the endpoint. +This could be one of the safest ways because accessing `SecurityIdentity` from endpoint methods is never the blocking operation. [source,java] ---- @@ -84,7 +92,7 @@ public class HelloService { } ---- -== How to customize authentication exception responses +== Customize authentication exception responses You can use Jakarta REST `ExceptionMapper` to capture Quarkus Security authentication exceptions such as `io.quarkus.security.AuthenticationFailedException`, for example: @@ -115,10 +123,11 @@ public class AuthenticationFailedExceptionMapper implements ExceptionMapper Date: Tue, 27 Jun 2023 09:59:05 +0300 Subject: [PATCH 03/11] Add support for java.time.Year as JAX-RS parameter Closes: #34324 (cherry picked from commit 633c793336744ae304a5ba169b960286dfd14369) --- .../common/processor/EndpointIndexer.java | 4 +- .../processor/ResteasyReactiveDotNames.java | 2 + .../processor/ServerEndpointIndexer.java | 4 + .../converters/YearParamConverter.java | 55 +++++++++ .../vertx/test/simple/YearParamTest.java | 104 ++++++++++++++++++ 5 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java create mode 100644 independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java index 1ecf00262239b..2f93845f8e282 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java @@ -75,6 +75,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.TRANSACTIONAL; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.UNI; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.URI_INFO; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.YEAR; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.ZONED_DATE_TIME; import java.lang.reflect.Modifier; @@ -147,8 +148,7 @@ public abstract class EndpointIndexer SUPPORT_TEMPORAL_PARAMS = Set.of(INSTANT, LOCAL_DATE, LOCAL_TIME, LOCAL_DATE_TIME, - OFFSET_TIME, - OFFSET_DATE_TIME, ZONED_DATE_TIME); + OFFSET_TIME, OFFSET_DATE_TIME, ZONED_DATE_TIME, YEAR); protected static final Logger log = Logger.getLogger(EndpointIndexer.class); protected static final String[] EMPTY_STRING_ARRAY = new String[] {}; diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java index 191449b553310..69d1747782895 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java @@ -10,6 +10,7 @@ import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.OffsetTime; +import java.time.Year; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Collection; @@ -200,6 +201,7 @@ public final class ResteasyReactiveDotNames { public static final DotName OFFSET_DATE_TIME = DotName.createSimple(OffsetDateTime.class.getName()); public static final DotName OFFSET_TIME = DotName.createSimple(OffsetTime.class.getName()); public static final DotName ZONED_DATE_TIME = DotName.createSimple(ZonedDateTime.class.getName()); + public static final DotName YEAR = DotName.createSimple(Year.class.getName()); public static final DotName UNI = DotName.createSimple(Uni.class.getName()); public static final DotName MULTI = DotName.createSimple(Multi.class.getName()); diff --git a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java index f562f684d943f..5044f7eb4b3ee 100644 --- a/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java +++ b/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java @@ -20,6 +20,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.OFFSET_TIME; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.SET; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.SORTED_SET; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.YEAR; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.ZONED_DATE_TIME; import java.io.File; @@ -79,6 +80,7 @@ import org.jboss.resteasy.reactive.server.core.parameters.converters.RuntimeResolvedConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.SetConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.SortedSetConverter; +import org.jboss.resteasy.reactive.server.core.parameters.converters.YearParamConverter; import org.jboss.resteasy.reactive.server.core.parameters.converters.ZonedDateTimeParamConverter; import org.jboss.resteasy.reactive.server.mapping.URITemplate; import org.jboss.resteasy.reactive.server.model.HandlerChainCustomizer; @@ -504,6 +506,8 @@ private ParameterConverterSupplier determineTemporalConverter(DotName paramType, return new OffsetTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName); } else if (ZONED_DATE_TIME.equals(paramType)) { return new ZonedDateTimeParamConverter.Supplier(format, dateTimeFormatterProviderClassName); + } else if (YEAR.equals(paramType)) { + return new YearParamConverter.Supplier(format, dateTimeFormatterProviderClassName); } throw new RuntimeException( diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java new file mode 100644 index 0000000000000..818a143ccdb8b --- /dev/null +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/parameters/converters/YearParamConverter.java @@ -0,0 +1,55 @@ +package org.jboss.resteasy.reactive.server.core.parameters.converters; + +import static java.time.temporal.ChronoField.YEAR; + +import java.time.Year; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.SignStyle; + +public class YearParamConverter extends TemporalParamConverter { + + // lifted from the JDK as PARSER is private... + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .toFormatter(); + + // this can be called by generated code + public YearParamConverter() { + super(PARSER); + } + + public YearParamConverter(DateTimeFormatter formatter) { + super(formatter); + } + + @Override + protected Year convert(String value) { + return Year.parse(value); + } + + @Override + protected Year convert(String value, DateTimeFormatter formatter) { + return Year.parse(value, formatter); + } + + public static class Supplier extends TemporalSupplier { + + public Supplier() { + } + + public Supplier(String pattern, String dateTimeFormatterProviderClassName) { + super(pattern, dateTimeFormatterProviderClassName); + } + + @Override + protected YearParamConverter createConverter(DateTimeFormatter dateTimeFormatter) { + return new YearParamConverter(dateTimeFormatter); + } + + @Override + public String getClassName() { + return YearParamConverter.class.getName(); + } + } +} diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java new file mode 100644 index 0000000000000..1764f6171220a --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/simple/YearParamTest.java @@ -0,0 +1,104 @@ +package org.jboss.resteasy.reactive.server.vertx.test.simple; + +import java.time.Year; +import java.time.format.DateTimeFormatter; + +import jakarta.ws.rs.CookieParam; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; + +import org.hamcrest.Matchers; +import org.jboss.resteasy.reactive.DateFormat; +import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.restassured.RestAssured; + +public class YearParamTest { + + @RegisterExtension + static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(HelloResource.class, CustomDateTimeFormatterProvider.class)); + + @Test + public void yearAsQueryParam() { + RestAssured.get("/hello?date=01984") + .then().statusCode(200).body(Matchers.equalTo("hello#1984")); + } + + @Test + public void yearAsPathParam() { + RestAssured.get("/hello/1821") + .then().statusCode(200).body(Matchers.equalTo("hello@1821")); + } + + @Test + public void yearAsFormParam() { + RestAssured.given().formParam("date", "995").post("/hello") + .then().statusCode(200).body(Matchers.equalTo("hello:995")); + } + + @Test + public void yearAsHeader() { + RestAssured.with().header("date", "1984") + .get("/hello/header") + .then().statusCode(200).body(Matchers.equalTo("hello=1984")); + } + + @Test + public void yearAsCookie() { + RestAssured.with().cookie("date", "1984") + .get("/hello/cookie") + .then().statusCode(200).body(Matchers.equalTo("hello/1984")); + } + + @Path("hello") + public static class HelloResource { + + @GET + public String helloQuery(@QueryParam("date") @DateFormat(pattern = "yyyyy") Year date) { + return "hello#" + date; + } + + @GET + @Path("{date}") + public String helloPath(@PathParam("date") Year date) { + return "hello@" + date; + } + + @POST + public String helloForm( + @FormParam("date") @DateFormat(dateTimeFormatterProvider = CustomDateTimeFormatterProvider.class) Year date) { + return "hello:" + date; + } + + @GET + @Path("cookie") + public String helloCookie( + @CookieParam("date") Year date) { + return "hello/" + date; + } + + @GET + @Path("header") + public String helloHeader( + @HeaderParam("date") Year date) { + return "hello=" + date; + } + } + + public static class CustomDateTimeFormatterProvider implements DateFormat.DateTimeFormatterProvider { + @Override + public DateTimeFormatter get() { + return DateTimeFormatter.ofPattern("yyy"); + } + } + +} From a24d5afa7409f2d3587d49bbed542391b804ff10 Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Tue, 27 Jun 2023 17:16:58 +0200 Subject: [PATCH 04/11] Add a section about march (graalvm 23+) (cherry picked from commit eff0eecfa3fe7c90b89c5cf060909e62346efd9f) --- docs/src/main/asciidoc/native-reference.adoc | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/src/main/asciidoc/native-reference.adoc b/docs/src/main/asciidoc/native-reference.adoc index c70057b1daf87..d5558350a09e5 100644 --- a/docs/src/main/asciidoc/native-reference.adoc +++ b/docs/src/main/asciidoc/native-reference.adoc @@ -2235,3 +2235,29 @@ If the amount is not in hundreds, it could be a problem. A possible workaround i export JAVA_OPTS=-Djava.security.egd=/dev/urandom ---- The proper solution is to increase the entropy available for the system. That is specific for each OS vendor and virtualization solution though. + +=== Work around missing CPU features + +When building on recent machines and running your native executable on older machines, you may see the following failure when starting the application: + +[source] +---- +The current machine does not support all of the following CPU features that are required by the image: [CX8, CMOV, FXSR, MMX, SSE, SSE2, SSE3, SSSE3, SSE4_1, SSE4_2, POPCNT, LZCNT, AVX, AVX2, BMI1, BMI2, FMA]. +Please rebuild the executable with an appropriate setting of the -march option. +---- + +This error message means that the native compilation used more advanced instruction sets, not supported by the CPU running the application. +To work around that issue, add the following line to the `application.properties`: + +[source, properties] +---- +quarkus.native.additional-build-args=-march=compatibility +---- + +Then, rebuild your native executable. +This setting forces the native compilation to use an older instruction set, increasing the chance of compatibility. + +To explicitly define the target architecture run `native-image -march=list` to get the supported configurations and then set `-march` to one of them, e.g., `quarkus.native.additional-build-args=-march=x86-64-v4`. +If you are targeting an AMD64 host, `-march=x86-64-v2` would work in most cases. + +NOTE: The `march` parameter is only available on GraalVM 23+. \ No newline at end of file From fb3d61d0147b23c51089b60eaa786366880e66aa Mon Sep 17 00:00:00 2001 From: rjtmahinay Date: Fri, 23 Jun 2023 02:53:21 +0800 Subject: [PATCH 05/11] Rephrase Non-mutable jar error message for remote-dev * Fix #34230 --- .../io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java index b51baa5427fea..9f01d40ddc4c6 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java @@ -92,7 +92,8 @@ private synchronized JarResult generateApplication() { AugmentResult start = augmentAction.createProductionApplication(); if (!start.getJar().getType().equalsIgnoreCase(PackageConfig.BuiltInType.MUTABLE_JAR.getValue())) { throw new RuntimeException( - "remote-dev can only be used with mutable applications generated with the fast-jar format"); + "remote-dev can only be used with mutable applications i.e, " + + "using the mutable-jar package type"); } //now extract the artifacts, to mirror the remote side DevModeTask.extractDevModeClasses(start.getJar().getPath().getParent(), From 3d02e9066d788c3ac4fb44ad77b88d1a9fe7e1f5 Mon Sep 17 00:00:00 2001 From: Daryl Koh <37805932+cambrian-dk@users.noreply.github.com> Date: Fri, 23 Jun 2023 19:04:34 +0800 Subject: [PATCH 06/11] Add extension suggestion in management interface reference (cherry picked from commit bb86758c0ea78752f40b57037cea56ed4cb7ed9e) --- docs/src/main/asciidoc/management-interface-reference.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/management-interface-reference.adoc b/docs/src/main/asciidoc/management-interface-reference.adoc index f9f97b3caaec4..f4b890be60490 100644 --- a/docs/src/main/asciidoc/management-interface-reference.adoc +++ b/docs/src/main/asciidoc/management-interface-reference.adoc @@ -27,10 +27,12 @@ quarkus.management.enabled=true ---- By default, management endpoints will be exposed on: `http://0.0.0.0:9000/q`. -For example, `http://0.0.0.0:9000/q/health/ready` for the readiness probe. +For example, if you have `smallrye-health` installed, the readiness probe will be exposed at `http://0.0.0.0:9000/q/health/ready`. SmallRye Health Checks, SmallRye Metrics, Micrometer and Info endpoints will be declared as management endpoints when the management interface is enabled. +NOTE: The management interface will not work properly without extensions that use it. e.g. `smallrye-health`, `quarkus-smallrye-openapi`. + == Configure the host, port and scheme By default, the management interface is exposed on the interface: `0.0.0.0` (all interfaces) and on the port `9000` (`9001` in test mode). From fa50108a1bf611a8ffd7db1563d8a06c96f29eae Mon Sep 17 00:00:00 2001 From: Daryl Koh <37805932+cambrian-dk@users.noreply.github.com> Date: Mon, 26 Jun 2023 16:04:18 +0800 Subject: [PATCH 07/11] Fix phrasing in note (cherry picked from commit 0d70551ff0a836bf89737fae015e25c3e7ab82f9) --- docs/src/main/asciidoc/management-interface-reference.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/management-interface-reference.adoc b/docs/src/main/asciidoc/management-interface-reference.adoc index f4b890be60490..d959a733cd81e 100644 --- a/docs/src/main/asciidoc/management-interface-reference.adoc +++ b/docs/src/main/asciidoc/management-interface-reference.adoc @@ -31,7 +31,7 @@ For example, if you have `smallrye-health` installed, the readiness probe will b SmallRye Health Checks, SmallRye Metrics, Micrometer and Info endpoints will be declared as management endpoints when the management interface is enabled. -NOTE: The management interface will not work properly without extensions that use it. e.g. `smallrye-health`, `quarkus-smallrye-openapi`. +NOTE: The management interface will be disabled without extensions that use it. e.g. `smallrye-health`, `quarkus-smallrye-openapi`. == Configure the host, port and scheme From 4278d7ad333c040060b32c29cc27b3ac9bd06c28 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 27 Jun 2023 16:36:35 +0200 Subject: [PATCH 08/11] Small doc adjustments noticed when backporting recent PRs (cherry picked from commit 55db899303344a306d2edddfd4b9dabdacb76dab) --- .../io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java | 2 +- docs/src/main/asciidoc/management-interface-reference.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java index 9f01d40ddc4c6..4eb1f162bbf56 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedRemoteDevModeMain.java @@ -92,7 +92,7 @@ private synchronized JarResult generateApplication() { AugmentResult start = augmentAction.createProductionApplication(); if (!start.getJar().getType().equalsIgnoreCase(PackageConfig.BuiltInType.MUTABLE_JAR.getValue())) { throw new RuntimeException( - "remote-dev can only be used with mutable applications i.e, " + + "remote-dev can only be used with mutable applications i.e. " + "using the mutable-jar package type"); } //now extract the artifacts, to mirror the remote side diff --git a/docs/src/main/asciidoc/management-interface-reference.adoc b/docs/src/main/asciidoc/management-interface-reference.adoc index d959a733cd81e..fd7e0ca4bd7b0 100644 --- a/docs/src/main/asciidoc/management-interface-reference.adoc +++ b/docs/src/main/asciidoc/management-interface-reference.adoc @@ -31,7 +31,7 @@ For example, if you have `smallrye-health` installed, the readiness probe will b SmallRye Health Checks, SmallRye Metrics, Micrometer and Info endpoints will be declared as management endpoints when the management interface is enabled. -NOTE: The management interface will be disabled without extensions that use it. e.g. `smallrye-health`, `quarkus-smallrye-openapi`. +NOTE: The management interface is disabled when no extensions relying on it (such as the SmallRye Health or SmallRye OpenAPI extensions) are installed. == Configure the host, port and scheme From b8d9b255daad56a9d2455bb71a5487fd7c50121d Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Wed, 14 Jun 2023 13:45:31 +0200 Subject: [PATCH 09/11] Filter out disabled REST methods from the OpenAPI document (cherry picked from commit 1e779c22607f41ba93573a2e50625a57e1e686a0) --- .../runtime/rest/DisabledRestEndpoints.java | 22 +++++ .../runtime/ResteasyReactiveRecorder.java | 2 + .../smallrye-openapi/deployment/pom.xml | 2 +- .../test/jaxrs/DisabledEndpointTestCase.java | 93 +++++++++++++++++++ ...steasyPathHttpRootDefaultPathTestCase.java | 2 +- .../OpenApiWithResteasyPathTestCase.java | 2 +- .../runtime/OpenApiDocumentService.java | 5 + .../filter/DisabledRestEndpointsFilter.java | 44 +++++++++ .../reactive/server/core/Deployment.java | 10 +- .../startup/RuntimeDeploymentManager.java | 52 ++++++++--- 10 files changed, 215 insertions(+), 19 deletions(-) create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/rest/DisabledRestEndpoints.java create mode 100644 extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/DisabledEndpointTestCase.java create mode 100644 extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/filter/DisabledRestEndpointsFilter.java diff --git a/core/runtime/src/main/java/io/quarkus/runtime/rest/DisabledRestEndpoints.java b/core/runtime/src/main/java/io/quarkus/runtime/rest/DisabledRestEndpoints.java new file mode 100644 index 0000000000000..90c49501016ac --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/rest/DisabledRestEndpoints.java @@ -0,0 +1,22 @@ +package io.quarkus.runtime.rest; + +import java.util.List; +import java.util.Map; + +/** + * This class serves for passing a list of disabled REST paths (via the `@EndpointDisabled` annotation) + * so that an OpenAPI filter can omit them from the generated OpenAPI document. + */ +public class DisabledRestEndpoints { + + // keys are REST paths, values are HTTP methods disabled on the given path + private static Map> endpoints; + + public static void set(Map> endpoints) { + DisabledRestEndpoints.endpoints = endpoints; + } + + public static Map> get() { + return endpoints; + } +} diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java index ede02c1d4f97b..fd802f5f30e62 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java @@ -53,6 +53,7 @@ import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; +import io.quarkus.runtime.rest.DisabledRestEndpoints; import io.quarkus.security.AuthenticationCompletionException; import io.quarkus.security.AuthenticationException; import io.quarkus.security.AuthenticationFailedException; @@ -182,6 +183,7 @@ public ResteasyReactiveRequestContext createContext(Deployment deployment, closeTaskHandler, contextFactory, new ArcThreadSetupAction(beanContainer.requestContext()), vertxConfig.rootPath); Deployment deployment = runtimeDeploymentManager.deploy(); + DisabledRestEndpoints.set(deployment.getDisabledEndpoints()); initClassFactory.createInstance().getInstance().init(deployment); currentDeployment = deployment; diff --git a/extensions/smallrye-openapi/deployment/pom.xml b/extensions/smallrye-openapi/deployment/pom.xml index 77b1ae6286bac..b7552a9aaee1e 100644 --- a/extensions/smallrye-openapi/deployment/pom.xml +++ b/extensions/smallrye-openapi/deployment/pom.xml @@ -69,7 +69,7 @@ io.quarkus - quarkus-resteasy-deployment + quarkus-resteasy-reactive-deployment test diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/DisabledEndpointTestCase.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/DisabledEndpointTestCase.java new file mode 100644 index 0000000000000..70e649c2d9f5b --- /dev/null +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/DisabledEndpointTestCase.java @@ -0,0 +1,93 @@ +package io.quarkus.smallrye.openapi.test.jaxrs; + +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.resteasy.reactive.server.EndpointDisabled; +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +/** + * Verify that REST endpoints that are disabled via the {@link EndpointDisabled} annotation are not included in the OpenAPI + * document. + */ +public class DisabledEndpointTestCase { + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(DisabledEndpoint.class, + EnabledEndpoint.class) + .add(new StringAsset("quarkus.http.root-path=/root\n"), "application.properties")); + + @EndpointDisabled(name = "xxx", disableIfMissing = true, stringValue = "xxx") + @Path("/disabled") + public static class DisabledEndpoint { + + @Path("/hello") + @GET + public String hello() { + return null; + } + + @Path("/hello2/{param1}") + @GET + public String hello2(@QueryParam("param1") String param1) { + return null; + } + + @Path("/hello5") + @PUT + public String hello5() { + return null; + } + + } + + @EndpointDisabled(name = "xxx", disableIfMissing = false, stringValue = "xxx") + @Path("/enabled") + public static class EnabledEndpoint { + + @Path("/hello3") + @GET + public String hello() { + return null; + } + + @Path("/hello4/{param1}") + @GET + public String hello4(@QueryParam("param1") String param1) { + return null; + } + + @Path("/hello5") + @POST + public String hello5() { + return null; + } + + } + + @Test + public void testDisabledEndpoint() { + RestAssured.given().header("Accept", "application/json") + .when().get("/q/openapi") + .prettyPeek().then() + .body("paths.\"/root/disabled/hello\".get", nullValue()) + .body("paths.\"/root/disabled/hello2/{param1}\".get", nullValue()) + .body("paths.\"/root/enabled/hello3\".get", notNullValue()) + .body("paths.\"/root/enabled/hello4/{param1}\".get", notNullValue()) + .body("paths.\"/root/enabled/hello5\".post", notNullValue()) + .body("paths.\"/root/enabled/hello5\".put", nullValue()); + } + +} diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathHttpRootDefaultPathTestCase.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathHttpRootDefaultPathTestCase.java index 324811c1ac319..50d3c78af607e 100644 --- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathHttpRootDefaultPathTestCase.java +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathHttpRootDefaultPathTestCase.java @@ -16,7 +16,7 @@ public class OpenApiWithResteasyPathHttpRootDefaultPathTestCase { .withApplicationRoot((jar) -> jar .addClasses(OpenApiResource.class, ResourceBean.class) .addAsResource(new StringAsset("quarkus.http.root-path=/http-root-path\n" + - "quarkus.resteasy.path=/resteasy-path"), + "quarkus.resteasy-reactive.path=/resteasy-path"), "application.properties")); @Test diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathTestCase.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathTestCase.java index 6f530cc49ce25..74321110f7e05 100644 --- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathTestCase.java +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiWithResteasyPathTestCase.java @@ -15,7 +15,7 @@ public class OpenApiWithResteasyPathTestCase { static QuarkusUnitTest runner = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(OpenApiResource.class, ResourceBean.class) - .addAsResource(new StringAsset("quarkus.resteasy.path=/foo/bar"), + .addAsResource(new StringAsset("quarkus.resteasy-reactive.path=/foo/bar"), "application.properties")); @Test diff --git a/extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/OpenApiDocumentService.java b/extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/OpenApiDocumentService.java index 2337c102d2d0c..230e9dbc4eeca 100644 --- a/extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/OpenApiDocumentService.java +++ b/extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/OpenApiDocumentService.java @@ -12,6 +12,7 @@ import org.eclipse.microprofile.openapi.models.OpenAPI; import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.smallrye.openapi.runtime.filter.DisabledRestEndpointsFilter; import io.smallrye.openapi.api.OpenApiConfig; import io.smallrye.openapi.api.OpenApiConfigImpl; import io.smallrye.openapi.api.OpenApiDocument; @@ -88,6 +89,7 @@ static class StaticDocument implements OpenApiDocumentHolder { if (autoFilter != null) { document.filter(autoFilter); } + document.filter(new DisabledRestEndpointsFilter()); document.filter(OpenApiProcessor.getFilter(openApiConfig, cl)); document.initialize(); @@ -122,6 +124,7 @@ static class DynamicDocument implements OpenApiDocumentHolder { private OpenApiConfig openApiConfig; private OASFilter userFilter; private OASFilter autoFilter; + private DisabledRestEndpointsFilter disabledEndpointsFilter; DynamicDocument(Config config, OASFilter autoFilter) { ClassLoader cl = OpenApiConstants.classLoader == null ? Thread.currentThread().getContextClassLoader() @@ -133,6 +136,7 @@ static class DynamicDocument implements OpenApiDocumentHolder { this.userFilter = OpenApiProcessor.getFilter(openApiConfig, cl); this.autoFilter = autoFilter; this.generatedOnBuild = OpenApiProcessor.modelFromStaticFile(this.openApiConfig, staticFile); + this.disabledEndpointsFilter = new DisabledRestEndpointsFilter(); } } } catch (IOException ex) { @@ -174,6 +178,7 @@ private OpenApiDocument getOpenApiDocument() { if (this.autoFilter != null) { document.filter(this.autoFilter); } + document.filter(this.disabledEndpointsFilter); document.filter(this.userFilter); document.initialize(); return document; diff --git a/extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/filter/DisabledRestEndpointsFilter.java b/extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/filter/DisabledRestEndpointsFilter.java new file mode 100644 index 0000000000000..0d60e0a42ba04 --- /dev/null +++ b/extensions/smallrye-openapi/runtime/src/main/java/io/quarkus/smallrye/openapi/runtime/filter/DisabledRestEndpointsFilter.java @@ -0,0 +1,44 @@ +package io.quarkus.smallrye.openapi.runtime.filter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.microprofile.openapi.OASFilter; +import org.eclipse.microprofile.openapi.models.OpenAPI; +import org.eclipse.microprofile.openapi.models.PathItem; + +import io.quarkus.runtime.rest.DisabledRestEndpoints; + +/** + * If the RESTEasy Reactive extension passed us a list of REST paths that are disabled via the @DisabledRestEndpoint + * annotation, remove them from the OpenAPI document. This has to be done at runtime because + * the annotation is controlled by a runtime config property. + */ +public class DisabledRestEndpointsFilter implements OASFilter { + + public void filterOpenAPI(OpenAPI openAPI) { + Map> disabledEndpointsMap = DisabledRestEndpoints.get(); + if (disabledEndpointsMap != null) { + Map pathItems = openAPI.getPaths().getPathItems(); + List emptyPathItems = new ArrayList<>(); + if (pathItems != null) { + for (Map.Entry entry : pathItems.entrySet()) { + String path = entry.getKey(); + PathItem pathItem = entry.getValue(); + List disabledMethodsForThisPath = disabledEndpointsMap.get(path); + if (disabledMethodsForThisPath != null) { + disabledMethodsForThisPath.forEach(method -> { + pathItem.setOperation(PathItem.HttpMethod.valueOf(method), null); + }); + // if the pathItem is now empty, remove it + if (pathItem.getOperations().isEmpty()) { + emptyPathItems.add(path); + } + } + } + emptyPathItems.forEach(openAPI.getPaths()::removePathItem); + } + } + } +} diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/Deployment.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/Deployment.java index 364cd328eb911..98a3906a73426 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/Deployment.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/Deployment.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.function.Supplier; import jakarta.ws.rs.core.Application; @@ -48,6 +49,7 @@ public class Deployment { private final RuntimeExceptionMapper exceptionMapper; private final boolean resumeOn404; private final ResteasyReactiveConfig resteasyReactiveConfig; + private final Map> disabledEndpoints; //this is not final, as it is set after startup private RuntimeConfiguration runtimeConfiguration; @@ -62,7 +64,8 @@ public Deployment(ExceptionMapping exceptionMapping, ContextResolvers contextRes List> runtimeConfigurableServerRestHandlers, RuntimeExceptionMapper exceptionMapper, boolean resumeOn404, - ResteasyReactiveConfig resteasyReactiveConfig) { + ResteasyReactiveConfig resteasyReactiveConfig, + Map> disabledEndpoints) { this.exceptionMapping = exceptionMapping; this.contextResolvers = contextResolvers; this.serialisers = serialisers; @@ -80,6 +83,7 @@ public Deployment(ExceptionMapping exceptionMapping, ContextResolvers contextRes this.exceptionMapper = exceptionMapper; this.resumeOn404 = resumeOn404; this.resteasyReactiveConfig = resteasyReactiveConfig; + this.disabledEndpoints = disabledEndpoints; } public RuntimeExceptionMapper getExceptionMapper() { @@ -206,4 +210,8 @@ public Deployment setRuntimeConfiguration(RuntimeConfiguration runtimeConfigurat this.runtimeConfiguration = runtimeConfiguration; return this; } + + public Map> getDisabledEndpoints() { + return disabledEndpoints; + } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java index 9da3e62088016..fb3e64b16110d 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeDeploymentManager.java @@ -104,17 +104,31 @@ public BeanFactory.BeanInstance apply(Class aClass) { return info.getFactoryCreator().apply(aClass).createInstance(); } }); + + // sanitise the prefix for our usage to make it either an empty string, or something which starts with a / and does not + // end with one + String prefix = rootPath; + if (prefix != null) { + prefix = sanitizePathPrefix(prefix); + } else { + prefix = ""; + } + if ((applicationPath != null) && !applicationPath.isEmpty()) { + prefix = prefix + sanitizePathPrefix(applicationPath); + } + // to use it inside lambdas + String finalPrefix = prefix; + List> runtimeConfigurableServerRestHandlers = new ArrayList<>(); RuntimeResourceDeployment runtimeResourceDeployment = new RuntimeResourceDeployment(info, executorSupplier, virtualExecutorSupplier, interceptorDeployment, dynamicEntityWriter, resourceLocatorHandler, requestContextFactory.isDefaultBlocking()); List possibleSubResource = new ArrayList<>(locatableResourceClasses); possibleSubResource.addAll(resourceClasses); //the TCK uses normal resources also as sub resources + Map> disabledEndpoints = new HashMap<>(); for (int i = 0; i < possibleSubResource.size(); i++) { ResourceClass clazz = possibleSubResource.get(i); - if ((clazz.getIsDisabled() != null) && clazz.getIsDisabled().get()) { - continue; - } + Map>>> templates = new HashMap<>(); URITemplate classPathTemplate = clazz.getPath() == null ? null : new URITemplate(clazz.getPath(), true); for (int j = 0; j < clazz.getMethods().size(); j++) { @@ -127,6 +141,24 @@ public BeanFactory.BeanInstance apply(Class aClass) { } Map> mappersByMethod = new RuntimeMappingDeployment(templates) .buildClassMapper(); + mappersByMethod.forEach((method, mapper) -> { + for (RequestMapper.RequestPath path : mapper.getTemplates()) { + if ((clazz.getIsDisabled() != null) && clazz.getIsDisabled().get()) { + String templateWithoutSlash = path.template.template.startsWith("/") + ? path.template.template.substring(1) + : path.template.template; + String fullPath = clazz.getPath().endsWith("/") ? finalPrefix + clazz.getPath() + templateWithoutSlash + : finalPrefix + clazz.getPath() + "/" + templateWithoutSlash; + if (!disabledEndpoints.containsKey(fullPath)) { + disabledEndpoints.put(fullPath, new ArrayList<>()); + } + disabledEndpoints.get(fullPath).add(method); + } + } + }); + if ((clazz.getIsDisabled() != null) && clazz.getIsDisabled().get()) { + continue; + } resourceLocatorHandler.addResource(loadClass(clazz.getClassName()), mappersByMethod); } @@ -172,17 +204,6 @@ public BeanFactory.BeanInstance apply(Class aClass) { abortHandlingChain.addAll(interceptorDeployment.getGlobalResponseInterceptorHandlers()); } abortHandlingChain.add(new ResponseWriterHandler(dynamicEntityWriter)); - // sanitise the prefix for our usage to make it either an empty string, or something which starts with a / and does not - // end with one - String prefix = rootPath; - if (prefix != null) { - prefix = sanitizePathPrefix(prefix); - } else { - prefix = ""; - } - if ((applicationPath != null) && !applicationPath.isEmpty()) { - prefix = prefix + sanitizePathPrefix(applicationPath); - } //pre matching interceptors are run first List preMatchHandlers = new ArrayList<>(); @@ -210,7 +231,8 @@ public BeanFactory.BeanInstance apply(Class aClass) { abortHandlingChain.toArray(EMPTY_REST_HANDLER_ARRAY), dynamicEntityWriter, prefix, paramConverterProviders, configurationImpl, applicationSupplier, threadSetupAction, requestContextFactory, preMatchHandlers, classMappers, - runtimeConfigurableServerRestHandlers, exceptionMapper, info.isResumeOn404(), info.getResteasyReactiveConfig()); + runtimeConfigurableServerRestHandlers, exceptionMapper, info.isResumeOn404(), info.getResteasyReactiveConfig(), + disabledEndpoints); } private void forEachMapperEntry(MappersKey key, From 814bec84b12c0ff252e8670ece8c7eb4c8ef8ec5 Mon Sep 17 00:00:00 2001 From: Rolfe Dlugy-Hegwer Date: Tue, 27 Jun 2023 12:00:56 -0400 Subject: [PATCH 10/11] Make necessary changes to share the topic with both community and product docs. (cherry picked from commit ee6493e250ebf2e0e555bb9f312af632f45671ad) --- docs/src/main/asciidoc/_attributes.adoc | 4 ++-- docs/src/main/asciidoc/update-quarkus.adoc | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/src/main/asciidoc/_attributes.adoc b/docs/src/main/asciidoc/_attributes.adoc index 16ea1b43215d8..102641c4cdfbd 100644 --- a/docs/src/main/asciidoc/_attributes.adoc +++ b/docs/src/main/asciidoc/_attributes.adoc @@ -53,9 +53,9 @@ :vault-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/index.html :vault-datasource-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/vault-datasource.html :micrometer-registry-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-micrometer-registry/dev/index.html -:quarkus-migration-guide: https://github.com/quarkusio/quarkus/wiki/Migration-Guides +:quarkus-migration-guide: https://github.com/quarkusio/quarkus/wiki/Migration-Guides[Migration Guides] // . :create-app-group-id: org.acme :create-cli-group-id: {create-app-group-id} // . -include::_attributes-local.adoc[] \ No newline at end of file +include::_attributes-local.adoc[] diff --git a/docs/src/main/asciidoc/update-quarkus.adoc b/docs/src/main/asciidoc/update-quarkus.adoc index e787c7724323a..b6f69f82fd3a4 100644 --- a/docs/src/main/asciidoc/update-quarkus.adoc +++ b/docs/src/main/asciidoc/update-quarkus.adoc @@ -10,12 +10,10 @@ include::_attributes.adoc[] :extension-status: "experimental" :summary: Learn how to upgrade your projects to the latest version of {project-name} -include::{includes}/extension-status.adoc[] - -You can update or upgrade your {project-name} projects to the latest version by using an update command. +You can update or upgrade your {project-name} projects to the latest version of {project-name} by using an update command. The update command primarily employs OpenRewrite recipes to automate updates for most project dependencies, source code, and documentation. -Although these recipes update many migration items, they do not cover all the items detailed in the {quarkus-migration-guide}[Migration Guide] topics. +Although these recipes update many migration items, they do not cover all the items detailed in the {quarkus-migration-guide}. Post-update, if expected updates are missing, consider the following reasons: @@ -38,8 +36,8 @@ include::{includes}/prerequisites.adoc[] . Create a working branch for your project by using your version control system. -. Install the *latest version* of the Quarkus CLI to use in the next step. For more information, see link:https://quarkus.io/guides/cli-tooling#installing-the-cli[Installing the CLI]. -Confirm the version number by using `quarkus -v`. +. To use the Quarkus CLI in the next step, link:https://quarkus.io/guides/cli-tooling#installing-the-cli[install the latest version of the Quarkus CLI]. +Confirm the version number using `quarkus -v`. . Go to the project directory and update the project to the latest stream: + @@ -74,7 +72,7 @@ ifdef::devtools-wrapped[+] . Use a diff tool to inspect all changes. -. Review the {quarkus-migration-guide}[Migration Guide] topics for items that were not updated by the update command. +. Review the {quarkus-migration-guide} for items that were not updated by the update command. If your project has such items, implement the additional steps advised in these topics. . Ensure the project builds without errors, all tests pass, and the application functions as required before deploying to production. From 9a87ee434b94a8bcceef6a3f6a9f7acfb7ace304 Mon Sep 17 00:00:00 2001 From: brunobat Date: Tue, 27 Jun 2023 13:51:56 +0100 Subject: [PATCH 11/11] Build Analytics - Config changes pointing to prod and final prompt (cherry picked from commit 36cf5481f5e9858dfcfa99605e10f337f3228113) --- .../main/java/io/quarkus/analytics/ConfigService.java | 10 +++------- .../java/io/quarkus/analytics/rest/RestClient.java | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/ConfigService.java b/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/ConfigService.java index 38aad6455ceb0..3b408770c0a72 100644 --- a/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/ConfigService.java +++ b/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/ConfigService.java @@ -32,13 +32,9 @@ public class ConfigService { public static final String QUARKUS_ANALYTICS_PROMPT_TIMEOUT = "quarkus.analytics.prompt.timeout"; private static final String NEW_LINE = System.lineSeparator(); public static final String ACCEPTANCE_PROMPT = NEW_LINE - + "********************************************************************************************************" - + NEW_LINE - + "********************************************************************************************************" - + NEW_LINE - + "********************************************************************************************************" - + NEW_LINE - + "* Please help improve Quarkus!" + NEW_LINE + + "----------------------------" + NEW_LINE + + "--- Help improve Quarkus ---" + NEW_LINE + + "----------------------------" + NEW_LINE + "* Learn more: https://quarkus.io/usage/" + NEW_LINE + "* Do you agree to contribute anonymous build time data to the Quarkus community? (y/n) " + NEW_LINE; private static final int DEFAULT_REFRESH_HOURS = 12; diff --git a/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/rest/RestClient.java b/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/rest/RestClient.java index d1c166476e7cd..4a1d5779a882a 100644 --- a/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/rest/RestClient.java +++ b/independent-projects/tools/analytics-common/src/main/java/io/quarkus/analytics/rest/RestClient.java @@ -34,9 +34,8 @@ public class RestClient implements ConfigClient, SegmentClient { public static final int DEFAULT_TIMEOUT = 3000;// milliseconds static final String IDENTITY_ENDPOINT = "v1/identify"; static final String TRACK_ENDPOINT = "v1/track"; - static final URI CONFIG_URI = getUri( - "https://raw.githubusercontent.com/brunobat/tests/main/03656937-19FD-4C83-9066-C76631D445EA");//FIXME config location - private static final String AUTH_HEADER = getAuthHeader("SGGi49IwHoDEpE4NVBEHJDZ4uyzeoI4M"); //FIXME dev key + static final URI CONFIG_URI = getUri("https://quarkus.io/assets/json/03656937-19FD-4C83-9066-C76631D445EA.json"); + private static final String AUTH_HEADER = getAuthHeader("WdCBreXheGC541sGjMMvUknY8c6lLxy5"); private static final int SEGMENT_POST_RESPONSE_CODE = 200; // sad but true static URI getUri(final String uri) {