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 74a824de046 CAMEL-21858: Checking the httpMethod parameter when decorating the sp… (#17448) 74a824de046 is described below commit 74a824de04685966be8c8c48cdc6f11df9291244 Author: Luis Sergio Faria Carneiro <luis.carne...@sensedia.com> AuthorDate: Fri Mar 14 10:48:25 2025 -0300 CAMEL-21858: Checking the httpMethod parameter when decorating the sp… (#17448) * CAMEL-21858: camel-tracing: Checking the httpMethod parameter when decorating the span for http components * CAMEL-21858: camel-telemtry: Checking the httpMethod parameter when decorating the span for http components * CAMEL-21858: Moving httpMethod parameter handling to HttpSpanDecorator * CAMEL-21858: Adding httpMethod parameter handling to vertx-http component --- .../decorators/AbstractHttpSpanDecorator.java | 2 +- .../telemetry/decorators/HttpMethodHelper.java | 65 ++++++++++++ .../telemetry/decorators/HttpSpanDecorator.java | 11 ++ .../decorators/VertxHttpSpanDecorator.java | 12 +++ .../decorators/AbstractHttpSpanDecoratorTest.java | 113 +++++--------------- .../telemetry/decorators/HttpMethodHelperTest.java | 55 ++++++++++ .../decorators/HttpSpanDecoratorTest.java | 67 ++++++++++++ .../decorators/AbstractHttpSpanDecorator.java | 3 +- .../camel/tracing/decorators/HttpMethodHelper.java | 65 ++++++++++++ .../tracing/decorators/HttpSpanDecorator.java | 13 +++ .../tracing/decorators/VertxHttpSpanDecorator.java | 12 +++ .../decorators/AbstractHttpSpanDecoratorTest.java | 117 +++++---------------- .../tracing/decorators/HttpMethodHelperTest.java | 55 ++++++++++ .../tracing/decorators/HttpSpanDecoratorTest.java | 67 ++++++++++++ .../decorators/VertxHttpSpanDecoratorTest.java | 67 ++++++++++++ 15 files changed, 547 insertions(+), 177 deletions(-) diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java index 270c8733391..bd02d9d0301 100644 --- a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java +++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecorator.java @@ -27,7 +27,7 @@ public abstract class AbstractHttpSpanDecorator extends AbstractSpanDecorator { public static final String POST_METHOD = "POST"; public static final String GET_METHOD = "GET"; - public static String getHttpMethod(Exchange exchange, Endpoint endpoint) { + public String getHttpMethod(Exchange exchange, Endpoint endpoint) { // 1. Use method provided in header. Object method = exchange.getIn().getHeader(Exchange.HTTP_METHOD); if (method instanceof String) { diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/HttpMethodHelper.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/HttpMethodHelper.java new file mode 100644 index 00000000000..e0e6ccc14c3 --- /dev/null +++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/HttpMethodHelper.java @@ -0,0 +1,65 @@ +/* + * 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.telemetry.decorators; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; + +class HttpMethodHelper { + + private static final Pattern HTTP_METHOD_PATTERN = Pattern.compile("(?i)httpMethod=([A-Z]+)"); + + /** + * This method searches for the httpMethod param on the endpoint and return it. + * + * @param exchange + * @param endpoint + * @return + */ + public static String getHttpMethodFromParameters(Exchange exchange, Endpoint endpoint) { + String queryStringHeader = (String) exchange.getIn().getHeader(Exchange.HTTP_QUERY); + if (queryStringHeader != null) { + String methodFromQuery = getMethodFromQueryString(queryStringHeader); + if (methodFromQuery != null) { + return methodFromQuery; + } + } + + // try to get the httpMethod parameter from the the query string in the uri + int queryIndex = endpoint.getEndpointUri().indexOf('?'); + if (queryIndex != -1) { + String queryString = endpoint.getEndpointUri().substring(queryIndex + 1); + String methodFromQuery = getMethodFromQueryString(queryString); + if (methodFromQuery != null) { + return methodFromQuery; + } + } + return null; + } + + private static String getMethodFromQueryString(String queryString) { + Matcher m = HTTP_METHOD_PATTERN.matcher(queryString); + if (m.find()) { + return m.group(1); + } + return null; + } + +} diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/HttpSpanDecorator.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/HttpSpanDecorator.java index 7c18ff4b676..6d80574394e 100644 --- a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/HttpSpanDecorator.java +++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/HttpSpanDecorator.java @@ -16,6 +16,9 @@ */ package org.apache.camel.telemetry.decorators; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; + public class HttpSpanDecorator extends AbstractHttpSpanDecorator { @Override @@ -28,4 +31,12 @@ public class HttpSpanDecorator extends AbstractHttpSpanDecorator { return "org.apache.camel.component.http.HttpComponent"; } + @Override + public String getHttpMethod(Exchange exchange, Endpoint endpoint) { + String methodFromParameters = HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint); + if (methodFromParameters != null) { + return methodFromParameters; + } + return super.getHttpMethod(exchange, endpoint); + } } diff --git a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/VertxHttpSpanDecorator.java b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/VertxHttpSpanDecorator.java index 64f58b07e56..20d869f1a63 100644 --- a/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/VertxHttpSpanDecorator.java +++ b/components/camel-telemetry/src/main/java/org/apache/camel/telemetry/decorators/VertxHttpSpanDecorator.java @@ -16,6 +16,9 @@ */ package org.apache.camel.telemetry.decorators; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; + public class VertxHttpSpanDecorator extends AbstractHttpSpanDecorator { @Override @@ -28,4 +31,13 @@ public class VertxHttpSpanDecorator extends AbstractHttpSpanDecorator { return "org.apache.camel.component.vertx.http.VertxHttpComponent"; } + @Override + public String getHttpMethod(Exchange exchange, Endpoint endpoint) { + String methodFromParameters = HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint); + if (methodFromParameters != null) { + return methodFromParameters; + } + return super.getHttpMethod(exchange, endpoint); + } + } diff --git a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java index fd72f39380a..9e7314b4e25 100644 --- a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java +++ b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/AbstractHttpSpanDecoratorTest.java @@ -19,9 +19,9 @@ package org.apache.camel.telemetry.decorators; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; -import org.apache.camel.telemetry.SpanDecorator; import org.apache.camel.telemetry.TagConstants; import org.apache.camel.telemetry.mock.MockSpanAdapter; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -32,15 +32,11 @@ public class AbstractHttpSpanDecoratorTest { private static final String TEST_URI = "http://localhost:8080/test"; - @Test - public void testGetOperationName() { - Exchange exchange = Mockito.mock(Exchange.class); - Message message = Mockito.mock(Message.class); + private AbstractHttpSpanDecorator decorator; - Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn("PUT"); - - SpanDecorator decorator = new AbstractHttpSpanDecorator() { + @BeforeEach + public void before() { + this.decorator = new AbstractHttpSpanDecorator() { @Override public String getComponent() { return null; @@ -51,6 +47,15 @@ public class AbstractHttpSpanDecoratorTest { return null; } }; + } + + @Test + public void testGetOperationName() { + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn("PUT"); assertEquals("PUT", decorator.getOperationName(exchange, null)); } @@ -59,34 +64,40 @@ public class AbstractHttpSpanDecoratorTest { public void testGetMethodFromMethodHeader() { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn("PUT"); - assertEquals("PUT", AbstractHttpSpanDecorator.getHttpMethod(exchange, null)); + assertEquals("PUT", decorator.getHttpMethod(exchange, endpoint)); } @Test public void testGetMethodFromMethodHeaderEnum() { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn(HttpMethods.GET); - assertEquals("GET", AbstractHttpSpanDecorator.getHttpMethod(exchange, null)); + assertEquals("GET", decorator.getHttpMethod(exchange, endpoint)); } @Test public void testGetMethodQueryStringHeader() { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(message.getHeader(Exchange.HTTP_QUERY)).thenReturn("MyQuery"); assertEquals(AbstractHttpSpanDecorator.GET_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, null)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -101,7 +112,7 @@ public class AbstractHttpSpanDecoratorTest { .thenReturn("http://localhost:8080/endpoint?query=hello"); assertEquals(AbstractHttpSpanDecorator.GET_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, endpoint)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -116,7 +127,7 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(message.getBody()).thenReturn("Message Body"); assertEquals(AbstractHttpSpanDecorator.POST_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, endpoint)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -130,7 +141,7 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn(TEST_URI); assertEquals(AbstractHttpSpanDecorator.GET_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, endpoint)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -143,18 +154,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(exchange.getIn()).thenReturn(message); Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); - SpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - MockSpanAdapter span = new MockSpanAdapter(); decorator.beforeTracingEvent(span, exchange, endpoint); @@ -174,18 +173,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn("Another URL"); Mockito.when(message.getHeader(Exchange.HTTP_URL, String.class)).thenReturn(TEST_URI); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -199,18 +186,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(exchange.getIn()).thenReturn(message); Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -223,18 +198,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); Mockito.when(exchange.getIn()).thenReturn(message); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -247,18 +210,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(endpoint.getEndpointUri()).thenReturn("netty-http:" + TEST_URI); Mockito.when(exchange.getIn()).thenReturn(message); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -270,18 +221,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(exchange.getMessage()).thenReturn(message); Mockito.when(message.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class)).thenReturn(200); - SpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - MockSpanAdapter span = new MockSpanAdapter(); decorator.afterTracingEvent(span, exchange); diff --git a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/HttpMethodHelperTest.java b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/HttpMethodHelperTest.java new file mode 100644 index 00000000000..e80c42d6553 --- /dev/null +++ b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/HttpMethodHelperTest.java @@ -0,0 +1,55 @@ +/* + * 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.telemetry.decorators; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class HttpMethodHelperTest { + + @Test + public void testHttpMethodPresent() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + assertEquals("POST", HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint)); + } + + @Test + public void testHttpMethodMissing() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); + assertNull(HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint)); + } + +} diff --git a/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/HttpSpanDecoratorTest.java b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/HttpSpanDecoratorTest.java new file mode 100644 index 00000000000..a3475de429a --- /dev/null +++ b/components/camel-telemetry/src/test/java/org/apache/camel/telemetry/decorators/HttpSpanDecoratorTest.java @@ -0,0 +1,67 @@ +/* + * 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.telemetry.decorators; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HttpSpanDecoratorTest { + + private HttpSpanDecorator decorator; + + @BeforeEach + public void before() { + this.decorator = new HttpSpanDecorator(); + } + + @Test + public void testMethodInHttpMethodParam() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + + assertEquals(AbstractHttpSpanDecorator.POST_METHOD, + decorator.getHttpMethod(exchange, endpoint)); + } + + @Test + public void testMethodInHttpMethodParamUsingHeader() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn(HttpMethods.GET); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + + assertEquals(AbstractHttpSpanDecorator.POST_METHOD, + decorator.getHttpMethod(exchange, endpoint)); + } +} diff --git a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java index 9de3987a4b8..058c4e660b6 100644 --- a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java +++ b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecorator.java @@ -27,7 +27,7 @@ public abstract class AbstractHttpSpanDecorator extends AbstractSpanDecorator { public static final String POST_METHOD = "POST"; public static final String GET_METHOD = "GET"; - public static String getHttpMethod(Exchange exchange, Endpoint endpoint) { + public String getHttpMethod(Exchange exchange, Endpoint endpoint) { // 1. Use method provided in header. Object method = exchange.getIn().getHeader(Exchange.HTTP_METHOD); if (method instanceof String) { @@ -105,4 +105,5 @@ public abstract class AbstractHttpSpanDecorator extends AbstractSpanDecorator { } } } + } diff --git a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/HttpMethodHelper.java b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/HttpMethodHelper.java new file mode 100644 index 00000000000..cee42ce014a --- /dev/null +++ b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/HttpMethodHelper.java @@ -0,0 +1,65 @@ +/* + * 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.tracing.decorators; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; + +class HttpMethodHelper { + + private static final Pattern HTTP_METHOD_PATTERN = Pattern.compile("(?i)httpMethod=([A-Z]+)"); + + /** + * This method searches for the httpMethod param on the endpoint and return it. + * + * @param exchange + * @param endpoint + * @return + */ + public static String getHttpMethodFromParameters(Exchange exchange, Endpoint endpoint) { + String queryStringHeader = (String) exchange.getIn().getHeader(Exchange.HTTP_QUERY); + if (queryStringHeader != null) { + String methodFromQuery = getMethodFromQueryString(queryStringHeader); + if (methodFromQuery != null) { + return methodFromQuery; + } + } + + // try to get the httpMethod parameter from the the query string in the uri + int queryIndex = endpoint.getEndpointUri().indexOf('?'); + if (queryIndex != -1) { + String queryString = endpoint.getEndpointUri().substring(queryIndex + 1); + String methodFromQuery = getMethodFromQueryString(queryString); + if (methodFromQuery != null) { + return methodFromQuery; + } + } + return null; + } + + private static String getMethodFromQueryString(String queryString) { + Matcher m = HTTP_METHOD_PATTERN.matcher(queryString); + if (m.find()) { + return m.group(1); + } + return null; + } + +} diff --git a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/HttpSpanDecorator.java b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/HttpSpanDecorator.java index def7a352fca..7430286ba09 100644 --- a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/HttpSpanDecorator.java +++ b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/HttpSpanDecorator.java @@ -16,6 +16,9 @@ */ package org.apache.camel.tracing.decorators; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; + public class HttpSpanDecorator extends AbstractHttpSpanDecorator { @Override @@ -28,4 +31,14 @@ public class HttpSpanDecorator extends AbstractHttpSpanDecorator { return "org.apache.camel.component.http.HttpComponent"; } + @Override + public String getHttpMethod(Exchange exchange, Endpoint endpoint) { + //this component supports the httpMethod parameter, so we try to find it first + String methodFromParameters = HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint); + if (methodFromParameters != null) { + return methodFromParameters; + } + return super.getHttpMethod(exchange, endpoint); + } + } diff --git a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/VertxHttpSpanDecorator.java b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/VertxHttpSpanDecorator.java index 6209535a245..079a2eb51ab 100644 --- a/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/VertxHttpSpanDecorator.java +++ b/components/camel-tracing/src/main/java/org/apache/camel/tracing/decorators/VertxHttpSpanDecorator.java @@ -16,6 +16,9 @@ */ package org.apache.camel.tracing.decorators; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; + public class VertxHttpSpanDecorator extends AbstractHttpSpanDecorator { @Override @@ -28,4 +31,13 @@ public class VertxHttpSpanDecorator extends AbstractHttpSpanDecorator { return "org.apache.camel.component.vertx.http.VertxHttpComponent"; } + @Override + public String getHttpMethod(Exchange exchange, Endpoint endpoint) { + //this component supports the httpMethod parameter, so we try to find it first + String methodFromParameters = HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint); + if (methodFromParameters != null) { + return methodFromParameters; + } + return super.getHttpMethod(exchange, endpoint); + } } diff --git a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java index fc04663312f..c48d8751f28 100644 --- a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java +++ b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/AbstractHttpSpanDecoratorTest.java @@ -20,8 +20,8 @@ import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.tracing.MockSpanAdapter; -import org.apache.camel.tracing.SpanDecorator; import org.apache.camel.tracing.TagConstants; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -32,15 +32,11 @@ public class AbstractHttpSpanDecoratorTest { private static final String TEST_URI = "http://localhost:8080/test"; - @Test - public void testGetOperationName() { - Exchange exchange = Mockito.mock(Exchange.class); - Message message = Mockito.mock(Message.class); + private AbstractHttpSpanDecorator decorator; - Mockito.when(exchange.getIn()).thenReturn(message); - Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn("PUT"); - - SpanDecorator decorator = new AbstractHttpSpanDecorator() { + @BeforeEach + public void before() { + this.decorator = new AbstractHttpSpanDecorator() { @Override public String getComponent() { return null; @@ -51,42 +47,59 @@ public class AbstractHttpSpanDecoratorTest { return null; } }; + } + + @Test + public void testGetOperationName() { + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); + + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn("PUT"); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); - assertEquals("PUT", decorator.getOperationName(exchange, null)); + assertEquals("PUT", decorator.getOperationName(exchange, endpoint)); } @Test public void testGetMethodFromMethodHeader() { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn("PUT"); - assertEquals("PUT", AbstractHttpSpanDecorator.getHttpMethod(exchange, null)); + assertEquals("PUT", decorator.getHttpMethod(exchange, endpoint)); } @Test public void testGetMethodFromMethodHeaderEnum() { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn(HttpMethods.GET); - assertEquals("GET", AbstractHttpSpanDecorator.getHttpMethod(exchange, null)); + assertEquals("GET", decorator.getHttpMethod(exchange, endpoint)); } @Test public void testGetMethodQueryStringHeader() { Exchange exchange = Mockito.mock(Exchange.class); Message message = Mockito.mock(Message.class); + Endpoint endpoint = Mockito.mock(Endpoint.class); Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); Mockito.when(message.getHeader(Exchange.HTTP_QUERY)).thenReturn("MyQuery"); assertEquals(AbstractHttpSpanDecorator.GET_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, null)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -101,7 +114,7 @@ public class AbstractHttpSpanDecoratorTest { .thenReturn("http://localhost:8080/endpoint?query=hello"); assertEquals(AbstractHttpSpanDecorator.GET_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, endpoint)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -116,7 +129,7 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(message.getBody()).thenReturn("Message Body"); assertEquals(AbstractHttpSpanDecorator.POST_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, endpoint)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -130,7 +143,7 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(message.getHeader(Exchange.HTTP_URI)).thenReturn(TEST_URI); assertEquals(AbstractHttpSpanDecorator.GET_METHOD, - AbstractHttpSpanDecorator.getHttpMethod(exchange, endpoint)); + decorator.getHttpMethod(exchange, endpoint)); } @Test @@ -143,18 +156,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(exchange.getIn()).thenReturn(message); Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); - SpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - MockSpanAdapter span = new MockSpanAdapter(); decorator.pre(span, exchange, endpoint); @@ -174,18 +175,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn("Another URL"); Mockito.when(message.getHeader(Exchange.HTTP_URL, String.class)).thenReturn(TEST_URI); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -199,18 +188,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(exchange.getIn()).thenReturn(message); Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)).thenReturn(TEST_URI); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -223,18 +200,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(endpoint.getEndpointUri()).thenReturn(TEST_URI); Mockito.when(exchange.getIn()).thenReturn(message); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -247,18 +212,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(endpoint.getEndpointUri()).thenReturn("netty-http:" + TEST_URI); Mockito.when(exchange.getIn()).thenReturn(message); - AbstractHttpSpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - assertEquals(TEST_URI, decorator.getHttpURL(exchange, endpoint)); } @@ -270,18 +223,6 @@ public class AbstractHttpSpanDecoratorTest { Mockito.when(exchange.getMessage()).thenReturn(message); Mockito.when(message.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class)).thenReturn(200); - SpanDecorator decorator = new AbstractHttpSpanDecorator() { - @Override - public String getComponent() { - return null; - } - - @Override - public String getComponentClassName() { - return null; - } - }; - MockSpanAdapter span = new MockSpanAdapter(); decorator.post(span, exchange, null); diff --git a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/HttpMethodHelperTest.java b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/HttpMethodHelperTest.java new file mode 100644 index 00000000000..0697a9e13f0 --- /dev/null +++ b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/HttpMethodHelperTest.java @@ -0,0 +1,55 @@ +/* + * 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.tracing.decorators; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class HttpMethodHelperTest { + + @Test + public void testHttpMethodPresent() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + assertEquals("POST", HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint)); + } + + @Test + public void testHttpMethodMissing() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint"); + assertNull(HttpMethodHelper.getHttpMethodFromParameters(exchange, endpoint)); + } + +} diff --git a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/HttpSpanDecoratorTest.java b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/HttpSpanDecoratorTest.java new file mode 100644 index 00000000000..7f1b38da04c --- /dev/null +++ b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/HttpSpanDecoratorTest.java @@ -0,0 +1,67 @@ +/* + * 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.tracing.decorators; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HttpSpanDecoratorTest { + + private HttpSpanDecorator decorator; + + @BeforeEach + public void before() { + this.decorator = new HttpSpanDecorator(); + } + + @Test + public void testMethodInHttpMethodParam() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + + assertEquals(AbstractHttpSpanDecorator.POST_METHOD, + decorator.getHttpMethod(exchange, endpoint)); + } + + @Test + public void testMethodInHttpMethodParamUsingHeader() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn(HttpMethods.GET); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + + assertEquals(AbstractHttpSpanDecorator.POST_METHOD, + decorator.getHttpMethod(exchange, endpoint)); + } +} diff --git a/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/VertxHttpSpanDecoratorTest.java b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/VertxHttpSpanDecoratorTest.java new file mode 100644 index 00000000000..a913dc144dd --- /dev/null +++ b/components/camel-tracing/src/test/java/org/apache/camel/tracing/decorators/VertxHttpSpanDecoratorTest.java @@ -0,0 +1,67 @@ +/* + * 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.tracing.decorators; + +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class VertxHttpSpanDecoratorTest { + + private VertxHttpSpanDecorator decorator; + + @BeforeEach + public void before() { + this.decorator = new VertxHttpSpanDecorator(); + } + + @Test + public void testMethodInHttpMethodParam() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("vertx-http://localhost:8080/endpoint?httpMethod=POST"); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("http://localhost:8080/endpoint?httpMethod=POST"); + + assertEquals(AbstractHttpSpanDecorator.POST_METHOD, + decorator.getHttpMethod(exchange, endpoint)); + } + + @Test + public void testMethodInHttpMethodParamUsingHeader() { + Endpoint endpoint = Mockito.mock(Endpoint.class); + Exchange exchange = Mockito.mock(Exchange.class); + Message message = Mockito.mock(Message.class); + + Mockito.when(endpoint.getEndpointUri()).thenReturn("vertx-http://localhost:8080/endpoint?httpMethod=POST"); + Mockito.when(exchange.getIn()).thenReturn(message); + Mockito.when(message.getHeader(Exchange.HTTP_METHOD)).thenReturn(HttpMethods.GET); + Mockito.when(message.getHeader(Exchange.HTTP_URI, String.class)) + .thenReturn("vertx-http://localhost:8080/endpoint?httpMethod=POST"); + + assertEquals(AbstractHttpSpanDecorator.POST_METHOD, + decorator.getHttpMethod(exchange, endpoint)); + } +}