This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch CAMEL-22429 in repository https://gitbox.apache.org/repos/asf/camel.git
commit a26a35c189929d24c3018d8dd4d493540e75878b Author: Andrea Cosentino <[email protected]> AuthorDate: Thu Jan 29 10:57:49 2026 +0100 CAMEL-22429 - camel-aws2-sns component fails when sending CloudEvents with subjects over 100 characters Signed-off-by: Andrea Cosentino <[email protected]> --- .../src/main/docs/aws2-sns-component.adoc | 6 ++ .../camel/component/aws2/sns/Sns2Constants.java | 5 ++ .../camel/component/aws2/sns/Sns2Producer.java | 7 ++ .../component/aws2/sns/AmazonSNSClientMock.java | 7 ++ .../camel/component/aws2/sns/SnsComponentTest.java | 61 +++++++++++++++ .../SnsTopicProducerSubjectTruncationIT.java | 87 ++++++++++++++++++++++ 6 files changed, 173 insertions(+) diff --git a/components/camel-aws/camel-aws2-sns/src/main/docs/aws2-sns-component.adoc b/components/camel-aws/camel-aws2-sns/src/main/docs/aws2-sns-component.adoc index 3a92ed73ae38..2f55b027b82c 100644 --- a/components/camel-aws/camel-aws2-sns/src/main/docs/aws2-sns-component.adoc +++ b/components/camel-aws/camel-aws2-sns/src/main/docs/aws2-sns-component.adoc @@ -165,6 +165,12 @@ When sending something to the FIFO topic, you'll need to always set up a message If the content-based message deduplication has been enabled on the SNS Fifo topic, where won't be the need of setting a message deduplication id strategy, otherwise you'll have to set it. +=== Message Subject Length Limitation + +AWS SNS has a maximum subject length of 100 characters. If you send a message with a subject longer than 100 characters (for example, when using CloudEvents with long subjects), the subject will be automatically truncated to 100 characters. + +This behavior ensures compatibility with AWS SNS constraints while allowing seamless integration with systems like CloudEvents that do not impose such restrictions. + == Examples === Producer Examples diff --git a/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Constants.java b/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Constants.java index 662fba1ff103..e5d355da0d54 100644 --- a/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Constants.java +++ b/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Constants.java @@ -23,6 +23,11 @@ import org.apache.camel.spi.Metadata; */ public interface Sns2Constants { + /** + * AWS SNS has a maximum subject length of 100 characters. Subjects longer than this will be truncated. + */ + int MAX_SUBJECT_LENGTH = 100; + @Metadata(description = "The Amazon SNS message ID.", javaType = "String") String MESSAGE_ID = "CamelAwsSnsMessageId"; @Metadata(description = "The Amazon SNS message subject. If not set, the subject from the\n" + diff --git a/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Producer.java b/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Producer.java index 8e947b9e43d1..6bad44284148 100644 --- a/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Producer.java +++ b/components/camel-aws/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Producer.java @@ -99,6 +99,13 @@ public class Sns2Producer extends DefaultProducer { subject = getConfiguration().getSubject(); } + // AWS SNS has a maximum subject length of 100 characters + if (subject != null && subject.length() > Sns2Constants.MAX_SUBJECT_LENGTH) { + LOG.debug("Subject exceeds AWS SNS maximum length of {} characters, truncating from {} to {} characters", + Sns2Constants.MAX_SUBJECT_LENGTH, subject.length(), Sns2Constants.MAX_SUBJECT_LENGTH); + subject = subject.substring(0, Sns2Constants.MAX_SUBJECT_LENGTH); + } + return subject; } diff --git a/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/AmazonSNSClientMock.java b/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/AmazonSNSClientMock.java index a01cbc4c0551..f3240855b059 100644 --- a/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/AmazonSNSClientMock.java +++ b/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/AmazonSNSClientMock.java @@ -37,9 +37,15 @@ public class AmazonSNSClientMock implements SnsClient { private static final String DEFAULT_TOPIC_ARN = "arn:aws:sns:us-east-1:541925086079:MyTopic"; + private PublishRequest lastPublishRequest; + public AmazonSNSClientMock() { } + public PublishRequest getLastPublishRequest() { + return lastPublishRequest; + } + @Override public SetTopicAttributesResponse setTopicAttributes(SetTopicAttributesRequest setTopicAttributesRequest) { assertEquals(DEFAULT_TOPIC_ARN, setTopicAttributesRequest.topicArn()); @@ -59,6 +65,7 @@ public class AmazonSNSClientMock implements SnsClient { @Override public PublishResponse publish(PublishRequest publishRequest) { + this.lastPublishRequest = publishRequest; return PublishResponse.builder().messageId("dcc8ce7a-7f18-4385-bedd-b97984b4363c").build(); } diff --git a/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/SnsComponentTest.java b/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/SnsComponentTest.java index 46652ee80052..a70ec46279bd 100644 --- a/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/SnsComponentTest.java +++ b/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/SnsComponentTest.java @@ -66,6 +66,67 @@ public class SnsComponentTest extends CamelTestSupport { }; } + @DisplayName(value = "Test for CAMEL-22429 - Subject truncation to 100 characters") + @Test + public void sendWithLongSubject() { + // Create a subject longer than 100 characters + String longSubject + = "This is a very long subject that exceeds the AWS SNS maximum subject length of 100 characters and should be truncated"; + + Exchange exchange = template.send("direct:start", ExchangePattern.InOnly, new Processor() { + public void process(Exchange exchange) { + exchange.getIn().setHeader(Sns2Constants.SUBJECT, longSubject); + exchange.getIn().setBody("This is my message text."); + } + }); + + assertEquals("dcc8ce7a-7f18-4385-bedd-b97984b4363c", exchange.getIn().getHeader(Sns2Constants.MESSAGE_ID)); + + // Verify the subject was truncated to 100 characters + String actualSubject = client.getLastPublishRequest().subject(); + assertEquals(Sns2Constants.MAX_SUBJECT_LENGTH, actualSubject.length()); + assertEquals(longSubject.substring(0, Sns2Constants.MAX_SUBJECT_LENGTH), actualSubject); + } + + @DisplayName(value = "Test for CAMEL-22429 - Subject exactly at 100 characters should not be truncated") + @Test + public void sendWithExact100CharSubject() { + // Create a subject exactly 100 characters + String exact100Subject = "A".repeat(Sns2Constants.MAX_SUBJECT_LENGTH); + + Exchange exchange = template.send("direct:start", ExchangePattern.InOnly, new Processor() { + public void process(Exchange exchange) { + exchange.getIn().setHeader(Sns2Constants.SUBJECT, exact100Subject); + exchange.getIn().setBody("This is my message text."); + } + }); + + assertEquals("dcc8ce7a-7f18-4385-bedd-b97984b4363c", exchange.getIn().getHeader(Sns2Constants.MESSAGE_ID)); + + // Verify the subject was not modified + String actualSubject = client.getLastPublishRequest().subject(); + assertEquals(exact100Subject, actualSubject); + } + + @DisplayName(value = "Test for CAMEL-22429 - Short subject should not be modified") + @Test + public void sendWithShortSubject() { + String shortSubject = "Short subject"; + + Exchange exchange = template.send("direct:start", ExchangePattern.InOnly, new Processor() { + public void process(Exchange exchange) { + exchange.getIn().setHeader(Sns2Constants.SUBJECT, shortSubject); + exchange.getIn().setBody("This is my message text."); + } + }); + + assertEquals("dcc8ce7a-7f18-4385-bedd-b97984b4363c", exchange.getIn().getHeader(Sns2Constants.MESSAGE_ID)); + + // Verify the subject was not modified + String actualSubject = client.getLastPublishRequest().subject(); + assertEquals(shortSubject, actualSubject); + } + @DisplayName(value = "Test for CAMEL-16586") @Test public void createMultipleEndpoints() throws Exception { diff --git a/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/integration/SnsTopicProducerSubjectTruncationIT.java b/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/integration/SnsTopicProducerSubjectTruncationIT.java new file mode 100644 index 000000000000..a9394d705e9f --- /dev/null +++ b/components/camel-aws/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/integration/SnsTopicProducerSubjectTruncationIT.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.aws2.sns.integration; + +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.aws2.sns.Sns2Constants; +import org.apache.camel.test.infra.common.SharedNameGenerator; +import org.apache.camel.test.infra.common.TestEntityNameGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * Integration test for CAMEL-22429: Verify that subjects longer than 100 characters are properly truncated when sending + * to AWS SNS, preventing InvalidParameterException. + */ +@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", disabledReason = "Flaky on GitHub Actions") +public class SnsTopicProducerSubjectTruncationIT extends Aws2SNSBase { + + @RegisterExtension + public static SharedNameGenerator sharedNameGenerator = new TestEntityNameGenerator(); + + @DisplayName("Test for CAMEL-22429 - Subject longer than 100 chars should be truncated and message sent successfully") + @Test + public void sendWithLongSubject() { + // Create a subject longer than 100 characters (e.g., CloudEvents style subject) + String longSubject + = "This is a very long subject that exceeds the AWS SNS maximum subject length of 100 characters and should be truncated automatically"; + + Exchange exchange = template.send("direct:start", ExchangePattern.InOnly, new Processor() { + public void process(Exchange exchange) { + exchange.getIn().setHeader(Sns2Constants.SUBJECT, longSubject); + exchange.getIn().setBody("This is my message text with a long subject."); + } + }); + + // If we get here without an exception, the truncation worked + assertNotNull(exchange.getIn().getHeader(Sns2Constants.MESSAGE_ID)); + } + + @DisplayName("Test for CAMEL-22429 - Subject exactly 100 chars should work without truncation") + @Test + public void sendWithExact100CharSubject() { + // Create a subject exactly 100 characters + String exact100Subject = "A".repeat(Sns2Constants.MAX_SUBJECT_LENGTH); + + Exchange exchange = template.send("direct:start", ExchangePattern.InOnly, new Processor() { + public void process(Exchange exchange) { + exchange.getIn().setHeader(Sns2Constants.SUBJECT, exact100Subject); + exchange.getIn().setBody("This is my message text with exact 100 char subject."); + } + }); + + assertNotNull(exchange.getIn().getHeader(Sns2Constants.MESSAGE_ID)); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .toF("aws2-sns://%s?autoCreateTopic=true", sharedNameGenerator.getName()); + } + }; + } +}
