diff options
Diffstat (limited to 'cps-ncmp-service/src')
29 files changed, 596 insertions, 80 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/DataJobService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/DataJobService.java new file mode 100644 index 0000000000..6122afc808 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/DataJobService.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api; + +import org.onap.cps.ncmp.api.models.datajob.DataJobMetadata; +import org.onap.cps.ncmp.api.models.datajob.DataJobReadRequest; +import org.onap.cps.ncmp.api.models.datajob.DataJobWriteRequest; + +public interface DataJobService { + + /** + * process read data job operations. + * + * @param dataJobId Unique identifier of the job within the request + * @param dataJobMetadata data job request headers + * @param dataJobReadRequest read data job request + */ + void readDataJob(String dataJobId, DataJobMetadata dataJobMetadata, DataJobReadRequest dataJobReadRequest); + + /** + * process write data job operations. + * + * @param dataJobId Unique identifier of the job within the request + * @param dataJobMetadata data job request headers + * @param dataJobWriteRequest write data job request + */ + void writeDataJob(String dataJobId, DataJobMetadata dataJobMetadata, DataJobWriteRequest dataJobWriteRequest); +}
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java index 462679e74f..bdc3dee772 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java @@ -37,7 +37,8 @@ public enum NcmpResponseStatus { UNKNOWN_ERROR("108", "Unknown error"), CM_HANDLE_ALREADY_EXIST("109", "cm-handle already exists"), CM_HANDLE_INVALID_ID("110", "cm-handle has an invalid character(s) in id"), - ALTERNATE_ID_ALREADY_ASSOCIATED("111", "alternate id already associated"); + ALTERNATE_ID_ALREADY_ASSOCIATED("111", "alternate id already associated"), + MESSAGE_TOO_LARGE("112", "message too large"); private final String code; private final String message; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/DataJobServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/DataJobServiceImpl.java new file mode 100644 index 0000000000..b4377b84f2 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/DataJobServiceImpl.java @@ -0,0 +1,43 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.impl; + +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.DataJobService; +import org.onap.cps.ncmp.api.models.datajob.DataJobMetadata; +import org.onap.cps.ncmp.api.models.datajob.DataJobReadRequest; +import org.onap.cps.ncmp.api.models.datajob.DataJobWriteRequest; + +@Slf4j +public class DataJobServiceImpl implements DataJobService { + + @Override + public void readDataJob(final String dataJobId, final DataJobMetadata dataJobMetadata, + final DataJobReadRequest dataJobReadRequest) { + log.info("data job id for read operation is: {}", dataJobId); + } + + @Override + public void writeDataJob(final String dataJobId, final DataJobMetadata dataJobMetadata, + final DataJobWriteRequest dataJobWriteRequest) { + log.info("data job id for write operation is: {}", dataJobId); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index c15df9c869..6aa09767be 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -51,6 +51,7 @@ import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries; import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; @@ -85,6 +86,7 @@ import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -103,7 +105,10 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler; private final CpsDataService cpsDataService; private final IMap<String, Object> moduleSyncStartedOnCmHandles; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; + private final TrustLevelManager trustLevelManager; private final AlternateIdChecker alternateIdChecker; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java index 171db52998..440cd3ded1 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================== - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,9 @@ import org.springframework.context.annotation.Configuration; @Configuration public class TrustLevelCacheConfig extends HazelcastCacheConfig { + public static final String TRUST_LEVEL_PER_DMI_PLUGIN = "trustLevelPerDmiPlugin"; + + public static final String TRUST_LEVEL_PER_CM_HANDLE = "trustLevelPerCmHandle"; private static final MapConfig trustLevelPerCmHandleCacheConfig = createMapConfig("trustLevelPerCmHandleCacheConfig"); @@ -41,10 +44,10 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of cm handle name as keys to trust-level for values. */ - @Bean + @Bean(TRUST_LEVEL_PER_CM_HANDLE) public Map<String, TrustLevel> trustLevelPerCmHandle() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerCmHandleMap", - trustLevelPerCmHandleCacheConfig).getMap("trustLevelPerCmHandle"); + trustLevelPerCmHandleCacheConfig).getMap(TRUST_LEVEL_PER_CM_HANDLE); } /** @@ -52,10 +55,10 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of dmi-plugin name as keys to trust-level for values. */ - @Bean + @Bean(TRUST_LEVEL_PER_DMI_PLUGIN) public Map<String, TrustLevel> trustLevelPerDmiPlugin() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerDmiPluginMap", - trustLevelPerDmiPluginCacheConfig).getMap("trustLevelPerDmiPlugin"); + trustLevelPerDmiPluginCacheConfig).getMap(TRUST_LEVEL_PER_DMI_PLUGIN); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java index 4f2674aca3..167df5a98d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import java.util.Map; import lombok.RequiredArgsConstructor; import org.apache.kafka.clients.producer.ProducerConfig; import org.springframework.boot.autoconfigure.kafka.KafkaProperties; +import org.springframework.boot.ssl.SslBundles; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @@ -51,6 +52,8 @@ public class KafkaConfig<T> { private final KafkaProperties kafkaProperties; + private static final SslBundles NO_SSL = null; + /** * This sets the strategy for creating legacy Kafka producer instance from kafka properties defined into * application.yml and replaces value-serializer by JsonSerializer. @@ -59,7 +62,7 @@ public class KafkaConfig<T> { */ @Bean public ProducerFactory<String, T> legacyEventProducerFactory() { - final Map<String, Object> producerConfigProperties = kafkaProperties.buildProducerProperties(); + final Map<String, Object> producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL); producerConfigProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); return new DefaultKafkaProducerFactory<>(producerConfigProperties); } @@ -72,7 +75,7 @@ public class KafkaConfig<T> { */ @Bean public ConsumerFactory<String, T> legacyEventConsumerFactory() { - final Map<String, Object> consumerConfigProperties = kafkaProperties.buildConsumerProperties(); + final Map<String, Object> consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL); consumerConfigProperties.put("spring.deserializer.value.delegate.class", JsonDeserializer.class); return new DefaultKafkaConsumerFactory<>(consumerConfigProperties); } @@ -112,7 +115,7 @@ public class KafkaConfig<T> { */ @Bean public ProducerFactory<String, CloudEvent> cloudEventProducerFactory() { - final Map<String, Object> producerConfigProperties = kafkaProperties.buildProducerProperties(); + final Map<String, Object> producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL); return new DefaultKafkaProducerFactory<>(producerConfigProperties); } @@ -124,7 +127,7 @@ public class KafkaConfig<T> { */ @Bean public ConsumerFactory<String, CloudEvent> cloudEventConsumerFactory() { - final Map<String, Object> consumerConfigProperties = kafkaProperties.buildConsumerProperties(); + final Map<String, Object> consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL); return new DefaultKafkaConsumerFactory<>(consumerConfigProperties); } @@ -136,7 +139,8 @@ public class KafkaConfig<T> { */ @Bean public KafkaTemplate<String, CloudEvent> cloudEventKafkaTemplate() { - final KafkaTemplate<String, CloudEvent> kafkaTemplate = new KafkaTemplate<>(cloudEventProducerFactory()); + final KafkaTemplate<String, CloudEvent> kafkaTemplate = + new KafkaTemplate<>(cloudEventProducerFactory()); kafkaTemplate.setConsumerFactory(cloudEventConsumerFactory()); return kafkaTemplate; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java index 21468c316c..76ee08e64c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducer.java @@ -23,10 +23,18 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; import java.net.URI; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.events.EventsPublisher; +import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper; +import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails; import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.beans.factory.annotation.Value; @@ -39,37 +47,87 @@ import org.springframework.stereotype.Component; @ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) public class CmNotificationSubscriptionNcmpOutEventProducer { - private final EventsPublisher<CloudEvent> eventsPublisher; - private final JsonObjectMapper jsonObjectMapper; - @Value("${app.ncmp.avc.subscription-outcome-topic}") private String cmNotificationSubscriptionNcmpOutEventTopic; + @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms}") + private Integer cmNotificationSubscriptionDmiOutEventTimeoutInMs; + + private final EventsPublisher<CloudEvent> eventsPublisher; + private final JsonObjectMapper jsonObjectMapper; + private final Map<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache; + private final CmNotificationSubscriptionNcmpOutEventMapper cmNotificationSubscriptionNcmpOutEventMapper; + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + private static final Map<String, ScheduledFuture<?>> scheduledTasksPerSubscriptionId = new ConcurrentHashMap<>(); + /** * Publish the event to the client who requested the subscription with key as subscription id and event is Cloud * Event compliant. * * @param subscriptionId Cm Subscription Id * @param eventType Type of event - * @param cmNotificationSubscriptionNcmpOutEvent Cm Notification Subscription Event for the client + * @param cmNotificationSubscriptionNcmpOutEvent Cm Notification Subscription Event for the + * client + * @param isScheduledEvent Determines if the event is to be scheduled + * or published now */ public void publishCmNotificationSubscriptionNcmpOutEvent(final String subscriptionId, final String eventType, - final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent) { + final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent, + final boolean isScheduledEvent) { - eventsPublisher.publishCloudEvent(cmNotificationSubscriptionNcmpOutEventTopic, subscriptionId, - buildAndGetCmNotificationNcmpOutEventAsCloudEvent(subscriptionId, eventType, - cmNotificationSubscriptionNcmpOutEvent)); + if (isScheduledEvent && !scheduledTasksPerSubscriptionId.containsKey(subscriptionId)) { + final ScheduledFuture<?> scheduledFuture = + scheduleAndPublishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType); + scheduledTasksPerSubscriptionId.putIfAbsent(subscriptionId, scheduledFuture); + log.debug("Scheduled the CmNotificationSubscriptionEvent for subscriptionId : {}", subscriptionId); + } else { + cancelScheduledTaskForSubscriptionId(subscriptionId); + publishCmNotificationSubscriptionNcmpOutEventNow(subscriptionId, eventType, + cmNotificationSubscriptionNcmpOutEvent); + log.info("Published CmNotificationSubscriptionEvent on demand for subscriptionId : {}", subscriptionId); + } + + } + + private ScheduledFuture<?> scheduleAndPublishCmNotificationSubscriptionNcmpOutEvent(final String subscriptionId, + final String eventType) { + final CmNotificationSubscriptionNcmpOutEventPublishingTask + cmNotificationSubscriptionNcmpOutEventPublishingTask = + new CmNotificationSubscriptionNcmpOutEventPublishingTask(cmNotificationSubscriptionNcmpOutEventTopic, + subscriptionId, eventType, eventsPublisher, jsonObjectMapper, cmNotificationSubscriptionCache, + cmNotificationSubscriptionNcmpOutEventMapper); + return scheduledExecutorService.schedule(cmNotificationSubscriptionNcmpOutEventPublishingTask, + cmNotificationSubscriptionDmiOutEventTimeoutInMs, TimeUnit.MILLISECONDS); + } + + private void cancelScheduledTaskForSubscriptionId(final String subscriptionId) { + + final ScheduledFuture<?> scheduledFuture = scheduledTasksPerSubscriptionId.get(subscriptionId); + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + scheduledTasksPerSubscriptionId.remove(subscriptionId); + } } - private CloudEvent buildAndGetCmNotificationNcmpOutEventAsCloudEvent(final String subscriptionId, - final String eventType, + + private void publishCmNotificationSubscriptionNcmpOutEventNow(final String subscriptionId, final String eventType, + final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent) { + final CloudEvent cmNotificationSubscriptionNcmpOutEventAsCloudEvent = + buildAndGetCmNotificationNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType, + cmNotificationSubscriptionNcmpOutEvent); + eventsPublisher.publishCloudEvent(cmNotificationSubscriptionNcmpOutEventTopic, subscriptionId, + cmNotificationSubscriptionNcmpOutEventAsCloudEvent); + } + + protected static CloudEvent buildAndGetCmNotificationNcmpOutEventAsCloudEvent( + final JsonObjectMapper jsonObjectMapper, final String subscriptionId, final String eventType, final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent) { return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withType(eventType) - .withSource(URI.create("NCMP")).withDataSchema(URI.create("org.onap.ncmp.cm.subscription:1.0.0")) - .withExtension("correlationid", subscriptionId) - .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionNcmpOutEvent)).build(); + .withSource(URI.create("NCMP")).withDataSchema(URI.create("org.onap.ncmp.cm.subscription:1.0.0")) + .withExtension("correlationid", subscriptionId) + .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionNcmpOutEvent)).build(); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java new file mode 100644 index 0000000000..f7ea4a465c --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.impl.events.cmsubscription; + +import static org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionNcmpOutEventProducer.buildAndGetCmNotificationNcmpOutEventAsCloudEvent; + +import io.cloudevents.CloudEvent; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.events.EventsPublisher; +import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper; +import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails; +import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent; +import org.onap.cps.utils.JsonObjectMapper; + +@Slf4j +@RequiredArgsConstructor +public class CmNotificationSubscriptionNcmpOutEventPublishingTask implements Runnable { + + + private final String topicName; + private final String subscriptionId; + private final String eventType; + private final EventsPublisher<CloudEvent> eventsPublisher; + private final JsonObjectMapper jsonObjectMapper; + private final Map<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache; + private final CmNotificationSubscriptionNcmpOutEventMapper cmNotificationSubscriptionNcmpOutEventMapper; + + /** + * Delegating the responsibility of publishing CmNotificationSubscriptionNcmpOutEvent as a separate task which will + * be called after a specified delay. + */ + @Override + public void run() { + final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap = + cmNotificationSubscriptionCache.get(subscriptionId); + final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent = + cmNotificationSubscriptionNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId, + dmiCmNotificationSubscriptionDetailsMap); + eventsPublisher.publishCloudEvent(topicName, subscriptionId, + buildAndGetCmNotificationNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType, + cmNotificationSubscriptionNcmpOutEvent)); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java index 5eca5e8c57..2efd321b8d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java @@ -20,7 +20,6 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription.service; -import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING; import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS; import java.io.Serializable; @@ -109,14 +108,8 @@ public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotif private void addNewSubscriptionViaDatastore(final DatastoreType datastoreType, final String cmHandleId, final String xpath, final String newSubscriptionId) { - final String parentXpathFormat = "/datastores/datastore[@name='%s']/cm-handles"; - String parentXpath = ""; - if (datastoreType == PASSTHROUGH_RUNNING) { - parentXpath = parentXpathFormat.formatted("ncmp-datastore:passthrough-running"); - } else { - parentXpath = parentXpathFormat.formatted("ncmp-datastore:passthrough-operational"); - } - + final String parentXpath = "/datastores/datastore[@name='%s']/cm-handles" + .formatted(datastoreType.getDatastoreName()); final String updatedJson = String.format("{\"cm-handle\":[{\"id\":\"%s\",\"filters\":{\"filter\":" + "[{\"xpath\":\"%s\",\"subscriptionIds\":[\"%s\"]}]}}]}", cmHandleId, xpath, newSubscriptionId); cpsDataService.saveData(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, parentXpath, updatedJson, diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java index 2d7ad698c5..6cffb4d274 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation + * Copyright (C) 2022-2024 Nordix Foundation * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,12 +34,14 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.inventory.enums.PropertyType; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.utils.CpsValidator; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @RequiredArgsConstructor @@ -49,8 +51,13 @@ public class CmHandleQueriesImpl implements CmHandleQueries { private static final String DESCENDANT_PATH = "//"; private static final String ANCESTOR_CM_HANDLES = "/ancestor::cm-handles"; private final CpsDataPersistenceService cpsDataPersistenceService; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE) private final Map<String, TrustLevel> trustLevelPerCmHandle; + private final CpsValidator cpsValidator; @Override diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java index f99fe86f66..3a281d740b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java @@ -67,7 +67,8 @@ public class DmiModelOperations extends DmiOperations { * @return module references */ public List<ModuleReference> getModuleReferences(final YangModelCmHandle yangModelCmHandle) { - final DmiRequestBody dmiRequestBody = DmiRequestBody.builder().build(); + final DmiRequestBody dmiRequestBody = DmiRequestBody.builder() + .moduleSetTag(yangModelCmHandle.getModuleSetTag()).build(); dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties()); final ResponseEntity<Object> dmiFetchModulesResponseEntity = getResourceFromDmiWithJsonData( yangModelCmHandle.resolveDmiServiceName(MODEL), diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java index 6613d3c87c..f1032f818f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java @@ -33,7 +33,7 @@ import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; @JsonInclude(JsonInclude.Include.NON_NULL) @Getter @Builder -@JsonPropertyOrder({"operation", "dataType", "data", "cmHandleProperties", "requestId"}) +@JsonPropertyOrder({"operation", "dataType", "data", "cmHandleProperties", "requestId", "moduleSetTag"}) public class DmiRequestBody { @JsonProperty("operation") @@ -43,6 +43,7 @@ public class DmiRequestBody { @JsonProperty("cmHandleProperties") private Map<String, String> dmiProperties; private String requestId; + private String moduleSetTag; /** * Set DMI Properties by converting a list of YangModelCmHandle.Property objects. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java index 82c7204028..9d65a66d8d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,10 +24,12 @@ import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Slf4j @@ -35,8 +37,12 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class TrustLevelManager { + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE) private final Map<String, TrustLevel> trustLevelPerCmHandle; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; + private final InventoryPersistence inventoryPersistence; private final AvcEventPublisher avcEventPublisher; private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel"; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java index 72dc295bf3..d6d6fd6bc1 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; +import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -39,6 +41,8 @@ public class DmiPluginWatchDog { private final DmiRestClient dmiRestClient; private final NetworkCmProxyDataService networkCmProxyDataService; private final TrustLevelManager trustLevelManager; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobMetadata.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobMetadata.java new file mode 100644 index 0000000000..dc8037b86f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobMetadata.java @@ -0,0 +1,33 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.models.datajob; + +/** + * Metadata of read/write data job request. + * + * @param destination The destination of the data job results. + * @param dataAcceptType Define the data response accept type. + * e.g. "application/vnd.3gpp.object-tree-hierarchical+json", + * "application/vnd.3gpp.object-tree-flat+json" etc. + * @param dataContentType Define the data request content type. + * e.g. "application/3gpp-json-patch+json" etc. + */ +public record DataJobMetadata(String destination, String dataAcceptType, String dataContentType) {}
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobReadRequest.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobReadRequest.java new file mode 100644 index 0000000000..f861c3d498 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobReadRequest.java @@ -0,0 +1,30 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.models.datajob; + +import java.util.List; + +/** + * Describes the read data job operation to be forwarded to dmi. + * + * @param data List of read operations to be executed. + */ +public record DataJobReadRequest(List<ReadOperation> data) {} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobWriteRequest.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobWriteRequest.java new file mode 100644 index 0000000000..254e198b81 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobWriteRequest.java @@ -0,0 +1,30 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.models.datajob; + +import java.util.List; + +/** + * Describes the write data job operation to be forwarded to dmi. + * + * @param data List of write operations to be executed. + */ +public record DataJobWriteRequest(List<WriteOperation> data) {} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/ReadOperation.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/ReadOperation.java new file mode 100644 index 0000000000..d2b0738969 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/ReadOperation.java @@ -0,0 +1,43 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.models.datajob; + +import java.util.List; + +/** + * Holds information of read data job operation. + * based on <a href="https://www.etsi.org/deliver/etsi_ts/128500_128599/128532/16.04.00_60/ts_128532v160400p.pdf">ETSI TS 128 532 V16.4.0 (2020-08)</a> + * + * @param path Identifier of a managed object (MO) on a network element. Defines the resource on which operation + * is executed. Url Encoded Fully Distinguished Name (FDN). + * @param op Describes the operation to execute. The value can only be "read". + * @param operationId Unique identifier of the operation within the request. + * @param attributes Specifies the attributes of the resources that are returned. + * @param fields Specifies the attribute fields of the resources that are returned. This should be used if an + * attribute is a struct and only a subset of its fields should be returned. + * @param filter This filters the managed Objects. + * @param scopeType This selects MOs depending on relationships with Base Managed Object. + * e.g. "BASE_ONLY", "BASE_ALL", "BASE_NTH_LEVEL" etc. + * @param scopeLevel Defines the level for objects to be returned for certain scopeTypes. The base level is zero. + */ +public record ReadOperation(String path, String op, String operationId, List<String> attributes, List<String> fields, + String filter, String scopeType, int scopeLevel) { +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/WriteOperation.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/WriteOperation.java new file mode 100644 index 0000000000..c2f6504ce2 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/WriteOperation.java @@ -0,0 +1,34 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.models.datajob; + +/** + * Holds information of write data job operation. + * based on <a href="https://www.etsi.org/deliver/etsi_ts/128500_128599/128532/16.04.00_60/ts_128532v160400p.pdf">ETSI TS 128 532 V16.4.0 (2020-08)</a> + * + * @param path Identifier of a managed object (MO) on a network element. Defines the resource on which operation + * is executed. Typically, is Fully Distinguished Name (FDN). + * @param op Describes the operation to execute. The value can be as below: + * e.g. "add", "replace", "remove", "action" etc. + * @param operationId Unique identifier of the operation within the request. + * @param value The value to be written depends on the type of operation. + */ +public record WriteOperation(String path, String op, String operationId, Object value) {} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java index a3ebec3c54..4cc8cdaa66 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java @@ -70,24 +70,6 @@ abstract class AbstractModelLoader implements ModelLoader { } } - void waitUntilDataspaceIsAvailable(final String dataspaceName) { - log.info("Model Loader start-up, waiting for database to be ready"); - int attemptCount = 0; - while (cpsDataspaceService.getDataspace(dataspaceName) == null) { - if (attemptCount < maximumAttemptCount) { - try { - Thread.sleep(attemptCount * retryTimeMs); - log.info("Retrieving dataspace {} ... {} attempt(s) ", dataspaceName, ++attemptCount); - } catch (final InterruptedException e) { - Thread.currentThread().interrupt(); - } - } else { - throw new NcmpStartUpException("Retrieval of NCMP dataspace failed", - dataspaceName + " not available (yet)"); - } - } - } - void createSchemaSet(final String dataspaceName, final String schemaSetName, final String... resourceNames) { try { final Map<String, String> yangResourcesContentMap = createYangResourcesToContentMap(resourceNames); @@ -100,6 +82,17 @@ abstract class AbstractModelLoader implements ModelLoader { } } + void createDataspace(final String dataspaceName) { + try { + cpsDataspaceService.createDataspace(dataspaceName); + } catch (final AlreadyDefinedException alreadyDefinedException) { + log.debug("Dataspace already exists"); + } catch (final Exception exception) { + log.error("Creating dataspace failed: {} ", exception.getMessage()); + throw new NcmpStartUpException("Creating dataspace failed", exception.getMessage()); + } + } + void deleteUnusedSchemaSets(final String dataspaceName, final String... schemaSetNames) { for (final String schemaSetName : schemaSetNames) { try { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java index 4c31719a29..a0b7bd5826 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java @@ -51,12 +51,12 @@ public class CmDataSubscriptionModelLoader extends AbstractModelLoader { @Override public void onboardOrUpgradeModel() { - waitUntilDataspaceIsAvailable(NCMP_DATASPACE_NAME); onboardSubscriptionModels(); log.info("Subscription Models onboarded successfully"); } private void onboardSubscriptionModels() { + createDataspace(NCMP_DATASPACE_NAME); createSchemaSet(NCMP_DATASPACE_NAME, SCHEMASET_NAME, MODEL_FILENAME); createAnchor(NCMP_DATASPACE_NAME, SCHEMASET_NAME, ANCHOR_NAME); createTopLevelDataNode(NCMP_DATASPACE_NAME, ANCHOR_NAME, REGISTRY_DATANODE_NAME); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java index d0d63ab8eb..7c25953f0d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.init; import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME; import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR; +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsAnchorService; @@ -33,9 +34,9 @@ import org.springframework.stereotype.Service; @Slf4j @Service public class InventoryModelLoader extends AbstractModelLoader { - private static final String NEW_MODEL_FILE_NAME = "dmi-registry@2024-02-23.yang"; private static final String NEW_SCHEMA_SET_NAME = "dmi-registry-2024-02-23"; + private static final String REGISTRY_DATANODE_NAME = "dmi-registry"; public InventoryModelLoader(final CpsDataspaceService cpsDataspaceService, final CpsModuleService cpsModuleService, @@ -46,20 +47,24 @@ public class InventoryModelLoader extends AbstractModelLoader { @Override public void onboardOrUpgradeModel() { - waitUntilDataspaceIsAvailable(NCMP_DATASPACE_NAME); updateInventoryModel(); log.info("Inventory Model updated successfully"); } private void updateInventoryModel() { + createDataspace(NCMP_DATASPACE_NAME); + createDataspace(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME); createSchemaSet(NCMP_DATASPACE_NAME, NEW_SCHEMA_SET_NAME, NEW_MODEL_FILE_NAME); + createAnchor(NCMP_DATASPACE_NAME, NEW_SCHEMA_SET_NAME, NCMP_DMI_REGISTRY_ANCHOR); updateAnchorSchemaSet(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NEW_SCHEMA_SET_NAME); + createTopLevelDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, REGISTRY_DATANODE_NAME); deleteOldButNotThePreviousSchemaSets(); } private void deleteOldButNotThePreviousSchemaSets() { //No schema sets passed in yet, but wil be required for future updates deleteUnusedSchemaSets(NCMP_DATASPACE_NAME); + deleteUnusedSchemaSets(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME); } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy new file mode 100644 index 0000000000..43787640a3 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.api.impl + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.Logger +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.read.ListAppender +import org.slf4j.LoggerFactory +import org.onap.cps.ncmp.api.models.datajob.DataJobReadRequest +import org.onap.cps.ncmp.api.models.datajob.DataJobWriteRequest +import org.onap.cps.ncmp.api.models.datajob.DataJobMetadata +import org.onap.cps.ncmp.api.models.datajob.ReadOperation +import org.onap.cps.ncmp.api.models.datajob.WriteOperation +import spock.lang.Specification + +class DataJobServiceImplSpec extends Specification{ + + def objectUnderTest = new DataJobServiceImpl() + + def logger = Spy(ListAppender<ILoggingEvent>) + + def setup() { + setupLogger() + } + + def cleanup() { + ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)).detachAndStopAllAppenders() + } + + def '#operation data job request.'() { + given: 'data job metadata' + def dataJobMetadata = new DataJobMetadata('client-topic', 'application/vnd.3gpp.object-tree-hierarchical+json', 'application/3gpp-json-patch+json') + when: 'read/write data job request is processed' + if (operation == 'read') { + objectUnderTest.readDataJob('some-job-id', dataJobMetadata, new DataJobReadRequest([getWriteOrReadOperationRequest(operation)])) + } else { + objectUnderTest.writeDataJob('some-job-id', dataJobMetadata, new DataJobWriteRequest([getWriteOrReadOperationRequest(operation)])) + } + then: 'the data job id is correctly logged' + def loggingEvent = logger.list[0] + assert loggingEvent.level == Level.INFO + assert loggingEvent.formattedMessage.contains('data job id for ' + operation + ' operation is: some-job-id') + where: 'the following data job operations are used' + operation << ['read', 'write'] + } + + def getWriteOrReadOperationRequest(operation) { + if (operation == 'write') { + return new WriteOperation('some/write/path', 'add', 'some-operation-id', 'some-value') + } + return new ReadOperation('some/read/path', 'read', 'some-operation-id', ['some-attrib-1'], ['some-field-1'], 'some-filter', 'some-scope-type', 1) + } + + def setupLogger() { + def setupLogger = ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)) + setupLogger.setLevel(Level.DEBUG) + setupLogger.addAppender(logger) + logger.start() + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index d47be6cd5c..4d0af6f490 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -23,9 +23,6 @@ package org.onap.cps.ncmp.api.impl -import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse -import org.onap.cps.ncmp.api.models.CmResourceAddress - import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR @@ -35,6 +32,8 @@ import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RU import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE +import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse +import org.onap.cps.ncmp.api.models.CmResourceAddress import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import com.hazelcast.map.IMap import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService @@ -57,7 +56,6 @@ import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle import org.onap.cps.ncmp.api.models.DataOperationRequest import org.onap.cps.spi.exceptions.CpsException import org.onap.cps.spi.model.ConditionProperties - import java.util.stream.Collectors import org.onap.cps.utils.JsonObjectMapper import com.fasterxml.jackson.databind.ObjectMapper diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy index d5b0915526..16f27d081b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-2024 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy index 7c1a148ad7..970d7e67b0 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy @@ -3,6 +3,8 @@ package org.onap.cps.ncmp.api.impl.events.cmsubscription import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import org.onap.cps.events.EventsPublisher +import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper +import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.Data @@ -13,18 +15,58 @@ class CmNotificationSubscriptionNcmpOutEventProducerSpec extends Specification { def mockEventsPublisher = Mock(EventsPublisher) def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) + def mockCmNotificationSubscriptionCache = Mock(Map<String, Map<String, DmiCmNotificationSubscriptionDetails>>) + def mockCmNotificationSubscriptionNcmpOutEventMapper = Mock(CmNotificationSubscriptionNcmpOutEventMapper) - def objectUnderTest = new CmNotificationSubscriptionNcmpOutEventProducer(mockEventsPublisher, jsonObjectMapper) + def objectUnderTest = new CmNotificationSubscriptionNcmpOutEventProducer(mockEventsPublisher, jsonObjectMapper, mockCmNotificationSubscriptionCache, mockCmNotificationSubscriptionNcmpOutEventMapper) - def 'Create and Publish Cm Notification Subscription DMI In Event'() { + def 'Create and #scenario Cm Notification Subscription NCMP out event'() { given: 'a cm subscription response for the client' - def subscriptionId = 'test-subscription-id' + def subscriptionId = 'test-subscription-id-2' def eventType = 'subscriptionCreateResponse' - def cmNotificationSubscriptionNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent(data: new Data(subscriptionId: 'sub-1', acceptedTargets: ['ch-1', 'ch-2'])) + def cmNotificationSubscriptionNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-2', acceptedTargets: ['ch-1', 'ch-2'])) and: 'also we have target topic for publishing to client' objectUnderTest.cmNotificationSubscriptionNcmpOutEventTopic = 'client-test-topic' + and: 'a deadline to an event' + objectUnderTest.cmNotificationSubscriptionDmiOutEventTimeoutInMs = 1000 when: 'the event is published' - objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType, cmNotificationSubscriptionNcmpOutEvent) + objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType, cmNotificationSubscriptionNcmpOutEvent, eventPublishingTaskToBeScheduled) + then: 'we conditionally wait for a while' + Thread.sleep(delayInMs) + then: 'the event contains the required attributes' + 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { + args -> + { + assert args[0] == 'client-test-topic' + assert args[1] == subscriptionId + def cmNotificationSubscriptionNcmpOutEventAsCloudEvent = (args[2] as CloudEvent) + assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.getExtension('correlationid') == subscriptionId + assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.type == 'subscriptionCreateResponse' + assert cmNotificationSubscriptionNcmpOutEventAsCloudEvent.source.toString() == 'NCMP' + assert CloudEventMapper.toTargetEvent(cmNotificationSubscriptionNcmpOutEventAsCloudEvent, CmNotificationSubscriptionNcmpOutEvent) == cmNotificationSubscriptionNcmpOutEvent + } + } + where: 'following scenarios are considered' + scenario | delayInMs | eventPublishingTaskToBeScheduled + 'publish event now' | 0 | false + 'schedule and publish after the configured time ' | 1500 | true + } + + def 'Schedule Cm Notification Subscription NCMP out event but later publish it on demand'() { + given: 'a cm subscription response for the client' + def subscriptionId = 'test-subscription-id-3' + def eventType = 'subscriptionCreateResponse' + def cmNotificationSubscriptionNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-3', acceptedTargets: ['ch-2', 'ch-3'])) + and: 'also we have target topic for publishing to client' + objectUnderTest.cmNotificationSubscriptionNcmpOutEventTopic = 'client-test-topic' + and: 'a deadline to an event' + objectUnderTest.cmNotificationSubscriptionDmiOutEventTimeoutInMs = 1000 + when: 'the event is scheduled to be published' + objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType, cmNotificationSubscriptionNcmpOutEvent, true) + then: 'we wait for 10ms and then we receive response from DMI' + Thread.sleep(10) + and: 'we receive response from DMI so we publish the message on demand' + objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId, eventType, cmNotificationSubscriptionNcmpOutEvent, false) then: 'the event contains the required attributes' 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> { args -> diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy index 56485fbf94..e99e8a3d02 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy @@ -58,7 +58,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { def moduleReferencesAsLisOfMaps = [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']] def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules" def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK) - mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) + mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{},"moduleSetTag":"tag1"}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) @@ -91,7 +91,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with tha expected parameters' def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK) mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules", - '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ, NO_AUTH_HEADER) >> responseFromDmi + '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":"tag1"}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'a get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) then: 'the result is the response from DMI service' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy index cc64255293..b7af502de8 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy @@ -74,5 +74,6 @@ abstract class DmiOperationsBaseSpec extends Specification { yangModelCmHandle.id = cmHandleId yangModelCmHandle.compositeState = new CompositeState() yangModelCmHandle.compositeState.cmHandleState = CmHandleState.READY + yangModelCmHandle.moduleSetTag = 'tag1' } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy index f122b57634..b0be29d933 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy @@ -81,14 +81,6 @@ class AbstractModelLoaderSpec extends Specification { assert logs.contains('test message') } - def 'Wait for non-existing dataspace'() { - when: 'wait for the dataspace' - objectUnderTest.waitUntilDataspaceIsAvailable('some dataspace') - then: 'a startup exception is thrown' - def thrown = thrown(NcmpStartUpException) - assert thrown.message.contains('Retrieval of NCMP dataspace failed') - } - def 'Create schema set.'() { when: 'creating a schema set' objectUnderTest.createSchemaSet('some dataspace','new name','cm-data-subscriptions@2024-02-12.yang') |