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") +
"®ion=" + 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") +
"®ion="
+ + 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());
+ }
+}