diff --git a/micronaut-camunda-bpm-feature/build.gradle b/micronaut-camunda-bpm-feature/build.gradle index 19935c71..c26f54f0 100644 --- a/micronaut-camunda-bpm-feature/build.gradle +++ b/micronaut-camunda-bpm-feature/build.gradle @@ -44,7 +44,7 @@ dependencies { // REST API + Webapps implementation("com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider") - implementation("org.camunda.bpm:camunda-engine-rest:$camundaVersion:classes") + implementation("org.camunda.bpm:camunda-engine-rest-jaxrs2:$camundaVersion") implementation("org.camunda.bpm.webapp:camunda-webapp-webjar:$camundaVersion") implementation("org.glassfish.jersey.inject:jersey-hk2:$jerseyVersion") implementation("org.glassfish.jersey.containers:jersey-container-servlet-core:$jerseyVersion") diff --git a/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/build.gradle b/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/build.gradle index cadb3e1c..40e61a54 100644 --- a/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/build.gradle +++ b/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/build.gradle @@ -24,6 +24,8 @@ dependencies { kaptTest("io.micronaut:micronaut-inject-java:$micronautVersion") testCompileOnly("io.micronaut.servlet:micronaut-http-server-jetty") + testImplementation("org.junit.jupiter:junit-jupiter-params") + testImplementation("org.assertj:assertj-core") testImplementation("io.micronaut:micronaut-http-client") testImplementation("org.eclipse.jetty:jetty-server:$jettyVersion") testImplementation("org.eclipse.jetty:jetty-servlet:$jettyVersion") diff --git a/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/src/test/kotlin/info/novatec/micronaut/camunda/bpm/feature/test/JettyRestTest.kt b/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/src/test/kotlin/info/novatec/micronaut/camunda/bpm/feature/test/JettyRestTest.kt index ff7a9b80..c2aedf78 100644 --- a/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/src/test/kotlin/info/novatec/micronaut/camunda/bpm/feature/test/JettyRestTest.kt +++ b/micronaut-camunda-bpm-feature/jetty-webapp-and-rest/src/test/kotlin/info/novatec/micronaut/camunda/bpm/feature/test/JettyRestTest.kt @@ -22,9 +22,15 @@ import io.micronaut.http.client.HttpClient import io.micronaut.http.client.annotation.Client import io.micronaut.test.extensions.junit5.annotation.MicronautTest import jakarta.inject.Inject +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.within import org.eclipse.jetty.server.Server import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource +import java.time.Duration +import java.time.Instant /** * Test the REST API on Jetty. @@ -49,4 +55,30 @@ class JettyRestTest { assertEquals("""[{"name":"default"}]""", body) } + + @ParameterizedTest + @ValueSource(longs = [0, 2000, 5000]) + fun `long polling`(duration: Long) { + val request: HttpRequest = HttpRequest.POST( + configuration.rest.contextPath + "/external-task/fetchAndLock", + """ + { + "maxTasks": 1, + "workerId": "aWorkerId", + "asyncResponseTimeout": $duration, + "topics": [ + { + "topicName": "aTopicName", + "lockDuration": 1000 + } + ] + } + """ + ) + val start = Instant.now() + val body = client.toBlocking().retrieve(request) + + assertEquals("[]", body) + assertThat(Duration.between(start, Instant.now()).toMillis()).isCloseTo(duration, within(500L)) + } } diff --git a/micronaut-camunda-bpm-feature/src/main/java/info/novatec/micronaut/camunda/bpm/feature/JettyServerCustomizer.java b/micronaut-camunda-bpm-feature/src/main/java/info/novatec/micronaut/camunda/bpm/feature/JettyServerCustomizer.java index 98c587a8..078a66f8 100644 --- a/micronaut-camunda-bpm-feature/src/main/java/info/novatec/micronaut/camunda/bpm/feature/JettyServerCustomizer.java +++ b/micronaut-camunda-bpm-feature/src/main/java/info/novatec/micronaut/camunda/bpm/feature/JettyServerCustomizer.java @@ -22,9 +22,10 @@ import jakarta.inject.Singleton; import org.camunda.bpm.admin.impl.web.bootstrap.AdminContainerBootstrap; import org.camunda.bpm.cockpit.impl.web.bootstrap.CockpitContainerBootstrap; -import org.camunda.bpm.engine.rest.security.auth.ProcessEngineAuthenticationFilter; import org.camunda.bpm.engine.rest.filter.CacheControlFilter; import org.camunda.bpm.engine.rest.filter.EmptyBodyFilter; +import org.camunda.bpm.engine.rest.impl.FetchAndLockContextListener; +import org.camunda.bpm.engine.rest.security.auth.ProcessEngineAuthenticationFilter; import org.camunda.bpm.tasklist.impl.web.bootstrap.TasklistContainerBootstrap; import org.camunda.bpm.webapp.impl.engine.ProcessEnginesFilter; import org.camunda.bpm.webapp.impl.security.auth.AuthenticationFilter; @@ -50,11 +51,11 @@ import java.util.HashMap; import java.util.Map; -import static java.util.Collections.*; -import static javax.servlet.DispatcherType.*; +import static java.util.Collections.singletonMap; +import static javax.servlet.DispatcherType.REQUEST; /** - * Using Micronaut Servlet with Jetty to run the REST API as a servlet. + * Using Micronaut Servlet with Jetty to run the REST API/Webapps as a servlet. * * see https://micronaut-projects.github.io/micronaut-servlet/latest/guide/#jetty * @@ -84,6 +85,13 @@ public Server onCreated(BeanCreatedEvent event) { ServletContextHandler restServletContextHandler = new ServletContextHandler(); restServletContextHandler.setContextPath(configuration.getRest().getContextPath()); restServletContextHandler.addServlet(new ServletHolder(new ServletContainer(new RestApp())), "/*"); + restServletContextHandler.addEventListener(new ServletContextListener() { + @Override + public void contextInitialized(ServletContextEvent sce) { + // Required for long polling + new FetchAndLockContextListener().contextInitialized(sce); + } + }); if (configuration.getRest().isBasicAuthEnabled()) { // see https://docs.camunda.org/manual/latest/reference/rest/overview/authentication/ @@ -167,9 +175,6 @@ public void contextInitialized(ServletContextEvent sce) { registerFilter("CacheControlFilter", CacheControlFilter.class, "/api/*", "/app/*"); } - @Override - public void contextDestroyed(ServletContextEvent sce) {} - protected Map getCsrfInitParams(){ Map initParams = new HashMap<>();