This is an automated email from the ASF dual-hosted git repository.
zhfeng 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 2b4f6b275bf CAMEL-21216: Apache Camel LRA does not work with Oracle
MicroTX LRA coordinator (#15558)
2b4f6b275bf is described below
commit 2b4f6b275bf924ed4a881f9b3233e9175f015f46
Author: DFiedler <[email protected]>
AuthorDate: Mon Sep 23 15:26:35 2024 +0200
CAMEL-21216: Apache Camel LRA does not work with Oracle MicroTX LRA
coordinator (#15558)
* CAMEL-21216: the call from the lra-coordinator is not correctly
url-decoded. As long as 'CAMEL-21197' is not solved, this workaround is needed.
* CAMEL-21216: The encoding of the query parameter is not needed, because
the generated url is part of the http put body.
* adding toNonnullString check
* implement own query parse method
* format file
* sorting imports
---------
Co-authored-by: Dirk Fiedler <[email protected]>
---
.../apache/camel/service/lra/LRASagaRoutes.java | 86 +++++++++++++------
.../apache/camel/service/lra/LRAUrlBuilder.java | 19 ++---
.../camel/service/lra/LRASagaRoutesTest.java | 99 ++++++++++++++++++++++
3 files changed, 162 insertions(+), 42 deletions(-)
diff --git
a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaRoutes.java
b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaRoutes.java
index 6d3b269872b..4d442cff869 100644
---
a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaRoutes.java
+++
b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaRoutes.java
@@ -16,24 +16,23 @@
*/
package org.apache.camel.service.lra;
-import java.net.URISyntaxException;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.stream.Collectors;
import org.apache.camel.Exchange;
-import org.apache.camel.RuntimeCamelException;
import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.util.URISupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import static
org.apache.camel.service.lra.LRAConstants.PARTICIPANT_PATH_COMPENSATE;
-import static
org.apache.camel.service.lra.LRAConstants.PARTICIPANT_PATH_COMPLETE;
-import static org.apache.camel.service.lra.LRAConstants.URL_COMPENSATION_KEY;
-import static org.apache.camel.service.lra.LRAConstants.URL_COMPLETION_KEY;
+import static org.apache.camel.service.lra.LRAConstants.*;
public class LRASagaRoutes extends RouteBuilder {
- private LRASagaService sagaService;
+ private static final Logger LOG =
LoggerFactory.getLogger(LRASagaRoutes.class);
+
+ private final LRASagaService sagaService;
public LRASagaRoutes(LRASagaService sagaService) {
this.sagaService = sagaService;
@@ -61,6 +60,39 @@ public class LRASagaRoutes extends RouteBuilder {
.end();
}
+ private Map<String, String> parseQuery(String queryStr) {
+
+ Map<String, String> result;
+
+ if (queryStr != null && !queryStr.isEmpty()) {
+
+ // first, split by parameter separator '&'
+ // then collect the map with the variable name '[0]' and value
'[1]', both url decoded
+ result = Arrays.stream(queryStr.split("&")).collect(
+ Collectors.toMap(element ->
decode(saveArrayAccess(element.split("="), 0)),
+ element ->
decode(saveArrayAccess(element.split("="), 1))));
+
+ } else {
+ LOG.debug("query param is empty, nothing to parse.");
+ result = new HashMap<>();
+ }
+
+ return result;
+ }
+
+ private String saveArrayAccess(String[] keyValuePair, int index) {
+ try {
+ return keyValuePair[index];
+ } catch (Exception ex) {
+ LOG.warn("unable to read array index '{}' from '{}'", index,
keyValuePair, ex);
+ return "";
+ }
+ }
+
+ private String decode(String encodedString) {
+ return URLDecoder.decode(encodedString, StandardCharsets.UTF_8);
+ }
+
/**
* Check if the request is pointing to an allowed URI to prevent
unauthorized remote uri invocation
*/
@@ -81,24 +113,22 @@ public class LRASagaRoutes extends RouteBuilder {
// CAMEL-17751: Extract URIs from the CamelHttpQuery header
if (usedURIs.isEmpty()) {
- try {
- Map<String, Object> queryParams
- =
URISupport.parseQuery(exchange.getIn().getHeader(Exchange.HTTP_QUERY,
String.class));
- if (!queryParams.isEmpty()) {
- if (queryParams.get(URL_COMPENSATION_KEY) != null) {
- compensationURI =
queryParams.get(URL_COMPENSATION_KEY).toString();
- usedURIs.add(compensationURI);
- exchange.getIn().setHeader(URL_COMPENSATION_KEY,
compensationURI);
- }
-
- if (queryParams.get(URL_COMPLETION_KEY) != null) {
- completionURI =
queryParams.get(URL_COMPLETION_KEY).toString();
- usedURIs.add(completionURI);
- exchange.getIn().setHeader(URL_COMPLETION_KEY,
completionURI);
- }
+ Map<String, String> queryParams
+ =
parseQuery(exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class));
+
+ if (!queryParams.isEmpty()) {
+
+ if (queryParams.get(URL_COMPENSATION_KEY) != null) {
+ compensationURI = queryParams.get(URL_COMPENSATION_KEY);
+ usedURIs.add(compensationURI);
+ exchange.getIn().setHeader(URL_COMPENSATION_KEY,
compensationURI);
+ }
+
+ if (queryParams.get(URL_COMPLETION_KEY) != null) {
+ completionURI = queryParams.get(URL_COMPLETION_KEY);
+ usedURIs.add(completionURI);
+ exchange.getIn().setHeader(URL_COMPLETION_KEY,
completionURI);
}
- } catch (URISyntaxException ex) {
- throw new RuntimeCamelException("URISyntaxException during " +
Exchange.HTTP_QUERY + " header parsing");
}
}
diff --git
a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRAUrlBuilder.java
b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRAUrlBuilder.java
index 4c247877f90..e3f4bf80c9c 100644
---
a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRAUrlBuilder.java
+++
b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRAUrlBuilder.java
@@ -16,9 +16,6 @@
*/
package org.apache.camel.service.lra;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
@@ -91,18 +88,12 @@ public class LRAUrlBuilder {
public LRAUrlBuilder query(String key, Object value) {
LRAUrlBuilder copy = copy();
- try {
- key = URLEncoder.encode(toNonnullString(key),
StandardCharsets.UTF_8.name());
- value = URLEncoder.encode(toNonnullString(value),
StandardCharsets.UTF_8.name());
- if (copy.query.isEmpty()) {
- copy.query += "?";
- } else {
- copy.query += "&";
- }
- copy.query += key + "=" + value;
- } catch (UnsupportedEncodingException e) {
- throw new IllegalStateException(e);
+ if (copy.query.isEmpty()) {
+ copy.query += "?";
+ } else {
+ copy.query += "&";
}
+ copy.query += toNonnullString(key) + "=" + toNonnullString(value);
return copy;
}
diff --git
a/components/camel-lra/src/test/java/org/apache/camel/service/lra/LRASagaRoutesTest.java
b/components/camel-lra/src/test/java/org/apache/camel/service/lra/LRASagaRoutesTest.java
new file mode 100644
index 00000000000..ae9ecfd7416
--- /dev/null
+++
b/components/camel-lra/src/test/java/org/apache/camel/service/lra/LRASagaRoutesTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.service.lra;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class LRASagaRoutesTest {
+
+ private Method getParseQueryMethod() throws NoSuchMethodException {
+ Method method = LRASagaRoutes.class.getDeclaredMethod("parseQuery",
String.class);
+ method.setAccessible(true);
+ return method;
+ }
+
+ @DisplayName("Tests whether parseQuery() is splitting unencoded query
params correct.")
+ @Test
+ void testParseQuerySuccessUnencoded() throws InvocationTargetException,
IllegalAccessException, NoSuchMethodException {
+
+ Map<String, String> testResult = (Map<String, String>)
getParseQueryMethod()
+ .invoke(new LRASagaRoutes(null),
+
"Camel-Saga-Compensate=direct://saga1_participant1_compensate&Camel-Saga-Complete=direct://saga1_participant1_complete");
+
+ System.out.println(testResult.toString());
+
+ Assertions.assertNotNull(testResult, "pared query must not be null");
+ Assertions.assertEquals(2, testResult.size(), "query parameter count
must be two");
+ Assertions.assertNotNull(testResult.get("Camel-Saga-Compensate"),
+ "query parameter value for name 'Camel-Saga-Compensate' must
not be null");
+ Assertions.assertEquals("direct://saga1_participant1_compensate",
testResult.get("Camel-Saga-Compensate"),
+ "query parameter value for name 'Camel-Saga-Compensate' has
unexpected content");
+ Assertions.assertNotNull(testResult.get("Camel-Saga-Complete"),
+ "query parameter value for name 'Camel-Saga-Complete' must not
be null");
+ Assertions.assertEquals("direct://saga1_participant1_complete",
testResult.get("Camel-Saga-Complete"),
+ "query parameter value for name 'Camel-Saga-Complete' has
unexpected content");
+ }
+
+ @DisplayName("Tests parseQuery() to handle incorrect query string (no
value is given)")
+ @Test
+ void testParseQueryInvalidUnencoded() throws InvocationTargetException,
IllegalAccessException, NoSuchMethodException {
+
+ Map<String, String> testResult = (Map<String, String>)
getParseQueryMethod()
+ .invoke(new LRASagaRoutes(null), "key1=value1&key2");
+
+ System.out.println(testResult.toString());
+
+ Assertions.assertNotNull(testResult, "pared query must not be null");
+ Assertions.assertEquals(2, testResult.size(), "query parameter count
must be two");
+ Assertions.assertNotNull(testResult.get("key1"),
+ "query parameter value for name 'key1' must not be null");
+ Assertions.assertEquals("value1", testResult.get("key1"),
+ "query parameter value for name 'key1' has unexpected
content");
+ Assertions.assertNotNull(testResult.get("key2"),
+ "query parameter value for name 'key2' must not be null");
+ Assertions.assertEquals("", testResult.get("key2"),
+ "query parameter value for name 'key2' has unexpected
content");
+ }
+
+ @DisplayName("Tests parseQuery() to handle incorrect query string (no
value is given)")
+ @Test
+ void testParseQuerySuccessEncoded() throws InvocationTargetException,
IllegalAccessException, NoSuchMethodException {
+
+ Map<String, String> testResult = (Map<String, String>)
getParseQueryMethod()
+ .invoke(new LRASagaRoutes(null),
+
"Camel-Saga-Compensate=direct%3A%2F%2Fsaga1_participant1_compensate&Camel-Saga-Complete=direct%3A%2F%2Fsaga1_participant1_complete");
+
+ System.out.println(testResult.toString());
+
+ Assertions.assertNotNull(testResult, "pared query must not be null");
+ Assertions.assertEquals(2, testResult.size(), "query parameter count
must be two");
+ Assertions.assertNotNull(testResult.get("Camel-Saga-Compensate"),
+ "query parameter value for name 'Camel-Saga-Compensate' must
not be null");
+ Assertions.assertEquals("direct://saga1_participant1_compensate",
testResult.get("Camel-Saga-Compensate"),
+ "query parameter value for name 'Camel-Saga-Compensate' has
unexpected content");
+ Assertions.assertNotNull(testResult.get("Camel-Saga-Complete"),
+ "query parameter value for name 'Camel-Saga-Complete' must not
be null");
+ Assertions.assertEquals("direct://saga1_participant1_complete",
testResult.get("Camel-Saga-Complete"),
+ "query parameter value for name 'Camel-Saga-Complete' has
unexpected content");
+ }
+}