summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhalil.cakal <halil.cakal@est.tech>2023-03-14 11:24:26 +0000
committerhalil.cakal <halil.cakal@est.tech>2023-03-29 15:13:47 +0100
commit8d8ec86444fb3e085d7dd350966beb92ca0a8ba8 (patch)
tree7ec78469a9031f86effd98cd531b5147c64ab95a
parent221ee7ddfe4a0bce0bc8ad57907404429821bc3d (diff)
Subscription Create Response Handling Dmi Part
- Consume suscription event (payload) with kafka message key and kafka timestamp from ncmp, and extract cm handle ids. - Generate subscription event response (payload) and revert it back to ncmp to specified topic with the corresponding kafka message key. - Configure kafka consumer properties and dmi service name. Issue-ID: CPS-1492 Change-Id: I87de30c00e0f93e350ce6f9fd6079504952da09b Signed-off-by: halil.cakal <halil.cakal@est.tech>
-rw-r--r--src/main/java/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumer.java110
-rw-r--r--src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponse.java36
-rw-r--r--src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponseStatus.java27
-rw-r--r--src/main/resources/application.yml15
-rw-r--r--src/test/groovy/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumerSpec.groovy109
-rw-r--r--src/test/resources/application.yml5
-rw-r--r--src/test/resources/avcSubscriptionCreationEvent.json45
7 files changed, 345 insertions, 2 deletions
diff --git a/src/main/java/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumer.java b/src/main/java/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumer.java
new file mode 100644
index 00000000..20949797
--- /dev/null
+++ b/src/main/java/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumer.java
@@ -0,0 +1,110 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.dmi.notifications.avc;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.dmi.service.model.SubscriptionEventResponse;
+import org.onap.cps.ncmp.dmi.service.model.SubscriptionEventResponseStatus;
+import org.onap.cps.ncmp.event.model.SubscriptionEvent;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.support.KafkaHeaders;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.messaging.handler.annotation.Payload;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class SubscriptionEventConsumer {
+
+ @Value("${app.dmi.avc.subscription-response-topic}")
+ private String cmAvcSubscriptionResponseTopic;
+ @Value("${dmi.service.name}")
+ private String dmiName;
+ private final KafkaTemplate<String, SubscriptionEventResponse> kafkaTemplate;
+
+ /**
+ * Consume the specified event.
+ *
+ * @param subscriptionEvent the event to be consumed
+ */
+ @KafkaListener(topics = "${app.dmi.avc.subscription-topic}",
+ properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.SubscriptionEvent"})
+ public void consumeSubscriptionEvent(@Payload final SubscriptionEvent subscriptionEvent,
+ @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) final String eventKey,
+ @Header(KafkaHeaders.RECEIVED_TIMESTAMP) final String timeStampReceived) {
+ final Date dateAndTimeReceived = new Date(Long.parseLong(timeStampReceived));
+ final String subscriptionName = subscriptionEvent.getEvent().getSubscription().getName();
+ log.info("Subscription for SubscriptionName {} is received at {} by dmi plugin.", subscriptionName,
+ dateAndTimeReceived);
+ sendSubscriptionResponseMessage(eventKey, formSubscriptionEventResponse(subscriptionEvent));
+ }
+
+ /**
+ * Sends message to the configured topic.
+ *
+ * @param eventKey is the kafka message key
+ * @param subscriptionEventResponse is the payload of the kafka message
+ */
+ public void sendSubscriptionResponseMessage(final String eventKey,
+ final SubscriptionEventResponse subscriptionEventResponse) {
+ kafkaTemplate.send(cmAvcSubscriptionResponseTopic, eventKey, subscriptionEventResponse);
+ }
+
+ private SubscriptionEventResponse formSubscriptionEventResponse(final SubscriptionEvent subscriptionEvent) {
+ final SubscriptionEventResponse subscriptionEventResponse = new SubscriptionEventResponse();
+ subscriptionEventResponse.setClientId(subscriptionEvent.getEvent().getSubscription().getClientID());
+ subscriptionEventResponse.setSubscriptionName(subscriptionEvent.getEvent().getSubscription().getName());
+ subscriptionEventResponse.setDmiName(dmiName);
+ final List<Object> cmHandleIdToCmHandlePropertyMap = subscriptionEvent.getEvent()
+ .getPredicates()
+ .getTargets();
+ subscriptionEventResponse
+ .setCmHandleIdToStatus(populateCmHandleIdToStatus(extractCmHandleIds(cmHandleIdToCmHandlePropertyMap)));
+ return subscriptionEventResponse;
+ }
+
+ private Set<String> extractCmHandleIds(final List<Object> cmHandleIdTocmHandlePropertyMap) {
+ final Set<String> cmHandleIds = new HashSet<>();
+ for (final Object obj: cmHandleIdTocmHandlePropertyMap) {
+ final Map<String, Object> cmHandleIdToPropertiesMap = (Map<String, Object>) obj;
+ cmHandleIds.addAll(cmHandleIdToPropertiesMap.keySet());
+ }
+ return cmHandleIds;
+ }
+
+ private Map<String, SubscriptionEventResponseStatus> populateCmHandleIdToStatus(final Set<String> cmHandleIds) {
+ final Map<String, SubscriptionEventResponseStatus> result = new HashMap<>();
+ for (final String cmHandleId : cmHandleIds) {
+ result.put(cmHandleId, SubscriptionEventResponseStatus.ACCEPTED);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponse.java b/src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponse.java
new file mode 100644
index 00000000..7666e540
--- /dev/null
+++ b/src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponse.java
@@ -0,0 +1,36 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.dmi.service.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Getter
+@Setter
+public class SubscriptionEventResponse {
+ private String clientId;
+ private String subscriptionName;
+ private String dmiName;
+ private Map<String, SubscriptionEventResponseStatus> cmHandleIdToStatus;
+}
diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponseStatus.java b/src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponseStatus.java
new file mode 100644
index 00000000..8987ddae
--- /dev/null
+++ b/src/main/java/org/onap/cps/ncmp/dmi/service/model/SubscriptionEventResponseStatus.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.dmi.service.model;
+
+public enum SubscriptionEventResponseStatus {
+ ACCEPTED,
+ REJECTED,
+ PENDING
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 6ad9d58d..04001435 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2022 Nordix Foundation
+# Copyright (C) 2021-2023 Nordix Foundation
# Modifications Copyright (C) 2021 Bell Canada.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +23,7 @@ server:
dmi:
service:
url: ${DMI_SERVICE_URL}
+ name: ${DMI_SERVICE_NAME:ncmp-dmi-plugin}
rest:
api:
@@ -52,11 +53,23 @@ spring:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
client-id: ncmp-dmi-plugin
+ consumer:
+ group-id: ${NCMP_CONSUMER_GROUP_ID:ncmp-group}
+ key-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
+ value-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
+ properties:
+ spring.deserializer.key.delegate.class: org.apache.kafka.common.serialization.StringDeserializer
+ spring.deserializer.value.delegate.class: org.springframework.kafka.support.serializer.JsonDeserializer
+ spring.json.use.type.headers: false
app:
ncmp:
async:
topic: ${NCMP_ASYNC_M2M_TOPIC:ncmp-async-m2m}
+ dmi:
+ avc:
+ subscription-topic: ${DMI_CM_AVC_SUBSCRIPTION:ncmp-dmi-cm-avc-subscription-${dmi.service.name}}
+ subscription-response-topic: ${DMI_CM_AVC_SUBSCRIPTION_RESPONSE:dmi-ncmp-cm-avc-subscription}
notification:
async:
diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumerSpec.groovy
new file mode 100644
index 00000000..65567ef8
--- /dev/null
+++ b/src/test/groovy/org/onap/cps/ncmp/dmi/notifications/avc/SubscriptionEventConsumerSpec.groovy
@@ -0,0 +1,109 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.dmi.notifications.avc
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.apache.kafka.clients.consumer.KafkaConsumer
+import org.onap.cps.ncmp.dmi.TestUtils
+import org.onap.cps.ncmp.dmi.api.kafka.MessagingBaseSpec
+import org.onap.cps.ncmp.dmi.service.model.SubscriptionEventResponse
+import org.onap.cps.ncmp.dmi.service.model.SubscriptionEventResponseStatus
+import org.onap.cps.ncmp.event.model.SubscriptionEvent
+import org.spockframework.spring.SpringBean
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.annotation.DirtiesContext
+import org.testcontainers.spock.Testcontainers
+
+import java.time.Duration
+
+@SpringBootTest(classes = [SubscriptionEventConsumer])
+@Testcontainers
+@DirtiesContext
+class SubscriptionEventConsumerSpec extends MessagingBaseSpec {
+
+ def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group'))
+
+ def objectMapper = new ObjectMapper()
+ def testTopic = 'dmi-ncmp-cm-avc-subscription'
+
+ @SpringBean
+ SubscriptionEventConsumer objectUnderTest = new SubscriptionEventConsumer(kafkaTemplate)
+
+ def 'Sends subscription event response successfully.'() {
+ given: 'an subscription event response'
+ def responseStatus = SubscriptionEventResponseStatus.ACCEPTED
+ def cmHandleIdToStatusMap = ['CmHandle1':responseStatus, 'CmHandle2':responseStatus]
+ def subscriptionEventResponse = new SubscriptionEventResponse(subscriptionName: 'cm-subscription-001',
+ clientId: 'SCO-9989752', dmiName: 'ncmp-dmi-plugin', cmHandleIdToStatus: cmHandleIdToStatusMap)
+ objectUnderTest.cmAvcSubscriptionResponseTopic = testTopic
+ and: 'consumer has a subscription'
+ kafkaConsumer.subscribe([testTopic] as List<String>)
+ when: 'an event is published'
+ def eventKey = UUID.randomUUID().toString()
+ objectUnderTest.sendSubscriptionResponseMessage(eventKey, subscriptionEventResponse)
+ and: 'topic is polled'
+ def records = kafkaConsumer.poll(Duration.ofMillis(1500))
+ then: 'poll returns one record'
+ assert records.size() == 1
+ def record = records.iterator().next()
+ and: 'the record value matches the expected event value'
+ def expectedValue = objectMapper.writeValueAsString(subscriptionEventResponse)
+ assert expectedValue == record.value
+ assert eventKey == record.key
+ }
+
+ def 'Consume valid message.'() {
+ given: 'an event'
+ def jsonData = TestUtils.getResourceFileContent('avcSubscriptionCreationEvent.json')
+ def testEventSent = objectMapper.readValue(jsonData, SubscriptionEvent.class)
+ objectUnderTest.cmAvcSubscriptionResponseTopic = testTopic
+ when: 'the valid event is consumed'
+ def eventKey = UUID.randomUUID().toString()
+ def timeStampReceived = '1679521929511'
+ objectUnderTest.consumeSubscriptionEvent(testEventSent, eventKey, timeStampReceived)
+ then: 'no exception is thrown'
+ noExceptionThrown()
+ }
+
+ def 'Extract cm handle ids from cm handle id to cm handle property map successfully.'() {
+ given: 'a list of cm handle id to cm handle property map'
+ def cmHandleIdToPropertyMap =
+ ['CmHandle1':['prop-x':'prop-valuex'], 'CmHandle2':['prop-y':'prop-valuey']]
+ def listOfCmHandleIdToPropertyMap =
+ [cmHandleIdToPropertyMap]
+ when: 'extract the cm handle ids'
+ def result = objectUnderTest.extractCmHandleIds(listOfCmHandleIdToPropertyMap)
+ then: 'cm handle ids are extracted as expected'
+ def expectedCmHandleIds = ['CmHandle1', 'CmHandle2'] as Set
+ assert expectedCmHandleIds == result
+ }
+
+ def 'Populate cm handle id to status map successfully.'() {
+ given: 'a set of cm handle id'
+ def cmHandleIds = ['CmHandle1', 'CmHandle2'] as Set
+ def responseStatus = SubscriptionEventResponseStatus.ACCEPTED
+ when: 'populate cm handle id to status map'
+ def result = objectUnderTest.populateCmHandleIdToStatus(cmHandleIds)
+ then: 'cm handle id to status map populated as expected'
+ def expectedMap = ['CmHandle1':responseStatus,'CmHandle2':responseStatus]
+ expectedMap == result
+ }
+} \ No newline at end of file
diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml
index 9ed37a73..d2aafbd7 100644
--- a/src/test/resources/application.yml
+++ b/src/test/resources/application.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2022 Nordix Foundation
+# Copyright (C) 2021-2023 Nordix Foundation
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -43,6 +43,9 @@ cps-core:
dmi:
service:
url: some url for the dmi service
+ avc:
+ subscription-topic: ncmp-dmi-cm-avc-subscription
+ subscription-response-topic: dmi-ncmp-cm-avc-subscription
spring:
application:
diff --git a/src/test/resources/avcSubscriptionCreationEvent.json b/src/test/resources/avcSubscriptionCreationEvent.json
new file mode 100644
index 00000000..d52a91ec
--- /dev/null
+++ b/src/test/resources/avcSubscriptionCreationEvent.json
@@ -0,0 +1,45 @@
+{
+ "version": "1.0",
+ "eventType": "CREATE",
+ "event": {
+ "subscription": {
+ "clientID": "SCO-9989752",
+ "name": "cm-subscription-001"
+ },
+ "dataType": {
+ "dataspace": "ALL",
+ "dataCategory": "CM",
+ "dataProvider": "CM-SERVICE",
+ "schemaName": "org.onap.ncmp:cm-network-avc-event.rfc8641",
+ "schemaVersion": "1.0"
+ },
+ "predicates": {
+ "targets": [
+ {
+ "CMHandle1": {
+ "cmhandle-properties": {
+ "prop1": "prop-value"
+ }
+ }
+ },
+ {
+ "CMHandle2": {
+ "cmhandle-properties": {
+ "prop-x": "prop-valuex",
+ "prop-p": "prop-valuep"
+ }
+ }
+ },
+ {
+ "CMHandle3": {
+ "cmhandle-properties": {
+ "prop-y": "prop-valuey"
+ }
+ }
+ }
+ ],
+ "datastore": "passthrough-running",
+ "xpath-filter": "//_3gpp-nr-nrm-gnbdufunction:GNBDUFunction/_3gpp-nr-nrm-nrcelldu:NRCellDU/ | //_3gpp-nr-nrm-gnbcuupfunction:GNBCUUPFunction// | //_3gpp-nr-nrm-gnbcucpfunction:GNBCUCPFunction/_3gpp-nr-nrm-nrcelldu:NRCellCU// | //_3gpp-nr-nrm-nrsectorcarrier:NRSectorCarrier//"
+ }
+ }
+} \ No newline at end of file