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

gnodet pushed a commit to branch fix/CAMEL-22849
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 12ece6f0b808f5a363775a69a09e4f374dbd1911
Author: Guillaume Nodet <[email protected]>
AuthorDate: Tue Jan 27 15:06:01 2026 +0100

    CAMEL-22849: Add comprehensive tests for regex special characters in AS2 
wildcard patterns
---
 .../component/as2/api/AS2ServerConnection.java     | 13 ++--
 .../AS2ServerConnectionPatternMatchingTest.java    | 87 ++++++++++++++++++++++
 .../component/as2/AS2ServerWildcardPatternIT.java  | 12 +--
 3 files changed, 100 insertions(+), 12 deletions(-)

diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
index e2694b24b678..7f87027a7eca 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
@@ -92,11 +92,12 @@ public class AS2ServerConnection {
     private final String accessToken;
 
     /**
-     * Stores the configuration for each consumer endpoint path (e.g., 
"/consumerA").
-     * Uses LinkedHashMap to preserve insertion order, ensuring that when 
multiple patterns match a request,
-     * the first registered pattern (in route definition order) takes 
precedence.
+     * Stores the configuration for each consumer endpoint path (e.g., 
"/consumerA"). Uses LinkedHashMap to preserve
+     * insertion order, ensuring that when multiple patterns match a request, 
the first registered pattern (in route
+     * definition order) takes precedence.
      */
-    private final Map<String, AS2ConsumerConfiguration> consumerConfigurations 
= Collections.synchronizedMap(new LinkedHashMap<>());
+    private final Map<String, AS2ConsumerConfiguration> consumerConfigurations
+            = Collections.synchronizedMap(new LinkedHashMap<>());
 
     /**
      * Cache of compiled regex patterns for wildcard matching. Key is the 
pattern string, value is the compiled Pattern
@@ -183,8 +184,8 @@ public class AS2ServerConnection {
      * </ul>
      *
      * <p>
-     * When multiple patterns match, the first registered pattern (in route 
definition order) takes precedence.
-     * Exact matches always take precedence over wildcard matches.
+     * When multiple patterns match, the first registered pattern (in route 
definition order) takes precedence. Exact
+     * matches always take precedence over wildcard matches.
      *
      * @param  path The canonical request URI path (e.g., "/consumerA").
      * @return      An Optional containing the configuration if a match is 
found, otherwise empty.
diff --git 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2ServerConnectionPatternMatchingTest.java
 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2ServerConnectionPatternMatchingTest.java
new file mode 100644
index 000000000000..eb4468a52c75
--- /dev/null
+++ 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2ServerConnectionPatternMatchingTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.as2.api;
+
+import java.util.regex.Pattern;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit test for AS2ServerConnection pattern matching logic
+ */
+public class AS2ServerConnectionPatternMatchingTest {
+
+    /**
+     * Simulates the getCompiledPattern logic from AS2ServerConnection
+     */
+    private Pattern getCompiledPattern(String pattern) {
+        String[] segments = pattern.split("\\*", -1);
+        StringBuilder regex = new StringBuilder();
+        for (int i = 0; i < segments.length; i++) {
+            regex.append(Pattern.quote(segments[i]));
+            if (i < segments.length - 1) {
+                regex.append(".*");
+            }
+        }
+        return Pattern.compile(regex.toString());
+    }
+
+    @Test
+    public void testWildcardPatternMatching() {
+        Pattern pattern = getCompiledPattern("/consumer/*");
+
+        assertTrue(pattern.matcher("/consumer/orders").matches());
+        assertTrue(pattern.matcher("/consumer/invoices").matches());
+        assertFalse(pattern.matcher("/admin/orders").matches());
+    }
+
+    @Test
+    public void testRegexSpecialCharactersWithWildcard() {
+        Pattern pattern = getCompiledPattern("/api/v2(3)/*");
+
+        // Should match - parentheses are literal
+        assertTrue(pattern.matcher("/api/v2(3)/orders").matches());
+        assertTrue(pattern.matcher("/api/v2(3)/invoices").matches());
+
+        // Should NOT match - parentheses are literal, not regex grouping
+        assertFalse(pattern.matcher("/api/v23/orders").matches());
+        assertFalse(pattern.matcher("/api/v2/orders").matches());
+    }
+
+    @Test
+    public void testRegexSpecialCharactersExactMatch() {
+        Pattern pattern = getCompiledPattern("/api/v1.2/endpoint");
+
+        // Should match - dot is literal
+        assertTrue(pattern.matcher("/api/v1.2/endpoint").matches());
+
+        // Should NOT match - dot is literal, not regex "any character"
+        assertFalse(pattern.matcher("/api/v1X2/endpoint").matches());
+    }
+
+    @Test
+    public void testMultipleWildcards() {
+        Pattern pattern = getCompiledPattern("/api/*/v2(3)/*");
+
+        assertTrue(pattern.matcher("/api/v1/v2(3)/orders").matches());
+        assertTrue(pattern.matcher("/api/test/v2(3)/invoices").matches());
+        assertFalse(pattern.matcher("/api/v1/v23/orders").matches());
+    }
+}
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerWildcardPatternIT.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerWildcardPatternIT.java
index 8743ca36838c..811007d5ab82 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerWildcardPatternIT.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerWildcardPatternIT.java
@@ -62,8 +62,8 @@ public class AS2ServerWildcardPatternIT extends 
AS2ServerSecTestBase {
                 
from("as2://server/listen?requestUriPattern=/api/v1.2/endpoint")
                         .to("mock:regexSpecialCharsConsumer");
 
-                // Consumer with wildcard and special characters
-                from("as2://server/listen?requestUriPattern=/api/v2+3/*")
+                // Consumer with wildcard and special characters (using 
parentheses which are regex special chars)
+                from("as2://server/listen?requestUriPattern=/api/v2(3)/*")
                         .to("mock:regexSpecialCharsWildcardConsumer");
             }
         };
@@ -216,8 +216,8 @@ public class AS2ServerWildcardPatternIT extends 
AS2ServerSecTestBase {
         MockEndpoint regexWildcardEndpoint = 
getMockEndpoint("mock:regexSpecialCharsWildcardConsumer");
         regexWildcardEndpoint.expectedMessageCount(1);
 
-        // Send to /api/v2+3/orders - the plus should be treated as a literal 
plus, not regex "one or more"
-        HttpCoreContext context = sendToPath("/api/v2+3/orders", 
AS2MessageStructure.PLAIN);
+        // Send to /api/v2(3)/orders - the parentheses should be treated as 
literal chars, not regex grouping
+        HttpCoreContext context = sendToPath("/api/v2(3)/orders", 
AS2MessageStructure.PLAIN);
 
         verifyOkResponse(context);
         regexWildcardEndpoint.assertIsSatisfied();
@@ -233,8 +233,8 @@ public class AS2ServerWildcardPatternIT extends 
AS2ServerSecTestBase {
         MockEndpoint regexWildcardEndpoint = 
getMockEndpoint("mock:regexSpecialCharsWildcardConsumer");
         regexWildcardEndpoint.expectedMessageCount(0);
 
-        // Send to /api/v23/orders - should NOT match because plus is literal, 
not regex "one or more"
-        // If Pattern.quote() wasn't working, this would incorrectly match
+        // Send to /api/v23/orders - should NOT match because parentheses are 
literal, not regex grouping
+        // If Pattern.quote() wasn't working, /api/v2(3)/* would match 
/api/v23/orders as a regex
         HttpCoreContext context = sendToPath("/api/v23/orders", 
AS2MessageStructure.PLAIN);
 
         // This should fail to find a matching consumer, but we're just 
verifying it doesn't match the wrong one

Reply via email to