diff --git a/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java
index bb6b858232c5a..3a629bf968b16 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/util/UriNormalizationUtil.java
@@ -104,4 +104,12 @@ public static URI normalizeWithBase(URI base, String segment, boolean trailingSl
URI resolvedUri = base.resolve(segmentUri);
return resolvedUri;
}
+
+ public static String relativize(String rootPath, String leafPath) {
+ if (leafPath.startsWith(rootPath)) {
+ return leafPath.substring(rootPath.length());
+ }
+
+ return null;
+ }
}
diff --git a/docs/src/main/asciidoc/dev-ui.adoc b/docs/src/main/asciidoc/dev-ui.adoc
index a788f9823678a..2f5cdc9940e1a 100644
--- a/docs/src/main/asciidoc/dev-ui.adoc
+++ b/docs/src/main/asciidoc/dev-ui.adoc
@@ -10,7 +10,7 @@ include::./attributes.adoc[]
This guide covers the Quarkus Dev UI for link:building-my-first-extension[extension authors].
Quarkus now ships with a new experimental Dev UI, which is available in dev mode (when you start
-quarkus with `mvn quarkus:dev`) at http://localhost:8080/q/dev[/q/dev] and will show you something like
+quarkus with `mvn quarkus:dev`) at http://localhost:8080/q/dev[/q/dev] by default. It will show you something like
this:
image::dev-ui-overview.png[alt=Dev UI overview,role="center"]
@@ -46,16 +46,56 @@ two links with some styling and icons:
[source,html]
----
-
-
+
+
OpenAPI
-
-
+
+
+
Swagger UI
----
TIP: We use the Font Awesome Free icon set.
+Note how the paths are specified: `{config:http-path('quarkus.smallrye-openapi.path')}`. This is a special
+directive that the quarkus dev console understands: it will replace that value with the resolved route
+named 'quarkus.smallrye-openapi.path'.
+
+The corresponding non-application endpoint is declared using `.routeConfigKey` to associate the route with a name:
+
+[source,java]
+----
+ nonApplicationRootPathBuildItem.routeBuilder()
+ .route(openApiConfig.path) // <1>
+ .routeConfigKey("quarkus.smallrye-openapi.path") // <2>
+ ...
+ .build();
+----
+<1> The configured path is resolved into a valid route.
+<2> The resolved route path is then associated with the key `quarkus.smallrye-openapi.path`.
+
+== Path considerations
+
+Paths are tricky business. Keep the following in mind:
+
+* Assume your UI will be nested under the dev endpoint. Do not provide a way to customize this without a strong reason.
+* Never construct your own absolute paths. Adding a suffix to a known, normalized and resolved path is fine.
+
+Configured paths, like the `dev` endpoint used by the console or the SmallRye OpenAPI path shown in the example above,
+need to be properly resolved against both `quarkus.http.root-path` and `quarkus.http.non-application-root-path`.
+Use `NonApplicationRootPathBuildItem` or `HttpRootPathBuildItem` to construct endpoint routes and identify resolved
+path values that can then be used in templates.
+
+The `{devRootAppend}` variable can also be used in templates to construct URLs for static dev console resources, for example:
+
+[source,html]
+----
+
+----
+
+Refer to the link:all-config#quarkus-vertx-http_quarkus.http.non-application-root-path[Quarkus Vertx HTTP configuration reference]
+for details on how the non-application root path is configured.
+
== Template and styling support
Both the `embedded.html` files and any full page you add in `/dev-templates` will be interpreted by
@@ -75,6 +115,9 @@ A `config:property(name)` expression can be used to output the config value for
The property name can be either a string literal or obtained dynamically by another expression.
For example `{config:property('quarkus.lambda.handler')}` and `{config:property(foo.propertyName)}`.
+Reminder: do not use this to retrieve raw configured path values. As shown above, use `{config:http-path(...)}` with
+a known route configuration key when working with resource paths.
+
== Adding full pages
To add full pages for your Dev UI extension such as this one:
@@ -137,17 +180,19 @@ link:building-my-first-extension#description-of-a-quarkus-extension[`deployment`
== Linking to your full-page templates
-Every full-page template lives under the `/q/dev/{groupId}.{artifactId}/` URI (for example
-`/q/dev/io.quarkus.quarkus-cache/`), so if you want to link
-to them from your `embedded.html` file you can use the `urlbase` template parameter to point to them:
+Full-page templates for extensions live under a pre-defined `{devRootAppend}/{groupId}.{artifactId}/` directory
+that is referenced using the `urlbase` template parameter. Using configuration defaults, that would resolve to
+`/q/dev/io.quarkus.quarkus-cache/`, as an example.
-[source,java]
+Use the `{urlbase}` template parameter to reference this folder in `embedded.html`:
+
+[source,html]
----
// <1>
Caches {info:cacheInfos.size()}
----
-<1> Use the `urlbase` template parameter to point to where your full-page templates are located
+<1> Use the `urlbase` template parameter to reference full-page templates for your extension
== Passing information to your templates
@@ -266,6 +311,7 @@ This can be done by adding another link:building-my-first-extension#deploying-th
declare the action in your extension's
link:building-my-first-extension#description-of-a-quarkus-extension[`deployment`] module:
+
[source,java]
----
package io.quarkus.cache.deployment.devconsole;
@@ -290,11 +336,13 @@ public class DevConsoleProcessor {
<1> Mark the recorder as optional, so it will only be invoked when in dev mode
<2> Declare a `POST {urlbase}/caches` route handled by the given handler
+
Note: you can see <>.
Now all you have to do is implement the recorder in your extension's
link:building-my-first-extension#description-of-a-quarkus-extension[`runtime module`]:
+
[source,java]
----
package io.quarkus.cache.runtime.devconsole;
@@ -338,6 +386,7 @@ public class CacheDevConsoleRecorder {
<3> Don't forget to add a message for the user to let them know everything went fine
<4> You can also add error messages
+
NOTE: Flash messages are handled by the `main` DEV template and will result in nice notifications for your
users:
diff --git a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java
index 7c512dd094d44..19d0bd12d5e04 100644
--- a/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java
+++ b/extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java
@@ -65,7 +65,7 @@ void createPrometheusRoute(BuildProducer routes,
.routeFunction(pConfig.path, recorder.route())
.handler(recorder.getHandler())
.requiresLegacyRedirect()
- .displayOnNotFoundPage("Metrics", pConfig.path)
+ .displayOnNotFoundPage("Metrics")
.build());
// Match paths that begin with the deployment path
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java
index 9fcc80a188bdc..07e7d63dfa004 100644
--- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java
@@ -558,10 +558,10 @@ public List scan(MethodInfo method, Map
});
}
- private String determineApplicationPath(IndexView index, String defaultPath) {
+ private String determineApplicationPath(IndexView index, Optional defaultPath) {
Collection applicationPaths = index.getAnnotations(ResteasyReactiveDotNames.APPLICATION_PATH);
if (applicationPaths.isEmpty()) {
- return defaultPath;
+ return defaultPath.orElse("/");
}
// currently we only examine the first class that is annotated with @ApplicationPath so best
// fail if the user code has multiple such annotations instead of surprising the user
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveServerConfig.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveServerConfig.java
index 5baba89e338c2..4c9721d275321 100644
--- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveServerConfig.java
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveServerConfig.java
@@ -1,5 +1,7 @@
package io.quarkus.resteasy.reactive.server.deployment;
+import java.util.Optional;
+
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;
@@ -7,9 +9,12 @@
public class ResteasyReactiveServerConfig {
/**
- * Set this to override the default path for JAX-RS resources if there are no
- * annotated application classes.
+ * Set this to define the application path that serves as the base URI for all
+ * JAX-RS resource URIs provided by {@code @Path} annotations when there are no
+ * {@code @ApplicationPath} annotations defined on {@code Application} classes.
+ *
+ * This value is always resolved relative to {@code quarkus.http.root-path}.
*/
- @ConfigItem(defaultValue = "/")
- String path;
+ @ConfigItem
+ Optional path;
}
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/HelloResource.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/HelloResource.java
index 5ff8b528d8cb6..c172e743f13df 100644
--- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/HelloResource.java
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/HelloResource.java
@@ -3,11 +3,26 @@
import javax.ws.rs.GET;
import javax.ws.rs.Path;
-@Path("/hello")
+/**
+ * Per spec:
+ *
+ * Paths are relative. For an annotated class the base URI is the application path, see ApplicationPath.
+ * For an annotated method the base URI is the effective URI of the containing class. For the purposes of
+ * absolutizing a path against the base URI , a leading '/' in a path is ignored and base URIs are treated
+ * as if they ended in '/'.
+ *
+ */
+@Path("hello")
public class HelloResource {
@GET
public String hello() {
return "hello";
}
+
+ @GET
+ @Path("/nested")
+ public String nested() {
+ return "world hello";
+ }
}
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RelativeRestPathTestCase.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RelativeRestPathTestCase.java
new file mode 100644
index 0000000000000..8d7c22e65d5eb
--- /dev/null
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RelativeRestPathTestCase.java
@@ -0,0 +1,29 @@
+package io.quarkus.resteasy.reactive.server.test.path;
+
+import org.hamcrest.Matchers;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusUnitTest;
+import io.restassured.RestAssured;
+
+public class RelativeRestPathTestCase {
+
+ @RegisterExtension
+ static QuarkusUnitTest test = new QuarkusUnitTest()
+ .withConfigurationResource("empty.properties")
+ .overrideConfigKey("quarkus.rest.path", "foo")
+ .overrideConfigKey("quarkus.http.root-path", "/app")
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClass(HelloResource.class));
+
+ @Test
+ public void testRestPath() {
+ RestAssured.basePath = "/";
+ // This is expected behavior (relative path appended to HTTP root path)
+ RestAssured.when().get("/app/foo/hello").then().body(Matchers.is("hello"));
+ RestAssured.when().get("/app/foo/hello/nested").then().body(Matchers.is("world hello"));
+ }
+}
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RestApplicationPathTestCase.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RestApplicationPathTestCase.java
new file mode 100644
index 0000000000000..2bdc84d39bd7b
--- /dev/null
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RestApplicationPathTestCase.java
@@ -0,0 +1,45 @@
+package io.quarkus.resteasy.reactive.server.test.path;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+import org.hamcrest.Matchers;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusUnitTest;
+import io.restassured.RestAssured;
+
+public class RestApplicationPathTestCase {
+
+ @RegisterExtension
+ static QuarkusUnitTest test = new QuarkusUnitTest()
+ .withConfigurationResource("empty.properties")
+ .overrideConfigKey("quarkus.rest.path", "/foo")
+ .overrideConfigKey("quarkus.http.root-path", "/app")
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClasses(HelloResource.class, BarApp.class));
+
+ /**
+ * Using @ApplicationPath will overlay/replace `quarkus.rest.path`.
+ * Per spec:
+ *
+ * Identifies the application path that serves as the base URI for all resource
+ * URIs provided by Path. May only be applied to a subclass of Application.
+ *
+ *
+ * This path will also be relative to the configured HTTP root
+ */
+ @ApplicationPath("/bar")
+ public static class BarApp extends Application {
+ }
+
+ @Test
+ public void testRestPath() {
+ RestAssured.basePath = "/";
+ RestAssured.when().get("/app/bar/hello").then().body(Matchers.is("hello"));
+ RestAssured.when().get("/app/bar/hello/nested").then().body(Matchers.is("world hello"));
+ }
+}
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RestPathTestCase.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RestPathTestCase.java
index dec30f56dd0e6..379f4c84644b5 100644
--- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RestPathTestCase.java
+++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/path/RestPathTestCase.java
@@ -2,7 +2,6 @@
import org.hamcrest.Matchers;
import org.jboss.shrinkwrap.api.ShrinkWrap;
-import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -14,15 +13,16 @@ public class RestPathTestCase {
@RegisterExtension
static QuarkusUnitTest test = new QuarkusUnitTest()
- .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class)
- .addAsResource(new StringAsset("quarkus.rest.path=/foo"), "application.properties"));
+ .withConfigurationResource("empty.properties")
+ .overrideConfigKey("quarkus.rest.path", "/foo")
+ .overrideConfigKey("quarkus.http.root-path", "/app")
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClass(HelloResource.class));
@Test
public void testRestPath() {
- RestAssured.get("/hello")
- .then().statusCode(404);
- RestAssured.get("/foo/hello")
- .then().statusCode(200).body(Matchers.equalTo("hello"));
-
+ RestAssured.basePath = "/";
+ RestAssured.when().get("/app/foo/hello").then().body(Matchers.is("hello"));
+ RestAssured.when().get("/app/foo/hello/nested").then().body(Matchers.is("world hello"));
}
}
diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/resources/empty.properties b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/resources/empty.properties
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLConfig.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLConfig.java
index ec2612bc1e34a..481963c940d1c 100644
--- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLConfig.java
+++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLConfig.java
@@ -11,9 +11,10 @@
public class SmallRyeGraphQLConfig {
/**
- * The rootPath under which queries will be served. Default to /graphql
+ * The rootPath under which queries will be served. Default to graphql
+ * By default, this value will be resolved as a path relative to `${quarkus.http.root-path}`.
*/
- @ConfigItem(defaultValue = "/graphql")
+ @ConfigItem(defaultValue = "graphql")
String rootPath;
/**
diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java
index 4b0cf6629825e..2eb4348ad00a0 100644
--- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java
+++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java
@@ -82,7 +82,7 @@
*/
public class SmallRyeGraphQLProcessor {
private static final Logger LOG = Logger.getLogger(SmallRyeGraphQLProcessor.class);
- private static final String SCHEMA_PATH = "/schema.graphql";
+ private static final String SCHEMA_PATH = "schema.graphql";
private static final String SPI_PATH = "META-INF/services/";
// For Service integration
@@ -194,14 +194,15 @@ void buildExecutionService(
@BuildStep
void buildSchemaEndpoint(
BuildProducer routeProducer,
+ HttpRootPathBuildItem httpRootPathBuildItem,
SmallRyeGraphQLInitializedBuildItem graphQLInitializedBuildItem,
SmallRyeGraphQLRecorder recorder,
SmallRyeGraphQLConfig graphQLConfig) {
Handler schemaHandler = recorder.schemaHandler(graphQLInitializedBuildItem.getInitialized());
- routeProducer.produce(new RouteBuildItem.Builder()
- .route(graphQLConfig.rootPath + SCHEMA_PATH)
+ routeProducer.produce(httpRootPathBuildItem.routeBuilder()
+ .nestedRoute(graphQLConfig.rootPath, SCHEMA_PATH)
.handler(schemaHandler)
.displayOnNotFoundPage("MicroProfile GraphQL Schema")
.blockingRoute()
@@ -214,6 +215,7 @@ void buildSchemaEndpoint(
@Consume(BeanContainerBuildItem.class)
void buildExecutionEndpoint(
BuildProducer routeProducer,
+ HttpRootPathBuildItem httpRootPathBuildItem,
SmallRyeGraphQLInitializedBuildItem graphQLInitializedBuildItem,
SmallRyeGraphQLRecorder recorder,
ShutdownContextBuildItem shutdownContext,
@@ -238,9 +240,10 @@ void buildExecutionEndpoint(
Handler executionHandler = recorder.executionHandler(graphQLInitializedBuildItem.getInitialized(),
allowGet);
- routeProducer.produce(new RouteBuildItem.Builder()
+ routeProducer.produce(httpRootPathBuildItem.routeBuilder()
.routeFunction(graphQLConfig.rootPath, recorder.routeFunction(bodyHandlerBuildItem.getHandler()))
.handler(executionHandler)
+ .routeConfigKey("quarkus.smallrye-graphql.root-path")
.displayOnNotFoundPage("MicroProfile GraphQL Endpoint")
.blockingRoute()
.build());
@@ -540,6 +543,7 @@ void registerGraphQLUiHandler(
smallRyeGraphQLBuildItem.getGraphqlUiPath(), runtimeConfig);
routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder()
.route(graphQLConfig.ui.rootPath)
+ .routeConfigKey("quarkus.smallrye-graphql.ui.root-path")
.displayOnNotFoundPage("MicroProfile GraphQL UI")
.handler(handler)
.requiresLegacyRedirect()
diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLUIConfig.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLUIConfig.java
index 19cee4b8415a6..f90f7aef7f132 100644
--- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLUIConfig.java
+++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLUIConfig.java
@@ -9,6 +9,7 @@ public class SmallRyeGraphQLUIConfig {
/**
* The path where GraphQL UI is available.
* The value `/` is not allowed as it blocks the application from serving anything else.
+ * By default, this URL will be resolved as a path relative to `${quarkus.http.non-application-root-path}`.
*/
@ConfigItem(defaultValue = "graphql-ui")
String rootPath;
diff --git a/extensions/smallrye-graphql/deployment/src/main/resources/dev-templates/embedded.html b/extensions/smallrye-graphql/deployment/src/main/resources/dev-templates/embedded.html
index 60015ff1e292d..772d905b9902b 100644
--- a/extensions/smallrye-graphql/deployment/src/main/resources/dev-templates/embedded.html
+++ b/extensions/smallrye-graphql/deployment/src/main/resources/dev-templates/embedded.html
@@ -1,7 +1,7 @@
-
+
GraphQL Schema
-
+
GraphQL UI
diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java
index 9a80dcc1bed0a..7cb60dfabf3fd 100644
--- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java
+++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java
@@ -9,30 +9,35 @@ public class SmallRyeHealthConfig {
/**
* Root path for health-checking endpoints.
+ * By default, this value will be resolved as a path relative to `${quarkus.http.non-application-root-path}`.
*/
@ConfigItem(defaultValue = "health")
String rootPath;
/**
* The relative path of the liveness health-checking endpoint.
+ * By default, this value will be resolved as a path relative to `${quarkus.smallrye-health.rootPath}`.
*/
@ConfigItem(defaultValue = "live")
String livenessPath;
/**
* The relative path of the readiness health-checking endpoint.
+ * By default, this value will be resolved as a path relative to `${quarkus.smallrye-health.rootPath}`.
*/
@ConfigItem(defaultValue = "ready")
String readinessPath;
/**
* The relative path of the health group endpoint.
+ * By default, this value will be resolved as a path relative to `${quarkus.smallrye-health.rootPath}`.
*/
@ConfigItem(defaultValue = "group")
String groupPath;
/**
* The relative path of the wellness health-checking endpoint.
+ * By default, this value will be resolved as a path relative to `${quarkus.smallrye-health.rootPath}`.
*/
@ConfigItem(defaultValue = "well")
String wellnessPath;
diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java
index 571a7a321c72b..4bfcd89cd8f42 100644
--- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java
+++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java
@@ -69,11 +69,8 @@
import io.quarkus.smallrye.health.runtime.SmallRyeReadinessHandler;
import io.quarkus.smallrye.health.runtime.SmallRyeWellnessHandler;
import io.quarkus.smallrye.openapi.deployment.spi.AddToOpenAPIDefinitionBuildItem;
-import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem;
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
import io.quarkus.vertx.http.deployment.RouteBuildItem;
-import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem;
-import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;
import io.smallrye.health.SmallRyeHealthReporter;
import io.smallrye.health.api.HealthGroup;
import io.smallrye.health.api.HealthGroups;
@@ -97,7 +94,8 @@ class SmallRyeHealthProcessor {
private static final String HEALTH_UI_WEBJAR_ARTIFACT_ID = "smallrye-health-ui";
private static final String HEALTH_UI_WEBJAR_PREFIX = "META-INF/resources/health-ui/";
private static final String HEALTH_UI_FINAL_DESTINATION = "META-INF/health-ui-files";
- private static final String FILE_TO_UPDATE = "healthui.js";
+ private static final String JS_FILE_TO_UPDATE = "healthui.js";
+ private static final String INDEX_FILE_TO_UPDATE = "index.html";
// Branding files to monitor for changes
private static final String BRANDING_DIR = "META-INF/branding/";
@@ -150,11 +148,7 @@ void healthCheck(BuildProducer buildItemBuildProducer,
void build(SmallRyeHealthRecorder recorder,
BuildProducer feature,
BuildProducer additionalBean,
- BuildProducer beanDefiningAnnotation,
- BuildProducer displayableEndpoints,
- NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
- LaunchModeBuildItem launchMode,
- SmallRyeHealthConfig healthConfig)
+ BuildProducer beanDefiningAnnotation)
throws IOException, ClassNotFoundException {
feature.produce(new FeatureBuildItem(Feature.SMALLRYE_HEALTH));
@@ -207,6 +201,7 @@ public void defineHealthRoutes(BuildProducer routes,
// Register the health handler
routes.produce(nonApplicationRootPathBuildItem.routeBuilder()
.route(healthConfig.rootPath)
+ .routeConfigKey("quarkus.smallrye-health.root-path")
.handler(new SmallRyeHealthHandler())
.requiresLegacyRedirect()
.displayOnNotFoundPage()
@@ -278,16 +273,17 @@ public void defineHealthRoutes(BuildProducer routes,
@BuildStep(onlyIf = OpenAPIIncluded.class)
public void includeInOpenAPIEndpoint(BuildProducer openAPIProducer,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
- HttpRootPathBuildItem httpRootPath,
Capabilities capabilities,
SmallRyeHealthConfig healthConfig) {
// Add to OpenAPI if OpenAPI is available
if (capabilities.isPresent(Capability.SMALLRYE_OPENAPI)) {
String healthRootPath = nonApplicationRootPathBuildItem.resolvePath(healthConfig.rootPath);
+
HealthOpenAPIFilter filter = new HealthOpenAPIFilter(healthRootPath,
nonApplicationRootPathBuildItem.resolveNestedPath(healthRootPath, healthConfig.livenessPath),
nonApplicationRootPathBuildItem.resolveNestedPath(healthRootPath, healthConfig.readinessPath));
+
openAPIProducer.produce(new AddToOpenAPIDefinitionBuildItem(filter));
}
}
@@ -316,17 +312,17 @@ private void warnIfJaxRsPathUsed(IndexView index, DotName healthAnnotation) {
}
@BuildStep
- public void kubernetes(HttpBuildTimeConfig httpConfig, NonApplicationRootPathBuildItem frameworkRootPath,
+ public void kubernetes(NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
SmallRyeHealthConfig healthConfig,
BuildProducer livenessPathItemProducer,
BuildProducer readinessPathItemProducer) {
livenessPathItemProducer.produce(
new KubernetesHealthLivenessPathBuildItem(
- frameworkRootPath.resolveNestedPath(healthConfig.rootPath, healthConfig.livenessPath)));
+ nonApplicationRootPathBuildItem.resolveNestedPath(healthConfig.rootPath, healthConfig.livenessPath)));
readinessPathItemProducer.produce(
new KubernetesHealthReadinessPathBuildItem(
- frameworkRootPath.resolveNestedPath(healthConfig.rootPath, healthConfig.readinessPath)));
+ nonApplicationRootPathBuildItem.resolveNestedPath(healthConfig.rootPath, healthConfig.readinessPath)));
}
@BuildStep
@@ -386,7 +382,6 @@ void registerUiExtension(
BuildProducer generatedResourceProducer,
BuildProducer nativeImageResourceProducer,
BuildProducer smallRyeHealthBuildProducer,
- HttpRootPathBuildItem httpRootPath,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
SmallRyeHealthConfig healthConfig,
CurateOutcomeBuildItem curateOutcomeBuildItem,
@@ -400,9 +395,8 @@ void registerUiExtension(
"quarkus.smallrye-health.root-path-ui was set to \"/\", this is not allowed as it blocks the application from serving anything else.");
}
- String healthPath = httpRootPath.resolvePath(nonApplicationRootPathBuildItem.resolvePath(healthConfig.rootPath));
- String healthUiPath = httpRootPath
- .resolvePath(nonApplicationRootPathBuildItem.resolvePath(healthConfig.ui.rootPath));
+ String healthPath = nonApplicationRootPathBuildItem.resolvePath(healthConfig.rootPath);
+ String healthUiPath = nonApplicationRootPathBuildItem.resolvePath(healthConfig.ui.rootPath);
AppArtifact artifact = WebJarUtil.getAppArtifact(curateOutcomeBuildItem, HEALTH_UI_WEBJAR_GROUP_ID,
HEALTH_UI_WEBJAR_ARTIFACT_ID);
@@ -410,7 +404,8 @@ void registerUiExtension(
if (launchMode.getLaunchMode().isDevOrTest()) {
Path tempPath = WebJarUtil.copyResourcesForDevOrTest(curateOutcomeBuildItem, launchMode, artifact,
HEALTH_UI_WEBJAR_PREFIX);
- updateApiUrl(tempPath.resolve(FILE_TO_UPDATE), healthPath);
+ updateApiUrl(tempPath.resolve(JS_FILE_TO_UPDATE), healthPath);
+ updateApiUrl(tempPath.resolve(INDEX_FILE_TO_UPDATE), healthPath);
smallRyeHealthBuildProducer
.produce(new SmallRyeHealthBuildItem(tempPath.toAbsolutePath().toString(), healthUiPath));
@@ -428,7 +423,7 @@ void registerUiExtension(
String fileName = file.getKey();
byte[] content = file.getValue();
- if (fileName.endsWith(FILE_TO_UPDATE)) {
+ if (fileName.endsWith(JS_FILE_TO_UPDATE) || fileName.endsWith(INDEX_FILE_TO_UPDATE)) {
content = updateApiUrl(new String(content, StandardCharsets.UTF_8), healthPath)
.getBytes(StandardCharsets.UTF_8);
}
@@ -457,8 +452,10 @@ void registerHealthUiHandler(
if (shouldInclude(launchMode, healthConfig)) {
Handler handler = recorder.uiHandler(smallRyeHealthBuildItem.getHealthUiFinalDestination(),
smallRyeHealthBuildItem.getHealthUiPath(), runtimeConfig);
+
routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder()
.route(healthConfig.ui.rootPath)
+ .routeConfigKey("quarkus.smallrye-health.ui.root-path")
.displayOnNotFoundPage("Health UI")
.requiresLegacyRedirect()
.handler(handler)
@@ -471,16 +468,18 @@ void registerHealthUiHandler(
}
}
- private void updateApiUrl(Path healthUiJs, String healthPath) throws IOException {
- String content = new String(Files.readAllBytes(healthUiJs), StandardCharsets.UTF_8);
+ private void updateApiUrl(Path fileToUpdate, String healthPath) throws IOException {
+ String content = new String(Files.readAllBytes(fileToUpdate), StandardCharsets.UTF_8);
String result = updateApiUrl(content, healthPath);
if (result != null) {
- Files.write(healthUiJs, result.getBytes(StandardCharsets.UTF_8));
+ Files.write(fileToUpdate, result.getBytes(StandardCharsets.UTF_8));
}
}
+ // Replace health URL in static files
public String updateApiUrl(String original, String healthPath) {
- return original.replace("url = \"/health\";", "url = \"" + healthPath + "\";");
+ return original.replace("url = \"/health\";", "url = \"" + healthPath + "\";")
+ .replace("placeholder=\"/health\"", "placeholder=\"" + healthPath + "\"");
}
private static boolean shouldInclude(LaunchModeBuildItem launchMode, SmallRyeHealthConfig healthConfig) {
diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthUIConfig.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthUIConfig.java
index f85e119bbce3c..be3861e301175 100644
--- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthUIConfig.java
+++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthUIConfig.java
@@ -8,6 +8,7 @@ public class SmallRyeHealthUIConfig {
/**
* The path where Health UI is available.
* The value `/` is not allowed as it blocks the application from serving anything else.
+ * By default, this value will be resolved as a path relative to `${quarkus.http.non-application-root-path}`.
*/
@ConfigItem(defaultValue = "health-ui")
String rootPath;
diff --git a/extensions/smallrye-health/deployment/src/main/resources/dev-templates/embedded.html b/extensions/smallrye-health/deployment/src/main/resources/dev-templates/embedded.html
index 6dff17579d7d8..36f058723ff00 100644
--- a/extensions/smallrye-health/deployment/src/main/resources/dev-templates/embedded.html
+++ b/extensions/smallrye-health/deployment/src/main/resources/dev-templates/embedded.html
@@ -1,7 +1,7 @@
-
+
Health
-
+
Health UI
diff --git a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthStaticHandler.java b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthStaticHandler.java
index 70a5a53d0e072..266d2cb33dcd5 100644
--- a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthStaticHandler.java
+++ b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthStaticHandler.java
@@ -44,7 +44,6 @@ public void handle(RoutingContext event) {
.setDefaultContentEncoding("UTF-8");
if (event.normalisedPath().length() == healthUiPath.length()) {
-
event.response().setStatusCode(302);
event.response().headers().set(HttpHeaders.LOCATION, healthUiPath + "/");
event.response().end();
diff --git a/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java b/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java
index 5bfbadd59f33d..310ae17e4d580 100644
--- a/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java
+++ b/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java
@@ -163,12 +163,12 @@ void createRoute(BuildProducer routes,
.route(metrics.path + (metrics.path.endsWith("/") ? "*" : "/*"))
.handler(recorder.handler(frameworkRoot.resolvePath(metrics.path)))
.requiresLegacyRedirect()
- .displayOnNotFoundPage("Metrics", metrics.path)
.blockingRoute()
.build());
routes.produce(frameworkRoot.routeBuilder()
.route(metrics.path)
.handler(recorder.handler(frameworkRoot.resolvePath(metrics.path)))
+ .displayOnNotFoundPage("Metrics")
.requiresLegacyRedirect()
.blockingRoute()
.build());
diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java
index 740bcde64b5d9..0322737bc436c 100644
--- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java
+++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java
@@ -172,6 +172,7 @@ RouteBuildItem handler(LaunchModeBuildItem launch,
Handler handler = recorder.handler(openApiRuntimeConfig);
return nonApplicationRootPathBuildItem.routeBuilder()
.route(openApiConfig.path)
+ .routeConfigKey("quarkus.smallrye-openapi.path")
.handler(handler)
.displayOnNotFoundPage("Open API Schema document")
.requiresLegacyRedirect()
diff --git a/extensions/smallrye-openapi/deployment/src/main/resources/dev-templates/embedded.html b/extensions/smallrye-openapi/deployment/src/main/resources/dev-templates/embedded.html
index 8f548cc42dd17..301c0af54e22a 100644
--- a/extensions/smallrye-openapi/deployment/src/main/resources/dev-templates/embedded.html
+++ b/extensions/smallrye-openapi/deployment/src/main/resources/dev-templates/embedded.html
@@ -1,7 +1,7 @@
-
+
OpenAPI
-
+
Swagger UI
diff --git a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java
index ccb86c99987ab..7f50ce0c10e54 100644
--- a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java
+++ b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java
@@ -18,6 +18,7 @@ public class SwaggerUiConfig {
* The path where Swagger UI is available.
*
* The value `/` is not allowed as it blocks the application from serving anything else.
+ * By default, this value will be resolved as a path relative to `${quarkus.http.non-application-root-path}`.
*/
@ConfigItem(defaultValue = "swagger-ui")
String path;
diff --git a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java
index 40c828dd7f9e3..c45e43a5675d6 100644
--- a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java
+++ b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java
@@ -27,10 +27,8 @@
import io.quarkus.smallrye.openapi.common.deployment.SmallRyeOpenApiConfig;
import io.quarkus.swaggerui.runtime.SwaggerUiRecorder;
import io.quarkus.swaggerui.runtime.SwaggerUiRuntimeConfig;
-import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem;
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
import io.quarkus.vertx.http.deployment.RouteBuildItem;
-import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem;
import io.smallrye.openapi.ui.IndexHtmlCreator;
import io.smallrye.openapi.ui.Option;
import io.smallrye.openapi.ui.ThemeHref;
@@ -79,12 +77,10 @@ public void getSwaggerUiFinalDestination(
BuildProducer nativeImageResourceBuildItemBuildProducer,
BuildProducer swaggerUiBuildProducer,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
- BuildProducer displayableEndpoints,
CurateOutcomeBuildItem curateOutcomeBuildItem,
LaunchModeBuildItem launchMode,
SwaggerUiConfig swaggerUiConfig,
SmallRyeOpenApiConfig openapi,
- HttpRootPathBuildItem httpRootPathBuildItem,
LiveReloadBuildItem liveReloadBuildItem) throws Exception {
if (shouldInclude(launchMode, swaggerUiConfig)) {
@@ -93,9 +89,8 @@ public void getSwaggerUiFinalDestination(
"quarkus.swagger-ui.path was set to \"/\", this is not allowed as it blocks the application from serving anything else.");
}
- String openApiPath = httpRootPathBuildItem.resolvePath(nonApplicationRootPathBuildItem.resolvePath(openapi.path));
- String swaggerUiPath = httpRootPathBuildItem
- .resolvePath(nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path));
+ String openApiPath = nonApplicationRootPathBuildItem.resolvePath(openapi.path);
+ String swaggerUiPath = nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path);
AppArtifact artifact = WebJarUtil.getAppArtifact(curateOutcomeBuildItem, SWAGGER_UI_WEBJAR_GROUP_ID,
SWAGGER_UI_WEBJAR_ARTIFACT_ID);
@@ -156,6 +151,7 @@ public void registerSwaggerUiHandler(SwaggerUiRecorder recorder,
routes.produce(nonApplicationRootPathBuildItem.routeBuilder()
.route(swaggerUiConfig.path)
.displayOnNotFoundPage("Open API UI")
+ .routeConfigKey("quarkus.swagger-ui.path")
.handler(handler)
.requiresLegacyRedirect()
.build());
diff --git a/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java b/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java
index 08cce8ddce3ec..8c00ac69b8bb4 100644
--- a/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java
+++ b/extensions/vertx-graphql/deployment/src/main/java/io/quarkus/vertx/graphql/deployment/VertxGraphqlProcessor.java
@@ -68,12 +68,17 @@ void registerVertxGraphqlUI(VertxGraphqlRecorder recorder,
}
Handler handler = recorder.handler();
- routes.produce(nonApplicationRootPathBuildItem.routeBuilder().route(path).handler(handler)
+ routes.produce(nonApplicationRootPathBuildItem.routeBuilder()
+ .route(path)
+ .handler(handler)
.requiresLegacyRedirect()
- .displayOnNotFoundPage("GraphQL UI", path + "/")
+ .displayOnNotFoundPage("GraphQL UI")
.build());
routes.produce(
- nonApplicationRootPathBuildItem.routeBuilder().route(path + "/*").handler(handler).requiresLegacyRedirect()
+ nonApplicationRootPathBuildItem.routeBuilder()
+ .route(path + "/*")
+ .handler(handler)
+ .requiresLegacyRedirect()
.build());
nativeResourcesProducer.produce(new NativeImageResourceDirectoryBuildItem("io/vertx/ext/web/handler/graphiql"));
}
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java
index a1bf1775c2867..28b897640ce6d 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java
@@ -1,9 +1,18 @@
package io.quarkus.vertx.http.deployment;
import java.net.URI;
+import java.util.function.Consumer;
+import java.util.function.Function;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.util.UriNormalizationUtil;
+import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem;
+import io.quarkus.vertx.http.deployment.devmode.console.ConfiguredPathInfo;
+import io.quarkus.vertx.http.runtime.HandlerType;
+import io.vertx.core.Handler;
+import io.vertx.ext.web.Route;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
public final class HttpRootPathBuildItem extends SimpleBuildItem {
@@ -65,4 +74,121 @@ public String adjustPath(String path) {
public String resolvePath(String path) {
return UriNormalizationUtil.normalizeWithBase(rootPath, path, false).getPath();
}
+
+ public HttpRootPathBuildItem.Builder routeBuilder() {
+ return new HttpRootPathBuildItem.Builder(this);
+ }
+
+ public static class Builder extends RouteBuildItem.Builder {
+ private final HttpRootPathBuildItem buildItem;
+ private RouteBuildItem.RouteType routeType = RouteBuildItem.RouteType.APPLICATION_ROUTE;
+ private String path;
+
+ Builder(HttpRootPathBuildItem buildItem) {
+ this.buildItem = buildItem;
+ }
+
+ @Override
+ public Builder routeFunction(Function routeFunction) {
+ throw new RuntimeException(
+ "This method is not supported using this builder. Use #routeFunction(String, Consumer)");
+ }
+
+ public Builder routeFunction(String route, Consumer routeFunction) {
+ route = super.absolutePath = buildItem.resolvePath(route);
+
+ if (route.startsWith(buildItem.getRootPath())) {
+ // relative to http root (leading slash for vert.x route)
+ this.path = "/" + UriNormalizationUtil.relativize(buildItem.getRootPath(), route);
+ this.routeType = RouteBuildItem.RouteType.APPLICATION_ROUTE;
+ } else if (route.startsWith("/")) {
+ // absolute path
+ this.path = route;
+ this.routeType = RouteBuildItem.RouteType.ABSOLUTE_ROUTE;
+ }
+
+ super.routeFunction(this.path, routeFunction);
+ return this;
+ }
+
+ @Override
+ public Builder route(String route) {
+ routeFunction(route, null);
+ return this;
+ }
+
+ public Builder nestedRoute(String baseRoute, String subRoute) {
+ if (subRoute.startsWith("/")) {
+ routeFunction(subRoute, null);
+ return this;
+ }
+
+ baseRoute = baseRoute.endsWith("/") ? baseRoute : baseRoute + "/";
+ routeFunction(baseRoute + subRoute, null);
+ return this;
+ }
+
+ @Override
+ public Builder handler(Handler handler) {
+ super.handler(handler);
+ return this;
+ }
+
+ @Override
+ public Builder handlerType(HandlerType handlerType) {
+ super.handlerType(handlerType);
+ return this;
+ }
+
+ @Override
+ public Builder blockingRoute() {
+ super.blockingRoute();
+ return this;
+ }
+
+ @Override
+ public Builder failureRoute() {
+ super.failureRoute();
+ return this;
+ }
+
+ @Override
+ public Builder displayOnNotFoundPage() {
+ super.displayOnNotFoundPage();
+ return this;
+ }
+
+ @Override
+ public Builder displayOnNotFoundPage(String notFoundPageTitle) {
+ super.displayOnNotFoundPage(notFoundPageTitle);
+ return this;
+ }
+
+ @Override
+ public Builder displayOnNotFoundPage(String notFoundPageTitle, String notFoundPagePath) {
+ super.displayOnNotFoundPage(notFoundPageTitle, notFoundPagePath);
+ return this;
+ }
+
+ @Override
+ public Builder routeConfigKey(String attributeName) {
+ super.routeConfigKey(attributeName);
+ return this;
+ }
+
+ @Override
+ public RouteBuildItem build() {
+ return new RouteBuildItem(this, routeType, false);
+ }
+
+ @Override
+ protected ConfiguredPathInfo getRouteConfigInfo() {
+ return super.getRouteConfigInfo();
+ }
+
+ @Override
+ protected NotFoundPageDisplayableEndpointBuildItem getNotFoundEndpoint() {
+ return super.getNotFoundEndpoint();
+ }
+ }
}
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java
index c6426ae14ebb5..e16242c878c30 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java
@@ -7,6 +7,7 @@
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.util.UriNormalizationUtil;
import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem;
+import io.quarkus.vertx.http.deployment.devmode.console.ConfiguredPathInfo;
import io.quarkus.vertx.http.runtime.HandlerType;
import io.vertx.core.Handler;
import io.vertx.ext.web.Route;
@@ -69,20 +70,12 @@ public boolean isAttachedToMainRouter() {
*/
String getVertxRouterPath() {
if (attachedToMainRouter) {
- return "/" + relativize(httpRootPath.getPath(), nonApplicationRootPath.getPath());
+ return "/" + UriNormalizationUtil.relativize(httpRootPath.getPath(), nonApplicationRootPath.getPath());
} else {
return getNonApplicationRootPath();
}
}
- String relativize(String rootPath, String leafPath) {
- if (leafPath.startsWith(rootPath)) {
- return leafPath.substring(rootPath.length());
- }
-
- return null;
- }
-
public String getNormalizedHttpRootPath() {
return httpRootPath.getPath();
}
@@ -189,7 +182,6 @@ public static class Builder extends RouteBuildItem.Builder {
private boolean requiresLegacyRedirect = false;
private RouteBuildItem.RouteType routeType = RouteBuildItem.RouteType.FRAMEWORK_ROUTE;
private String path;
- private String absolute;
Builder(NonApplicationRootPathBuildItem buildItem) {
this.buildItem = buildItem;
@@ -197,23 +189,23 @@ public static class Builder extends RouteBuildItem.Builder {
@Override
public Builder routeFunction(Function routeFunction) {
- throw new RuntimeException("This method is not supported for non-application routes");
+ throw new RuntimeException(
+ "This method is not supported using this builder. Use #routeFunction(String, Consumer)");
}
public Builder routeFunction(String route, Consumer routeFunction) {
- String temp = route;
- route = absolute = buildItem.resolvePath(route);
+ route = super.absolutePath = buildItem.resolvePath(route);
boolean isFrameworkRoute = buildItem.dedicatedRouterRequired
&& route.startsWith(buildItem.getNonApplicationRootPath());
if (isFrameworkRoute) {
- // relative non-application root
- this.path = "/" + buildItem.relativize(buildItem.getNonApplicationRootPath(), route);
+ // relative non-application root (leading slash for vert.x)
+ this.path = "/" + UriNormalizationUtil.relativize(buildItem.getNonApplicationRootPath(), route);
this.routeType = RouteBuildItem.RouteType.FRAMEWORK_ROUTE;
} else if (route.startsWith(buildItem.httpRootPath.getPath())) {
- // relative to http root
- this.path = "/" + buildItem.relativize(buildItem.httpRootPath.getPath(), route);
+ // relative to http root (leading slash for vert.x route)
+ this.path = "/" + UriNormalizationUtil.relativize(buildItem.httpRootPath.getPath(), route);
this.routeType = RouteBuildItem.RouteType.APPLICATION_ROUTE;
} else if (route.startsWith("/")) {
// absolute path
@@ -277,43 +269,45 @@ public Builder failureRoute() {
@Override
public Builder displayOnNotFoundPage() {
- this.displayOnNotFoundPage = true;
+ super.displayOnNotFoundPage();
return this;
}
@Override
public Builder displayOnNotFoundPage(String notFoundPageTitle) {
- this.displayOnNotFoundPage = true;
- this.notFoundPageTitle = notFoundPageTitle;
+ super.displayOnNotFoundPage(notFoundPageTitle);
return this;
}
@Override
public Builder displayOnNotFoundPage(String notFoundPageTitle, String notFoundPagePath) {
- this.displayOnNotFoundPage = true;
- this.notFoundPageTitle = notFoundPageTitle;
- this.notFoundPagePath = notFoundPagePath;
+ super.displayOnNotFoundPage(notFoundPageTitle, notFoundPagePath);
+ return this;
+ }
+
+ @Override
+ public Builder routeConfigKey(String attributeName) {
+ super.routeConfigKey(attributeName);
return this;
}
+ @Override
public RouteBuildItem build() {
// If path is same as absolute, we don't enable legacy redirect
- if (requiresLegacyRedirect && path.equals(absolute)) {
+ if (requiresLegacyRedirect && path.equals(super.absolutePath)) {
requiresLegacyRedirect = false;
}
return new RouteBuildItem(this, routeType, requiresLegacyRedirect);
}
+ @Override
+ protected ConfiguredPathInfo getRouteConfigInfo() {
+ return super.getRouteConfigInfo();
+ }
+
@Override
protected NotFoundPageDisplayableEndpointBuildItem getNotFoundEndpoint() {
- if (!displayOnNotFoundPage) {
- return null;
- }
- if (notFoundPagePath == null) {
- throw new RuntimeException("Cannot display " + routeFunction
- + " on not found page as no explicit path was specified and a route function is in use");
- }
- return new NotFoundPageDisplayableEndpointBuildItem(absolute, notFoundPageTitle, true);
+ return super.getNotFoundEndpoint();
}
}
}
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java
index 2f732f16c473e..f3bf8101515bb 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java
@@ -5,6 +5,7 @@
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem;
+import io.quarkus.vertx.http.deployment.devmode.console.ConfiguredPathInfo;
import io.quarkus.vertx.http.runtime.BasicRoute;
import io.quarkus.vertx.http.runtime.HandlerType;
import io.vertx.core.Handler;
@@ -24,6 +25,7 @@ public static Builder builder() {
private final RouteType routeType;
private final boolean requiresLegacyRedirect;
private final NotFoundPageDisplayableEndpointBuildItem notFoundPageDisplayableEndpoint;
+ private final ConfiguredPathInfo devConsoleResolvedPathBuildItem;
/**
* @deprecated Use the Builder instead.
@@ -36,6 +38,7 @@ public RouteBuildItem(Function routeFunction, Handler handler) {
this.routeType = routeType;
this.requiresLegacyRedirect = requiresLegacyRedirect;
this.notFoundPageDisplayableEndpoint = builder.getNotFoundEndpoint();
+ this.devConsoleResolvedPathBuildItem = builder.getRouteConfigInfo();
}
public Handler getHandler() {
@@ -119,6 +123,10 @@ public NotFoundPageDisplayableEndpointBuildItem getNotFoundPageDisplayableEndpoi
return notFoundPageDisplayableEndpoint;
}
+ public ConfiguredPathInfo getDevConsoleResolvedPath() {
+ return devConsoleResolvedPathBuildItem;
+ }
+
public enum RouteType {
FRAMEWORK_ROUTE,
APPLICATION_ROUTE,
@@ -126,7 +134,7 @@ public enum RouteType {
}
/**
- * NonApplicationRootPathBuildItem.Builder extends this.
+ * HttpRootPathBuildItem.Builder and NonApplicationRootPathBuildItem.Builder extend this.
* Please verify the extended builders behavior when changing this one.
*/
public static class Builder {
@@ -136,12 +144,27 @@ public static class Builder {
protected boolean displayOnNotFoundPage;
protected String notFoundPageTitle;
protected String notFoundPagePath;
+ protected String routePath;
+ protected String routeConfigKey;
+ protected String absolutePath;
+
+ /**
+ * Use HttpRootPathBuildItem and NonApplicationRootPathBuildItem to
+ * ensure paths are constructed/normalized correctly
+ *
+ * @deprecated
+ * @see HttpRootPathBuildItem#routeBuilder()
+ * @see NonApplicationRootPathBuildItem#routeBuilder()
+ */
+ @Deprecated
+ public Builder() {
+ }
/**
* {@link #routeFunction(String, Consumer)} should be used instead
*
* @param routeFunction
- * @return
+ * @see #routeFunction(String, Consumer)
*/
@Deprecated
public Builder routeFunction(Function routeFunction) {
@@ -149,15 +172,25 @@ public Builder routeFunction(Function routeFunction) {
return this;
}
+ /**
+ * @param path A normalized path (e.g. use HttpRootPathBuildItem to construct/resolve the path value) defining
+ * the route. This path this is also used on the "Not Found" page in dev mode.
+ * @param routeFunction a Consumer of Route
+ */
public Builder routeFunction(String path, Consumer routeFunction) {
this.routeFunction = new BasicRoute(path, null, routeFunction);
- this.notFoundPagePath = path;
+ this.notFoundPagePath = this.routePath = path;
return this;
}
+ /**
+ * @param route A normalized path used to define a basic route
+ * (e.g. use HttpRootPathBuildItem to construct/resolve the path value). This path this is also
+ * used on the "Not Found" page in dev mode.
+ */
public Builder route(String route) {
this.routeFunction = new BasicRoute(route);
- this.notFoundPagePath = route;
+ this.notFoundPagePath = this.routePath = route;
return this;
}
@@ -192,6 +225,12 @@ public Builder displayOnNotFoundPage(String notFoundPageTitle) {
return this;
}
+ /**
+ * @deprecated Specify the path as part of defining the route
+ * @see #route(String)
+ * @see #routeFunction(String, Consumer)
+ */
+ @Deprecated
public Builder displayOnNotFoundPage(String notFoundPageTitle, String notFoundPagePath) {
this.displayOnNotFoundPage = true;
this.notFoundPageTitle = notFoundPageTitle;
@@ -199,10 +238,29 @@ public Builder displayOnNotFoundPage(String notFoundPageTitle, String notFoundPa
return this;
}
+ public Builder routeConfigKey(String attributeName) {
+ this.routeConfigKey = attributeName;
+ return this;
+ }
+
public RouteBuildItem build() {
return new RouteBuildItem(this, RouteType.APPLICATION_ROUTE, false);
}
+ protected ConfiguredPathInfo getRouteConfigInfo() {
+ if (routeConfigKey == null) {
+ return null;
+ }
+ if (routePath == null) {
+ throw new RuntimeException("Cannot discover value of " + routeConfigKey
+ + " as no explicit path was specified and a route function is in use");
+ }
+ if (absolutePath != null) {
+ return new ConfiguredPathInfo(routeConfigKey, absolutePath, true);
+ }
+ return new ConfiguredPathInfo(routeConfigKey, routePath, false);
+ }
+
protected NotFoundPageDisplayableEndpointBuildItem getNotFoundEndpoint() {
if (!displayOnNotFoundPage) {
return null;
@@ -211,7 +269,10 @@ protected NotFoundPageDisplayableEndpointBuildItem getNotFoundEndpoint() {
throw new RuntimeException("Cannot display " + routeFunction
+ " on not found page as no explicit path was specified and a route function is in use");
}
- return new NotFoundPageDisplayableEndpointBuildItem(notFoundPagePath, notFoundPageTitle);
+ if (absolutePath != null) {
+ return new NotFoundPageDisplayableEndpointBuildItem(absolutePath, notFoundPageTitle, true);
+ }
+ return new NotFoundPageDisplayableEndpointBuildItem(notFoundPagePath, notFoundPageTitle, false);
}
}
}
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
index dd39d2a01b3a2..347fa4fc38dca 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
@@ -120,14 +120,13 @@ public KubernetesPortBuildItem kubernetes() {
}
@BuildStep
- void notRoundRoutes(
+ void notFoundRoutes(
List routes,
BuildProducer notFound) {
for (RouteBuildItem i : routes) {
if (i.getNotFoundPageDisplayableEndpoint() != null) {
notFound.produce(i.getNotFoundPageDisplayableEndpoint());
}
-
}
}
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/NotFoundPageDisplayableEndpointBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/NotFoundPageDisplayableEndpointBuildItem.java
index a0d88468946d6..638db01bcf52a 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/NotFoundPageDisplayableEndpointBuildItem.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/NotFoundPageDisplayableEndpointBuildItem.java
@@ -13,10 +13,10 @@ public NotFoundPageDisplayableEndpointBuildItem(String endpoint, String descript
this(endpoint, description, false);
}
- public NotFoundPageDisplayableEndpointBuildItem(String endpoint, String description, boolean absolutePath) {
+ public NotFoundPageDisplayableEndpointBuildItem(String endpoint, String description, boolean isAbsolutePath) {
this.endpoint = endpoint;
this.description = description;
- this.absolutePath = absolutePath;
+ this.absolutePath = isAbsolutePath;
}
public NotFoundPageDisplayableEndpointBuildItem(String endpoint) {
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfiguredPathInfo.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfiguredPathInfo.java
new file mode 100644
index 0000000000000..a522178d15ab9
--- /dev/null
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfiguredPathInfo.java
@@ -0,0 +1,37 @@
+package io.quarkus.vertx.http.deployment.devmode.console;
+
+import io.quarkus.runtime.TemplateHtmlBuilder;
+import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem;
+import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
+
+public class ConfiguredPathInfo {
+ private final String name;
+ private final String endpointPath;
+ private final boolean absolutePath;
+
+ public ConfiguredPathInfo(String name, String endpointPath, boolean isAbsolutePath) {
+ this.name = name;
+ this.endpointPath = endpointPath;
+ this.absolutePath = isAbsolutePath;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getEndpointPath(HttpRootPathBuildItem httpRoot) {
+ if (absolutePath) {
+ return endpointPath;
+ } else {
+ return TemplateHtmlBuilder.adjustRoot(httpRoot.getRootPath(), endpointPath);
+ }
+ }
+
+ public String getEndpointPath(NonApplicationRootPathBuildItem nonAppRoot) {
+ if (absolutePath) {
+ return endpointPath;
+ } else {
+ return TemplateHtmlBuilder.adjustRoot(nonAppRoot.getNormalizedHttpRootPath(), endpointPath);
+ }
+ }
+}
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsole.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsole.java
index 6158504c2889b..559c9604dcfba 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsole.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsole.java
@@ -44,8 +44,13 @@ public class DevConsole implements Handler {
DevConsole(Engine engine, String httpRootPath, String frameworkRootPath) {
this.engine = engine;
+ // Both of these paths will end in slash
this.globalData.put("httpRootPath", httpRootPath);
this.globalData.put("frameworkRootPath", frameworkRootPath);
+
+ // This includes the dev segment, but does not include a trailing slash (for append)
+ this.globalData.put("devRootAppend", frameworkRootPath + "dev");
+
this.globalData.put("quarkusVersion", Version.getVersion());
this.globalData.put("applicationName", config.getOptionalValue("quarkus.application.name", String.class).orElse(""));
this.globalData.put("applicationVersion",
diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsoleProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsoleProcessor.java
index cbe6b2c5a67f3..98acfda35f6e9 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsoleProcessor.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/DevConsoleProcessor.java
@@ -248,22 +248,65 @@ public void runtimeTemplates(List items,
}
@BuildStep(onlyIf = IsDevelopment.class)
- public void setupActions(List routes,
- BuildProducer routeBuildItemBuildProducer,
- List devTemplatePaths,
+ public ServiceStartBuildItem setupDeploymentSideHandling(List devTemplatePaths,
+ CurateOutcomeBuildItem curateOutcomeBuildItem,
+ List allRoutes,
+ List routes,
+ NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, LaunchModeBuildItem launchModeBuildItem) {
+ if (launchModeBuildItem.getDevModeType().orElse(null) != DevModeType.LOCAL) {
+ return null;
+ }
+
+ initializeVirtual();
+ Engine quteEngine = buildEngine(devTemplatePaths,
+ allRoutes,
+ nonApplicationRootPathBuildItem);
+ newRouter(quteEngine, nonApplicationRootPathBuildItem);
+
+ for (DevConsoleRouteBuildItem i : routes) {
+ Entry groupAndArtifact = i.groupIdAndArtifactId(curateOutcomeBuildItem);
+ // deployment side handling
+ if (!(i.getHandler() instanceof BytecodeRecorderImpl.ReturnedProxy)) {
+ router.route(HttpMethod.valueOf(i.getMethod()),
+ "/" + groupAndArtifact.getKey() + "." + groupAndArtifact.getValue() + "/" + i.getPath())
+ .handler(i.getHandler());
+ }
+ }
+
+ return null;
+ }
+
+ @Record(ExecutionTime.RUNTIME_INIT)
+ @BuildStep(onlyIf = IsDevelopment.class)
+ public void setupDevConsoleRoutes(
+ DevConsoleRecorder recorder,
+ List routes,
CurateOutcomeBuildItem curateOutcomeBuildItem,
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
- LaunchModeBuildItem launchModeBuildItem) {
+ LaunchModeBuildItem launchModeBuildItem,
+ ShutdownContextBuildItem shutdownContext,
+ BuildProducer routeBuildItemBuildProducer) throws IOException {
if (launchModeBuildItem.getDevModeType().orElse(null) != DevModeType.LOCAL) {
return;
}
- initializeVirtual();
- newRouter(buildEngine(devTemplatePaths), nonApplicationRootPathBuildItem);
+ // Add the static resources
+ AppArtifact devConsoleResourcesArtifact = WebJarUtil.getAppArtifact(curateOutcomeBuildItem, "io.quarkus",
+ "quarkus-vertx-http-deployment");
+
+ Path devConsoleStaticResourcesDeploymentPath = WebJarUtil.copyResourcesForDevOrTest(curateOutcomeBuildItem,
+ launchModeBuildItem,
+ devConsoleResourcesArtifact, STATIC_RESOURCES_PATH);
+
+ routeBuildItemBuildProducer.produce(nonApplicationRootPathBuildItem.routeBuilder()
+ .route("dev/resources/*")
+ .handler(recorder.devConsoleHandler(devConsoleStaticResourcesDeploymentPath.toString(), shutdownContext))
+ .build());
for (DevConsoleRouteBuildItem i : routes) {
Entry groupAndArtifact = i.groupIdAndArtifactId(curateOutcomeBuildItem);
// if the handler is a proxy, then that means it's been produced by a recorder and therefore belongs in the regular runtime Vert.x instance
+ // otherwise this is handled in the setupDeploymentSideHandling method
if (i.getHandler() instanceof BytecodeRecorderImpl.ReturnedProxy) {
routeBuildItemBuildProducer.produce(nonApplicationRootPathBuildItem.routeBuilder()
.routeFunction(
@@ -271,10 +314,6 @@ public void setupActions(List routes,
new RuntimeDevConsoleRoute(i.getMethod()))
.handler(i.getHandler())
.build());
- } else {
- router.route(HttpMethod.valueOf(i.getMethod()),
- "/" + groupAndArtifact.getKey() + "." + groupAndArtifact.getValue() + "/" + i.getPath())
- .handler(i.getHandler());
}
}
@@ -291,30 +330,9 @@ public void setupActions(List routes,
.build());
}
- @BuildStep(onlyIf = IsDevelopment.class)
- @Record(ExecutionTime.RUNTIME_INIT)
- public void deployStaticResources(DevConsoleRecorder recorder, CurateOutcomeBuildItem curateOutcomeBuildItem,
- LaunchModeBuildItem launchMode, ShutdownContextBuildItem shutdownContext,
- BuildProducer routeBuildItemBuildProducer,
- NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
- LaunchModeBuildItem launchModeBuildItem) throws IOException {
-
- if (launchModeBuildItem.getDevModeType().orElse(DevModeType.LOCAL) != DevModeType.LOCAL) {
- return;
- }
- AppArtifact devConsoleResourcesArtifact = WebJarUtil.getAppArtifact(curateOutcomeBuildItem, "io.quarkus",
- "quarkus-vertx-http-deployment");
-
- Path devConsoleStaticResourcesDeploymentPath = WebJarUtil.copyResourcesForDevOrTest(curateOutcomeBuildItem, launchMode,
- devConsoleResourcesArtifact, STATIC_RESOURCES_PATH);
-
- routeBuildItemBuildProducer.produce(nonApplicationRootPathBuildItem.routeBuilder()
- .route("dev/resources/*")
- .handler(recorder.devConsoleHandler(devConsoleStaticResourcesDeploymentPath.toString(), shutdownContext))
- .build());
- }
-
- private Engine buildEngine(List devTemplatePaths) {
+ private Engine buildEngine(List devTemplatePaths,
+ List allRoutes,
+ NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) {
EngineBuilder builder = Engine.builder().addDefaults();
// Escape some characters for HTML templates
@@ -336,16 +354,35 @@ private Engine buildEngine(List devTemplatePaths) {
return result == null ? Results.Result.NOT_FOUND : result;
}).build());
+ // Create map of resolved paths
+ Map resolvedPaths = new HashMap<>();
+ for (RouteBuildItem item : allRoutes) {
+ ConfiguredPathInfo resolvedPathBuildItem = item.getDevConsoleResolvedPath();
+ if (resolvedPathBuildItem != null) {
+ resolvedPaths.put(resolvedPathBuildItem.getName(),
+ resolvedPathBuildItem.getEndpointPath(nonApplicationRootPathBuildItem));
+ }
+ }
+
// {config:property('quarkus.lambda.handler')}
+ // {config:http-path('quarkus.smallrye-graphql.ui.root-path')}
+ // Note that the output value is always string!
builder.addNamespaceResolver(NamespaceResolver.builder("config").resolveAsync(ctx -> {
List params = ctx.getParams();
- if (params.size() != 1 || !ctx.getName().equals("property")) {
+ if (params.size() != 1 || (!ctx.getName().equals("property") && !ctx.getName().equals("http-path"))) {
return Results.NOT_FOUND;
}
- return ctx.evaluate(params.get(0)).thenCompose(propertyName -> {
- Optional val = ConfigProvider.getConfig().getOptionalValue(propertyName.toString(), String.class);
- return CompletableFuture.completedFuture(val.isPresent() ? val.get() : Result.NOT_FOUND);
- });
+ if (ctx.getName().equals("http-path")) {
+ return ctx.evaluate(params.get(0)).thenCompose(propertyName -> {
+ String value = resolvedPaths.get(propertyName.toString());
+ return CompletableFuture.completedFuture(value != null ? value : Result.NOT_FOUND);
+ });
+ } else {
+ return ctx.evaluate(params.get(0)).thenCompose(propertyName -> {
+ Optional val = ConfigProvider.getConfig().getOptionalValue(propertyName.toString(), String.class);
+ return CompletableFuture.completedFuture(val.isPresent() ? val.get() : Result.NOT_FOUND);
+ });
+ }
}).build());
// JavaDoc formatting
diff --git a/extensions/vertx-http/deployment/src/main/resources/dev-templates/main.html b/extensions/vertx-http/deployment/src/main/resources/dev-templates/main.html
index a38578c0c4c41..675736e8490f9 100644
--- a/extensions/vertx-http/deployment/src/main/resources/dev-templates/main.html
+++ b/extensions/vertx-http/deployment/src/main/resources/dev-templates/main.html
@@ -6,11 +6,12 @@
-
-
-
+
+
+
+
-
+