This is an automated email from the ASF dual-hosted git repository. ningjiang 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 eac293a [CAMEL-16001] Camel component for HuaweiCloud Simple Notification Services (SMN) se… (#4900) eac293a is described below commit eac293ae4e8f5472f4aea0d29994d6e65aa2fde0 Author: Reji Mathews <reji...@yahoo.com> AuthorDate: Wed Jan 27 19:38:37 2021 -0500 [CAMEL-16001] Camel component for HuaweiCloud Simple Notification Services (SMN) se… (#4900) * Camel component for HuaweiCloud Simple Notification Services (SMN) services SMN is one among the Cloud product offering within HuaweiCloud ecosystem which enables cloud application users to broadcast/send out notifications to subscribers. It provides a single unified endpoint aka. topic for the application to push data. Multiple subscribers can be associated with a given topic. Simple Message Notification (SMN) enables you to broadcast messages to subscribers who can chose to receive the notifications via an email addresses, phone numbers, serverless functions and HTTP/HTTPS servers and connect cloud services through notifications, reducing system complexity and developmental efforts to the publishing app. * CAMEL-16001 Fixing typos in documentation * CAMEL-16001 updating doc with unique identifiers returned by smn server once api request is processed. these are mapped to exchange properties * CAMEL-16001 - adding license headers to all test java classes * CAMEL-16001 - updated code for SMN endpoint resolver * CAMEL-16001 removed redundant member simpleNotificationEndpoint since its already part of superclass * CAMEL-16001 Moving all exchange properties to SmnProperties constants class * CAMEL-16001 remove lazy initialization of SmnClient * CAMEL-16001 - Replacing wiremocks and Mockito with SmnClientMock to stub the SmnClient method. Replacing wiremocks and Mockito with SmnClientMock to stub the SmnClient method. * CAMEL-16001 - Updating logging level * CAMEL-16001 : removed unused dependencies/imports * CAMEL-16001 adding ASF licenses / final immutable to constants and smnclient init to overriden doStart() adding ASF licenses / final immutable to constants and smnclient init to overriden doStart() * CAMEL-16001 - removing unit tests for models * CAMEL-16001 - adding Apache license headers Co-authored-by: Reji Mathews 84131876 <reji.math...@huawei.com> --- components/camel-huaweicloud-smn/pom.xml | 117 +++++++ .../src/main/docs/hwcloud-component.adoc | 148 +++++++++ .../smn/SimpleNotificationComponent.java | 32 ++ .../smn/SimpleNotificationEndpoint.java | 239 +++++++++++++ .../smn/SimpleNotificationProducer.java | 368 +++++++++++++++++++++ .../huaweicloud/smn/SimpleNotificationUtils.java | 61 ++++ .../huaweicloud/smn/constants/SmnConstants.java | 25 ++ .../huaweicloud/smn/constants/SmnOperations.java | 26 ++ .../huaweicloud/smn/constants/SmnProperties.java | 19 ++ .../huaweicloud/smn/constants/SmnServices.java | 25 ++ .../smn/models/ClientConfigurations.java | 138 ++++++++ .../huaweicloud/smn/models/ServiceKeys.java | 59 ++++ .../org/apache/camel/component/hwcloud-smn | 1 + .../smn/PublishTemplatedMessageTest.java | 86 +++++ .../huaweicloud/smn/PublishTextMessageTest.java | 78 +++++ .../component/huaweicloud/smn/SmnClientMock.java | 36 ++ .../huaweicloud/smn/TestConfiguration.java | 66 ++++ .../smn/constants/SmnConstantsTest.java | 27 ++ .../smn/constants/SmnOperationsTest.java | 28 ++ .../smn/constants/SmnPropertiesTest.java | 33 ++ .../huaweicloud/smn/constants/SmnServicesTest.java | 27 ++ .../src/test/resources/log4j2.properties | 22 ++ .../test/resources/testconfiguration.properties | 22 ++ 23 files changed, 1683 insertions(+) diff --git a/components/camel-huaweicloud-smn/pom.xml b/components/camel-huaweicloud-smn/pom.xml new file mode 100644 index 0000000..c860fb5 --- /dev/null +++ b/components/camel-huaweicloud-smn/pom.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.camel</groupId> + <artifactId>camel-huaweicloud-smn</artifactId> + <packaging>jar</packaging> + <version>3.8.0-SNAPSHOT</version> + + <name>Huawei Cloud SimpleNotification Component</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <!-- Camel BOM --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-bom</artifactId> + <version>3.8.0-SNAPSHOT</version> + <scope>import</scope> + <type>pom</type> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + + <!-- camel --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-support</artifactId> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.12.0</version> + </dependency> + + <!-- HuaweiCloud SDK v3--> + <dependency> + <groupId>com.huaweicloud.sdk</groupId> + <artifactId>huaweicloud-sdk-core</artifactId> + <version>3.0.30-rc</version> + </dependency> + <dependency> + <groupId>com.huaweicloud.sdk</groupId> + <artifactId>huaweicloud-sdk-smn</artifactId> + <version>3.0.30-rc</version> + </dependency> + + <!-- logging --> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-slf4j-impl</artifactId> + <version>2.13.3</version> + <scope>test</scope> + </dependency> + + <!-- testing --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test</artifactId> + <scope>test</scope> + </dependency> + <!-- testing --> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>5.7.0</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <defaultGoal>install</defaultGoal> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>3.2.0</version> + <configuration> + <encoding>UTF-8</encoding> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/components/camel-huaweicloud-smn/src/main/docs/hwcloud-component.adoc b/components/camel-huaweicloud-smn/src/main/docs/hwcloud-component.adoc new file mode 100644 index 0000000..7a4c19a --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/docs/hwcloud-component.adoc @@ -0,0 +1,148 @@ +[[hwcloud-smn-component]] += Huawei Cloud Smn Component +:docTitle: Huawei Cloud SMN (Simple notification services) +:artifactId: camel-huaweicloud-smn +:description: Send message to simple notification services +:since: 3.8.0 +:supportLevel: Stable +:component-header: Only producer is supported +include::{cq-version}@camel-quarkus:ROOT:partial$reference/components/hwcloud-smn.adoc[opts=optional] + +*Since Camel {since}* + +*{component-header}* + +Huawei Cloud SMN component allowes you to integrate with Simple notification services[https://www.huaweicloud.com/en-us/product/smn.html] provided by Huawei cloud. + +Maven users will need to add the following dependency to their `pom.xml` +for this component: + +[source,xml] +------------------------------------------------------------ +<dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-huaweicloud-smn</artifactId> + <version>x.x.x</version> + <!-- use the same version as your Camel core version --> +</dependency> +------------------------------------------------------------ + +== URI format + +To send a notification. + +[source,java] +------------------------ +hwcloud-smn:service[?options] +------------------------ + + +== Options + +// component options: START +The SMN component supports 4 options, which are listed below. + + + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...] +| *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean +|=== +// component options: END + +// endpoint options: START +The SMN endpoint is configured using URI syntax: + +---- +hwcloud-smn:service +---- + +with the following path and query parameters: + +=== Path Parameters (1 parameters): + + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *service* | *Required* name of the available services in SMN | | String +|=== + + +=== Query Parameters (28 parameters): + + +[width="100%",cols="2,5,^1,2",options="header"] +|=== +| Name | Description | Default | Type +| *operation* (producer) | *Required* The actual operation to invoke under the mentioned service | | String +| *serviceKeys* (advanced) | Configuration object of class org.apache.camel.component.huaweicloud.smn.models.ServiceKeys containing connectivity parameters like AK, SK, ProjectID and region | null | ServiceKeys +| *authKey* | *Required* Authentication Key (AK) can be generated from your cloud account user settings | null | String +| *secretKey* | *Required* Secret Key (AK) can be generated from your cloud account user settings | | String +| *projectId* | *Required* Project ID for your specific region. Refer your cloud account settings | | String +| *proxyHost* | *Optional* IP/Hostname of the proxy server to access the public cloud from your deployment landscape | | String +| *proxyPort* | *Optional* Port number of the proxy service on proxy host | | String +| *proxyUser* | *Optional* Proxy user id (if applicable) | | String +| *proxyPassword* | *Optional* Proxy user password (if applicable) | | String +| *region*| *Required* Region where your SMN service is hosted | | String +| *messageTtl* | *Optional* Time-to-live parameter for each message published to the topic. The subcriptions which are added to the topic within this timeout value will receive the notification | 3600 | String +| *ignoreSslVerification* | *Optional* whether to ignore SSL verification while connecting to huawei cloud services. It's not recommended in production environment | false | Boolean +|=== +// endpoint options: END + +== Usage + +=== Message properties evaluated by the SMN producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Header |Type |Description + +|`CamelHwCloudSmnSubject` |`String` |Subject tag for the outgoing notification + +|`CamelHwCloudSmnTopic` |`String` |Smn topic into which the message is to be posted + +|`CamelHwCloudSmnMessageTtl` |`Integer` | Validity of the posted notification message + +|`CamelHwCloudSmnTemplateTags` |`Map<String, String>` | Contains K,V pairs of tags and values when using operation `publishAsTemplatedMessage` + +|`CamelHwCloudSmnTemplateName` |`String` |Name of the template to use while using operation `publishAsTemplatedMessage` + + +|======================================================================= + +=== Message properties set by the SMN producer + +[width="100%",cols="10%,10%,80%",options="header",] +|======================================================================= +|Header |Type |Description + +|`CamelHwCloudSmnMesssageId` |`String` | Unique message id returned by simple message notification server after processing the request + +|`CamelHwCloudSmnRequestId` |`String` | Unique request id returned by simple message notification server after processing the request + +|======================================================================= + +== Supported smn services + +- publishMessageService + + +== Supported smn operations + +- publishAsTextMessage +- publishAsTemplatedMessage + + +[source,java] +-------------------------------------------------------------------------------- +from("direct:triggerRoute") +.setProperty("CamelHwCloudSmnSubject", constant("This is my subjectline")) +.setProperty("CamelHwCloudSmnTopic", constant("reji-test")) +.setProperty("CamelHwCloudSmnMessageTtl", constant(60)) +.setProperty("CamelHwCloudSmnTemplateTags", constant(tags)) +.setProperty("CamelHwCloudSmnTemplateName", constant("hello-template")) +.to("hwcloud-smn:publishMessageService?operation=publishAsTextMessage&authKey=*********&secretKey=********&projectId=9071a38e7f6a4ba7b7bcbeb7d4ea6efc®ion=cn-north-4") +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationComponent.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationComponent.java new file mode 100644 index 0000000..812f554 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationComponent.java @@ -0,0 +1,32 @@ +/* + * 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 java.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.support.DefaultComponent; + +@org.apache.camel.spi.annotations.Component("hwcloud-smn") +public class SimpleNotificationComponent extends DefaultComponent { + + protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { + Endpoint endpoint = new SimpleNotificationEndpoint(uri, remaining, this); + setProperties(endpoint, parameters); + return endpoint; + } +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationEndpoint.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationEndpoint.java new file mode 100644 index 0000000..60145a4 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationEndpoint.java @@ -0,0 +1,239 @@ +/* + * 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 java.util.concurrent.ExecutorService; + +import com.huaweicloud.sdk.smn.v2.SmnClient; +import org.apache.camel.Category; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.component.huaweicloud.smn.models.ServiceKeys; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriPath; +import org.apache.camel.support.DefaultEndpoint; + +/** + * Huawei Cloud component to integrate with SimpleNotification services + */ +@UriEndpoint(firstVersion = "3.8.0", scheme = "hwcloud-smn", title = "SimpleNotification", + syntax = "hwcloud-smn:smnService", + category = { Category.CLOUD, Category.MESSAGING }, producerOnly = true) +public class SimpleNotificationEndpoint extends DefaultEndpoint { + + @UriPath(description = "Name of SMN service to invoke", displayName = "Service name", label = "producer") + @Metadata(required = true) + private String smnService; + + @UriParam(description = "Name of operation to perform", displayName = "Operation name", label = "producer") + @Metadata(required = true) + private String operation; + + @UriParam(description = "Configuration object for cloud service authentication", displayName = "Service Configuration", + secret = true) + @Metadata(required = false) + private ServiceKeys serviceKeys; + + @UriParam(description = "Authentication key for the cloud user", displayName = "API authentication key (AK)", secret = true) + @Metadata(required = true) + private String authKey; + + @UriParam(description = "Secret key for the cloud user", displayName = "API secret key (SK)", secret = true) + @Metadata(required = true) + private String secretKey; + + @UriParam(description = "Cloud project ID", displayName = "Project ID", secret = false) + @Metadata(required = true) + private String projectId; + + @UriParam(description = "Proxy server ip/hostname", displayName = "Proxy server host", secret = false) + @Metadata(required = false) + private String proxyHost; + + @UriParam(description = "Proxy server port", displayName = "Proxy server port", secret = false) + @Metadata(required = false) + private int proxyPort; + + @UriParam(description = "Proxy authentication user", displayName = "Proxy user", secret = true) + @Metadata(required = false) + private String proxyUser; + + @UriParam(description = "Proxy authentication password", displayName = "Proxy password", secret = true) + @Metadata(required = false) + private String proxyPassword; + + @UriParam(description = "SMN service region", displayName = "Service region", secret = false) + @Metadata(required = true) + private String region; + + @UriParam(description = "TTL for published message", displayName = "Message TTL", secret = false, defaultValue = "3600") + @Metadata(required = false) + private int messageTtl = 3600; + + @UriParam(description = "Ignore SSL verification", displayName = "SSL Verification Ignored", secret = false, + defaultValue = "false") + @Metadata(required = false) + private boolean ignoreSslVerification = false; + + private SmnClient smnClient; + + public SimpleNotificationEndpoint() { + } + + public SimpleNotificationEndpoint(String uri, String smnService, SimpleNotificationComponent component) { + super(uri, component); + this.smnService = smnService; + } + + @Override + public Producer createProducer() throws Exception { + return new SimpleNotificationProducer(this); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + throw new UnsupportedOperationException("You cannot receive messages from this endpoint"); + } + + public String getSmnService() { + return smnService; + } + + public void setSmnService(String smnService) { + this.smnService = smnService; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public ServiceKeys getCredentials() { + return serviceKeys; + } + + public void setCredentials(ServiceKeys serviceKeys) { + this.serviceKeys = serviceKeys; + } + + public ServiceKeys getServiceKeys() { + return serviceKeys; + } + + public void setServiceKeys(ServiceKeys serviceKeys) { + this.serviceKeys = serviceKeys; + } + + public String getAuthKey() { + return authKey; + } + + public void setAuthKey(String authKey) { + this.authKey = authKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getProjectId() { + return projectId; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public String getProxyUser() { + return proxyUser; + } + + public void setProxyUser(String proxyUser) { + this.proxyUser = proxyUser; + } + + public String getProxyPassword() { + return proxyPassword; + } + + public void setProxyPassword(String proxyPassword) { + this.proxyPassword = proxyPassword; + } + + public String getProxyHost() { + return proxyHost; + } + + public void setProxyHost(String proxyHost) { + this.proxyHost = proxyHost; + } + + public int getProxyPort() { + return proxyPort; + } + + public void setProxyPort(int proxyPort) { + this.proxyPort = proxyPort; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public int getMessageTtl() { + return messageTtl; + } + + public void setMessageTtl(int messageTtl) { + this.messageTtl = messageTtl; + } + + public boolean isIgnoreSslVerification() { + return ignoreSslVerification; + } + + public void setIgnoreSslVerification(boolean ignoreSslVerification) { + this.ignoreSslVerification = ignoreSslVerification; + } + + public SmnClient getSmnClient() { + return smnClient; + } + + public void setSmnClient(SmnClient smnClient) { + this.smnClient = smnClient; + } + + public ExecutorService createExecutor() { + // TODO: Delete me when you implemented your custom component + return getCamelContext().getExecutorServiceManager().newSingleThreadExecutor(this, "SimpleNotificationConsumer"); + } +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationProducer.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationProducer.java new file mode 100644 index 0000000..119ac6c --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationProducer.java @@ -0,0 +1,368 @@ +/* + * 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 java.util.HashMap; + +import com.huaweicloud.sdk.core.auth.BasicCredentials; +import com.huaweicloud.sdk.core.http.HttpConfig; +import com.huaweicloud.sdk.smn.v2.SmnClient; +import com.huaweicloud.sdk.smn.v2.model.PublishMessageRequest; +import com.huaweicloud.sdk.smn.v2.model.PublishMessageRequestBody; +import com.huaweicloud.sdk.smn.v2.model.PublishMessageResponse; +import org.apache.camel.Exchange; +import org.apache.camel.component.huaweicloud.smn.constants.SmnConstants; +import org.apache.camel.component.huaweicloud.smn.constants.SmnOperations; +import org.apache.camel.component.huaweicloud.smn.constants.SmnProperties; +import org.apache.camel.component.huaweicloud.smn.constants.SmnServices; +import org.apache.camel.component.huaweicloud.smn.models.ClientConfigurations; +import org.apache.camel.support.DefaultProducer; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SimpleNotificationProducer extends DefaultProducer { + private static final Logger LOG = LoggerFactory.getLogger(SimpleNotificationProducer.class); + private SmnClient smnClient; + private ClientConfigurations clientConfigurations; + + public SimpleNotificationProducer(SimpleNotificationEndpoint endpoint) { + super(endpoint); + } + + @Override + protected void doStart() throws Exception { + super.doStart(); + validateAndInitializeSmnClient((SimpleNotificationEndpoint) super.getEndpoint()); + } + + public void process(Exchange exchange) throws Exception { + + String service = ((SimpleNotificationEndpoint) super.getEndpoint()).getSmnService(); + + if (!ObjectHelper.isEmpty(service)) { + switch (service) { + case SmnServices.PUBLISH_MESSAGE: + if (LOG.isDebugEnabled()) { + LOG.debug("Using message publishing service"); + } + performPublishMessageServiceOperations((SimpleNotificationEndpoint) super.getEndpoint(), exchange); + if (LOG.isDebugEnabled()) { + LOG.debug("Completed publishing message"); + } + break; + default: + if (LOG.isErrorEnabled()) { + LOG.error("Unsupported service name {}", service); + } + throw new UnsupportedOperationException(String.format("service %s is not a supported service", service)); + } + } else { + if (LOG.isErrorEnabled()) { + LOG.error("Service name is null/empty"); + } + throw new IllegalStateException("service name cannot be null/empty"); + } + } + + /** + * Publish message service operations + * + * @param endpoint + * @param exchange + */ + private void performPublishMessageServiceOperations(SimpleNotificationEndpoint endpoint, Exchange exchange) { + PublishMessageResponse response; + + PublishMessageRequestBody apiBody; + this.clientConfigurations = validateServiceConfigurations(endpoint, exchange); + + if (LOG.isDebugEnabled()) { + LOG.debug("Checking operation name"); + } + switch (clientConfigurations.getOperation()) { + + case SmnOperations.PUBLISH_AS_TEXT_MESSAGE: + if (LOG.isDebugEnabled()) { + LOG.debug("Publishing as text message"); + } + apiBody = new PublishMessageRequestBody() + .withMessage(exchange.getMessage().getBody(String.class)) + .withSubject(clientConfigurations.getSubject()) + .withTimeToLive(String.valueOf(clientConfigurations.getMessageTtl())); + + response = smnClient.publishMessage(new PublishMessageRequest() + .withBody(apiBody) + .withTopicUrn(clientConfigurations.getTopicUrn())); + break; + + case SmnOperations.PUBLISH_AS_TEMPLATED_MESSAGE: + if (LOG.isDebugEnabled()) { + LOG.debug("Publishing as templated message"); + } + apiBody = new PublishMessageRequestBody() + .withMessage(exchange.getMessage().getBody(String.class)) + .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())); + + response = smnClient.publishMessage(new PublishMessageRequest() + .withBody(apiBody) + .withTopicUrn(clientConfigurations.getTopicUrn())); + break; + + default: + throw new UnsupportedOperationException( + String.format("operation %s not supported in publishMessage service", + clientConfigurations.getOperation())); + } + setResponseParameters(exchange, response); + } + + /** + * maps api response parameters as exchange property + * + * @param exchange + * @param response + */ + private void setResponseParameters(Exchange exchange, PublishMessageResponse response) { + if (response == null) { + return; // mapping is not required if response object is null + } + if (!ObjectHelper.isEmpty(response.getMessageId())) { + exchange.setProperty(SmnProperties.SERVICE_MESSAGE_ID, response.getMessageId()); + } + if (!ObjectHelper.isEmpty(response.getRequestId())) { + exchange.setProperty(SmnProperties.SERVICE_REQUEST_ID, response.getRequestId()); + } + } + + /** + * validation and initialization of SmnClient object + * + * @param simpleNotificationEndpoint + */ + private void validateAndInitializeSmnClient(SimpleNotificationEndpoint simpleNotificationEndpoint) { + if(simpleNotificationEndpoint.getSmnClient() != null) { + if(LOG.isWarnEnabled()) { + LOG.warn("Instance of SmnClient was set on the endpoint. Skipping creation of SmnClient from endpoint parameters"); + } + this.smnClient = simpleNotificationEndpoint.getSmnClient(); + return; + } + this.clientConfigurations = new ClientConfigurations(); + + //checking for cloud SK (secret key) + if (ObjectHelper.isEmpty(simpleNotificationEndpoint.getSecretKey()) && + ObjectHelper.isEmpty(simpleNotificationEndpoint.getServiceKeys())) { + if (LOG.isErrorEnabled()) { + LOG.error("secret key (SK) not found"); + } + throw new IllegalArgumentException("authentication parameter 'secret key (SK)' not found"); + } else { + clientConfigurations.setSecretKey(simpleNotificationEndpoint.getSecretKey() != null + ? simpleNotificationEndpoint.getSecretKey() : simpleNotificationEndpoint.getServiceKeys().getSecretKey()); + } + + //checking for cloud AK (auth key) + if (ObjectHelper.isEmpty(simpleNotificationEndpoint.getAuthKey()) && + ObjectHelper.isEmpty(simpleNotificationEndpoint.getServiceKeys())) { + if (LOG.isErrorEnabled()) { + LOG.error("authentication key (AK) not found"); + } + throw new IllegalArgumentException("authentication parameter 'authentication key (AK)' not found"); + } else { + clientConfigurations.setAuthenticationkey(simpleNotificationEndpoint.getAuthKey() != null + ? simpleNotificationEndpoint.getAuthKey() + : simpleNotificationEndpoint.getServiceKeys().getAuthenticationKey()); + } + + //checking for project ID + if (ObjectHelper.isEmpty(simpleNotificationEndpoint.getProjectId())) { + if (LOG.isErrorEnabled()) { + LOG.error("Project ID not found"); + } + throw new IllegalArgumentException("project ID not found"); + } else { + clientConfigurations.setProjectId(simpleNotificationEndpoint.getProjectId()); + } + + //checking for region + String endpointUrl = SimpleNotificationUtils.resolveSmnServiceEndpoint(simpleNotificationEndpoint.getRegion()); + if (endpointUrl == null) { + if (LOG.isErrorEnabled()) { + LOG.error("Valid region not found"); + } + throw new IllegalArgumentException("enter a valid region"); + } else { + clientConfigurations.setServiceEndpoint(endpointUrl); + } + + //checking for ignore ssl verification + boolean ignoreSslVerification = simpleNotificationEndpoint.isIgnoreSslVerification(); + if (ignoreSslVerification) { + if (LOG.isWarnEnabled()) { + LOG.warn("SSL verification is ignored. This is unsafe in production environment"); + } + clientConfigurations.setIgnoreSslVerification(ignoreSslVerification); + } + + //checking if http proxy authentication is used + if (simpleNotificationEndpoint.getProxyHost() != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Reading http proxy configurations"); + } + clientConfigurations.setProxyHost(simpleNotificationEndpoint.getProxyHost()); + clientConfigurations.setProxyPort(simpleNotificationEndpoint.getProxyPort()); + clientConfigurations.setProxyUser(simpleNotificationEndpoint.getProxyUser()); + clientConfigurations.setProxyPassword(simpleNotificationEndpoint.getProxyPassword()); + } + + this.smnClient = initializeClient(clientConfigurations); + } + + /** + * initialization of smn client. this is lazily initialized on the first message + * + * @param clientConfigurations + * @return + */ + private SmnClient initializeClient(ClientConfigurations clientConfigurations) { + if (LOG.isDebugEnabled()) { + LOG.debug("Initializing Smn client"); + } + HttpConfig httpConfig = null; + + if (clientConfigurations.getProxyHost() != null) { + httpConfig = HttpConfig.getDefaultHttpConfig(); + httpConfig.withProxyHost(clientConfigurations.getProxyHost()) + .withProxyPort(clientConfigurations.getProxyPort()) + .setIgnoreSSLVerification(clientConfigurations.isIgnoreSslVerification()); + + if (clientConfigurations.getProxyUser() != null) { + httpConfig.withProxyUsername(clientConfigurations.getProxyUser()); + httpConfig.withProxyPassword(clientConfigurations.getProxyPassword()); + } + } + + BasicCredentials credentials = new BasicCredentials() + .withAk(clientConfigurations.getAuthenticationkey()) + .withSk(clientConfigurations.getSecretKey()) + .withProjectId(clientConfigurations.getProjectId()); + + if (LOG.isDebugEnabled()) { + LOG.debug("Building Smn client"); + } + + // building smn client object + SmnClient smnClient = SmnClient.newBuilder() + .withCredential(credentials) + .withHttpConfig(httpConfig) + .withEndpoint(clientConfigurations.getServiceEndpoint()) + .build(); + + if (LOG.isDebugEnabled()) { + LOG.debug("Successfully initialized Smn client"); + } + return smnClient; + } + + /** + * validation of all user inputs before attempting to invoke a service operation + * + * @param simpleNotificationEndpoint + * @param exchange + * @return + */ + private ClientConfigurations validateServiceConfigurations( + SimpleNotificationEndpoint simpleNotificationEndpoint, Exchange exchange) { + + ClientConfigurations clientConfigurations = new ClientConfigurations(); + 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' + if (LOG.isDebugEnabled()) { + LOG.debug("Inspecting operation name"); + } + if (ObjectHelper.isEmpty(exchange.getProperty(SmnProperties.SMN_OPERATION)) + && ObjectHelper.isEmpty(simpleNotificationEndpoint.getOperation())) { + if (LOG.isErrorEnabled()) { + LOG.error("Found null/empty operation name. Cannot proceed with Smn operations"); + } + throw new IllegalArgumentException("operation name not found"); + } else { + clientConfigurations.setOperation(exchange.getProperty(SmnProperties.SMN_OPERATION) != null + ? (String) exchange.getProperty(SmnProperties.SMN_OPERATION) : simpleNotificationEndpoint.getOperation()); + } + + // checking for mandatory field 'topic name' + if (LOG.isDebugEnabled()) { + LOG.debug("Inspecting topic name"); + } + if (ObjectHelper.isEmpty(exchange.getProperty(SmnProperties.NOTIFICATION_TOPIC_NAME))) { + if (LOG.isErrorEnabled()) { + LOG.error("Found null/empty topic name"); + } + throw new IllegalArgumentException("topic name not found"); + } else { + clientConfigurations.setTopicUrn(String.format(SmnConstants.TOPIC_URN_FORMAT, + simpleNotificationEndpoint.getRegion(), simpleNotificationEndpoint.getProjectId(), + exchange.getProperty(SmnProperties.NOTIFICATION_TOPIC_NAME))); + } + + // checking for optional field 'message subject' + if (LOG.isDebugEnabled()) { + LOG.debug("Inspecting notification subject value"); + } + if (ObjectHelper.isEmpty(exchange.getProperty(SmnProperties.NOTIFICATION_SUBJECT))) { + if (LOG.isWarnEnabled()) { + LOG.warn("notification subject not found. defaulting to 'DEFAULT_SUBJECT'"); + } + clientConfigurations.setSubject("DEFAULT_SUBJECT"); + } else { + clientConfigurations.setSubject((String) exchange.getProperty(SmnProperties.NOTIFICATION_SUBJECT)); + } + + // checking for optional field 'message ttl' + if (LOG.isDebugEnabled()) { + LOG.debug("Inspecting TTL"); + } + if (ObjectHelper.isEmpty(exchange.getProperty(SmnProperties.NOTIFICATION_TTL))) { + if (LOG.isWarnEnabled()) { + LOG.warn("TTL not found. defaulting to default value {}", simpleNotificationEndpoint.getMessageTtl()); + } + clientConfigurations.setMessageTtl(simpleNotificationEndpoint.getMessageTtl()); + } else { + clientConfigurations.setMessageTtl((int) exchange.getProperty(SmnProperties.NOTIFICATION_TTL)); + } + + return clientConfigurations; + } +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationUtils.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationUtils.java new file mode 100644 index 0000000..b7abd32 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/SimpleNotificationUtils.java @@ -0,0 +1,61 @@ +/* + * 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 com.huaweicloud.sdk.smn.v2.region.SmnRegion; +import org.apache.camel.util.ObjectHelper; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * utility functions for the component + */ +public class SimpleNotificationUtils { + private static final Logger LOG = LoggerFactory.getLogger(SimpleNotificationUtils.class.getName()); + + private SimpleNotificationUtils() { + } + + /** + * resolves endpoint url for the given region + * + * @param region + * @return + */ + public static String resolveSmnServiceEndpoint(String region) { + if (region == null || StringUtils.isEmpty(region)) { + return null; + } + + String result = SmnRegion.valueOf(region).getEndpoint(); + + if(LOG.isDebugEnabled()) { + LOG.debug("endpoint resolved as {} for region {}", result, region); + } + + if(ObjectHelper.isEmpty(result)) { + LOG.error("Couldn't resolve endpoint for region : {}", region); + result = null; + } + + if (LOG.isDebugEnabled()) { + LOG.info("Returning endpoint {} for region {}", result, region); + } + return result; + } +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnConstants.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnConstants.java new file mode 100644 index 0000000..1fb0c0a --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnConstants.java @@ -0,0 +1,25 @@ +/* + * 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.constants; + +public class SmnConstants { + + private SmnConstants() { + } + + public static final String TOPIC_URN_FORMAT = "urn:smn:%s:%s:%s"; +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnOperations.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnOperations.java new file mode 100644 index 0000000..4f1c399 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnOperations.java @@ -0,0 +1,26 @@ +/* + * 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.constants; + +public class SmnOperations { + + private SmnOperations() { + } + + public static final String PUBLISH_AS_TEXT_MESSAGE = "publishAsTextMessage"; + public static final String PUBLISH_AS_TEMPLATED_MESSAGE = "publishAsTemplatedMessage"; +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnProperties.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnProperties.java new file mode 100644 index 0000000..5c1b64c --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnProperties.java @@ -0,0 +1,19 @@ +package org.apache.camel.component.huaweicloud.smn.constants; + +public class SmnProperties { + + public SmnProperties() { + } + + // request properties + public static final String TEMPLATE_NAME = "CamelHwCloudSmnTemplateName"; + public static final String TEMPLATE_TAGS = "CamelHwCloudSmnTemplateTags"; + public static final String SMN_OPERATION = "CamelHwCloudSmnOperation"; + public static final String NOTIFICATION_TOPIC_NAME = "CamelHwCloudSmnTopic"; + public static final String NOTIFICATION_SUBJECT = "CamelHwCloudSmnSubject"; + public static final String NOTIFICATION_TTL = "CamelHwCloudSmnMessageTtl"; + + //response properties + public static final String SERVICE_MESSAGE_ID = "CamelHwCloudSmnMesssageId"; + public static final String SERVICE_REQUEST_ID = "CamelHwCloudSmnRequestId"; +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnServices.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnServices.java new file mode 100644 index 0000000..e68fc5e --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/constants/SmnServices.java @@ -0,0 +1,25 @@ +/* + * 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.constants; + +public class SmnServices { + + private SmnServices() { + } + + public static final String PUBLISH_MESSAGE = "publishMessageService"; +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/models/ClientConfigurations.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/models/ClientConfigurations.java new file mode 100644 index 0000000..6fd412e --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/models/ClientConfigurations.java @@ -0,0 +1,138 @@ +/* + * 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.models; + +public class ClientConfigurations { + + private String operation; + private String secretKey; + private String authenticationkey; + private String projectId; + private String topicUrn; + private String subject; + private String proxyHost; + private int proxyPort; + private String proxyUser; + private String proxyPassword; + private String serviceEndpoint; + private int messageTtl; + private boolean ignoreSslVerification; + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getAuthenticationkey() { + return authenticationkey; + } + + public void setAuthenticationkey(String authenticationkey) { + this.authenticationkey = authenticationkey; + } + + public String getProjectId() { + return projectId; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public String getTopicUrn() { + return topicUrn; + } + + public void setTopicUrn(String topicUrn) { + this.topicUrn = topicUrn; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getProxyHost() { + return proxyHost; + } + + public void setProxyHost(String proxyHost) { + this.proxyHost = proxyHost; + } + + public int getProxyPort() { + return proxyPort; + } + + public void setProxyPort(int proxyPort) { + this.proxyPort = proxyPort; + } + + public String getProxyUser() { + return proxyUser; + } + + public void setProxyUser(String proxyUser) { + this.proxyUser = proxyUser; + } + + public String getProxyPassword() { + return proxyPassword; + } + + public void setProxyPassword(String proxyPassword) { + this.proxyPassword = proxyPassword; + } + + public String getServiceEndpoint() { + return serviceEndpoint; + } + + public void setServiceEndpoint(String serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + } + + public int getMessageTtl() { + return messageTtl; + } + + public void setMessageTtl(int messageTtl) { + this.messageTtl = messageTtl; + } + + public boolean isIgnoreSslVerification() { + return ignoreSslVerification; + } + + public void setIgnoreSslVerification(boolean ignoreSslVerification) { + this.ignoreSslVerification = ignoreSslVerification; + } +} diff --git a/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/models/ServiceKeys.java b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/models/ServiceKeys.java new file mode 100644 index 0000000..726726a --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/java/org/apache/camel/component/huaweicloud/smn/models/ServiceKeys.java @@ -0,0 +1,59 @@ +/* + * 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.models; + +public class ServiceKeys { + /** + * cloud service authentication key (AK) + */ + private String authenticationKey; + + /** + * cloud service secret key (SK) + */ + private String secretKey; + + public ServiceKeys() { + } + + public ServiceKeys(String authenticationKey, String secretKey) { + this.authenticationKey = authenticationKey; + this.secretKey = secretKey; + } + + public ServiceKeys(String authenticationKey, String secretKey, String projectId) { + this.authenticationKey = authenticationKey; + this.secretKey = secretKey; + } + + public String getAuthenticationKey() { + return authenticationKey; + } + + public void setAuthenticationKey(String authenticationKey) { + this.authenticationKey = authenticationKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + +} diff --git a/components/camel-huaweicloud-smn/src/main/resources/META-INF/services/org/apache/camel/component/hwcloud-smn b/components/camel-huaweicloud-smn/src/main/resources/META-INF/services/org/apache/camel/component/hwcloud-smn new file mode 100644 index 0000000..a076ce6 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/main/resources/META-INF/services/org/apache/camel/component/hwcloud-smn @@ -0,0 +1 @@ +class=org.apache.camel.component.huaweicloud.smn.SimpleNotificationComponent diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTemplatedMessageTest.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTemplatedMessageTest.java new file mode 100644 index 0000000..3b48fdb --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTemplatedMessageTest.java @@ -0,0 +1,86 @@ +/* + * 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.SmnProperties; +import org.apache.camel.component.huaweicloud.smn.models.ServiceKeys; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +public class PublishTemplatedMessageTest extends CamelTestSupport { + private static final Logger LOGGER = LoggerFactory.getLogger(PublishTemplatedMessageTest.class.getName()); + + TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("serviceKeys") + ServiceKeys serviceKeys + = new ServiceKeys(testConfiguration.getProperty("authKey"), testConfiguration.getProperty("secretKey")); + + @BindToRegistry("smnClient") + SmnClientMock smnClientMock = new SmnClientMock(null); // creating mock smn client to stub method behavior for unit testing + + protected RouteBuilder createRouteBuilder() throws Exception { + // populating tag values. user has to adjust the map entries according to the structure of their respective templates + Map<String, String> tags = new HashMap<>(); + tags.put("name", "reji"); + tags.put("phone", "1234567890"); + + return new RouteBuilder() { + public void configure() { + from("direct:publish_templated_message") + .setProperty(SmnProperties.NOTIFICATION_SUBJECT, constant("This is my subjectline")) + .setProperty(SmnProperties.NOTIFICATION_TOPIC_NAME, constant(testConfiguration.getProperty("topic"))) + .setProperty(SmnProperties.NOTIFICATION_TTL, constant(60)) + .setProperty(SmnProperties.TEMPLATE_TAGS, constant(tags)) + .setProperty(SmnProperties.TEMPLATE_NAME, constant("hello-template")) + .to("hwcloud-smn:publishMessageService?serviceKeys=#serviceKeys&operation=publishAsTemplatedMessage" + + "&projectId=" + testConfiguration.getProperty("projectId") + "®ion=" + + testConfiguration.getProperty("region") + "&ignoreSslVerification=true" + + "&smnClient=#smnClient") + .log("templated notification sent") + .to("mock:publish_templated_message_result"); + } + }; + } + + @Test + public void testTemplatedNotificationSend() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:publish_templated_message_result"); + mock.expectedMinimumMessageCount(1); + template.sendBody("direct:publish_templated_message", null); + Exchange responseExchange = mock.getExchanges().get(0); + + mock.assertIsSatisfied(); + + Assert.assertNotNull(responseExchange.getProperty(SmnProperties.SERVICE_MESSAGE_ID)); + Assert.assertNotNull(responseExchange.getProperty(SmnProperties.SERVICE_REQUEST_ID)); + Assert.assertTrue(responseExchange.getProperty(SmnProperties.SERVICE_MESSAGE_ID).toString().length() > 0); + Assert.assertTrue(responseExchange.getProperty(SmnProperties.SERVICE_REQUEST_ID).toString().length() > 0); + } + + +} diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTextMessageTest.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTextMessageTest.java new file mode 100644 index 0000000..31d5907 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/PublishTextMessageTest.java @@ -0,0 +1,78 @@ +/* + * 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.SmnProperties; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PublishTextMessageTest extends CamelTestSupport { + private static final Logger LOGGER = LoggerFactory.getLogger(PublishTextMessageTest.class.getName()); + + TestConfiguration testConfiguration = new TestConfiguration(); + + @BindToRegistry("smnClient") + SmnClientMock smnClientMock = new SmnClientMock(null); // creating mock smn client to stub method behavior for unit testing + + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() { + from("direct:publish_text_message") + .setProperty(SmnProperties.NOTIFICATION_SUBJECT, constant("Dummy Subject Line")) + .setProperty(SmnProperties.NOTIFICATION_TOPIC_NAME, constant(testConfiguration.getProperty("topic"))) + .setProperty(SmnProperties.NOTIFICATION_TTL, constant(60)) + .to("hwcloud-smn:publishMessageService?operation=publishAsTextMessage&authKey=" + + testConfiguration.getProperty("authKey") + "&secretKey=" + + testConfiguration.getProperty("secretKey") + "&projectId=" + + testConfiguration.getProperty("projectId") + "®ion=" + testConfiguration.getProperty("region") + + "&ignoreSslVerification=true" + + "&smnClient=#smnClient") + .log("publish message successful") + .to("mock:publish_text_message_result"); + } + }; + } + + @Test + public void testTextNotificationSend() throws Exception { + + MockEndpoint mock = getMockEndpoint("mock:publish_text_message_result"); + mock.expectedMinimumMessageCount(1); + template.sendBody("direct:publish_text_message", "message content"); + Exchange responseExchange = mock.getExchanges().get(0); + + mock.assertIsSatisfied(); + + Assert.assertNotNull(responseExchange.getProperty(SmnProperties.SERVICE_MESSAGE_ID)); + Assert.assertNotNull(responseExchange.getProperty(SmnProperties.SERVICE_REQUEST_ID)); + Assert.assertTrue(responseExchange.getProperty(SmnProperties.SERVICE_MESSAGE_ID).toString().length() > 0); + Assert.assertTrue(responseExchange.getProperty(SmnProperties.SERVICE_REQUEST_ID).toString().length() > 0); + + Assert.assertEquals("bf94b63a5dfb475994d3ac34664e24f2", responseExchange.getProperty(SmnProperties.SERVICE_MESSAGE_ID)); + Assert.assertEquals("6a63a18b8bab40ffb71ebd9cb80d0085", responseExchange.getProperty(SmnProperties.SERVICE_REQUEST_ID)); + } + + +} diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/SmnClientMock.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/SmnClientMock.java new file mode 100644 index 0000000..dda88c9 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/SmnClientMock.java @@ -0,0 +1,36 @@ +/* + * 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 com.huaweicloud.sdk.core.HcClient; +import com.huaweicloud.sdk.smn.v2.SmnClient; +import com.huaweicloud.sdk.smn.v2.model.PublishMessageRequest; +import com.huaweicloud.sdk.smn.v2.model.PublishMessageResponse; + +public class SmnClientMock extends SmnClient { + public SmnClientMock(HcClient hcClient) { + super(null); + } + + @Override + public PublishMessageResponse publishMessage(PublishMessageRequest request) { + PublishMessageResponse response = new PublishMessageResponse() + .withRequestId("6a63a18b8bab40ffb71ebd9cb80d0085") + .withMessageId("bf94b63a5dfb475994d3ac34664e24f2"); + return response; + } +} diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/TestConfiguration.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/TestConfiguration.java new file mode 100644 index 0000000..a4b32f3 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/TestConfiguration.java @@ -0,0 +1,66 @@ +/* + * 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 java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestConfiguration { + private static final Logger LOGGER = LoggerFactory.getLogger(TestConfiguration.class.getName()); + private static Map<String, String> propertyMap; + + public TestConfiguration() { + initPropertyMap(); + } + + public void initPropertyMap() { + Properties properties = null; + if (propertyMap == null) { + propertyMap = new HashMap<>(); + String propertyFileName = "testconfiguration.properties"; + try { + properties = new Properties(); + InputStream inputStream = getClass().getClassLoader().getResourceAsStream(propertyFileName); + if (inputStream != null) { + properties.load(inputStream); + } else { + throw new FileNotFoundException("property file '" + propertyFileName + "' not found in the classpath"); + } + + for (String key : properties.stringPropertyNames()) { + propertyMap.put(key, properties.getProperty(key)); + } + } catch (Exception e) { + LOGGER.error("Cannot load property file {}, reason {}", propertyFileName, e.getMessage()); + } + + } + } + + public String getProperty(String key) { + if (propertyMap == null) { + initPropertyMap(); + } + return propertyMap.get(key); + } +} diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnConstantsTest.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnConstantsTest.java new file mode 100644 index 0000000..2b406a9 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnConstantsTest.java @@ -0,0 +1,27 @@ +/* + * 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.constants; + +import org.junit.Assert; +import org.junit.Test; + +public class SmnConstantsTest { + @Test + public void testConstants() { + Assert.assertEquals("urn:smn:%s:%s:%s", SmnConstants.TOPIC_URN_FORMAT); + } +} diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnOperationsTest.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnOperationsTest.java new file mode 100644 index 0000000..a8467b3 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnOperationsTest.java @@ -0,0 +1,28 @@ +/* + * 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.constants; + +import org.junit.Assert; +import org.junit.Test; + +public class SmnOperationsTest { + @Test + public void testOperationsName() { + Assert.assertEquals("publishAsTextMessage", SmnOperations.PUBLISH_AS_TEXT_MESSAGE); + Assert.assertEquals("publishAsTemplatedMessage", SmnOperations.PUBLISH_AS_TEMPLATED_MESSAGE); + } +} diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnPropertiesTest.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnPropertiesTest.java new file mode 100644 index 0000000..57dff53 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnPropertiesTest.java @@ -0,0 +1,33 @@ +/* + * 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.constants; + +import org.junit.Assert; +import org.junit.Test; + +public class SmnPropertiesTest { + @Test + public void testHwCloudSmnPropertyNames() { + Assert.assertEquals("CamelHwCloudSmnTemplateName", SmnProperties.TEMPLATE_NAME); + Assert.assertEquals("CamelHwCloudSmnTemplateTags", SmnProperties.TEMPLATE_TAGS); + Assert.assertEquals("CamelHwCloudSmnOperation", SmnProperties.SMN_OPERATION); + Assert.assertEquals("CamelHwCloudSmnTopic", SmnProperties.NOTIFICATION_TOPIC_NAME); + Assert.assertEquals("CamelHwCloudSmnSubject", SmnProperties.NOTIFICATION_SUBJECT); + Assert.assertEquals("CamelHwCloudSmnMesssageId", SmnProperties.SERVICE_MESSAGE_ID); + Assert.assertEquals("CamelHwCloudSmnRequestId", SmnProperties.SERVICE_REQUEST_ID); + } +} diff --git a/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnServicesTest.java b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnServicesTest.java new file mode 100644 index 0000000..b8af8ac --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/java/org/apache/camel/component/huaweicloud/smn/constants/SmnServicesTest.java @@ -0,0 +1,27 @@ +/* + * 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.constants; + +import org.junit.Assert; +import org.junit.Test; + +public class SmnServicesTest { + @Test + public void testSmnServicesName() { + Assert.assertEquals("publishMessageService", SmnServices.PUBLISH_MESSAGE); + } +} diff --git a/components/camel-huaweicloud-smn/src/test/resources/log4j2.properties b/components/camel-huaweicloud-smn/src/test/resources/log4j2.properties new file mode 100644 index 0000000..abf6bc4 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/resources/log4j2.properties @@ -0,0 +1,22 @@ +# +# 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. +# +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n +rootLogger.level = INFO +rootLogger.appenderRef.out.ref = out diff --git a/components/camel-huaweicloud-smn/src/test/resources/testconfiguration.properties b/components/camel-huaweicloud-smn/src/test/resources/testconfiguration.properties new file mode 100644 index 0000000..06bb4a3 --- /dev/null +++ b/components/camel-huaweicloud-smn/src/test/resources/testconfiguration.properties @@ -0,0 +1,22 @@ +# +# 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. +# +## Test configurations +authKey=dummy_auth_key +secretKey=dummy_secret_key +projectId=9071a38e7f6a4ba7b7bcbeb7d4ea6efc +region = unit-test +topic = reji-test \ No newline at end of file