You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2024/03/05 19:32:40 UTC

(camel-quarkus) 04/07: Support loadOnStartup, async, forceAwait & executorRef configuration options

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch 3.8.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit e77cbd02a8cd6c947c12f1f93b5e2371bf42ad6e
Author: James Netherton <ja...@gmail.com>
AuthorDate: Mon Mar 4 15:50:48 2024 +0000

    Support loadOnStartup, async, forceAwait & executorRef configuration options
    
    Fixes #5834
---
 .../ROOT/pages/reference/extensions/servlet.adoc   | 48 ++++++++++++
 .../servlet/deployment/ServletProcessor.java       | 19 ++++-
 .../servlet/runtime/CamelServletConfig.java        | 27 +++++++
 .../quarkus/component/servlet/CamelRoute.java      | 34 +++++++--
 .../component/servlet/ServletProducers.java        | 71 +++++++++++++++++
 .../src/main/resources/application.properties      | 50 ++++++++----
 .../component/servlet/CamelServletTest.java        | 89 ++++++++++++++++++----
 7 files changed, 304 insertions(+), 34 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/extensions/servlet.adoc b/docs/modules/ROOT/pages/reference/extensions/servlet.adoc
index ac9303ed92..848ac1299c 100644
--- a/docs/modules/ROOT/pages/reference/extensions/servlet.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/servlet.adoc
@@ -156,6 +156,30 @@ A servletName as it would be defined in a `web.xml` file or in the `jakarta.serv
 | `string`
 | `CamelServlet`
 
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.load-on-startup]]`link:#quarkus.camel.servlet.load-on-startup[quarkus.camel.servlet.load-on-startup]`
+
+Sets the loadOnStartup priority on the Servlet. A loadOnStartup is a value greater than or equal to zero, indicates to the container the initialization priority of the Servlet. If loadOnStartup is a negative integer, the Servlet is initialized lazily.
+| `java.lang.Integer`
+| `-1`
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.async]]`link:#quarkus.camel.servlet.async[quarkus.camel.servlet.async]`
+
+Enables Camel to benefit from asynchronous Servlet support.
+| `boolean`
+| `false`
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.force-await]]`link:#quarkus.camel.servlet.force-await[quarkus.camel.servlet.force-await]`
+
+When set to `true` used in conjunction with `quarkus.camel.servlet.async = true`, this will force route processing to run synchronously.
+| `boolean`
+| `false`
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.executor-ref]]`link:#quarkus.camel.servlet.executor-ref[quarkus.camel.servlet.executor-ref]`
+
+The name of a bean to configure an optional custom thread pool for handling Camel Servlet processing.
+| `string`
+| 
+
 |icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.multipart.location]]`link:#quarkus.camel.servlet.multipart.location[quarkus.camel.servlet.multipart.location]`
 
 An absolute path to a directory on the file system to store files temporarily while the parts are processed or when the size of the file exceeds the specified file-size-threshold configuration value.
@@ -198,6 +222,30 @@ A servletName as it would be defined in a `web.xml` file or in the `jakarta.serv
 | `string`
 | `CamelServlet`
 
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.-named-servlets-.load-on-startup]]`link:#quarkus.camel.servlet.-named-servlets-.load-on-startup[quarkus.camel.servlet."named-servlets".load-on-startup]`
+
+Sets the loadOnStartup priority on the Servlet. A loadOnStartup is a value greater than or equal to zero, indicates to the container the initialization priority of the Servlet. If loadOnStartup is a negative integer, the Servlet is initialized lazily.
+| `java.lang.Integer`
+| `-1`
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.-named-servlets-.async]]`link:#quarkus.camel.servlet.-named-servlets-.async[quarkus.camel.servlet."named-servlets".async]`
+
+Enables Camel to benefit from asynchronous Servlet support.
+| `boolean`
+| `false`
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.-named-servlets-.force-await]]`link:#quarkus.camel.servlet.-named-servlets-.force-await[quarkus.camel.servlet."named-servlets".force-await]`
+
+When set to `true` used in conjunction with `quarkus.camel.servlet.async = true`, this will force route processing to run synchronously.
+| `boolean`
+| `false`
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.-named-servlets-.executor-ref]]`link:#quarkus.camel.servlet.-named-servlets-.executor-ref[quarkus.camel.servlet."named-servlets".executor-ref]`
+
+The name of a bean to configure an optional custom thread pool for handling Camel Servlet processing.
+| `string`
+| 
+
 |icon:lock[title=Fixed at build time] [[quarkus.camel.servlet.-named-servlets-.multipart.location]]`link:#quarkus.camel.servlet.-named-servlets-.multipart.location[quarkus.camel.servlet."named-servlets".multipart.location]`
 
 An absolute path to a directory on the file system to store files temporarily while the parts are processed or when the size of the file exceeds the specified file-size-threshold configuration value.
diff --git a/extensions/servlet/deployment/src/main/java/org/apache/camel/quarkus/component/servlet/deployment/ServletProcessor.java b/extensions/servlet/deployment/src/main/java/org/apache/camel/quarkus/component/servlet/deployment/ServletProcessor.java
index 7e21a43adb..6afaf14202 100644
--- a/extensions/servlet/deployment/src/main/java/org/apache/camel/quarkus/component/servlet/deployment/ServletProcessor.java
+++ b/extensions/servlet/deployment/src/main/java/org/apache/camel/quarkus/component/servlet/deployment/ServletProcessor.java
@@ -63,7 +63,6 @@ class ServletProcessor {
             throw new IllegalStateException(
                     "Map at least one servlet to a path using quarkus.camel.servlet.url-patterns or quarkus.camel.servlet.[your-servlet-name].url-patterns");
         }
-
     }
 
     static ServletBuildItem newServlet(String key, ServletConfig servletConfig) {
@@ -80,6 +79,24 @@ class ServletProcessor {
             builder.addMapping(pattern);
         }
 
+        // NOTE: We only configure loadOnStartup, async & forceAwait if the default values were overridden
+        if (servletConfig.loadOnStartup > -1) {
+            builder.setLoadOnStartup(servletConfig.loadOnStartup);
+        }
+
+        if (servletConfig.async) {
+            builder.setAsyncSupported(servletConfig.async);
+            builder.addInitParam("async", "true");
+        }
+
+        if (servletConfig.forceAwait) {
+            builder.addInitParam("forceAwait", "true");
+        }
+
+        servletConfig.executorRef.ifPresent(executorRef -> {
+            builder.addInitParam("executorRef", executorRef);
+        });
+
         MultipartConfig multipartConfig = servletConfig.multipart;
         if (multipartConfig != null) {
             builder.setMultipartConfig(new MultipartConfigElement(
diff --git a/extensions/servlet/runtime/src/main/java/org/apache/camel/quarkus/servlet/runtime/CamelServletConfig.java b/extensions/servlet/runtime/src/main/java/org/apache/camel/quarkus/servlet/runtime/CamelServletConfig.java
index 62ac5c7131..ff20269995 100644
--- a/extensions/servlet/runtime/src/main/java/org/apache/camel/quarkus/servlet/runtime/CamelServletConfig.java
+++ b/extensions/servlet/runtime/src/main/java/org/apache/camel/quarkus/servlet/runtime/CamelServletConfig.java
@@ -64,6 +64,33 @@ public final class CamelServletConfig {
         @ConfigItem(defaultValue = DEFAULT_SERVLET_NAME)
         public String servletName;
 
+        /**
+         * Sets the loadOnStartup priority on the Servlet. A loadOnStartup is a value greater than or equal to zero,
+         * indicates to the container the initialization priority of the Servlet. If loadOnStartup is a negative
+         * integer, the Servlet is initialized lazily.
+         */
+        @ConfigItem(defaultValue = "-1")
+        public Integer loadOnStartup;
+
+        /**
+         * Enables Camel to benefit from asynchronous Servlet support.
+         */
+        @ConfigItem(defaultValue = "false")
+        public boolean async;
+
+        /**
+         * When set to {@code true} used in conjunction with {@code quarkus.camel.servlet.async = true}, this will force
+         * route processing to run synchronously.
+         */
+        @ConfigItem(defaultValue = "false")
+        public boolean forceAwait;
+
+        /**
+         * The name of a bean to configure an optional custom thread pool for handling Camel Servlet processing.
+         */
+        @ConfigItem
+        public Optional<String> executorRef;
+
         /**
          * Servlet multipart request configuration.
          */
diff --git a/integration-tests/servlet/src/main/java/org/apache/camel/quarkus/component/servlet/CamelRoute.java b/integration-tests/servlet/src/main/java/org/apache/camel/quarkus/component/servlet/CamelRoute.java
index aabc992357..6c8c117c35 100644
--- a/integration-tests/servlet/src/main/java/org/apache/camel/quarkus/component/servlet/CamelRoute.java
+++ b/integration-tests/servlet/src/main/java/org/apache/camel/quarkus/component/servlet/CamelRoute.java
@@ -18,6 +18,8 @@ package org.apache.camel.quarkus.component.servlet;
 
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import org.apache.camel.Processor;
 import org.apache.camel.builder.RouteBuilder;
 
 @ApplicationScoped
@@ -25,6 +27,10 @@ public class CamelRoute extends RouteBuilder {
     @Inject
     MultiPartProcessor multiPartProcessor;
 
+    @Inject
+    @Named("servletConfigInfoProcessor")
+    Processor servletConfigInfoProcessor;
+
     @Override
     public void configure() {
         // by default the camel-quarkus-rest component sets platform-http
@@ -43,11 +49,14 @@ public class CamelRoute extends RouteBuilder {
         from("servlet://hello?matchOnUriPrefix=true")
                 .setBody(constant("GET: /hello"));
 
-        from("servlet://custom?servletName=my-named-servlet")
+        from("servlet://configuration")
+                .process(servletConfigInfoProcessor);
+
+        from("servlet://custom?servletName=custom-servlet")
                 .setBody(constant("GET: /custom"));
 
-        from("servlet://favorite?servletName=my-favorite-servlet")
-                .setBody(constant("GET: /favorite"));
+        from("servlet://named?servletName=my-named-servlet")
+                .setBody(constant("GET: /my-named-servlet"));
 
         from("direct:echoMethodPath")
                 .setBody().simple("${header.CamelHttpMethod}: ${header.CamelServletContextPath}");
@@ -55,8 +64,23 @@ public class CamelRoute extends RouteBuilder {
         from("servlet://multipart/default?attachmentMultipartBinding=true")
                 .process(multiPartProcessor);
 
-        from("servlet://multipart?servletName=my-named-servlet&attachmentMultipartBinding=true")
+        from("servlet://multipart?servletName=multipart-servlet&attachmentMultipartBinding=true")
                 .process(multiPartProcessor);
-    }
 
+        from("servlet://eager-init?servletName=eager-init-servlet&matchOnUriPrefix=true")
+                .setHeader("servletName").constant("eager-init-servlet")
+                .process(servletConfigInfoProcessor);
+
+        from("servlet://async?servletName=async-servlet&matchOnUriPrefix=true")
+                .setHeader("servletName").constant("async-servlet")
+                .process(servletConfigInfoProcessor);
+
+        from("servlet://force-await?servletName=sync-async-servlet&matchOnUriPrefix=true")
+                .setHeader("servletName").constant("sync-async-servlet")
+                .process(servletConfigInfoProcessor);
+
+        from("servlet://execute?servletName=custom-executor-servlet&matchOnUriPrefix=true")
+                .setHeader("servletName").constant("custom-executor-servlet")
+                .process(servletConfigInfoProcessor);
+    }
 }
diff --git a/integration-tests/servlet/src/main/java/org/apache/camel/quarkus/component/servlet/ServletProducers.java b/integration-tests/servlet/src/main/java/org/apache/camel/quarkus/component/servlet/ServletProducers.java
new file mode 100644
index 0000000000..292be43a1e
--- /dev/null
+++ b/integration-tests/servlet/src/main/java/org/apache/camel/quarkus/component/servlet/ServletProducers.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.servlet;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import io.undertow.servlet.api.Deployment;
+import io.undertow.servlet.api.ServletInfo;
+import io.undertow.servlet.core.ManagedServlet;
+import io.undertow.servlet.core.ManagedServlets;
+import io.undertow.servlet.spec.ServletContextImpl;
+import io.vertx.core.json.JsonObject;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Named;
+import jakarta.inject.Singleton;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpServletRequest;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.spi.MimeType;
+
+import static org.apache.camel.quarkus.servlet.runtime.CamelServletConfig.ServletConfig.DEFAULT_SERVLET_NAME;
+
+@ApplicationScoped
+public class ServletProducers {
+    @Singleton
+    @Named("customServletExecutor")
+    public Executor customServletExecutor() {
+        return Executors.newSingleThreadExecutor(r -> new Thread(r, "custom-executor"));
+    }
+
+    @Singleton
+    @Named("servletConfigInfoProcessor")
+    public Processor servletConfigInfoProcessor() {
+        return exchange -> {
+            JsonObject json = new JsonObject();
+            Message message = exchange.getMessage();
+            HttpServletRequest request = message.getHeader(Exchange.HTTP_SERVLET_REQUEST, HttpServletRequest.class);
+            String servletName = message.getHeader("servletName", DEFAULT_SERVLET_NAME, String.class);
+            ServletContext servletContext = request.getServletContext();
+            Deployment deployment = ((ServletContextImpl) servletContext).getDeployment();
+            ManagedServlets servlets = deployment.getServlets();
+            ManagedServlet servlet = servlets.getManagedServlet(servletName);
+            ServletInfo servletInfo = servlet.getServletInfo();
+
+            json.put("isAsync", request.isAsyncSupported());
+            json.put("threadName", Thread.currentThread().getName());
+            json.put("loadOnStartup", servletInfo.getLoadOnStartup());
+            json.put("initParams", servletInfo.getInitParams());
+
+            message.setHeader(Exchange.CONTENT_TYPE, MimeType.JSON.type());
+            message.setBody(json.encode());
+        };
+    }
+}
diff --git a/integration-tests/servlet/src/main/resources/application.properties b/integration-tests/servlet/src/main/resources/application.properties
index 0251262894..06920af73f 100644
--- a/integration-tests/servlet/src/main/resources/application.properties
+++ b/integration-tests/servlet/src/main/resources/application.properties
@@ -15,17 +15,39 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-#
-# Quarkus :: Camel :: Servlet
-#
-quarkus.camel.servlet.url-patterns=/folder-1/*,/folder-2/*
-
-quarkus.camel.servlet.my-named-servlet.url-patterns=/my-named-folder/*
-quarkus.camel.servlet.my-named-servlet.servlet-class=org.apache.camel.quarkus.component.servlet.CustomServlet
-quarkus.camel.servlet.my-named-servlet.multipart.location=${java.io.tmpdir}/my-named-servlet
-quarkus.camel.servlet.my-named-servlet.multipart.max-file-size=11
-quarkus.camel.servlet.my-named-servlet.multipart.max-request-size=11
-quarkus.camel.servlet.my-named-servlet.multipart.file-size-threshold=5
-
-quarkus.camel.servlet.ignored-key.servlet-name=my-favorite-servlet
-quarkus.camel.servlet.ignored-key.url-patterns=/my-favorite-folder/*
+# Default servlet configuration
+quarkus.camel.servlet.url-patterns=/folder-1/*,/folder-2/*,/debug/*
+
+# Explicit definition of the servlet name
+quarkus.camel.servlet.ignored-key.servlet-name=my-named-servlet
+quarkus.camel.servlet.ignored-key.url-patterns=/my-named-folder/*
+
+# Custom servlet class
+quarkus.camel.servlet.custom-servlet.url-patterns=/my-custom-folder/*
+quarkus.camel.servlet.custom-servlet.servlet-class=org.apache.camel.quarkus.component.servlet.CustomServlet
+
+# Servlet configured with multipart support
+quarkus.camel.servlet.multipart-servlet.url-patterns=/multipart-servlet/*
+quarkus.camel.servlet.multipart-servlet.multipart.location=${java.io.tmpdir}/my-named-servlet
+quarkus.camel.servlet.multipart-servlet.multipart.max-file-size=11
+quarkus.camel.servlet.multipart-servlet.multipart.max-request-size=11
+quarkus.camel.servlet.multipart-servlet.multipart.file-size-threshold=5
+
+# Servlet configured for eager initialization
+quarkus.camel.servlet.eager-init-servlet.url-patterns=/eager-init-servlet/*
+quarkus.camel.servlet.eager-init-servlet.load-on-startup=1
+
+# Servlet configured for async processing
+quarkus.camel.servlet.async-servlet.url-patterns=/async-servlet/*
+quarkus.camel.servlet.async-servlet.async=true
+
+# Servlet configured for async + sync processing
+quarkus.camel.servlet.sync-async-servlet.url-patterns=/sync-async-servlet/*
+quarkus.camel.servlet.sync-async-servlet.async=true
+quarkus.camel.servlet.sync-async-servlet.force-await=true
+
+# Servlet with custom executor
+quarkus.camel.servlet.custom-executor-servlet.url-patterns=/custom-executor/*
+quarkus.camel.servlet.custom-executor-servlet.async=true
+quarkus.camel.servlet.custom-executor-servlet.executor-ref=customServletExecutor
+
diff --git a/integration-tests/servlet/src/test/java/org/apache/camel/quarkus/component/servlet/CamelServletTest.java b/integration-tests/servlet/src/test/java/org/apache/camel/quarkus/component/servlet/CamelServletTest.java
index 593e56cb9b..73bdd78dbe 100644
--- a/integration-tests/servlet/src/test/java/org/apache/camel/quarkus/component/servlet/CamelServletTest.java
+++ b/integration-tests/servlet/src/test/java/org/apache/camel/quarkus/component/servlet/CamelServletTest.java
@@ -20,36 +20,52 @@ import java.nio.charset.StandardCharsets;
 
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
-import org.hamcrest.core.IsEqual;
 import org.junit.jupiter.api.Test;
 
+import static org.hamcrest.Matchers.anEmptyMap;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
 import static org.hamcrest.Matchers.oneOf;
+import static org.hamcrest.Matchers.startsWith;
+import static org.hamcrest.core.IsEqual.equalTo;
 
 @QuarkusTest
 public class CamelServletTest {
+    @Test
+    public void defaultConfiguration() {
+        RestAssured.get("/debug/configuration")
+                .then()
+                .body(
+                        "isAsync", equalTo(false),
+                        "threadName", startsWith("executor-thread"),
+                        "initParams", anEmptyMap(),
+                        "loadOnStartup", nullValue());
+    }
 
     @Test
     public void multiplePaths() {
-        RestAssured.when().get("/folder-1/rest-get").then().body(IsEqual.equalTo("GET: /rest-get"));
-        RestAssured.when().get("/folder-2/rest-get").then().body(IsEqual.equalTo("GET: /rest-get"));
-        RestAssured.when().post("/folder-1/rest-post").then().body(IsEqual.equalTo("POST: /rest-post"));
-        RestAssured.when().post("/folder-2/rest-post").then().body(IsEqual.equalTo("POST: /rest-post"));
-        RestAssured.when().get("/folder-1/hello").then().body(IsEqual.equalTo("GET: /hello"));
-        RestAssured.when().get("/folder-2/hello").then().body(IsEqual.equalTo("GET: /hello"));
+        RestAssured.get("/folder-1/rest-get").then().body(equalTo("GET: /rest-get"));
+        RestAssured.get("/folder-2/rest-get").then().body(equalTo("GET: /rest-get"));
+        RestAssured.post("/folder-1/rest-post").then().body(equalTo("POST: /rest-post"));
+        RestAssured.post("/folder-2/rest-post").then().body(equalTo("POST: /rest-post"));
+        RestAssured.get("/folder-1/hello").then().body(equalTo("GET: /hello"));
+        RestAssured.get("/folder-2/hello").then().body(equalTo("GET: /hello"));
     }
 
     @Test
-    public void namedWithservletClass() {
-        RestAssured.when().get("/my-named-folder/custom").then()
-                .body(IsEqual.equalTo("GET: /custom"))
-                .and().header("x-servlet-class-name", CustomServlet.class.getName());
+    public void namedWithServletClass() {
+        RestAssured.get("/my-custom-folder/custom")
+                .then()
+                .body(equalTo("GET: /custom"))
+                .and()
+                .header("x-servlet-class-name", CustomServlet.class.getName());
     }
 
     @Test
     public void ignoredKey() {
-        RestAssured.when().get("/my-favorite-folder/favorite").then()
-                .body(IsEqual.equalTo("GET: /favorite"));
+        RestAssured.get("/my-named-folder/named")
+                .then()
+                .body(equalTo("GET: /my-named-servlet"));
     }
 
     @Test
@@ -76,9 +92,54 @@ public class CamelServletTest {
         // Request body exceeding the limits defined on the multipart config
         RestAssured.given()
                 .multiPart("test-multipart", "file", body.repeat(10).getBytes(StandardCharsets.UTF_8))
-                .post("/my-named-folder/multipart")
+                .post("/multipart-servlet/multipart")
                 .then()
                 // TODO: Expect 413 only - https://github.com/apache/camel-quarkus/issues/5830
                 .statusCode(oneOf(413, 500));
     }
+
+    @Test
+    public void eagerInitServlet() {
+        RestAssured.get("/eager-init-servlet/eager-init")
+                .then()
+                .body(
+                        "isAsync", equalTo(false),
+                        "threadName", startsWith("executor-thread"),
+                        "initParams", anEmptyMap(),
+                        "loadOnStartup", equalTo(1));
+    }
+
+    @Test
+    public void asyncServlet() {
+        RestAssured.get("/async-servlet/async")
+                .then()
+                .body(
+                        "isAsync", equalTo(true),
+                        "threadName", startsWith("executor-thread"),
+                        "initParams.async", equalTo("true"),
+                        "loadOnStartup", nullValue());
+    }
+
+    @Test
+    public void asyncWithForceAwaitServlet() {
+        RestAssured.get("/sync-async-servlet/force-await")
+                .then()
+                .body(
+                        "isAsync", equalTo(true),
+                        "threadName", startsWith("executor-thread"),
+                        "initParams.async", equalTo("true"),
+                        "initParams.forceAwait", equalTo("true"),
+                        "loadOnStartup", nullValue());
+    }
+
+    @Test
+    public void asyncWithCustomExecutor() {
+        RestAssured.get("/custom-executor/execute/get")
+                .then()
+                .body(
+                        "isAsync", equalTo(true),
+                        "threadName", equalTo("custom-executor"),
+                        "initParams.async", equalTo("true"),
+                        "loadOnStartup", nullValue());
+    }
 }