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 c70e76241353 CAMEL-24766: camel-huaweicloud-smn - resolve the 
operation before the empty-body check (#26499)
c70e76241353 is described below

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

    CAMEL-24766: camel-huaweicloud-smn - resolve the operation before the 
empty-body check (#26499)
    
    Resolve the operation (property-preferred) before the empty-body guard and 
compare against the SmnOperations constant, so an empty text body fails with a 
clear error instead of an NPE or a silently-published empty message.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 .../smn/SimpleNotificationProducer.java            |  25 +++--
 ...PublishTextMessageOperationViaPropertyTest.java | 117 +++++++++++++++++++++
 2 files changed, 129 insertions(+), 13 deletions(-)

diff --git 
a/components/camel-huawei/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationProducer.java
 
b/components/camel-huawei/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationProducer.java
index ee1b28f95c13..f5cec86a8c13 100644
--- 
a/components/camel-huawei/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationProducer.java
+++ 
b/components/camel-huawei/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationProducer.java
@@ -124,8 +124,7 @@ public class SimpleNotificationProducer extends 
DefaultProducer {
                         .withSubject(clientConfigurations.getSubject())
                         
.withTimeToLive(String.valueOf(clientConfigurations.getMessageTtl()))
                         .withMessageTemplateName((String) 
exchange.getProperty(SmnProperties.TEMPLATE_NAME))
-                        .withTags((HashMap<String, String>) 
exchange.getProperty(SmnProperties.TEMPLATE_TAGS))
-                        
.withTimeToLive(String.valueOf(clientConfigurations.getMessageTtl()));
+                        .withTags((HashMap<String, String>) 
exchange.getProperty(SmnProperties.TEMPLATE_TAGS));
 
                 response = smnClient.publishMessage(new PublishMessageRequest()
                         .withBody(apiBody)
@@ -307,17 +306,8 @@ public class SimpleNotificationProducer extends 
DefaultProducer {
         if (LOG.isDebugEnabled()) {
             LOG.debug("Inspecting exchange body");
         }
-        // verifying if exchange has valid body content. this is mandatory for 
'publish as text' operation
-        if (ObjectHelper.isEmpty(exchange.getMessage().getBody())) {
-            if 
(simpleNotificationEndpoint.getOperation().equals("publishAsTextMessage")) {
-                if (LOG.isErrorEnabled()) {
-                    LOG.error("Found null/empty body. Cannot perform publish 
as text operation");
-                }
-                throw new IllegalArgumentException("exchange body cannot be 
null / empty");
-            }
-        }
-
-        // checking for mandatory field 'operation name'
+        // resolve the operation first: the CamelHwCloudSmnOperation exchange 
property takes precedence over the
+        // endpoint parameter, so the body check below must test the operation 
that is actually dispatched
         if (LOG.isDebugEnabled()) {
             LOG.debug("Inspecting operation name");
         }
@@ -332,6 +322,15 @@ public class SimpleNotificationProducer extends 
DefaultProducer {
                     ? (String) 
exchange.getProperty(SmnProperties.SMN_OPERATION) : 
simpleNotificationEndpoint.getOperation());
         }
 
+        // verifying if exchange has valid body content. this is mandatory for 
'publish as text' operation
+        if (ObjectHelper.isEmpty(exchange.getMessage().getBody())
+                && 
SmnOperations.PUBLISH_AS_TEXT_MESSAGE.equals(clientConfigurations.getOperation()))
 {
+            if (LOG.isErrorEnabled()) {
+                LOG.error("Found null/empty body. Cannot perform publish as 
text operation");
+            }
+            throw new IllegalArgumentException("exchange body cannot be null / 
empty");
+        }
+
         // checking for mandatory field 'topic name'
         if (LOG.isDebugEnabled()) {
             LOG.debug("Inspecting topic name");
diff --git 
a/components/camel-huawei/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTextMessageOperationViaPropertyTest.java
 
b/components/camel-huawei/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTextMessageOperationViaPropertyTest.java
new file mode 100644
index 000000000000..d7a3389144fb
--- /dev/null
+++ 
b/components/camel-huawei/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTextMessageOperationViaPropertyTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.huaweicloud.smn;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.huaweicloud.smn.constants.SmnOperations;
+import org.apache.camel.component.huaweicloud.smn.constants.SmnProperties;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * When the operation is supplied only through the {@code 
CamelHwCloudSmnOperation} exchange property (with no
+ * {@code operation} endpoint parameter), an empty text-message body must fail 
with the clear
+ * {@code IllegalArgumentException} - not a {@code NullPointerException} from 
the guard testing the (null) endpoint
+ * operation, which was the behaviour before the operation was resolved ahead 
of the body check.
+ */
+public class PublishTextMessageOperationViaPropertyTest extends 
CamelTestSupport {
+
+    TestConfiguration testConfiguration = new TestConfiguration();
+
+    @BindToRegistry("smnClient")
+    SmnClientMock smnClientMock = new SmnClientMock(null);
+
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:publish_without_operation_param")
+                        .setProperty(SmnProperties.NOTIFICATION_SUBJECT, 
constant("Dummy Subject Line"))
+                        .setProperty(SmnProperties.NOTIFICATION_TOPIC_NAME, 
constant(testConfiguration.getProperty("topic")))
+                        .setProperty(SmnProperties.NOTIFICATION_TTL, 
constant(60))
+                        // operation supplied only via the exchange property; 
the endpoint has no operation= parameter
+                        .setProperty(SmnProperties.SMN_OPERATION, 
constant(SmnOperations.PUBLISH_AS_TEXT_MESSAGE))
+                        .to("hwcloud-smn:publishMessageService?accessKey="
+                            + testConfiguration.getProperty("accessKey") + 
"&secretKey="
+                            + testConfiguration.getProperty("secretKey") + 
"&projectId="
+                            + testConfiguration.getProperty("projectId") + 
"&region=" + testConfiguration.getProperty("region")
+                            + "&ignoreSslVerification=true"
+                            + "&smnClient=#smnClient")
+                        .to("mock:result");
+
+                from("direct:templated_endpoint_text_property")
+                        .setProperty(SmnProperties.NOTIFICATION_SUBJECT, 
constant("Dummy Subject Line"))
+                        .setProperty(SmnProperties.NOTIFICATION_TOPIC_NAME, 
constant(testConfiguration.getProperty("topic")))
+                        .setProperty(SmnProperties.NOTIFICATION_TTL, 
constant(60))
+                        // endpoint operation is templated, but the property 
overrides it to text
+                        .setProperty(SmnProperties.SMN_OPERATION, 
constant(SmnOperations.PUBLISH_AS_TEXT_MESSAGE))
+                        .to("hwcloud-smn:publishMessageService?operation=" + 
SmnOperations.PUBLISH_AS_TEMPLATED_MESSAGE
+                            + "&accessKey=" + 
testConfiguration.getProperty("accessKey") + "&secretKey="
+                            + testConfiguration.getProperty("secretKey") + 
"&projectId="
+                            + testConfiguration.getProperty("projectId") + 
"&region="
+                            + testConfiguration.getProperty("region")
+                            + "&ignoreSslVerification=true"
+                            + "&smnClient=#smnClient")
+                        .to("mock:result");
+            }
+        };
+    }
+
+    @Test
+    public void emptyBodyReportsAClearErrorNotAnNpe() {
+        Exchange result = 
template.request("direct:publish_without_operation_param", e -> 
e.getIn().setBody(null));
+
+        Throwable cause = result.getException();
+        assertNotNull(cause, "an empty text-message body was expected to 
fail");
+        boolean clearError = false;
+        while (cause != null) {
+            if (cause instanceof IllegalArgumentException && 
cause.getMessage() != null
+                    && cause.getMessage().contains("exchange body cannot be 
null / empty")) {
+                clearError = true;
+                break;
+            }
+            cause = cause.getCause();
+        }
+        assertTrue(clearError,
+                "expected a clear 'exchange body cannot be null / empty' 
IllegalArgumentException, got: "
+                               + result.getException());
+    }
+
+    @Test
+    public void propertyOverridingTemplatedEndpointToTextRejectsEmptyBody() {
+        // endpoint operation is publishAsTemplatedMessage but the property 
overrides to publishAsTextMessage;
+        // the guard must test the RESOLVED operation, otherwise an empty text 
message is silently published
+        Exchange result = 
template.request("direct:templated_endpoint_text_property", e -> 
e.getIn().setBody(null));
+
+        Throwable cause = result.getException();
+        assertNotNull(cause, "an empty text-message body was expected to 
fail");
+        boolean clearError = false;
+        while (cause != null) {
+            if (cause instanceof IllegalArgumentException && 
cause.getMessage() != null
+                    && cause.getMessage().contains("exchange body cannot be 
null / empty")) {
+                clearError = true;
+                break;
+            }
+            cause = cause.getCause();
+        }
+        assertTrue(clearError, "expected 'exchange body cannot be null / 
empty', got: " + result.getException());
+    }
+}

Reply via email to