This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 3a9b3a2 CAMEL-16220: camel-vertx-http - optimize producer when sending to uri without any change 3a9b3a2 is described below commit 3a9b3a2f65f8734533ed73e588e4ec84f4b728aa Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Feb 17 08:17:13 2021 +0100 CAMEL-16220: camel-vertx-http - optimize producer when sending to uri without any change --- .../vertx/http/DefaultVertxHttpBinding.java | 51 ++++++++++------ .../component/vertx/http/VertxHttpHelper.java | 24 ++------ .../component/vertx/http/VertxHttpProducer.java | 24 ++++---- .../vertx/http/VertxHttpProducerLoadTest.java | 67 ++++++++-------------- 4 files changed, 75 insertions(+), 91 deletions(-) diff --git a/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java b/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java index 8c955b5..959486e 100644 --- a/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java +++ b/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/DefaultVertxHttpBinding.java @@ -21,6 +21,7 @@ import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import io.vertx.core.AsyncResult; import io.vertx.core.MultiMap; @@ -44,6 +45,8 @@ import static org.apache.camel.component.vertx.http.VertxHttpConstants.CONTENT_T public class DefaultVertxHttpBinding implements VertxHttpBinding { + private volatile Map<String, Object> defaultQueryParams; + @Override public HttpRequest<Buffer> prepareHttpRequest(VertxHttpEndpoint endpoint, Exchange exchange) throws Exception { VertxHttpConfiguration configuration = endpoint.getConfiguration(); @@ -51,8 +54,14 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { // Resolve query string from the HTTP_QUERY header or default to those provided on the endpoint HTTP URI String queryString = VertxHttpHelper.resolveQueryString(exchange); + Map<String, Object> queryParams = null; if (ObjectHelper.isEmpty(queryString)) { + // use default query string from endpoint configuration queryString = configuration.getHttpUri().getQuery(); + if (defaultQueryParams == null) { + defaultQueryParams = URISupport.parseQuery(queryString); + } + queryParams = defaultQueryParams; } // Determine the HTTP method to use if not specified in the HTTP_METHOD header @@ -83,7 +92,9 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { // Configure query params if (ObjectHelper.isNotEmpty(queryString)) { - Map<String, Object> queryParams = URISupport.parseQuery(queryString); + if (queryParams == null) { + queryParams = URISupport.parseQuery(queryString); + } for (Map.Entry<String, Object> entry : queryParams.entrySet()) { request.addQueryParam(entry.getKey(), entry.getValue().toString()); } @@ -111,10 +122,13 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { @Override public void populateRequestHeaders(Exchange exchange, HttpRequest<Buffer> request, HeaderFilterStrategy strategy) { + // optimize to use add on MultiMap as putHeader on request does a remove/add + MultiMap headers = request.headers(); + // Ensure the Content-Type header is always added if the corresponding exchange header is present String contentType = ExchangeHelper.getContentType(exchange); if (ObjectHelper.isNotEmpty(contentType)) { - request.putHeader(Exchange.CONTENT_TYPE, contentType); + headers.add(Exchange.CONTENT_TYPE, contentType); } // Transfer exchange headers to the HTTP request while applying the filter strategy @@ -125,7 +139,7 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { Object headerValue = entry.getValue(); if (!strategy.applyFilterToCamelHeaders(key, headerValue, exchange)) { String str = tc.convertTo(String.class, headerValue); - request.putHeader(key, str); + headers.add(key, str); } } } @@ -157,21 +171,24 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { message.setHeader(Exchange.HTTP_RESPONSE_TEXT, response.statusMessage()); MultiMap headers = response.headers(); + headers.forEach(new Consumer<Map.Entry<String, String>>() { + boolean found = false; - boolean found = false; - for (String headerName : headers.names()) { - String name = headerName; - String value = headers.get(headerName); - if (!found && name.equalsIgnoreCase("content-type")) { - found = true; - name = Exchange.CONTENT_TYPE; - exchange.setProperty(Exchange.CHARSET_NAME, IOHelper.getCharsetNameFromContentType(value)); - } - Object extracted = HttpHelper.extractHttpParameterValue(value); - if (strategy != null && !strategy.applyFilterToExternalHeaders(name, extracted, exchange)) { - HttpHelper.appendHeader(message.getHeaders(), name, extracted); + @Override + public void accept(Map.Entry<String, String> entry) { + String name = entry.getKey(); + String value = entry.getValue(); + if (!found && name.equalsIgnoreCase("content-type")) { + found = true; + name = Exchange.CONTENT_TYPE; + exchange.setProperty(Exchange.CHARSET_NAME, IOHelper.getCharsetNameFromContentType(value)); + } + Object extracted = HttpHelper.extractHttpParameterValue(value); + if (strategy != null && !strategy.applyFilterToExternalHeaders(name, extracted, exchange)) { + HttpHelper.appendHeader(message.getHeaders(), name, extracted); + } } - } + }); } @Override @@ -181,7 +198,7 @@ public class DefaultVertxHttpBinding implements VertxHttpBinding { Buffer responseBody = result.body(); if (responseBody != null) { String contentType = result.getHeader(Exchange.CONTENT_TYPE); - if (VertxHttpHelper.isContentTypeMatching(CONTENT_TYPE_JAVA_SERIALIZED_OBJECT, contentType)) { + if (CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) { boolean transferException = endpoint.getConfiguration().isTransferException(); boolean allowJavaSerializedObject = endpoint.getComponent().isAllowJavaSerializedObject(); diff --git a/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java b/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java index 43b3e9a..ecb2f52 100644 --- a/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java +++ b/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpHelper.java @@ -34,7 +34,6 @@ import io.vertx.core.net.TCPSSLOptions; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.http.base.HttpHelper; -import org.apache.camel.support.ExchangeHelper; import org.apache.camel.support.jsse.KeyManagersParameters; import org.apache.camel.support.jsse.SSLContextParameters; import org.apache.camel.support.jsse.TrustManagersParameters; @@ -129,27 +128,16 @@ public final class VertxHttpHelper { } /** - * Verifies whether the Content-Type exchange header value matches an expected value - */ - public static boolean isContentTypeMatching(Exchange exchange, String expected) { - return isContentTypeMatching(expected, ExchangeHelper.getContentType(exchange)); - } - - /** - * Verifies whether the expected Content-Type value matches an expected value - */ - public static boolean isContentTypeMatching(String expected, String actual) { - return actual != null && expected.equals(actual); - } - - /** * Writes the given target object to an {@link ObjectOutputStream} */ public static void writeObjectToStream(OutputStream stream, Object target) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(stream); - oos.writeObject(target); - oos.flush(); - IOHelper.close(oos); + try { + oos.writeObject(target); + oos.flush(); + } finally { + IOHelper.close(oos); + } } /** diff --git a/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java b/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java index 51e7412..e5a7df4 100644 --- a/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java +++ b/components/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpProducer.java @@ -33,7 +33,7 @@ import org.apache.camel.CamelExchangeException; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.support.DefaultAsyncProducer; -import org.apache.camel.util.ObjectHelper; +import org.apache.camel.support.MessageHelper; import org.apache.camel.util.URISupport; import static org.apache.camel.component.vertx.http.VertxHttpConstants.CONTENT_TYPE_FORM_URLENCODED; @@ -41,8 +41,11 @@ import static org.apache.camel.component.vertx.http.VertxHttpConstants.CONTENT_T public class VertxHttpProducer extends DefaultAsyncProducer { + private final VertxHttpBinding vertxHttpBinding; + public VertxHttpProducer(VertxHttpEndpoint endpoint) { super(endpoint); + this.vertxHttpBinding = endpoint.getConfiguration().getVertxHttpBinding(); } @Override @@ -59,7 +62,6 @@ public class VertxHttpProducer extends DefaultAsyncProducer { Message message = exchange.getMessage(); try { - VertxHttpBinding vertxHttpBinding = getEndpoint().getConfiguration().getVertxHttpBinding(); HttpRequest<Buffer> request = vertxHttpBinding.prepareHttpRequest(getEndpoint(), exchange); Handler<AsyncResult<HttpResponse<Buffer>>> resultHandler = createResultHandler(exchange, callback); @@ -67,6 +69,8 @@ public class VertxHttpProducer extends DefaultAsyncProducer { if (body == null) { request.send(resultHandler); } else { + String contentType = MessageHelper.getContentType(message); + // Handle the request body payload if (body instanceof MultiMap) { request.sendForm((MultiMap) body, resultHandler); @@ -76,27 +80,21 @@ public class VertxHttpProducer extends DefaultAsyncProducer { request.sendStream((ReadStream<Buffer>) body, resultHandler); } else if (body instanceof String) { // Try to extract URL encoded form data from the message body - if (VertxHttpHelper.isContentTypeMatching(exchange, CONTENT_TYPE_FORM_URLENCODED)) { + if (CONTENT_TYPE_FORM_URLENCODED.equals(contentType)) { MultiMap map = MultiMap.caseInsensitiveMultiMap(); Map<String, Object> formParams = URISupport.parseQuery((String) body); formParams.keySet().forEach(key -> map.add(key, String.valueOf(formParams.get(key)))); request.sendForm(map, resultHandler); } else { // Fallback to send as Buffer - Buffer buffer; - String charset = VertxHttpHelper.getCharsetFromExchange(exchange); - if (ObjectHelper.isNotEmpty(charset)) { - buffer = Buffer.buffer((String) body, charset); - } else { - buffer = Buffer.buffer((String) body); - } + Buffer buffer = VertxBufferConverter.toBuffer((String) body, exchange); request.sendBuffer(buffer, resultHandler); } } else if (body instanceof Buffer) { request.sendBuffer((Buffer) body, resultHandler); } else { // Handle x-java-serialized-object Content-Type - if (VertxHttpHelper.isContentTypeMatching(exchange, CONTENT_TYPE_JAVA_SERIALIZED_OBJECT)) { + if (CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) { if (!getComponent().isAllowJavaSerializedObject()) { throw new CamelExchangeException( "Content-type " + CONTENT_TYPE_JAVA_SERIALIZED_OBJECT + " is not allowed", exchange); @@ -126,9 +124,7 @@ public class VertxHttpProducer extends DefaultAsyncProducer { private Handler<AsyncResult<HttpResponse<Buffer>>> createResultHandler(Exchange exchange, AsyncCallback callback) { return response -> { try { - VertxHttpEndpoint endpoint = getEndpoint(); - VertxHttpBinding vertxHttpBinding = endpoint.getConfiguration().getVertxHttpBinding(); - vertxHttpBinding.handleResponse(endpoint, exchange, response); + vertxHttpBinding.handleResponse(getEndpoint(), exchange, response); } catch (Exception e) { exchange.setException(e); } finally { diff --git a/components/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpProducerLoadTest.java b/components/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpProducerLoadTest.java index 670e076..18701e13 100644 --- a/components/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpProducerLoadTest.java +++ b/components/camel-vertx-http/src/test/java/org/apache/camel/component/vertx/http/VertxHttpProducerLoadTest.java @@ -16,6 +16,12 @@ */ package org.apache.camel.component.vertx.http; +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Producer; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.util.StopWatch; @@ -46,51 +52,28 @@ public class VertxHttpProducerLoadTest extends VertxHttpTestSupport { @Test public void testProducerLoad() throws Exception { + Map<String, Object> map = new HashMap<>(); + for (int i = 0; i < 40; i++) { + map.put("mykey" + i, "myvalue" + i); + } + StopWatch watch = new StopWatch(); + + // do not use template but reuse exchange/producer to be light-weight + // and not create additional objects in the JVM as we want to analyze + // the "raw" http producer + Endpoint to = getMandatoryEndpoint("direct:echo"); + Producer producer = to.createProducer(); + producer.start(); + + Exchange exchange = to.createExchange(); + exchange.getMessage().setHeaders(map); for (int i = 0; i < 10000000; i++) { - fluentTemplate.to("direct:echo") - .withHeader("a", "aaa") - .withHeader("b", "bbb") - .withHeader("c", "ccc") - .withHeader("d", "ddd") - .withHeader("e", "eee") - .withHeader("f", "fff") - .withHeader("g", "ggg") - .withHeader("h", "hhh") - .withHeader("i", "iii") - .withHeader("j", "jjj") - .withHeader("a2", "aaa") - .withHeader("b2", "bbb") - .withHeader("c2", "ccc") - .withHeader("d2", "ddd") - .withHeader("e2", "eee") - .withHeader("f2", "fff") - .withHeader("g2", "ggg") - .withHeader("h2", "hhh") - .withHeader("i2", "iii") - .withHeader("j2", "jjj") - .withHeader("a3", "aaa") - .withHeader("b3", "bbb") - .withHeader("c3", "ccc") - .withHeader("d3", "ddd") - .withHeader("e3", "eee") - .withHeader("f3", "fff") - .withHeader("g3", "ggg") - .withHeader("h3", "hhh") - .withHeader("i3", "iii") - .withHeader("j3", "jjj") - .withHeader("a4", "aaa") - .withHeader("b4", "bbb") - .withHeader("c4", "ccc") - .withHeader("d4", "ddd") - .withHeader("e4", "eee") - .withHeader("f4", "fff") - .withHeader("g4", "ggg") - .withHeader("h4", "hhh") - .withHeader("i4", "iii") - .withHeader("j4", "jjj") - .withHeader("myHeader", "msg" + i).send(); + exchange.getMessage().setBody("Message " + i); + producer.process(exchange); } + producer.stop(); + LOG.info("Took {} ms", watch.taken()); }