This is an automated email from the ASF dual-hosted git repository. orpiske pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 0ade008 CAMEL-15840: avoid keeping duplicate copies of the configuration object in camel-aws2-sns (#4592) 0ade008 is described below commit 0ade008d9e7968403bb36015d11f4f053fd1af90 Author: Otavio Rodolfo Piske <orpi...@users.noreply.github.com> AuthorDate: Wed Nov 11 12:47:19 2020 +0100 CAMEL-15840: avoid keeping duplicate copies of the configuration object in camel-aws2-sns (#4592) Includes a reproducer for CAMEL-15840 --- .../camel/component/aws2/sns/Sns2Component.java | 67 +++++++++++++++++--- .../camel/component/aws2/sns/Sns2Endpoint.java | 6 +- ...SnsTopicProducerCustomConfigLocalstackTest.java | 71 ++++++++++++++++++++++ .../aws2/sns/localstack/TestSnsConfiguration.java | 41 +++++++++++++ 4 files changed, 170 insertions(+), 15 deletions(-) diff --git a/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Component.java b/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Component.java index 689b2e8..6bf75a9 100644 --- a/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Component.java +++ b/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Component.java @@ -18,6 +18,7 @@ package org.apache.camel.component.aws2.sns; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; @@ -50,23 +51,30 @@ public class Sns2Component extends DefaultComponent { @Override protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { - if (remaining == null || remaining.trim().length() == 0) { throw new IllegalArgumentException("Topic name must be specified."); } - Sns2Configuration configuration = this.configuration != null ? this.configuration.copy() : new Sns2Configuration(); + + if (containsTransientParameters(parameters)) { + Map<String, Object> transientParameters = getTransientParameters(parameters); + + setProperties(getCamelContext(), this, transientParameters); + } + + configuration = this.configuration != null ? this.configuration : new Sns2Configuration(); + Sns2Endpoint endpoint = new Sns2Endpoint(uri, this, configuration); + + Map<String, Object> nonTransientParameters = getNonTransientParameters(parameters); + + setProperties(endpoint, nonTransientParameters); + if (remaining.startsWith("arn:")) { - String[] parts = remaining.split(":"); - if (parts.length != 6 || !parts[2].equals("sns")) { - throw new IllegalArgumentException("Topic arn must be in format arn:aws:sns:region:account:name."); - } - configuration.setTopicArn(remaining); - configuration.setRegion(Region.of(parts[3]).toString()); + parseRemaining(remaining); } else { configuration.setTopicName(remaining); + LOG.debug("Created the endpoint with topic {}", configuration.getTopicName()); } - Sns2Endpoint endpoint = new Sns2Endpoint(uri, this, configuration); - setProperties(endpoint, parameters); + if (endpoint.getConfiguration().isAutoDiscoverClient()) { checkAndSetRegistryClient(configuration, endpoint); } @@ -78,6 +86,44 @@ public class Sns2Component extends DefaultComponent { return endpoint; } + /* + This method, along with getTransientParameters, getNonTransientParameters and validateParameters handle transient + parameters. Transient parameters, in this sense, means temporary parameters passed to the URI, that should + no be directly set on the endpoint because they apply to a different lifecycle in the component/endpoint creation. + For example, the "configuration" parameter is used to set a different Component/Endpoint configuration class other + than the one provided by Camel. Because the configuration object is required to configure these objects, it must + be used earlier in the life cycle ... and not later as part of the transport setup. Therefore, transient. + */ + private boolean containsTransientParameters(Map<String, Object> parameters) { + return parameters.containsKey("configuration"); + } + + private Map<String, Object> getNonTransientParameters(Map<String, Object> parameters) { + return parameters.entrySet().stream().filter(k -> !k.getKey().equals("configuration")) + .collect(Collectors.toMap(k -> k.getKey(), k -> k.getValue())); + } + + private Map<String, Object> getTransientParameters(Map<String, Object> parameters) { + return parameters.entrySet().stream().filter(k -> k.getKey().equals("configuration")) + .collect(Collectors.toMap(k -> k.getKey(), k -> k.getValue())); + } + + @Override + protected void validateParameters(String uri, Map<String, Object> parameters, String optionPrefix) { + super.validateParameters(uri, getNonTransientParameters(parameters), optionPrefix); + } + + private void parseRemaining(String remaining) { + String[] parts = remaining.split(":"); + if (parts.length != 6 || !parts[2].equals("sns")) { + throw new IllegalArgumentException("Topic arn must be in format arn:aws:sns:region:account:name."); + } + configuration.setTopicArn(remaining); + configuration.setRegion(Region.of(parts[3]).toString()); + + LOG.debug("Created the endpoint with topic arn {}", configuration.getTopicArn()); + } + public Sns2Configuration getConfiguration() { return configuration; } @@ -103,4 +149,5 @@ public class Sns2Component extends DefaultComponent { LOG.debug("SnsClient instance is already set at endpoint level: skipping the check in the registry"); } } + } diff --git a/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Endpoint.java b/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Endpoint.java index ef5b00c..05db0f1 100644 --- a/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Endpoint.java +++ b/components/camel-aws2-sns/src/main/java/org/apache/camel/component/aws2/sns/Sns2Endpoint.java @@ -62,7 +62,7 @@ public class Sns2Endpoint extends DefaultEndpoint implements HeaderFilterStrateg @Metadata(required = true) private String topicNameOrArn; // to support component docs @UriParam - private Sns2Configuration configuration; + private final Sns2Configuration configuration; @UriParam private HeaderFilterStrategy headerFilterStrategy; @@ -185,10 +185,6 @@ public class Sns2Endpoint extends DefaultEndpoint implements HeaderFilterStrateg return configuration; } - public void setConfiguration(Sns2Configuration configuration) { - this.configuration = configuration; - } - public void setSNSClient(SnsClient snsClient) { this.snsClient = snsClient; } diff --git a/components/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/localstack/SnsTopicProducerCustomConfigLocalstackTest.java b/components/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/localstack/SnsTopicProducerCustomConfigLocalstackTest.java new file mode 100644 index 0000000..d096e22 --- /dev/null +++ b/components/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/localstack/SnsTopicProducerCustomConfigLocalstackTest.java @@ -0,0 +1,71 @@ +/* + * 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.localstack; + +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.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class SnsTopicProducerCustomConfigLocalstackTest extends Aws2SNSBaseTest { + + @RegisterExtension + public static SharedNameGenerator sharedNameGenerator = new TestEntityNameGenerator(); + + @Test + public void sendInOnly() throws Exception { + Exchange exchange = template.send("direct:start", ExchangePattern.InOnly, new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(Sns2Constants.SUBJECT, "This is my subject"); + exchange.getIn().setBody("This is my message text."); + } + }); + + assertNotNull(exchange.getIn().getHeader(Sns2Constants.MESSAGE_ID)); + } + + @Test + public void sendInOut() throws Exception { + Exchange exchange = template.send("direct:start", ExchangePattern.InOut, new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(Sns2Constants.SUBJECT, "This is my subject"); + exchange.getIn().setBody("This is my message text."); + } + }); + + assertNotNull(exchange.getMessage().getHeader(Sns2Constants.MESSAGE_ID)); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .toF("aws2-sns://%s?subject=The+subject+message&configuration=#class:%s", + sharedNameGenerator.getName(), TestSnsConfiguration.class.getName()); + } + }; + } +} diff --git a/components/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/localstack/TestSnsConfiguration.java b/components/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/localstack/TestSnsConfiguration.java new file mode 100644 index 0000000..10a8f5f --- /dev/null +++ b/components/camel-aws2-sns/src/test/java/org/apache/camel/component/aws2/sns/localstack/TestSnsConfiguration.java @@ -0,0 +1,41 @@ +/* + * 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.localstack; + +import org.apache.camel.component.aws2.sns.Sns2Configuration; +import org.apache.camel.test.infra.aws2.clients.AWSSDKClientUtils; +import software.amazon.awssdk.services.sns.SnsClient; + +public class TestSnsConfiguration extends Sns2Configuration { + private SnsClient snsClient; + + public TestSnsConfiguration() { + snsClient = AWSSDKClientUtils.newSNSClient(); + super.setAmazonSNSClient(snsClient); + } + + @Override + public void setAmazonSNSClient(SnsClient amazonSNSClient) { + // NO-OP + } + + @Override + public SnsClient getAmazonSNSClient() { + return snsClient; + } +}