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

oscerd 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 b2dfac0906db CAMEL-24765: camel-huaweicloud-functiongraph - keep the 
region in the invoke URN and read the response body robustly (#26496)
b2dfac0906db is described below

commit b2dfac0906dbb665c2365fa67a4eff8f81f492d5
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Sep 17 09:54:47 2026 +0200

    CAMEL-24765: camel-huaweicloud-functiongraph - keep the region in the 
invoke URN and read the response body robustly (#26496)
    
    Populate region independently of the endpoint/region client-init choice so 
the invoke URN is never urn:fss:null; extract the response body robustly 
(string/primitive/absent, not just objects); require proxyPort > 0.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 .../org/apache/camel/FunctionGraphEndpoint.java    |  2 +-
 .../java/org/apache/camel/FunctionGraphUtils.java  | 13 ++++-
 .../apache/camel/models/ClientConfigurations.java  | 13 +++--
 .../FunctionGraphClientConfigurationsTest.java     | 51 ++++++++++++++++++
 .../org/apache/camel/FunctionGraphUtilsTest.java   | 61 ++++++++++++++++++++++
 5 files changed, 133 insertions(+), 7 deletions(-)

diff --git 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
index 3f561840fec1..0992b4c9a41f 100644
--- 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
+++ 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphEndpoint.java
@@ -264,7 +264,7 @@ public class FunctionGraphEndpoint extends DefaultEndpoint {
         HttpConfig httpConfig = HttpConfig.getDefaultHttpConfig();
         httpConfig.withIgnoreSSLVerification(isIgnoreSslVerification());
         if (ObjectHelper.isNotEmpty(getProxyHost())
-                && ObjectHelper.isNotEmpty(getProxyPort())) {
+                && getProxyPort() > 0) {
             httpConfig.withProxyHost(getProxyHost())
                     .withProxyPort(getProxyPort());
 
diff --git 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
index 1bad9f917dc0..b895a6b92e1f 100644
--- 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
+++ 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/FunctionGraphUtils.java
@@ -17,6 +17,7 @@
 package org.apache.camel;
 
 import com.google.gson.Gson;
+import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import org.apache.camel.models.ClientConfigurations;
 
@@ -34,7 +35,17 @@ public final class FunctionGraphUtils {
      */
     public static String extractJsonFieldAsString(String jsonString, String 
fieldName) {
         Gson gson = new Gson();
-        return gson.fromJson(jsonString, 
JsonObject.class).getAsJsonObject(fieldName).toString();
+        JsonObject root = gson.fromJson(jsonString, JsonObject.class);
+        if (root == null) {
+            return null;
+        }
+        JsonElement field = root.get(fieldName);
+        if (field == null || field.isJsonNull()) {
+            return null;
+        }
+        // a FunctionGraph 'body' is commonly a JSON-encoded string/primitive 
(HTTP-triggered functions),
+        // not always an object; return the raw value for primitives and the 
JSON text for objects/arrays
+        return field.isJsonPrimitive() ? field.getAsString() : 
field.toString();
     }
 
     /**
diff --git 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
index b18f1e5aaf8f..43192c76c03e 100644
--- 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
+++ 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/main/java/org/apache/camel/models/ClientConfigurations.java
@@ -40,20 +40,23 @@ public class ClientConfigurations {
 
     public ClientConfigurations(FunctionGraphEndpoint endpoint) {
 
-        // checking for required region
+        // checking for required region/endpoint (endpoint takes precedence 
for client initialization)
         if (ObjectHelper.isNotEmpty(endpoint.getEndpoint())) {
             this.setEndpoint(endpoint.getEndpoint());
-        } else if (ObjectHelper.isNotEmpty(endpoint.getRegion())) {
-            this.setRegion(endpoint.getRegion());
-        } else {
+        } else if (ObjectHelper.isEmpty(endpoint.getRegion())) {
             if (LOG.isErrorEnabled()) {
                 LOG.error("No region/endpoint given. Cannot proceed with 
FunctionGraph operations.");
             }
             throw new IllegalArgumentException("Region/endpoint not found");
         }
+        // the invoke URN always needs the region, even when the client is 
initialized from 'endpoint',
+        // so copy it independently instead of only in the region branch above
+        if (ObjectHelper.isNotEmpty(endpoint.getRegion())) {
+            this.setRegion(endpoint.getRegion());
+        }
 
         // checking for optional proxy authentication
-        if (ObjectHelper.isNotEmpty(endpoint.getProxyHost()) && 
ObjectHelper.isNotEmpty(endpoint.getProxyPort())) {
+        if (ObjectHelper.isNotEmpty(endpoint.getProxyHost()) && 
endpoint.getProxyPort() > 0) {
             this.setProxyHost(endpoint.getProxyHost());
             this.setProxyPort(endpoint.getProxyPort());
         }
diff --git 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphClientConfigurationsTest.java
 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphClientConfigurationsTest.java
new file mode 100644
index 000000000000..76469f969a3b
--- /dev/null
+++ 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphClientConfigurationsTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.apache.camel.constants.FunctionGraphConstants;
+import org.apache.camel.models.ClientConfigurations;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Verifies that the invoke URN keeps the region even when the client is 
initialized from the {@code endpoint}
+ * parameter. Uses {@link CamelTestSupport} because it resolves a real {@link 
FunctionGraphEndpoint} from the context.
+ */
+public class FunctionGraphClientConfigurationsTest extends CamelTestSupport {
+
+    @Test
+    public void urnKeepsRegionWhenEndpointIsAlsoConfigured() {
+        FunctionGraphEndpoint endpoint = context.getEndpoint(
+                
"hwcloud-functiongraph:invokeFunction?region=eu-west-101&endpoint=https://function.example.com";
+                                                             + 
"&projectId=proj-1&functionName=fn&functionPackage=pkg"
+                                                             + 
"&accessKey=ak&secretKey=sk&ignoreSslVerification=true",
+                FunctionGraphEndpoint.class);
+
+        ClientConfigurations clientConfigurations = new 
ClientConfigurations(endpoint);
+
+        assertEquals("eu-west-101", clientConfigurations.getRegion(),
+                "region must be populated even when the client is initialized 
from the endpoint");
+        // functionName/functionPackage are filled in by the producer at 
invoke time; here we only assert the
+        // region segment is present (previously it was 'urn:fss:null:...' 
whenever endpoint was configured)
+        String urn = 
FunctionGraphUtils.composeUrn(FunctionGraphConstants.URN_FORMAT, 
clientConfigurations);
+        assertTrue(urn.startsWith("urn:fss:eu-west-101:proj-1:function:"),
+                "the invoke URN must carry the region, was: " + urn);
+    }
+}
diff --git 
a/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java
 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java
new file mode 100644
index 000000000000..9245eb3b2777
--- /dev/null
+++ 
b/components/camel-huawei/camel-huaweicloud-functiongraph/src/test/java/org/apache/camel/FunctionGraphUtilsTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Unit tests for the static {@link 
FunctionGraphUtils#extractJsonFieldAsString} helper. It must not assume 'body' 
is a
+ * JSON object (HTTP-triggered functions return it as a JSON-encoded 
string/primitive) and must tolerate an absent/null
+ * field and a null/blank result.
+ */
+public class FunctionGraphUtilsTest {
+
+    @Test
+    public void extractObjectBodyReturnsItsJson() {
+        String result = 
FunctionGraphUtils.extractJsonFieldAsString("{\"body\":{\"orderId\":1,\"ok\":true}}",
 "body");
+        assertEquals("{\"orderId\":1,\"ok\":true}", result);
+    }
+
+    @Test
+    public void extractStringBodyReturnsTheRawString() {
+        // previously threw ClassCastException because getAsJsonObject was 
forced on a string member
+        String result = 
FunctionGraphUtils.extractJsonFieldAsString("{\"body\":\"hello world\"}", 
"body");
+        assertEquals("hello world", result);
+    }
+
+    @Test
+    public void extractNumericBodyReturnsItsValue() {
+        String result = 
FunctionGraphUtils.extractJsonFieldAsString("{\"body\":42}", "body");
+        assertEquals("42", result);
+    }
+
+    @Test
+    public void extractAbsentFieldReturnsNull() {
+        // previously threw NullPointerException
+        
assertNull(FunctionGraphUtils.extractJsonFieldAsString("{\"statusCode\":200}", 
"body"));
+    }
+
+    @Test
+    public void extractNullJsonReturnsNull() {
+        // a function that returns no result (response.getResult() == null) 
hits the root == null guard
+        assertNull(FunctionGraphUtils.extractJsonFieldAsString(null, "body"));
+    }
+}

Reply via email to