You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2026/09/21 09:10:17 UTC
(camel) branch camel-4.18.x updated: [backport camel-4.18.x] CAMEL-24766: camel-huaweicloud-smn - resolve the operation before the empty-body check
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch camel-4.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.18.x by this push:
new 237f0628a1fb [backport camel-4.18.x] CAMEL-24766: camel-huaweicloud-smn - resolve the operation before the empty-body check
237f0628a1fb is described below
commit 237f0628a1fb8bf528b7bc86990005f02552beb6
Author: Guillaume Nodet - AI Bot <gn...@gmail.com>
AuthorDate: Mon Sep 21 11:10:09 2026 +0200
[backport camel-4.18.x] CAMEL-24766: camel-huaweicloud-smn - resolve the operation before the empty-body check
* [backport camel-4.18.x] CAMEL-24766: camel-huaweicloud-smn - resolve the operation before the empty-body check
* Fix: add camel-test-junit5 alongside camel-test-junit6 for 4.18.x compatibility
* fix: use camel-test-junit5 instead of camel-test-junit6 on camel-4.18.x
camel-4.18.x uses junit6-jupiter-version=6.0.1 which pulls in JUnit
Platform 1.12+. The 3-argument Store.computeIfAbsent() was removed in
JUnit Platform 1.12, causing NoSuchMethodError in TestLoggerExtension.
Switch the backported test to camel-test-junit5 (already used by the
other tests in this module) to avoid the incompatibility.
---------
Co-authored-by: gnodet-bot <gn...@users.noreply.github.com>
Co-authored-by: Guillaume Nodet <gn...@gmail.com>
---
.../camel-huawei/camel-huaweicloud-smn/pom.xml | 2 +-
.../smn/SimpleNotificationProducer.java | 25 +++--
...PublishTextMessageOperationViaPropertyTest.java | 117 +++++++++++++++++++++
3 files changed, 130 insertions(+), 14 deletions(-)
diff --git a/components/camel-huawei/camel-huaweicloud-smn/pom.xml b/components/camel-huawei/camel-huaweicloud-smn/pom.xml
index bd59a908a995..78e72f0c289e 100644
--- a/components/camel-huawei/camel-huaweicloud-smn/pom.xml
+++ b/components/camel-huawei/camel-huaweicloud-smn/pom.xml
@@ -69,7 +69,7 @@
<!-- for testing -->
<dependency>
<groupId>org.apache.camel</groupId>
- <artifactId>camel-test-spring-junit5</artifactId>
+ <artifactId>camel-test-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
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..42dace6ba496
--- /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.junit5.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());
+ }
+}