You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/10/17 19:39:48 UTC

[camel] branch main updated: CAMEL-19994: camel-platform-http-vertx - Allow access to vertx request object. Add support for pooled exchange like we have in other http components. (#11739)

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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new fb21cbd87ac CAMEL-19994: camel-platform-http-vertx - Allow access to vertx request object. Add support for pooled exchange like we have in other http components. (#11739)
fb21cbd87ac is described below

commit fb21cbd87ac6b01a3d74fd4c6685798f9a594b06
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Oct 17 21:39:41 2023 +0200

    CAMEL-19994: camel-platform-http-vertx - Allow access to vertx request object. Add support for pooled exchange like we have in other http components. (#11739)
---
 components/camel-platform-http-vertx/pom.xml       |   6 +
 .../src/main/docs/platform-http-vertx.adoc         |  20 ++++
 .../component/platform/http/vertx/HttpMessage.java |  66 +++++++++++
 .../http/vertx/VertxPlatformHttpConsumer.java      |  16 ++-
 .../http/vertx/VertxPlatformHttpEngineTest.java    |  30 +++++
 .../vertx/VertxPlatformHttpPooledExchangeTest.java | 126 +++++++++++++++++++++
 6 files changed, 259 insertions(+), 5 deletions(-)

diff --git a/components/camel-platform-http-vertx/pom.xml b/components/camel-platform-http-vertx/pom.xml
index ec47987865f..200bdc6cd3c 100644
--- a/components/camel-platform-http-vertx/pom.xml
+++ b/components/camel-platform-http-vertx/pom.xml
@@ -108,6 +108,12 @@
             <version>${wiremock-version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <version>${awaitility-version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc b/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc
index e4f7ac16dfb..118225964ff 100644
--- a/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc
+++ b/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc
@@ -76,3 +76,23 @@ from("platform-http:proxy")
     .toD("http://"
         + "${headers." + Exchange.HTTP_HOST + "}");
 ----
+
+== Access to Request and Response
+
+The Vertx HTTP server has its own API abstraction for HTTP request/response objects which you can access via
+Camel `HttpMessage` as shown in the custom `Processor` below :
+
+[source,java]
+----
+.process(exchange -> {
+    // grab message as HttpMessage
+    HttpMessage message = exchange.getMessage(HttpMessage.class);
+    // use getRequest() / getResponse() to access Vertx directly
+    // you can add custom headers
+    message.getResponse().putHeader("beer", "Heineken");
+    // also access request details and use that in the code
+    String p = message.getRequest().path();
+    message.setBody("request path: " + p);
+});
+----
+
diff --git a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/HttpMessage.java b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/HttpMessage.java
new file mode 100644
index 00000000000..cece097b89c
--- /dev/null
+++ b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/HttpMessage.java
@@ -0,0 +1,66 @@
+/*
+ * 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.component.platform.http.vertx;
+
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpServerResponse;
+import org.apache.camel.Exchange;
+import org.apache.camel.support.DefaultMessage;
+import org.apache.camel.util.ObjectHelper;
+
+public class HttpMessage extends DefaultMessage {
+
+    private HttpServerRequest request;
+    private HttpServerResponse response;
+
+    public HttpMessage(Exchange exchange, HttpServerRequest request, HttpServerResponse response) {
+        super(exchange);
+        init(exchange, request, response);
+    }
+
+    public void init(Exchange exchange, HttpServerRequest request, HttpServerResponse response) {
+        setExchange(exchange);
+        this.request = request;
+        this.response = response;
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        request = null;
+        response = null;
+    }
+
+    public HttpServerRequest getRequest() {
+        return request;
+    }
+
+    public HttpServerResponse getResponse() {
+        return response;
+    }
+
+    @Override
+    public HttpMessage newInstance() {
+        return new HttpMessage(getExchange(), request, response);
+    }
+
+    @Override
+    public String toString() {
+        // do not use toString on HTTP message
+        return "HttpMessage@" + ObjectHelper.getIdentityHashCode(this);
+    }
+}
diff --git a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
index 4ab809ec411..4b96d86c504 100644
--- a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
+++ b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
@@ -230,7 +230,16 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
         final Exchange exchange = createExchange(false);
         exchange.setPattern(ExchangePattern.InOut);
 
-        final Message in = toCamelMessage(ctx, exchange);
+        // reuse existing http message if pooled
+        Message in = exchange.getIn();
+        if (in instanceof HttpMessage hm) {
+            hm.init(exchange, ctx.request(), ctx.response());
+        } else {
+            in = new HttpMessage(exchange, ctx.request(), ctx.response());
+            exchange.setMessage(in);
+        }
+        populateCamelMessage(ctx, exchange, in);
+
         final String charset = ctx.parsedHeaders().contentType().parameter("charset");
         if (charset != null) {
             exchange.setProperty(ExchangePropertyKey.CHARSET_NAME, charset);
@@ -245,9 +254,7 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
         return exchange;
     }
 
-    protected Message toCamelMessage(RoutingContext ctx, Exchange exchange) {
-        final Message result = exchange.getIn();
-
+    protected void populateCamelMessage(RoutingContext ctx, Exchange exchange, Message result) {
         final HeaderFilterStrategy headerFilterStrategy = getEndpoint().getHeaderFilterStrategy();
         populateCamelHeaders(ctx, result.getHeaders(), exchange, headerFilterStrategy);
         final String mimeType = ctx.parsedHeaders().contentType().value();
@@ -281,7 +288,6 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
                 result.setBody(null);
             }
         }
-        return result;
     }
 
     protected void populateAttachments(List<FileUpload> uploads, Message message) {
diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpEngineTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpEngineTest.java
index 683b2327e1d..633826ad959 100644
--- a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpEngineTest.java
+++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpEngineTest.java
@@ -846,6 +846,36 @@ public class VertxPlatformHttpEngineTest {
         }
     }
 
+    @Test
+    public void testVertxRequestResponseObjects() throws Exception {
+        final CamelContext context = createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("platform-http:/vertx/objects")
+                            .process(exchange -> {
+                                HttpMessage message = exchange.getMessage(HttpMessage.class);
+                                String p = message.getRequest().path();
+                                message.getResponse().putHeader("beer", "Heineken");
+                                message.setBody("request path: " + p);
+                            });
+                }
+            });
+
+            context.start();
+
+            get("/vertx/objects")
+                    .then()
+                    .statusCode(200)
+                    .header("beer", "Heineken")
+                    .body(is("request path: /vertx/objects"));
+        } finally {
+            context.stop();
+        }
+    }
+
     static CamelContext createCamelContext() throws Exception {
         return createCamelContext(null);
     }
diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpPooledExchangeTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpPooledExchangeTest.java
new file mode 100644
index 00000000000..05083e3a2f3
--- /dev/null
+++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpPooledExchangeTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.component.platform.http.vertx;
+
+import java.util.concurrent.TimeUnit;
+
+import io.restassured.RestAssured;
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.platform.http.PlatformHttpComponent;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.PooledExchangeFactory;
+import org.apache.camel.impl.engine.PooledProcessorExchangeFactory;
+import org.apache.camel.spi.PooledObjectFactory;
+import org.apache.camel.test.AvailablePortFinder;
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.get;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class VertxPlatformHttpPooledExchangeTest {
+
+    @Test
+    public void testEngineSetup() throws Exception {
+        final CamelContext context = createCamelContext();
+        try {
+            context.start();
+
+            assertThat(VertxPlatformHttpRouter.lookup(context)).isNotNull();
+            assertThat(context.getComponent("platform-http")).isInstanceOfSatisfying(PlatformHttpComponent.class, component -> {
+                assertThat(component.getEngine()).isInstanceOf(VertxPlatformHttpEngine.class);
+            });
+
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void testPooledExchange() throws Exception {
+        final CamelContext context = createCamelContext();
+
+        try {
+            context.addRoutes(new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("platform-http:/vertx/pooled")
+                            .transform().simple("Bye World");
+                }
+            });
+
+            context.start();
+
+            for (int i = 0; i < 3; i++) {
+                get("/vertx/pooled")
+                        .then()
+                        .statusCode(200)
+                        .body(is("Bye World"));
+            }
+
+            MockEndpoint.assertIsSatisfied(context);
+
+            Awaitility.waitAtMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+                PooledObjectFactory.Statistics stat
+                        = context.getCamelContextExtension().getExchangeFactoryManager().getStatistics();
+                assertEquals(1, stat.getCreatedCounter());
+                assertEquals(2, stat.getAcquiredCounter());
+                assertEquals(3, stat.getReleasedCounter());
+                assertEquals(0, stat.getDiscardedCounter());
+            });
+        } finally {
+            context.stop();
+        }
+    }
+
+    static CamelContext createCamelContext() throws Exception {
+        return createCamelContext(null);
+    }
+
+    private static CamelContext createCamelContext(ServerConfigurationCustomizer customizer) throws Exception {
+        int port = AvailablePortFinder.getNextAvailable();
+        VertxPlatformHttpServerConfiguration conf = new VertxPlatformHttpServerConfiguration();
+        conf.setBindPort(port);
+
+        RestAssured.port = port;
+
+        if (customizer != null) {
+            customizer.customize(conf);
+        }
+
+        CamelContext context = new DefaultCamelContext();
+        context.addService(new VertxPlatformHttpServer(conf));
+
+        ExtendedCamelContext ecc = context.getCamelContextExtension();
+
+        ecc.setExchangeFactory(new PooledExchangeFactory());
+        ecc.setProcessorExchangeFactory(new PooledProcessorExchangeFactory());
+        ecc.getExchangeFactory().setStatisticsEnabled(true);
+        ecc.getProcessorExchangeFactory().setStatisticsEnabled(true);
+
+        return context;
+    }
+
+    interface ServerConfigurationCustomizer {
+        void customize(VertxPlatformHttpServerConfiguration configuration);
+    }
+}