aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--checkstyle/pom.xml2
-rw-r--r--cps-application/pom.xml10
-rw-r--r--cps-application/src/main/resources/application.yml56
-rw-r--r--cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java8
-rw-r--r--cps-bom/pom.xml2
-rw-r--r--cps-dependencies/pom.xml27
-rw-r--r--cps-events/pom.xml2
-rw-r--r--cps-ncmp-events/pom.xml2
-rw-r--r--cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-in-event-schema-1.0.0.json (renamed from cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-in-event-schema-1.0.0.json)17
-rw-r--r--cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-out-event-schema-1.0.0.json (renamed from cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-out-event-schema-1.0.0.json)8
-rw-r--r--cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-in-event-schema-1.0.0.json (renamed from cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-in-event-schema-1.0.0.json)13
-rw-r--r--cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-out-event-schema-1.0.0.json57
-rw-r--r--cps-ncmp-events/src/main/resources/schemas/dmidataavc/avc-event-schema-1.0.0.json22
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java5
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy16
-rw-r--r--cps-ncmp-rest-stub/pom.xml2
-rw-r--r--cps-ncmp-rest/docs/openapi/components.yaml12
-rwxr-xr-xcps-ncmp-rest/docs/openapi/ncmp.yml22
-rwxr-xr-xcps-ncmp-rest/docs/openapi/openapi-inventory.yml4
-rwxr-xr-xcps-ncmp-rest/docs/openapi/openapi.yml4
-rw-r--r--cps-ncmp-rest/pom.xml2
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java178
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java21
-rw-r--r--[-rwxr-xr-x]cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandler.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java)32
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java100
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java114
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java154
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java71
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleStateMapper.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java)6
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/DataOperationRequestMapper.java)6
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java4
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/NcmpRestInputMapper.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java)8
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy245
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy27
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy (renamed from cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy)97
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutorSpec.groovy99
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleStateMapperSpec.groovy (renamed from cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy)15
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy4
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/NcmpRestInputMapperSpec.groovy (renamed from cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy)8
-rw-r--r--cps-ncmp-rest/src/test/resources/application.yml2
-rw-r--r--cps-ncmp-service/pom.xml30
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java204
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidDatastoreException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDatastoreException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidOperationException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidOperationException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/OperationNotSupportedException.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/OperationNotSupportedException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java41
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationDefinition.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationRequest.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationRequest.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DatastoreType.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DatastoreType.java)4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/OperationType.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/OperationType.java)21
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobResultService.java45
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobService.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/DataJobService.java)27
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobStatusService.java43
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DataJobMetadata.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobMetadata.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DataJobReadRequest.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobReadRequest.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DataJobWriteRequest.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/DataJobWriteRequest.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DmiWriteOperation.java43
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ProducerKey.java36
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ReadOperation.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/ReadOperation.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/SubJobWriteRequest.java44
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/SubJobWriteResponse.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmResourceAddress.java)17
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/WriteOperation.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/datajob/WriteOperation.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiClientRequestException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiRequestException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiRequestException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/InvalidTopicException.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/InvalidTopicException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PayloadTooLargeException.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/PayloadTooLargeException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java)23
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/ServerNcmpException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/ServerNcmpException.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/DataJobServiceImpl.java43
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java144
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java94
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDelta.java75
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java70
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java78
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java63
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java193
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java103
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapper.java114
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java146
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java98
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceService.java84
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java166
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java302
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java47
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java152
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java100
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java191
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmDataSubscriptionEvent.java76
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java228
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleQueryApiParameters.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleQueryServiceParameters.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryServiceParameters.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponse.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java)4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CompositeState.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeState.java)5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilder.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateBuilder.java)11
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/ConditionApiProperties.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistration.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistrationResponse.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java)4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/NcmpServiceCmHandle.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java)7
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/TrustLevel.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/UpgradedCmHandles.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/YangResource.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/YangResource.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/CpsApplicationContext.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContext.java)4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/DmiHttpClientConfig.java57
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/KafkaConfig.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java)37
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java141
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfig.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java)40
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/ServiceConfig.java36
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NcmpStartUpException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpStartUpException.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NoAlternateIdMatchFoundException.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NoAlternateIdParentFoundException.java)9
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfig.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfig.java)8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandler.java227
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java)21
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapper.java103
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapper.java)53
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java)32
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumer.java115
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/CmSubscriptionStatus.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/CmNotificationSubscriptionStatus.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionDetails.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionDetails.java)8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionKey.java30
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionPredicate.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionPredicate.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionTuple.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyQueryService.java)31
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java83
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandler.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerService.java)24
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImpl.java229
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java)41
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapper.java114
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducer.java139
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventPublishingTask.java62
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceService.java244
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java310
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java75
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandler.java96
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java102
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java129
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryService.java50
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImpl.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImpl.java)13
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/AsyncRestRequestResponseEventConsumer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/AsyncRestRequestResponseEventConsumer.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumer.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapper.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategies.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategies.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperation.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperationRequest.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationRequest.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiOperationCmHandle.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperationCmHandle.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java185
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DataOperationEventCreator.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java)77
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImpl.java55
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImpl.java67
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobStatusServiceImpl.java66
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java96
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java109
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java55
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java225
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfiguration.java68
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/AlternateIdChecker.java115
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryParametersValidator.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/RestQueryParametersValidator.java)8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryService.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java)34
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java)51
-rw-r--r--[-rwxr-xr-x]cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java)359
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java)51
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CompositeStateUtils.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java)4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/DataStoreSyncState.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/DataStoreSyncState.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java)24
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java)68
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/NcmpPersistence.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/ncmppersistence/NcmpPersistence.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/NcmpPersistenceImpl.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/NcmpPersistenceImpl.java)5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandleQueryService.java)21
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java)94
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditions.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditions.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleState.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleState.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/InventoryQueryConditions.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/InventoryQueryConditions.java)5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/LockReasonCategory.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/ModelledDmiServiceLeaves.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/ModelledDmiServiceLeaves.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/PropertyType.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/enums/PropertyType.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandle.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java)16
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/AsyncTaskExecutor.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/executor/AsyncTaskExecutor.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DataSyncWatchdog.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/DataSyncWatchdog.java)20
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java)55
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java)147
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java)50
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java)46
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java)15
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/WatchdogSchedulingConfigurer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/config/WatchdogSchedulingConfigurer.java)4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java)10
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java)26
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java)8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java)12
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java)57
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java)22
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java)30
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java)4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java)95
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/DmiRequestBody.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java)5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/RequiredDmiService.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/policyexecutor/PolicyExecutorWebClientConfiguration.java (renamed from dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/config/NcmpRequestLoggingConfig.java)31
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java78
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatter.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatter.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/YangDataConverter.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java)46
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java134
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/UrlTemplateParameters.java (renamed from dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DmiOperationCmHandle.java)20
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/WebClientConfiguration.java83
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/ModelLoader.java8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java)2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java)5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java)6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java (renamed from cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/TopicValidator.java)4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/DatastoreTypeSpec.groovy46
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/OperationTypeSpec.groovy48
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy79
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy411
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy181
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy64
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDeltaSpec.groovy49
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy58
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy64
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy88
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapperSpec.groovy64
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy97
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImplSpec.groovy136
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy168
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy54
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy85
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy97
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy19
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponseSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy)11
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilderSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CompositeStateBuilderSpec.groovy)11
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CompositeStateSpec.groovy)14
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/TrustLevelSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelSpec.groovy)2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/YangResourceTest.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangResourceTest.groovy)3
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy39
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/DmiHttpClientConfigSpec.groovy73
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/KafkaConfigSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy)4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryConfigSpec.groovy113
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy)34
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfigSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfigSpec.groovy)24
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy)144
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy)18
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapperSpec.groovy52
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapperSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapperSpec.groovy)28
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy)31
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy)55
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparatorSpec.groovy62
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImplSpec.groovy172
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy)47
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapperSpec.groovy69
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducerSpec.groovy106
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceServiceSpec.groovy204
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy218
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy80
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy (renamed from cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy)111
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy109
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImplSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImplSpec.groovy)8
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy)5
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy)9
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/FilterStrategiesIntegrationSpec.groovy)7
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapperSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapperSpec.groovy)2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategiesSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategiesSpec.groovy)4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/SerializationIntegrationSpec.groovy)6
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy45
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy154
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy)75
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImplSpec.groovy55
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy84
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobStatusServiceImplSpec.groovy53
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy40
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy63
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy)25
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy38
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy191
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfigurationSpec.groovy70
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/AlternateIdCheckerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy)83
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryParametersValidatorSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/RestQueryParametersValidatorSpec.groovy)27
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImplSpec.groovy)80
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy)42
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy)109
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy)92
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy274
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy)47
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditionsSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditionsSpec.groovy)3
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/InventoryQueryConditionsSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/InventoryQueryConditionsSpec.groovy)13
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandleSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy)16
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/AsyncTaskExecutorSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/executor/AsyncTaskExecutorSpec.groovy)5
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DataSyncWatchdogSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/DataSyncWatchdogSpec.groovy)16
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy)43
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy)115
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy)55
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasksSpec.groovy)102
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy)8
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfigSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy)3
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/WatchdogSchedulingConfigurerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/config/WatchdogSchedulingConfigurerSpec.groovy)3
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy)26
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy)18
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy)4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy)57
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy)11
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy)28
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy)4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManagerSpec.groovy)73
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/policyexecutor/PolicyExecutorWebClientConfigurationSpec.groovy53
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy80
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy46
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/YangDataConverterSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/YangDataConverterSpec.groovy)7
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilderSpec.groovy63
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy20
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy10
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy17
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy)13
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/ConsumerBaseSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/ConsumerBaseSpec.groovy)3
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/MessagingBaseSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy)2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy (renamed from cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/TopicValidatorSpec.groovy)4
-rw-r--r--cps-ncmp-service/src/test/java/org/onap/cps/ncmp/utils/WebClientBuilderTestConfig.java40
-rw-r--r--cps-ncmp-service/src/test/resources/application.yml45
-rw-r--r--cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json4
-rw-r--r--cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json7
-rw-r--r--cps-parent/pom.xml27
-rw-r--r--cps-path-parser/pom.xml2
-rw-r--r--cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g425
-rw-r--r--cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java78
-rw-r--r--cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java18
-rw-r--r--cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy27
-rw-r--r--cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathUtilSpec.groovy59
-rw-r--r--cps-rest/docs/openapi/components.yml24
-rw-r--r--cps-rest/docs/openapi/cpsData.yml38
-rw-r--r--cps-rest/docs/openapi/cpsDataV2.yml57
-rw-r--r--cps-rest/docs/openapi/openapi.yml12
-rw-r--r--cps-rest/pom.xml2
-rwxr-xr-xcps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java63
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy131
-rw-r--r--cps-ri/pom.xml2
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/CpsAdminPersistenceServiceImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java)37
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java)16
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java)27
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/models/AnchorEntity.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/models/DataspaceEntity.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/models/FragmentEntity.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/models/SchemaSetEntity.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/entities/SchemaSetEntity.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/models/YangResourceEntity.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/entities/YangResourceEntity.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/models/YangResourceModuleReference.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/entities/YangResourceModuleReference.java)2
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java)8
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/repository/DataspaceRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java)4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentPrefetchRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepository.java)4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentPrefetchRepositoryImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java)6
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java)180
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java)280
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java)8
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQueryImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java)15
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceQuery.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java)9
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java)4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java179
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java)6
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetYangResourceRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepository.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetYangResourceRepositoryImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepositoryImpl.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/TempTableCreator.java)4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceNativeRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceNativeRepository.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceNativeRepositoryImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceNativeRepositoryImpl.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java)6
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/utils/CpsSessionFactory.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/config/CpsSessionFactory.java)10
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/impl/utils/CpsValidatorImpl.java)4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/utils/EscapeUtils.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/utils/EscapeUtils.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/utils/SessionManager.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/utils/SessionManager.java)11
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/utils/TimeLimiterProvider.java (renamed from cps-ri/src/main/java/org/onap/cps/spi/utils/TimeLimiterProvider.java)2
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java87
-rw-r--r--cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/README.md23
-rw-r--r--cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2021-12-13.yang63
-rw-r--r--cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-02-10.yang81
-rw-r--r--cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-05-10.yang123
-rw-r--r--cps-ri/src/main/resources/yangResourceCsvGenerator.py66
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/ri/CpsDataPersistenceServiceImplSpec.groovy (renamed from cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy)20
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceConcurrencySpec.groovy (renamed from cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceConcurrencySpec.groovy)14
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceImplSpec.groovy (renamed from cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy)15
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/ri/utils/CpsValidatorImplSpec.groovy (renamed from cps-ri/src/test/groovy/org/onap/cps/spi/impl/utils/CpsValidatorSpec.groovy)5
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/ri/utils/EscapeUtilsSpec.groovy (renamed from cps-ri/src/test/groovy/org/onap/cps/spi/utils/EscapeUtilsSpec.groovy)2
-rw-r--r--cps-ri/src/test/groovy/org/onap/cps/ri/utils/SessionManagerSpec.groovy (renamed from cps-ri/src/test/groovy/org/onap/cps/spi/utils/SessionManagerSpec.groovy)12
-rw-r--r--cps-service/pom.xml14
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java33
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java50
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java33
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java32
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java191
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataspaceServiceImpl.java2
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDeltaServiceImpl.java5
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java20
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java2
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java2
-rw-r--r--cps-service/src/main/java/org/onap/cps/impl/utils/CpsValidator.java (renamed from cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java)2
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java47
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java16
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/DeltaReport.java6
-rw-r--r--cps-service/src/main/java/org/onap/cps/spi/model/DeltaReportBuilder.java8
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/YangParser.java28
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java10
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy37
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy188
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataspaceServiceImplSpec.groovy2
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDeltaServiceImplSpec.groovy14
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy38
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy2
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy13
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy3
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/spi/model/DeltaReportBuilderSpec.groovy10
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/utils/JsonObjectMapperSpec.groovy2
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy19
-rwxr-xr-xcsit/install-deps.sh36
-rw-r--r--csit/plans/cps/pnfsim/docker-compose.yml5
-rw-r--r--csit/plans/cps/pnfsim/tls/ca.pem23
-rw-r--r--csit/plans/cps/pnfsim/tls/server_cert.pem21
-rw-r--r--csit/plans/cps/pnfsim/tls/server_key.pem28
-rw-r--r--csit/plans/cps/sdnc/certs/keys0.zipbin5057 -> 3769 bytes
-rwxr-xr-xcsit/plans/cps/setup.sh9
-rwxr-xr-xcsit/plans/cps/teardown.sh10
-rw-r--r--csit/plans/cps/test.properties2
-rw-r--r--csit/plans/cps/testplanNcmp.txt2
-rwxr-xr-xcsit/prepare-csit.sh2
-rw-r--r--csit/pylibs.txt2
-rwxr-xr-xcsit/run-csit.sh1
-rwxr-xr-xcsit/run-project-csit.sh3
-rw-r--r--csit/tests/cps-data-operations/cps-data-operations.robot13
-rw-r--r--csit/tests/cps-data-sync/cps-data-sync.robot16
-rw-r--r--csit/tests/cps-model-sync/cps-model-sync.robot30
-rw-r--r--csit/tests/cps-trust-level/cps-trust-level.robot4
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml113
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml61
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java323
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DataOperationRequest.java39
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/utils/ResourceFileReaderUtil.java51
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml64
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/data/operational/ietf-network-topology-sample-rfc8345.json76
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResourcesResponse.json52
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResponse.json44
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResourcesResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResourcesResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResourcesResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResourcesResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/pom.xml42
-rw-r--r--docker-compose/config/grafana/jvm-micrometer-dashboard.json3613
-rw-r--r--docker-compose/config/grafana/provisioning/dashboards/dashboard.yml9
-rw-r--r--docker-compose/config/grafana/provisioning/datasources/datasource.yml8
-rw-r--r--docker-compose/config/nginx/nginx.conf52
-rw-r--r--docker-compose/config/nginx/proxy_params4
-rw-r--r--docker-compose/config/postgres-init.sql (renamed from docker-compose/postgres-init.sql)0
-rw-r--r--docker-compose/config/prometheus.yml (renamed from docker-compose/prometheus.yml)6
-rw-r--r--docker-compose/docker-compose.yml69
-rw-r--r--docs/_static/cps-delta-mechanism.pngbin69416 -> 46182 bytes
-rw-r--r--docs/_static/logo_onap_2024.pngbin0 -> 11627 bytes
-rw-r--r--docs/admin-guide.rst4
-rw-r--r--docs/api/swagger/cps/openapi.yaml205
-rw-r--r--docs/api/swagger/ncmp/openapi-inventory.yaml2
-rw-r--r--docs/api/swagger/ncmp/openapi.yaml38
-rw-r--r--docs/api/swagger/policy-executor/openapi.yaml198
-rw-r--r--docs/cm-notification-subscriptions.rst48
-rwxr-xr-xdocs/conf.py2
-rw-r--r--docs/cps-delta-endpoints.rst6
-rw-r--r--docs/cps-delta-feature.rst6
-rw-r--r--docs/cps-events.rst1
-rw-r--r--docs/cps-ncmp-message-status-codes.rst8
-rw-r--r--docs/design.rst17
-rw-r--r--docs/ncmp-inventory-querying.rst20
-rw-r--r--docs/policy-executor.rst23
-rw-r--r--docs/release-notes.rst120
-rw-r--r--docs/schemas/ncmp-in-event-schema-1.0.0.json73
-rw-r--r--docs/schemas/ncmp-out-event-schema-1.0.0.json (renamed from cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-out-event-schema-1.0.0.json)22
-rw-r--r--docs/schemas/policy-executor/ncmp-create-schema-1.0.0.json29
-rw-r--r--docs/schemas/policy-executor/ncmp-delete-schema-1.0.0.json25
-rw-r--r--docs/schemas/policy-executor/ncmp-patch-schema-1.0.0.json29
-rw-r--r--docs/schemas/policy-executor/ncmp-update-schema-1.0.0.json29
-rw-r--r--integration-test/pom.xml7
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy108
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy78
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy74
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy95
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/AnchorServiceIntegrationSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAnchorServiceIntegrationSpec.groovy)14
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy)107
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataspaceServiceIntegrationSpec.groovy)6
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy)4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy)8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/SessionManagerIntegrationSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/SessionManagerIntegrationSpec.groovy)4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy54
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/BearerTokenPassthroughSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy)49
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy)153
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy89
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy)93
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmNotificationSubscriptionSpec.groovy112
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobResultServiceSpec.groovy44
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy23
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DmiUrlEncodingPassthroughSpec.groovy65
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy63
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/RestApiSpec.groovy (renamed from integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy)39
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy75
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy12
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy5
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy12
-rw-r--r--integration-test/src/test/java/org/onap/cps/integration/DmiStubTestContainer.java61
-rw-r--r--integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java7
-rw-r--r--integration-test/src/test/resources/application.yml24
-rw-r--r--jacoco-report/pom.xml8
-rw-r--r--k6-tests/README.md24
-rwxr-xr-xk6-tests/install-deps.sh47
-rw-r--r--k6-tests/ncmp/common/cmhandle-crud.js72
-rw-r--r--k6-tests/ncmp/common/passthrough-crud.js74
-rw-r--r--k6-tests/ncmp/common/search-base.js59
-rw-r--r--k6-tests/ncmp/common/utils.js107
-rw-r--r--k6-tests/ncmp/ncmp-kpi.js240
-rwxr-xr-xk6-tests/ncmp/run-all-tests.sh52
-rwxr-xr-xk6-tests/run-k6-tests.sh43
-rwxr-xr-xk6-tests/setup.sh30
-rwxr-xr-xk6-tests/teardown.sh28
-rw-r--r--policy-executor-stub/pom.xml207
-rw-r--r--policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/PolicyExecutorApplication.java (renamed from dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/DmiDemoApplication.java)11
-rw-r--r--policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java103
-rw-r--r--policy-executor-stub/src/main/resources/application.yml19
-rw-r--r--policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/PolicyExecutorApplicationSpec.groovy (renamed from dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DmiDataOperationRequest.java)22
-rw-r--r--policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy151
-rw-r--r--pom.xml4
-rw-r--r--postman-collections/CPS Environment.postman_environment.json24
-rw-r--r--postman-collections/DMI Stub.postman_collection.json161
-rw-r--r--releases/3.5.0-container.yaml8
-rw-r--r--releases/3.5.0.yaml4
-rw-r--r--releases/3.5.1-container.yaml8
-rw-r--r--releases/3.5.1.yaml4
-rw-r--r--releases/3.5.2-container.yaml8
-rw-r--r--releases/3.5.2.yaml4
-rw-r--r--spotbugs/pom.xml2
-rw-r--r--spotbugs/src/main/resources/spotbugs-exclude.xml1
-rw-r--r--version.properties2
543 files changed, 18122 insertions, 10198 deletions
diff --git a/checkstyle/pom.xml b/checkstyle/pom.xml
index 9ecfa2d329..f618836d0d 100644
--- a/checkstyle/pom.xml
+++ b/checkstyle/pom.xml
@@ -26,7 +26,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>checkstyle</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<profiles>
<profile>
diff --git a/cps-application/pom.xml b/cps-application/pom.xml
index 6804c7de65..19710be80b 100644
--- a/cps-application/pom.xml
+++ b/cps-application/pom.xml
@@ -28,7 +28,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -75,7 +75,7 @@
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
- <artifactId>micrometer-tracing-bridge-brave</artifactId>
+ <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
@@ -84,11 +84,6 @@
<!-- T E S T D E P E N D E N C I E S -->
<dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<scope>test</scope>
@@ -111,6 +106,7 @@
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml
index 094046ca21..25bc63b44e 100644
--- a/cps-application/src/main/resources/application.yml
+++ b/cps-application/src/main/resources/application.yml
@@ -151,8 +151,24 @@ security:
username: ${CPS_USERNAME:cpsuser}
password: ${CPS_PASSWORD:cpsr0cks!}
+cps:
+ tracing:
+ sampler:
+ jaeger_remote:
+ endpoint: ${ONAP_OTEL_SAMPLER_JAEGER_REMOTE_ENDPOINT:http://onap-otel-collector:14250}
+ exporter:
+ endpoint: ${ONAP_OTEL_EXPORTER_ENDPOINT:http://onap-otel-collector:4317}
+ protocol: ${ONAP_OTEL_EXPORTER_PROTOCOL:grpc}
+ enabled: ${ONAP_TRACING_ENABLED:false}
+ excluded-observation-names: ${ONAP_EXCLUDED_OBSERVATION_NAMES:tasks.scheduled.execution}
+
# Actuator
management:
+ tracing:
+ propagation:
+ produce: ${ONAP_PROPAGATOR_PRODUCE:[W3C]}
+ sampling:
+ probability: 1.0
endpoints:
web:
exposure:
@@ -172,13 +188,35 @@ logging:
onap:
cps: INFO
ncmp:
+ policy-executor:
+ enabled: ${POLICY_SERVICE_ENABLED:false}
+ server:
+ address: ${POLICY_SERVICE_URL:http://policy-executor-stub}
+ port: ${POLICY_SERVICE_PORT:8093}
+ httpclient:
+ all-services:
+ maximumInMemorySizeInMegabytes: 16
+ maximumConnectionsTotal: 100
+ pendingAcquireMaxCount: 50
+ connectionTimeoutInSeconds: 30
+ readTimeoutInSeconds: 30
+ writeTimeoutInSeconds: 30
dmi:
httpclient:
- connectionTimeoutInSeconds: 30
- maximumConnectionsPerRoute: 50
- maximumConnectionsTotal: 100
- idleConnectionEvictionThresholdInSeconds: 5
- maximumInMemorySizeInMegabytes: 16
+ data-services:
+ maximumInMemorySizeInMegabytes: 16
+ maximumConnectionsTotal: 100
+ pendingAcquireMaxCount: 50
+ connectionTimeoutInSeconds: 30
+ readTimeoutInSeconds: 30
+ writeTimeoutInSeconds: 30
+ model-services:
+ maximumInMemorySizeInMegabytes: 16
+ maximumConnectionsTotal: 100
+ pendingAcquireMaxCount: 50
+ connectionTimeoutInSeconds: 30
+ readTimeoutInSeconds: 30
+ writeTimeoutInSeconds: 30
auth:
username: ${DMI_USERNAME:cpsuser}
password: ${DMI_PASSWORD:cpsr0cks!}
@@ -190,7 +228,7 @@ ncmp:
advised-modules-sync:
sleep-time-ms: 5000
locked-modules-sync:
- sleep-time-ms: 300000
+ sleep-time-ms: 15000
cm-handle-data-sync:
sleep-time-ms: 30000
subscription-forwarding:
@@ -214,3 +252,9 @@ hazelcast:
kubernetes:
enabled: ${HAZELCAST_MODE_KUBERNETES_ENABLED:false}
service-name: ${CPS_NCMP_SERVICE_NAME:"cps-and-ncmp-service"}
+
+otel:
+ exporter:
+ otlp:
+ traces:
+ protocol: ${ONAP_OTEL_EXPORTER_OTLP_TRACES_PROTOCOL:grpc}
diff --git a/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java b/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java
index c18a3ed10b..82fdc7f487 100644
--- a/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java
+++ b/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java
@@ -25,6 +25,7 @@ import static com.tngtech.archunit.library.freeze.FreezingArchRule.freeze;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
+import com.tngtech.archunit.junit.ArchIgnore;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
@@ -37,9 +38,9 @@ public class LayeredArchitectureTest {
private static final String REST_CONTROLLER_PACKAGE = "org.onap.cps.rest..";
private static final String NCMP_REST_PACKAGE = "org.onap.cps.ncmp.rest..";
private static final String API_SERVICE_PACKAGE = "org.onap.cps.api..";
- private static final String SPI_SERVICE_PACKAGE = "org.onap.cps.spi..";
+ private static final String SPI_SERVICE_PACKAGE = "org.onap.cps.ri..";
private static final String NCMP_SERVICE_PACKAGE = "org.onap.cps.ncmp.api..";
- private static final String SPI_REPOSITORY_PACKAGE = "org.onap.cps.spi.repository..";
+ private static final String SPI_REPOSITORY_PACKAGE = "org.onap.cps.ri.repository..";
private static final String YANG_SCHEMA_PACKAGE = "org.onap.cps.yang..";
private static final String NOTIFICATION_PACKAGE = "org.onap.cps.notification..";
private static final String CPS_UTILS_PACKAGE = "org.onap.cps.utils..";
@@ -47,12 +48,15 @@ public class LayeredArchitectureTest {
private static final String CPS_CACHE_PACKAGE = "org.onap.cps.cache..";
private static final String CPS_EVENTS_PACKAGE = "org.onap.cps.events..";
+ //TODO We need to revisit these rules, the first one doesn't even make any sense: CPS-2293
+
@ArchTest
static final ArchRule restControllerShouldOnlyDependOnRestController =
classes().that().resideInAPackage(REST_CONTROLLER_PACKAGE).should().onlyHaveDependentClassesThat()
.resideInAPackage(REST_CONTROLLER_PACKAGE);
@ArchTest
+ @ArchIgnore
static final ArchRule apiOrSpiServiceShouldOnlyBeDependedOnByControllerAndServicesAndCommonUtilityPackages =
freeze(classes().that().resideInAPackage(API_SERVICE_PACKAGE)
.or().resideInAPackage(SPI_SERVICE_PACKAGE).should().onlyHaveDependentClassesThat()
diff --git a/cps-bom/pom.xml b/cps-bom/pom.xml
index 4548eb21c3..31aedab40e 100644
--- a/cps-bom/pom.xml
+++ b/cps-bom/pom.xml
@@ -25,7 +25,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>cps-bom</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<packaging>pom</packaging>
<description>This artifact contains dependencyManagement declarations of all published CPS components.</description>
diff --git a/cps-dependencies/pom.xml b/cps-dependencies/pom.xml
index f323cd7077..adef9031ab 100644
--- a/cps-dependencies/pom.xml
+++ b/cps-dependencies/pom.xml
@@ -27,7 +27,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>cps-dependencies</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<packaging>pom</packaging>
<name>${project.groupId}:${project.artifactId}</name>
@@ -42,6 +42,7 @@
<testcontainers.version>1.18.3</testcontainers.version>
<mapstruct.version>1.4.2.Final</mapstruct.version>
<jetty-version>11.0.16</jetty-version>
+ <version.opentelemetry-instrumentation-bom>2.1.0-alpha</version.opentelemetry-instrumentation-bom>
</properties>
<build>
@@ -128,6 +129,11 @@
<version>4.2.3</version>
</dependency>
<dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>annotations</artifactId>
+ <version>3.0.1</version>
+ </dependency>
+ <dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
@@ -140,7 +146,7 @@
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-spring</artifactId>
- <version>5.3.1</version>
+ <version>5.3.7</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
@@ -177,9 +183,18 @@
<version>3.7.3</version>
</dependency>
<dependency>
- <groupId>io.micrometer</groupId>
- <artifactId>micrometer-tracing-bridge-brave</artifactId>
- <version>1.0.0</version>
+ <groupId>io.opentelemetry.instrumentation</groupId>
+ <artifactId>opentelemetry-instrumentation-bom-alpha</artifactId>
+ <version>${version.opentelemetry-instrumentation-bom}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-bom</artifactId>
+ <version>1.37.0</version>
+ <type>pom</type>
+ <scope>import</scope>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
@@ -234,7 +249,7 @@
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
- <version>4.21.0</version>
+ <version>4.29.0</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
diff --git a/cps-events/pom.xml b/cps-events/pom.xml
index ec0c96bc24..e5fab868c2 100644
--- a/cps-events/pom.xml
+++ b/cps-events/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-events/pom.xml b/cps-ncmp-events/pom.xml
index 3804e5bd21..b0b28992e7 100644
--- a/cps-ncmp-events/pom.xml
+++ b/cps-ncmp-events/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-in-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-in-event-schema-1.0.0.json
index dcba93c014..93ec216e3d 100644
--- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-in-event-schema-1.0.0.json
+++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-in-event-schema-1.0.0.json
@@ -1,12 +1,12 @@
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-dmi-in-event-schema:1.0.0",
- "$ref": "#/definitions/CmNotificationSubscriptionDmiInEvent",
+ "$ref": "#/definitions/DmiInEvent",
"definitions": {
- "CmNotificationSubscriptionDmiInEvent": {
+ "DmiInEvent": {
"description": "The payload for cm notification subscription event incoming message from NCMP.",
"type": "object",
- "javaType": "org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent",
+ "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent",
"additionalProperties": false,
"properties": {
"data": {
@@ -22,7 +22,7 @@
"description": "Information about the targets and subscription",
"additionalProperties": false,
"properties": {
- "cmhandles": {
+ "cmHandles": {
"type": "array",
"items": {
"type": "object",
@@ -32,7 +32,7 @@
"cmhandleId": {
"type": "string"
},
- "private-properties": {
+ "privateProperties": {
"type": "object",
"existingJavaType": "java.util.Map<String,String>",
"items": {
@@ -63,7 +63,7 @@
"type": "string",
"enum": ["ncmp-datastore:passthrough-operational", "ncmp-datastore:passthrough-running"]
},
- "xpath-filter": {
+ "xpathFilter": {
"description": "Filter to be applied to the CM Handles through this event",
"type": "array",
"items": {
@@ -73,7 +73,7 @@
},
"additionalProperties": false,
"required": [
- "xpath-filter"
+ "xpathFilter"
]
}
},
@@ -86,8 +86,7 @@
}
},
"required": [
- "cmhandles",
- "predicates"
+ "cmHandles"
]
}
}
diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-out-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-out-event-schema-1.0.0.json
index 538716ab55..0910de1529 100644
--- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-dmi-out-event-schema-1.0.0.json
+++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/dmi-out-event-schema-1.0.0.json
@@ -1,13 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-dmi-out-event-schema:1.0.0",
- "$ref": "#/definitions/CmNotificationSubscriptionDmiOutEvent",
+ "$ref": "#/definitions/DmiOutEvent",
"definitions": {
- "CmNotificationSubscriptionDmiOutEvent": {
+ "DmiOutEvent": {
"description": "The payload for cm notification subscription merge event coming out from DMI Plugin.",
"type": "object",
"additionalProperties": false,
- "javaType": "org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent",
+ "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.DmiOutEvent",
"properties": {
"data": {
"$ref": "#/definitions/Data"
@@ -16,7 +16,7 @@
"required": [
"data"
],
- "title": "CmNotificationSubscriptionDmiOutEvent"
+ "title": "DmiOutEvent"
},
"Data": {
"type": "object",
diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-in-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-in-event-schema-1.0.0.json
index 55769338b1..f8b6c2e680 100644
--- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-in-event-schema-1.0.0.json
+++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-in-event-schema-1.0.0.json
@@ -1,11 +1,11 @@
{
"$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-ncmp-in-event:1.0.0",
- "$ref": "#/definitions/CmNotificationSubscriptionNcmpInEvent",
+ "$ref": "#/definitions/NcmpInEvent",
"$schema": "https://json-schema.org/draft/2019-09/schema",
"definitions": {
- "CmNotificationSubscriptionNcmpInEvent": {
+ "NcmpInEvent": {
"description": "The payload for subscription merge event.",
- "javaType": "org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent",
+ "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent",
"properties": {
"data": {
"properties": {
@@ -34,7 +34,7 @@
"type": "string",
"enum": ["ncmp-datastore:passthrough-operational", "ncmp-datastore:passthrough-running"]
},
- "xpath-filter": {
+ "xpathFilter": {
"description": "Filter to be applied to the CM Handles through this event",
"type": "array",
"items": {
@@ -44,7 +44,7 @@
},
"additionalProperties": false,
"required": [
- "xpath-filter"
+ "xpathFilter"
]
}
},
@@ -57,8 +57,7 @@
}
},
"required": [
- "subscriptionId",
- "predicates"
+ "subscriptionId"
],
"type": "object",
"additionalProperties": false
diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-out-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-out-event-schema-1.0.0.json
new file mode 100644
index 0000000000..11dc4e1114
--- /dev/null
+++ b/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/ncmp-out-event-schema-1.0.0.json
@@ -0,0 +1,57 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-ncmp-out-event-schema:1.0.0",
+ "$ref": "#/definitions/NcmpOutEvent",
+ "definitions": {
+ "NcmpOutEvent": {
+ "type": "object",
+ "description": "The payload applied cm subscription merge event coming out from NCMP.",
+ "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent",
+ "additionalProperties": false,
+ "properties": {
+ "data": {
+ "$ref": "#/definitions/Data"
+ }
+ },
+ "required": [
+ "data"
+ ],
+ "title": "NcmpOutEvent"
+ },
+ "Data": {
+ "type": "object",
+ "description": "Information about the targets and subscription",
+ "additionalProperties": false,
+ "properties": {
+ "subscriptionId": {
+ "type": "string",
+ "description": "The unique subscription id"
+ },
+ "acceptedTargets": {
+ "type": "object",
+ "existingJavaType": "java.util.Collection<String>",
+ "description": "Unique Collection of accepted targets"
+ },
+ "rejectedTargets": {
+ "type": "object",
+ "existingJavaType": "java.util.Collection<String>",
+ "description": "Unique Collection of rejected targets"
+ },
+ "pendingTargets": {
+ "type": "object",
+ "existingJavaType": "java.util.Collection<String>",
+ "description": "Unique Collection of pending targets"
+ }
+ },
+ "required": [
+ "subscriptionId",
+ "acceptedTargets",
+ "rejectedTargets",
+ "pendingTargets"
+ ],
+ "title": "Data"
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/cps-ncmp-events/src/main/resources/schemas/dmidataavc/avc-event-schema-1.0.0.json b/cps-ncmp-events/src/main/resources/schemas/dmidataavc/avc-event-schema-1.0.0.json
index a5bed939bf..474520d142 100644
--- a/cps-ncmp-events/src/main/resources/schemas/dmidataavc/avc-event-schema-1.0.0.json
+++ b/cps-ncmp-events/src/main/resources/schemas/dmidataavc/avc-event-schema-1.0.0.json
@@ -16,7 +16,8 @@
"type": "string"
},
"value": {
- "$ref": "#/definitions/Value"
+ "type": "object",
+ "existingJavaType": "java.lang.Object"
}
},
"required": [
@@ -25,25 +26,6 @@
"target"
]
},
- "Value": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "attributes": {
- "type": "array",
- "items": {
- "type": "object",
- "existingJavaType": "java.util.Map<String,Object>",
- "additionalProperties": false,
- "properties": {
- "isHoAllowed": {
- "type": "boolean"
- }
- }
- }
- }
- }
- },
"AvcEvent": {
"description": "The payload for AVC event.",
"type": "object",
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
index 7b277cdb3a..c73a2519ac 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-ncmp-rest-stub</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
</parent>
<artifactId>cps-ncmp-rest-stub-app</artifactId>
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
index cb655320f5..eee0431904 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
@@ -21,7 +21,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-ncmp-rest-stub</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
</parent>
<artifactId>cps-ncmp-rest-stub-service</artifactId>
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
index 08a492e0f7..183698c4f5 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
@@ -35,7 +35,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
import org.onap.cps.ncmp.rest.model.DataOperationRequest;
@@ -165,7 +165,8 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
}
@Override
- public ResponseEntity<RestOutputCmHandleCompositeState> getCmHandleStateByCmHandleId(final String cmHandle) {
+ public ResponseEntity<RestOutputCmHandleCompositeState> getCmHandleStateByCmHandleId(
+ final String cmHandleReference) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy
index b36e25ada0..177febd8ae 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/test/groovy/org/onap/cps/ncmp/rest/stub/SampleCpsNcmpClientSpec.groovy
@@ -19,24 +19,18 @@
*/
package org.onap.cps.ncmp.rest.stub
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType
+import com.fasterxml.jackson.core.JsonProcessingException
+import com.fasterxml.jackson.core.type.TypeReference
+import com.fasterxml.jackson.databind.JsonMappingException
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.data.models.DatastoreType
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration
-import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.http.HttpStatus
import org.springframework.test.context.ActiveProfiles
-import org.springframework.test.context.ContextConfiguration
-
-import com.fasterxml.jackson.core.JsonProcessingException
-import com.fasterxml.jackson.core.type.TypeReference
-import com.fasterxml.jackson.databind.JsonMappingException
-import com.fasterxml.jackson.databind.ObjectMapper
-
-import spock.lang.Shared
import spock.lang.Specification
@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
diff --git a/cps-ncmp-rest-stub/pom.xml b/cps-ncmp-rest-stub/pom.xml
index 441ce43f45..01604e89ff 100644
--- a/cps-ncmp-rest-stub/pom.xml
+++ b/cps-ncmp-rest-stub/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index 8aa38c0f70..112dddf61c 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -505,6 +505,14 @@ components:
schema:
type: string
example: my-cm-handle
+ cmHandleReferenceInPath:
+ name: cm-handle
+ in: path
+ description: The identifier (cmHandle or alternate) for a network function, network element, subnetwork or any other cm object by managed Network CM Proxy
+ required: true
+ schema:
+ type: string
+ example: my-cm-handle-reference
moduleNameInQuery:
name: module-name
in: query
@@ -578,7 +586,6 @@ components:
in: query
description: The format of resource identifier depend on the associated DMI Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but it can really be anything.
required: true
- allowReserved: true
schema:
type: string
examples:
@@ -598,7 +605,6 @@ components:
required: false
schema:
type: string
- allowReserved: true
examples:
sample 1:
value:
@@ -616,7 +622,6 @@ components:
required: false
schema:
type: string
- allowReserved: true
examples:
sample 1:
value:
@@ -628,7 +633,6 @@ components:
required: true
schema:
type: string
- allowReserved: true
examples:
sample 1:
value:
diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml
index d0b1f35eaa..adb2419c8a 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp.yml
@@ -27,7 +27,7 @@ resourceDataForCmHandle:
operationId: getResourceDataForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/datastoreName'
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
- $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/optionsParamInQuery'
- $ref: 'components.yaml#/components/parameters/topicParamInQuery'
@@ -60,7 +60,7 @@ resourceDataForCmHandle:
operationId: createResourceDataRunningForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/datastoreName'
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
- $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/contentParamInHeader'
- $ref: 'components.yaml#/components/parameters/authorizationParamInHeader'
@@ -99,7 +99,7 @@ resourceDataForCmHandle:
operationId: updateResourceDataRunningForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/datastoreName'
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
- $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/contentParamInHeader'
- $ref: 'components.yaml#/components/parameters/authorizationParamInHeader'
@@ -138,7 +138,7 @@ resourceDataForCmHandle:
operationId: patchResourceDataRunningForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/datastoreName'
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
- $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/contentParamInHeader'
- $ref: 'components.yaml#/components/parameters/authorizationParamInHeader'
@@ -171,7 +171,7 @@ resourceDataForCmHandle:
operationId: deleteResourceDataRunningForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/datastoreName'
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
- $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/contentParamInHeader'
- $ref: 'components.yaml#/components/parameters/authorizationParamInHeader'
@@ -194,7 +194,7 @@ dataOperationForCmHandle:
tags:
- network-cm-proxy
summary: Execute a data operation for group of cm handle ids
- description: This request will be handled asynchronously using messaging to the supplied topic. The rest response will be an acknowledge with a requestId to identify the relevant messages. A maximum of 50 cm handles per operation is supported.
+ description: This request will be handled asynchronously using messaging to the supplied topic. The rest response will be an acknowledge with a requestId to identify the relevant messages. A maximum of 200 cm handles per operation is supported.
operationId: executeDataOperationForCmHandles
parameters:
- $ref: 'components.yaml#/components/parameters/requiredTopicParamInQuery'
@@ -264,7 +264,7 @@ fetchModuleReferencesByCmHandle:
summary: Fetch all module references (name and revision) for a given cm handle
operationId: getModuleReferencesByCmHandle
parameters:
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
responses:
200:
description: OK
@@ -289,7 +289,7 @@ getModuleDefinitions:
description: Get module definitions (module name, revision, yang resource) with options to filter on module name and revision
operationId: getModuleDefinitions
parameters:
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
- $ref: 'components.yaml#/components/parameters/moduleNameInQuery'
- $ref: 'components.yaml#/components/parameters/revisionInQuery'
responses:
@@ -354,7 +354,7 @@ retrieveCmHandleDetailsById:
summary: Retrieve CM handle details
operationId: retrieveCmHandleDetailsById
parameters:
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
responses:
200:
description: OK
@@ -377,7 +377,7 @@ getCmHandlePropertiesById:
summary: Get CM handle properties
operationId: getCmHandlePublicPropertiesByCmHandleId
parameters:
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
responses:
200:
description: OK
@@ -400,7 +400,7 @@ getCmHandleStateById:
summary: Get CM handle state
operationId: getCmHandleStateByCmHandleId
parameters:
- - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath'
responses:
200:
description: OK
diff --git a/cps-ncmp-rest/docs/openapi/openapi-inventory.yml b/cps-ncmp-rest/docs/openapi/openapi-inventory.yml
index b794082875..8c0ad41705 100755
--- a/cps-ncmp-rest/docs/openapi/openapi-inventory.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi-inventory.yml
@@ -21,7 +21,7 @@ openapi: 3.0.3
info:
title: NCMP Inventory API
description: NCMP Inventory API
- version: "1.0"
+ version: "3.5.2"
servers:
- url: /ncmpInventory
components:
@@ -40,4 +40,4 @@ paths:
$ref: 'ncmp-inventory.yml#/searchCmHandleIds'
security:
- - basicAuth: [] \ No newline at end of file
+ - basicAuth: []
diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml
index dd6d7c8baa..78fb141820 100755
--- a/cps-ncmp-rest/docs/openapi/openapi.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi.yml
@@ -22,7 +22,7 @@ openapi: 3.0.3
info:
title: NCMP to CPS Proxy API
description: NCMP to CPS Proxy API
- version: "1.0"
+ version: "3.5.2"
servers:
- url: /ncmp
components:
@@ -64,4 +64,4 @@ paths:
/v1/ch/{cm-handle}/data-sync:
$ref: 'ncmp.yml#/setDataSyncEnabledFlag'
security:
- - basicAuth: [] \ No newline at end of file
+ - basicAuth: []
diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml
index e333344798..adac504eae 100644
--- a/cps-ncmp-rest/pom.xml
+++ b/cps-ncmp-rest/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
index 45c7c33fd2..42f709dcf5 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
@@ -23,36 +23,29 @@
package org.onap.cps.ncmp.rest.controller;
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL;
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING;
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE;
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE;
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH;
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE;
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL;
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING;
+import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE;
+import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE;
+import static org.onap.cps.ncmp.api.data.models.OperationType.PATCH;
+import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE;
import io.micrometer.core.annotation.Timed;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
-import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig;
-import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel;
-import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
-import org.onap.cps.ncmp.api.models.CmResourceAddress;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException;
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade;
import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
-import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandler;
-import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastoreRequestHandler;
-import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler;
-import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper;
-import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper;
import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties;
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
import org.onap.cps.ncmp.rest.model.DataOperationRequest;
@@ -61,10 +54,13 @@ import org.onap.cps.ncmp.rest.model.RestModuleReference;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandle;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandleCompositeState;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties;
+import org.onap.cps.ncmp.rest.util.CmHandleStateMapper;
+import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper;
import org.onap.cps.ncmp.rest.util.DeprecationHelper;
+import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper;
+import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.utils.JsonObjectMapper;
-import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
@@ -78,22 +74,19 @@ import org.springframework.web.bind.annotation.RestController;
public class NetworkCmProxyController implements NetworkCmProxyApi {
private static final String NO_BODY = null;
- private final NetworkCmProxyDataService networkCmProxyDataService;
+ private final NetworkCmProxyFacade networkCmProxyFacade;
+ private final NetworkCmProxyInventoryFacade networkCmProxyInventoryFacade;
private final JsonObjectMapper jsonObjectMapper;
private final DeprecationHelper deprecationHelper;
private final NcmpRestInputMapper ncmpRestInputMapper;
private final CmHandleStateMapper cmHandleStateMapper;
- private final NcmpCachedResourceRequestHandler ncmpCachedResourceRequestHandler;
- private final NcmpPassthroughResourceRequestHandler ncmpPassthroughResourceRequestHandler;
private final DataOperationRequestMapper dataOperationRequestMapper;
- @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE)
- private final Map<String, TrustLevel> trustLevelPerCmHandle;
/**
* Get resource data from datastore.
*
* @param datastoreName name of the datastore
- * @param cmHandle cm handle identifier
+ * @param cmHandleReference cm handle or alternate id identifier
* @param resourceIdentifier resource identifier
* @param optionsParamInQuery options query parameter
* @param topicParamInQuery topic query parameter
@@ -104,36 +97,38 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
@Override
@Timed(value = "cps.ncmp.controller.get", description = "Time taken to get resource data from datastore")
public ResponseEntity<Object> getResourceDataForCmHandle(final String datastoreName,
- final String cmHandle,
+ final String cmHandleReference,
final String resourceIdentifier,
final String optionsParamInQuery,
final String topicParamInQuery,
final Boolean includeDescendants,
final String authorization) {
- final NcmpDatastoreRequestHandler ncmpDatastoreRequestHandler = getNcmpDatastoreRequestHandler(datastoreName);
- final CmResourceAddress cmResourceAddress = new CmResourceAddress(datastoreName, cmHandle, resourceIdentifier);
- return ncmpDatastoreRequestHandler.executeRequest(cmResourceAddress, optionsParamInQuery, topicParamInQuery,
- includeDescendants, authorization);
+ final CmResourceAddress cmResourceAddress = new CmResourceAddress(datastoreName, cmHandleReference,
+ resourceIdentifier);
+ final Object result = networkCmProxyFacade.getResourceDataForCmHandle(cmResourceAddress, optionsParamInQuery,
+ topicParamInQuery, includeDescendants, authorization);
+ return ResponseEntity.ok(result);
}
@Override
public ResponseEntity<Object> executeDataOperationForCmHandles(final String topicParamInQuery,
final DataOperationRequest dataOperationRequest,
final String authorization) {
- return ncmpPassthroughResourceRequestHandler.executeRequest(topicParamInQuery,
+ final Object result = networkCmProxyFacade.executeDataOperationForCmHandles(topicParamInQuery,
dataOperationRequestMapper.toDataOperationRequest(dataOperationRequest), authorization);
+ return ResponseEntity.ok(result);
}
/**
* Query resource data from datastore.
*
- * @param datastoreName name of the datastore
+ * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:operational")
* @param cmHandle cm handle identifier
* @param cpsPath CPS Path
* @param optionsParamInQuery options query parameter
* @param topicParamInQuery topic query parameter
* @param includeDescendants whether to include descendants or not
- * @return {@code ResponseEntity} response from dmi plugin
+ * @return {@code ResponseEntity} response. Body contains a collection of DataNodes
*/
@Override
@@ -144,14 +139,16 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
final String topicParamInQuery,
final Boolean includeDescendants) {
validateDataStore(OPERATIONAL, datastoreName);
- return ncmpCachedResourceRequestHandler.executeRequest(cmHandle, cpsPath, includeDescendants);
+ final Collection<DataNode> dataNodes = networkCmProxyFacade.queryResourceDataForCmHandle(cmHandle, cpsPath,
+ includeDescendants);
+ return ResponseEntity.ok(dataNodes);
}
/**
- * Patch resource data from passthrough-running.
+ * Patch resource data.
*
- * @param datastoreName name of the datastore
- * @param cmHandle cm handle identifier
+ * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running")
+ * @param cmHandleReference cm handle or alternate identifier
* @param resourceIdentifier resource identifier
* @param requestBody the request body
* @param contentType content type of body
@@ -161,7 +158,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
@Override
public ResponseEntity<Object> patchResourceDataRunningForCmHandle(final String datastoreName,
- final String cmHandle,
+ final String cmHandleReference,
final String resourceIdentifier,
final Object requestBody,
final String contentType,
@@ -169,18 +166,18 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
validateDataStore(PASSTHROUGH_RUNNING, datastoreName);
- final Object responseObject = networkCmProxyDataService
+ final Object responseObject = networkCmProxyFacade
.writeResourceDataPassThroughRunningForCmHandle(
- cmHandle, resourceIdentifier, PATCH,
+ cmHandleReference, resourceIdentifier, PATCH,
jsonObjectMapper.asJsonString(requestBody), contentType, authorization);
return ResponseEntity.ok(responseObject);
}
/**
- * Create resource data in datastore pass-through running for given cm-handle.
+ * Create resource data for given cm-handle.
*
- * @param datastoreName name of the datastore
- * @param cmHandle cm handle identifier
+ * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running")
+ * @param cmHandleReference cm handle or alternate identifier
* @param resourceIdentifier resource identifier
* @param requestBody the request body
* @param contentType content type of body
@@ -189,23 +186,23 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
*/
@Override
public ResponseEntity<Void> createResourceDataRunningForCmHandle(final String datastoreName,
- final String cmHandle,
+ final String cmHandleReference,
final String resourceIdentifier,
final Object requestBody,
final String contentType,
final String authorization) {
validateDataStore(PASSTHROUGH_RUNNING, datastoreName);
- networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle,
+ networkCmProxyFacade.writeResourceDataPassThroughRunningForCmHandle(cmHandleReference,
resourceIdentifier, CREATE, jsonObjectMapper.asJsonString(requestBody), contentType, authorization);
return new ResponseEntity<>(HttpStatus.CREATED);
}
/**
- * Update resource data in datastore pass-through running for given cm-handle.
+ * Update resource data for given cm-handle.
*
- * @param datastoreName name of the datastore
- * @param cmHandle cm handle identifier
+ * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running")
+ * @param cmHandleReference cm handle or alternate identifier
* @param resourceIdentifier resource identifier
* @param requestBody the request body
* @param contentType content type of the body
@@ -215,23 +212,23 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
@Override
public ResponseEntity<Object> updateResourceDataRunningForCmHandle(final String datastoreName,
- final String cmHandle,
+ final String cmHandleReference,
final String resourceIdentifier,
final Object requestBody,
final String contentType,
final String authorization) {
validateDataStore(PASSTHROUGH_RUNNING, datastoreName);
- networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle,
+ networkCmProxyFacade.writeResourceDataPassThroughRunningForCmHandle(cmHandleReference,
resourceIdentifier, UPDATE, jsonObjectMapper.asJsonString(requestBody), contentType, authorization);
return new ResponseEntity<>(HttpStatus.OK);
}
/**
- * Delete resource data in datastore pass-through running for a given cm-handle.
+ * Delete resource data for a given cm-handle.
*
- * @param datastoreName name of the datastore
- * @param cmHandle cm handle identifier
+ * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running")
+ * @param cmHandleReference cm handle or alternate identifier
* @param resourceIdentifier resource identifier
* @param contentType content type of the body
* @param authorization contents of Authorization header, or null if not present
@@ -239,14 +236,14 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
*/
@Override
public ResponseEntity<Void> deleteResourceDataRunningForCmHandle(final String datastoreName,
- final String cmHandle,
+ final String cmHandleReference,
final String resourceIdentifier,
final String contentType,
final String authorization) {
validateDataStore(PASSTHROUGH_RUNNING, datastoreName);
- networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle,
+ networkCmProxyFacade.writeResourceDataPassThroughRunningForCmHandle(cmHandleReference,
resourceIdentifier, DELETE, NO_BODY, contentType, authorization);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@@ -263,11 +260,11 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
final CmHandleQueryParameters cmHandleQueryParameters) {
final CmHandleQueryApiParameters cmHandleQueryApiParameters =
deprecationHelper.mapOldConditionProperties(cmHandleQueryParameters);
- final Collection<NcmpServiceCmHandle> cmHandles = networkCmProxyDataService
+ final Collection<NcmpServiceCmHandle> cmHandles = networkCmProxyInventoryFacade
.executeCmHandleSearch(cmHandleQueryApiParameters);
- final List<RestOutputCmHandle> outputCmHandles =
+ final List<RestOutputCmHandle> restOutputCmHandles =
cmHandles.stream().map(this::toRestOutputCmHandle).collect(Collectors.toList());
- return ResponseEntity.ok(outputCmHandles);
+ return ResponseEntity.ok(restOutputCmHandles);
}
/**
@@ -282,34 +279,35 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
final CmHandleQueryApiParameters cmHandleQueryApiParameters =
jsonObjectMapper.convertToValueType(cmHandleQueryParameters, CmHandleQueryApiParameters.class);
final Collection<String> cmHandleIds
- = networkCmProxyDataService.executeCmHandleIdSearch(cmHandleQueryApiParameters);
+ = networkCmProxyInventoryFacade.executeCmHandleIdSearch(cmHandleQueryApiParameters);
return ResponseEntity.ok(List.copyOf(cmHandleIds));
}
/**
* Search for Cm Handle and Properties by Name.
*
- * @param cmHandleId cm-handle identifier
+ * @param cmHandleReference cm-handle or alternate identifier
* @return cm handle and its properties
*/
@Override
- public ResponseEntity<RestOutputCmHandle> retrieveCmHandleDetailsById(final String cmHandleId) {
- final NcmpServiceCmHandle ncmpServiceCmHandle = networkCmProxyDataService.getNcmpServiceCmHandle(cmHandleId);
+ public ResponseEntity<RestOutputCmHandle> retrieveCmHandleDetailsById(final String cmHandleReference) {
+ final NcmpServiceCmHandle ncmpServiceCmHandle
+ = networkCmProxyInventoryFacade.getNcmpServiceCmHandle(cmHandleReference);
final RestOutputCmHandle restOutputCmHandle = toRestOutputCmHandle(ncmpServiceCmHandle);
return ResponseEntity.ok(restOutputCmHandle);
}
/**
- * Get Cm Handle Properties by Cm Handle Id.
+ * Get Cm Handle Properties by Cm Handle or alternate Identifier.
*
- * @param cmHandleId cm-handle identifier
+ * @param cmHandleReference cm-handle or alternate identifier
* @return cm handle properties
*/
@Override
public ResponseEntity<RestOutputCmHandlePublicProperties> getCmHandlePublicPropertiesByCmHandleId(
- final String cmHandleId) {
+ final String cmHandleReference) {
final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties();
- cmHandlePublicProperties.add(networkCmProxyDataService.getCmHandlePublicProperties(cmHandleId));
+ cmHandlePublicProperties.add(networkCmProxyInventoryFacade.getCmHandlePublicProperties(cmHandleReference));
final RestOutputCmHandlePublicProperties restOutputCmHandlePublicProperties =
new RestOutputCmHandlePublicProperties();
restOutputCmHandlePublicProperties.setPublicCmHandleProperties(cmHandlePublicProperties);
@@ -319,13 +317,13 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
/**
* Get Cm Handle State by Cm Handle Id.
*
- * @param cmHandleId cm-handle identifier
+ * @param cmHandleReference cm-handle or alternate identifier
* @return cm handle state
*/
@Override
public ResponseEntity<RestOutputCmHandleCompositeState> getCmHandleStateByCmHandleId(
- final String cmHandleId) {
- final CompositeState cmHandleState = networkCmProxyDataService.getCmHandleCompositeState(cmHandleId);
+ final String cmHandleReference) {
+ final CompositeState cmHandleState = networkCmProxyInventoryFacade.getCmHandleCompositeState(cmHandleReference);
final RestOutputCmHandleCompositeState restOutputCmHandleCompositeState =
new RestOutputCmHandleCompositeState();
restOutputCmHandleCompositeState.setState(
@@ -336,21 +334,23 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
/**
* Return module definitions.
*
- * @param cmHandleId cm-handle identifier
- * @param moduleName module name
- * @param revision the revision of the module
+ * @param cmHandleReference cm handle or alternate id identifier
+ * @param moduleName module name
+ * @param revision the revision of the module
* @return list of module definitions (module name, revision, yang resource content)
*/
@Override
- public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleId,
+ public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleReference,
final String moduleName,
final String revision) {
final Collection<ModuleDefinition> moduleDefinitions;
if (StringUtils.hasText(moduleName)) {
moduleDefinitions =
- networkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, revision);
+ networkCmProxyInventoryFacade.getModuleDefinitionsByCmHandleAndModule(cmHandleReference,
+ moduleName, revision);
} else {
- moduleDefinitions = networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId);
+ moduleDefinitions =
+ networkCmProxyInventoryFacade.getModuleDefinitionsByCmHandleReference(cmHandleReference);
if (StringUtils.hasText(revision)) {
log.warn("Ignoring revision filter as no module name is provided");
}
@@ -365,12 +365,12 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
/**
* Return module references for a cm handle.
*
- * @param cmHandle the cm handle
+ * @param cmHandleReference cm handle or alternate id identifier
* @return module references for cm handle. Namespace will be always blank because restConf does not include this.
*/
- public ResponseEntity<List<RestModuleReference>> getModuleReferencesByCmHandle(final String cmHandle) {
+ public ResponseEntity<List<RestModuleReference>> getModuleReferencesByCmHandle(final String cmHandleReference) {
final List<RestModuleReference> restModuleReferences =
- networkCmProxyDataService.getYangResourcesModuleReferences(cmHandle).stream()
+ networkCmProxyInventoryFacade.getYangResourcesModuleReferences(cmHandleReference).stream()
.map(ncmpRestInputMapper::toRestModuleReference)
.collect(Collectors.toList());
return new ResponseEntity<>(restModuleReferences, HttpStatus.OK);
@@ -386,22 +386,20 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
@Override
public ResponseEntity<Object> setDataSyncEnabledFlagForCmHandle(final String cmHandleId,
final Boolean dataSyncEnabledFlag) {
- networkCmProxyDataService.setDataSyncEnabled(cmHandleId, dataSyncEnabledFlag);
+ networkCmProxyInventoryFacade.setDataSyncEnabled(cmHandleId, dataSyncEnabledFlag);
return new ResponseEntity<>(HttpStatus.OK);
}
-
private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) {
final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle();
final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties();
- final TrustLevel cmHandleCurrentTrustLevel = trustLevelPerCmHandle.get(ncmpServiceCmHandle.getCmHandleId());
restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleId());
cmHandlePublicProperties.add(ncmpServiceCmHandle.getPublicProperties());
restOutputCmHandle.setPublicCmHandleProperties(cmHandlePublicProperties);
restOutputCmHandle.setState(cmHandleStateMapper.toCmHandleCompositeStateExternalLockReason(
ncmpServiceCmHandle.getCompositeState()));
- if (cmHandleCurrentTrustLevel != null) {
- restOutputCmHandle.setTrustLevel(cmHandleCurrentTrustLevel.toString());
+ if (ncmpServiceCmHandle.getCurrentTrustLevel() != null) {
+ restOutputCmHandle.setTrustLevel(ncmpServiceCmHandle.getCurrentTrustLevel().toString());
}
restOutputCmHandle.setModuleSetTag(ncmpServiceCmHandle.getModuleSetTag());
restOutputCmHandle.setAlternateId(ncmpServiceCmHandle.getAlternateId());
@@ -417,13 +415,5 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
}
}
- private NcmpDatastoreRequestHandler getNcmpDatastoreRequestHandler(final String datastoreName) {
- if (OPERATIONAL.equals(DatastoreType.fromDatastoreName(datastoreName))) {
- return ncmpCachedResourceRequestHandler;
- }
- return ncmpPassthroughResourceRequestHandler;
- }
-
-
}
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
index 5467eeffca..8aa86ade36 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
@@ -27,16 +27,17 @@ import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status;
-import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse.Status;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse;
import org.onap.cps.ncmp.rest.api.NetworkCmProxyInventoryApi;
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse;
import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse;
import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration;
+import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -47,7 +48,7 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class NetworkCmProxyInventoryController implements NetworkCmProxyInventoryApi {
- private final NetworkCmProxyDataService networkCmProxyDataService;
+ private final NetworkCmProxyInventoryFacade networkCmProxyInventoryFacade;
private final NcmpRestInputMapper ncmpRestInputMapper;
@Override
@@ -55,8 +56,8 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor
final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = ncmpRestInputMapper
.toCmHandleQueryServiceParameters(cmHandleQueryParameters);
- final Collection<String> cmHandleIds = networkCmProxyDataService
- .executeCmHandleIdSearchForInventory(cmHandleQueryServiceParameters);
+ final Collection<String> cmHandleIds = networkCmProxyInventoryFacade
+ .executeParameterizedCmHandleIdSearch(cmHandleQueryServiceParameters);
return ResponseEntity.ok(List.copyOf(cmHandleIds));
}
@@ -69,7 +70,7 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor
@Override
public ResponseEntity<List<String>> getAllCmHandleIdsForRegisteredDmi(final String dmiPluginIdentifier) {
final Collection<String> cmHandleIds =
- networkCmProxyDataService.getAllCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifier);
+ networkCmProxyInventoryFacade.getAllCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifier);
return ResponseEntity.ok(List.copyOf(cmHandleIds));
}
@@ -84,7 +85,7 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor
public ResponseEntity updateDmiPluginRegistration(
final @Valid RestDmiPluginRegistration restDmiPluginRegistration) {
final DmiPluginRegistrationResponse dmiPluginRegistrationResponse =
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ networkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(
ncmpRestInputMapper.toDmiPluginRegistration(restDmiPluginRegistration));
final DmiPluginRegistrationErrorResponse failedRegistrationErrorResponse =
getFailureRegistrationResponse(dmiPluginRegistrationResponse);
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandler.java
index 7263000896..6910003c54 100755..100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandler.java
@@ -18,19 +18,21 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.exceptions;
+package org.onap.cps.ncmp.rest.controller;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException;
-import org.onap.cps.ncmp.api.impl.exception.DmiRequestException;
-import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException;
-import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException;
-import org.onap.cps.ncmp.api.impl.exception.NcmpException;
-import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException;
-import org.onap.cps.ncmp.rest.controller.NetworkCmProxyController;
-import org.onap.cps.ncmp.rest.controller.NetworkCmProxyInventoryController;
+import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException;
+import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException;
+import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException;
+import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException;
+import org.onap.cps.ncmp.api.exceptions.DmiRequestException;
+import org.onap.cps.ncmp.api.exceptions.InvalidTopicException;
+import org.onap.cps.ncmp.api.exceptions.NcmpException;
+import org.onap.cps.ncmp.api.exceptions.PayloadTooLargeException;
+import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException;
+import org.onap.cps.ncmp.api.exceptions.ServerNcmpException;
import org.onap.cps.ncmp.rest.model.DmiErrorMessage;
import org.onap.cps.ncmp.rest.model.DmiErrorMessageDmiResponse;
import org.onap.cps.ncmp.rest.model.ErrorMessage;
@@ -76,15 +78,15 @@ public class NetworkCmProxyRestExceptionHandler {
return wrapDmiErrorResponse(dmiClientRequestException);
}
- @ExceptionHandler({DmiRequestException.class, DataValidationException.class, OperationNotSupportedException.class,
- HttpMessageNotReadableException.class, InvalidTopicException.class, InvalidDatastoreException.class,
- InvalidDmiResourceUrlException.class})
+ @ExceptionHandler({DmiRequestException.class, DataValidationException.class, InvalidOperationException.class,
+ OperationNotSupportedException.class, HttpMessageNotReadableException.class, InvalidTopicException.class,
+ InvalidDatastoreException.class})
public static ResponseEntity<Object> handleDmiRequestExceptions(final Exception exception) {
return buildErrorResponse(HttpStatus.BAD_REQUEST, exception);
}
- @ExceptionHandler({AlreadyDefinedException.class})
- public static ResponseEntity<Object> handleAlreadyDefinedExceptions(final Exception exception) {
+ @ExceptionHandler({AlreadyDefinedException.class, PolicyExecutorException.class})
+ public static ResponseEntity<Object> handleConflictExceptions(final Exception exception) {
return buildErrorResponse(HttpStatus.CONFLICT, exception);
}
@@ -112,8 +114,6 @@ public class NetworkCmProxyRestExceptionHandler {
} else {
errorMessage.setDetails(CHECK_LOGS_FOR_DETAILS);
}
- errorMessage.setDetails(
- exception instanceof CpsException ? ((CpsException) exception).getDetails() : CHECK_LOGS_FOR_DETAILS);
return new ResponseEntity<>(errorMessage, status);
}
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java
deleted file mode 100644
index e6d6faf983..0000000000
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022-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.rest.controller.handlers;
-
-import java.util.function.Supplier;
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
-import org.onap.cps.ncmp.api.NetworkCmProxyQueryService;
-import org.onap.cps.ncmp.api.models.CmResourceAddress;
-import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor;
-import org.onap.cps.spi.FetchDescendantsOption;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
-
-@Component
-public class NcmpCachedResourceRequestHandler extends NcmpDatastoreRequestHandler {
-
- private final NetworkCmProxyDataService networkCmProxyDataService;
- private final NetworkCmProxyQueryService networkCmProxyQueryService;
-
- /**
- * Constructor.
- *
- * @param cpsNcmpTaskExecutor @see org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
- * @param networkCmProxyDataService @see org.onap.cps.ncmp.api.NetworkCmProxyDataService
- * @param networkCmProxyQueryService @see org.onap.cps.ncmp.api.NetworkCmProxyQueryService
- */
- public NcmpCachedResourceRequestHandler(final CpsNcmpTaskExecutor cpsNcmpTaskExecutor,
- final NetworkCmProxyDataService networkCmProxyDataService,
- final NetworkCmProxyQueryService networkCmProxyQueryService) {
- super(cpsNcmpTaskExecutor);
- this.networkCmProxyDataService = networkCmProxyDataService;
- this.networkCmProxyQueryService = networkCmProxyQueryService;
- }
-
- /**
- * Executes a synchronous query request for given cm handle.
- * Note. Currently only ncmp-datastore:operational supports query operations.
- *
- * @param cmHandleId the cm handle
- * @param resourceIdentifier the resource identifier
- * @param includeDescendants whether include descendants
- * @return the response entity
- */
- public ResponseEntity<Object> executeRequest(final String cmHandleId,
- final String resourceIdentifier,
- final boolean includeDescendants) {
-
- final Supplier<Object> taskSupplier = getTaskSupplierForQueryRequest(cmHandleId, resourceIdentifier,
- includeDescendants);
- return executeTaskSync(taskSupplier);
- }
-
- @Override
- protected Supplier<Object> getTaskSupplierForGetRequest(final CmResourceAddress cmResourceAddress,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final String requestId,
- final boolean includeDescendants,
- final String authorization) {
-
- final FetchDescendantsOption fetchDescendantsOption = getFetchDescendantsOption(includeDescendants);
-
- return () -> networkCmProxyDataService.getResourceDataForCmHandle(cmResourceAddress, fetchDescendantsOption);
- }
-
- private Supplier<Object> getTaskSupplierForQueryRequest(final String cmHandleId,
- final String resourceIdentifier,
- final boolean includeDescendants) {
-
- final FetchDescendantsOption fetchDescendantsOption = getFetchDescendantsOption(includeDescendants);
-
- return () -> networkCmProxyQueryService.queryResourceDataOperational(cmHandleId, resourceIdentifier,
- fetchDescendantsOption);
- }
-
- private static FetchDescendantsOption getFetchDescendantsOption(final boolean includeDescendants) {
- return includeDescendants ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
- : FetchDescendantsOption.OMIT_DESCENDANTS;
- }
-
-
-}
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java
deleted file mode 100644
index 1ae16820a1..0000000000
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022-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.rest.controller.handlers;
-
-import java.util.Map;
-import java.util.UUID;
-import java.util.function.Supplier;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.models.CmResourceAddress;
-import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor;
-import org.onap.cps.ncmp.rest.util.TopicValidator;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Service;
-
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public abstract class NcmpDatastoreRequestHandler {
-
- private static final String NO_REQUEST_ID = null;
- private static final String NO_TOPIC = null;
-
- @Value("${notification.async.executor.time-out-value-in-ms:60000}")
- protected int timeOutInMilliSeconds;
-
- @Value("${notification.enabled:true}")
- protected boolean notificationFeatureEnabled;
-
- protected final CpsNcmpTaskExecutor cpsNcmpTaskExecutor;
-
- /**
- * Executes synchronous/asynchronous get request for given cm handle.
- *
- * @param cmResourceAddress the name of the datastore, cm handle and resource identifier
- * @param optionsParamInQuery the options param in query
- * @param topicParamInQuery the topic param in query
- * @param includeDescendants whether include descendants
- * @param authorization contents of Authorization header, or null if not present
- * @return the response entity
- */
- public ResponseEntity<Object> executeRequest(final CmResourceAddress cmResourceAddress,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final boolean includeDescendants,
- final String authorization) {
-
- final boolean asyncResponseRequested = topicParamInQuery != null;
- if (asyncResponseRequested && notificationFeatureEnabled) {
- return executeAsyncTaskAndGetResponseEntity(cmResourceAddress, optionsParamInQuery, topicParamInQuery,
- includeDescendants, authorization);
- }
-
- if (asyncResponseRequested) {
- log.warn("Asynchronous request is unavailable as notification feature is currently disabled, "
- + "will use synchronous operation.");
- }
- final Supplier<Object> taskSupplier = getTaskSupplierForGetRequest(cmResourceAddress, optionsParamInQuery,
- NO_TOPIC, NO_REQUEST_ID, includeDescendants, authorization);
- return executeTaskSync(taskSupplier);
- }
-
-
- private ResponseEntity<Object> executeTaskAsync(final String topicParamInQuery,
- final String requestId,
- final Supplier<Object> taskSupplier) {
- TopicValidator.validateTopicName(topicParamInQuery);
- log.debug("Received Async request with id {}", requestId);
- cpsNcmpTaskExecutor.executeTask(taskSupplier, timeOutInMilliSeconds);
- return ResponseEntity.ok(Map.of("requestId", requestId));
- }
-
- protected ResponseEntity<Object> executeTaskSync(final Supplier<Object> taskSupplier) {
- return ResponseEntity.ok(taskSupplier.get());
- }
-
- private ResponseEntity<Object> executeAsyncTaskAndGetResponseEntity(final CmResourceAddress cmResourceAddress,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final boolean includeDescendants,
- final String authorization) {
- final String requestId = UUID.randomUUID().toString();
- final Supplier<Object> taskSupplier = getTaskSupplierForGetRequest(cmResourceAddress,
- optionsParamInQuery, topicParamInQuery, requestId, includeDescendants, authorization);
- return executeTaskAsync(topicParamInQuery, requestId, taskSupplier);
- }
-
- protected abstract Supplier<Object> getTaskSupplierForGetRequest(final CmResourceAddress cmResourceAddress,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final String requestId,
- final boolean includeDescendant,
- final String authorization);
-
-}
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java
deleted file mode 100644
index be5b93c47b..0000000000
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022-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.rest.controller.handlers;
-
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL;
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ;
-
-import java.util.Map;
-import java.util.UUID;
-import java.util.function.BiConsumer;
-import java.util.function.Supplier;
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
-import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
-import org.onap.cps.ncmp.api.impl.operations.OperationType;
-import org.onap.cps.ncmp.api.impl.utils.data.operation.ResourceDataOperationRequestUtils;
-import org.onap.cps.ncmp.api.models.CmResourceAddress;
-import org.onap.cps.ncmp.api.models.DataOperationRequest;
-import org.onap.cps.ncmp.rest.exceptions.OperationNotSupportedException;
-import org.onap.cps.ncmp.rest.exceptions.PayloadTooLargeException;
-import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor;
-import org.onap.cps.ncmp.rest.util.TopicValidator;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
-
-@Component
-public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestHandler {
-
- private final NetworkCmProxyDataService networkCmProxyDataService;
-
- private static final Object noReturn = null;
-
- private static final int MAXIMUM_CM_HANDLES_PER_OPERATION = 200;
-
- private static final String PAYLOAD_TOO_LARGE_TEMPLATE = "Operation '%s' affects too many (%d) cm handles";
-
- /**
- * Constructor.
- *
- * @param cpsNcmpTaskExecutor @see org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
- * @param networkCmProxyDataService @see org.onap.cps.ncmp.api.NetworkCmProxyDataService
- */
- public NcmpPassthroughResourceRequestHandler(final CpsNcmpTaskExecutor cpsNcmpTaskExecutor,
- final NetworkCmProxyDataService networkCmProxyDataService) {
- super(cpsNcmpTaskExecutor);
- this.networkCmProxyDataService = networkCmProxyDataService;
- }
-
- /**
- * Executes asynchronous request for group of cm handles to resource data.
- *
- * @param topicParamInQuery the topic param in query
- * @param dataOperationRequest data operation request details for resource data
- * @param authorization contents of Authorization header, or null if not present
- * @return the response entity
- */
- public ResponseEntity<Object> executeRequest(final String topicParamInQuery,
- final DataOperationRequest dataOperationRequest,
- final String authorization) {
- validateDataOperationRequest(topicParamInQuery, dataOperationRequest);
- if (!notificationFeatureEnabled) {
- return ResponseEntity.ok(Map.of("status",
- "Asynchronous request is unavailable as notification feature is currently disabled."));
- }
- return getRequestIdAndSendDataOperationRequestToDmiService(topicParamInQuery, dataOperationRequest,
- authorization);
- }
-
- @Override
- protected Supplier<Object> getTaskSupplierForGetRequest(final CmResourceAddress cmResourceAddress,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final String requestId,
- final boolean includeDescendants,
- final String authorization) {
-
- return () -> networkCmProxyDataService.getResourceDataForCmHandle(cmResourceAddress, optionsParamInQuery,
- topicParamInQuery, requestId, authorization);
- }
-
- private ResponseEntity<Object> getRequestIdAndSendDataOperationRequestToDmiService(
- final String topicParamInQuery,
- final DataOperationRequest dataOperationRequest,
- final String authorization) {
- final String requestId = UUID.randomUUID().toString();
- cpsNcmpTaskExecutor.executeTaskWithErrorHandling(
- getTaskSupplierForDataOperationRequest(topicParamInQuery, dataOperationRequest, requestId, authorization),
- getTaskCompletionHandlerForDataOperationRequest(topicParamInQuery, dataOperationRequest, requestId),
- timeOutInMilliSeconds);
- return ResponseEntity.ok(Map.of("requestId", requestId));
- }
-
- private void validateDataOperationRequest(final String topicParamInQuery,
- final DataOperationRequest dataOperationRequest) {
- TopicValidator.validateTopicName(topicParamInQuery);
- dataOperationRequest.getDataOperationDefinitions().forEach(dataOperationDetail -> {
- if (OperationType.fromOperationName(dataOperationDetail.getOperation()) != READ) {
- throw new OperationNotSupportedException(
- dataOperationDetail.getOperation() + " operation not yet supported");
- }
- if (DatastoreType.fromDatastoreName(dataOperationDetail.getDatastore()) == OPERATIONAL) {
- throw new InvalidDatastoreException(dataOperationDetail.getDatastore()
- + " datastore is not supported");
- }
- if (dataOperationDetail.getCmHandleIds().size() > MAXIMUM_CM_HANDLES_PER_OPERATION) {
- final String errorMessage = String.format(PAYLOAD_TOO_LARGE_TEMPLATE,
- dataOperationDetail.getOperationId(),
- dataOperationDetail.getCmHandleIds().size());
- throw new PayloadTooLargeException(errorMessage);
- }
- });
- }
-
- private Supplier<Object> getTaskSupplierForDataOperationRequest(final String topicParamInQuery,
- final DataOperationRequest dataOperationRequest,
- final String requestId,
- final String authorization) {
- return () -> {
- networkCmProxyDataService.executeDataOperationForCmHandles(topicParamInQuery,
- dataOperationRequest,
- requestId,
- authorization);
- return noReturn;
- };
- }
-
- private static BiConsumer<Object, Throwable> getTaskCompletionHandlerForDataOperationRequest(
- final String topicParamInQuery,
- final DataOperationRequest dataOperationRequest,
- final String requestId) {
- return (result, throwable) ->
- ResourceDataOperationRequestUtils.handleAsyncTaskCompletionForDataOperationsRequest(topicParamInQuery,
- requestId, dataOperationRequest, throwable);
- }
-
-}
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java
deleted file mode 100644
index 2601c7a5b3..0000000000
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutor.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022-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.rest.executor;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.function.BiConsumer;
-import java.util.function.Supplier;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-@Slf4j
-@Service
-public class CpsNcmpTaskExecutor {
-
- /**
- * Execute a task asynchronously, and invoke completion handler when done.
- *
- * @param taskSupplier functional method is get() task needed to be executed asynchronously
- * @param taskCompletionHandler the action to perform on task completion or error
- * @param timeOutInMillis the time-out value in milliseconds
- */
- public void executeTaskWithErrorHandling(final Supplier<Object> taskSupplier,
- final BiConsumer<Object, Throwable> taskCompletionHandler,
- final long timeOutInMillis) {
- CompletableFuture.supplyAsync(taskSupplier)
- .orTimeout(timeOutInMillis, MILLISECONDS)
- .whenCompleteAsync(taskCompletionHandler);
- }
-
- /**
- * Execute a task asynchronously.
- *
- * @param taskSupplier functional method is get() task needed to be executed asynchronously
- * @param timeOutInMillis the time-out value in milliseconds
- */
- public void executeTask(final Supplier<Object> taskSupplier, final long timeOutInMillis) {
- executeTaskWithErrorHandling(taskSupplier, (taskResult, throwable) -> handleTaskCompletion(throwable),
- timeOutInMillis);
- }
-
- private void handleTaskCompletion(final Throwable throwable) {
- if (throwable == null) {
- log.info("Async task completed successfully.");
- } else {
- log.error("Async task failed. caused by : {}", throwable.toString());
- }
- }
-}
-
-
-
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleStateMapper.java
index b436540fc2..4abcb72308 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/CmHandleStateMapper.java
@@ -18,16 +18,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.mapper;
+package org.onap.cps.ncmp.rest.util;
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.LOCKED_MISBEHAVING;
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.LOCKED_MISBEHAVING;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.NullValuePropertyMappingStrategy;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
import org.onap.cps.ncmp.rest.model.CmHandleCompositeState;
import org.onap.cps.ncmp.rest.model.DataStores;
import org.onap.cps.ncmp.rest.model.LockReason;
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/DataOperationRequestMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java
index 51ee8ca174..42622a2ca2 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/DataOperationRequestMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DataOperationRequestMapper.java
@@ -18,14 +18,14 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.mapper;
+package org.onap.cps.ncmp.rest.util;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.NullValuePropertyMappingStrategy;
-import org.onap.cps.ncmp.api.models.DataOperationDefinition;
-import org.onap.cps.ncmp.api.models.DataOperationRequest;
+import org.onap.cps.ncmp.api.data.models.DataOperationDefinition;
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest;
@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java
index 573491ca3f..7492c1fcac 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/DeprecationHelper.java
@@ -23,8 +23,8 @@ package org.onap.cps.ncmp.rest.util;
import java.util.ArrayList;
import java.util.Collections;
import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
-import org.onap.cps.ncmp.api.models.ConditionApiProperties;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters;
+import org.onap.cps.ncmp.api.inventory.models.ConditionApiProperties;
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Component;
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/NcmpRestInputMapper.java
index 045b8a7414..b9a814dce4 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/NcmpRestInputMapper.java
@@ -18,16 +18,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.controller;
+package org.onap.cps.ncmp.rest.util;
import org.mapstruct.InheritConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.NullValuePropertyMappingStrategy;
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters;
import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration;
import org.onap.cps.ncmp.rest.model.RestInputCmHandle;
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index 2d7e9b2d03..43403fa890 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -28,27 +28,25 @@ import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.read.ListAppender
import com.fasterxml.jackson.databind.ObjectMapper
+import groovy.json.JsonSlurper
import org.mapstruct.factory.Mappers
import org.onap.cps.TestUtils
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
-import org.onap.cps.ncmp.api.models.CmResourceAddress
-import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandler
-import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler
-import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
-import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper
-import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
+import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
import org.onap.cps.ncmp.rest.model.DataOperationDefinition
import org.onap.cps.ncmp.rest.model.DataOperationRequest
+import org.onap.cps.ncmp.rest.util.CmHandleStateMapper
+import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper
import org.onap.cps.ncmp.rest.util.DeprecationHelper
-import org.onap.cps.spi.FetchDescendantsOption
+import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.utils.JsonObjectMapper
@@ -59,7 +57,9 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
+import org.springframework.http.ResponseEntity
import org.springframework.test.web.servlet.MockMvc
+import reactor.core.publisher.Mono
import spock.lang.Shared
import spock.lang.Specification
@@ -67,17 +67,14 @@ import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE
+import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE
+import static org.onap.cps.ncmp.api.data.models.OperationType.PATCH
+import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE
+import static org.onap.cps.ncmp.api.inventory.models.CompositeState.DataStores
+import static org.onap.cps.ncmp.api.inventory.models.CompositeState.Operational
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
@@ -91,10 +88,13 @@ class NetworkCmProxyControllerSpec extends Specification {
MockMvc mvc
@SpringBean
- NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
+ NetworkCmProxyFacade mockNetworkCmProxyFacade = Mock()
@SpringBean
- NetworkCmProxyQueryService mockNetworkCmProxyQueryService = Mock()
+ NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
+
+ @SpringBean
+ AlternateIdMatcher mockAlternateIdMatcher = Mock()
@SpringBean
ObjectMapper objectMapper = new ObjectMapper()
@@ -112,20 +112,8 @@ class NetworkCmProxyControllerSpec extends Specification {
DataOperationRequestMapper dataOperationRequestMapper = Mappers.getMapper(DataOperationRequestMapper)
@SpringBean
- Map<String, TrustLevel> trustLevelPerCmHandle = [:]
-
- @SpringBean
- CpsNcmpTaskExecutor mockCpsTaskExecutor = Mock()
-
- @SpringBean
DeprecationHelper stubbedDeprecationHelper = Stub()
- @SpringBean
- NcmpCachedResourceRequestHandler ncmpCachedResourceRequestHandler = new NcmpCachedResourceRequestHandler(mockCpsTaskExecutor, mockNetworkCmProxyDataService, mockNetworkCmProxyQueryService)
-
- @SpringBean
- NcmpPassthroughResourceRequestHandler ncmpPassthroughResourceRequestHandler = new NcmpPassthroughResourceRequestHandler(mockCpsTaskExecutor, mockNetworkCmProxyDataService)
-
@Value('${rest.api.ncmp-base-path}/v1')
def ncmpBasePathV1
@@ -135,17 +123,12 @@ class NetworkCmProxyControllerSpec extends Specification {
@Shared
def NO_TOPIC = null
- def NO_REQUEST_ID = null
+ def NO_OPTIONS = null
def NO_AUTH_HEADER = null
- def TIMEOUT_FOR_TEST = 1234
def logger = Spy(ListAppender<ILoggingEvent>)
def setup() {
- ncmpCachedResourceRequestHandler.notificationFeatureEnabled = true
- ncmpCachedResourceRequestHandler.timeOutInMilliSeconds = TIMEOUT_FOR_TEST
- ncmpPassthroughResourceRequestHandler.notificationFeatureEnabled = true
- ncmpPassthroughResourceRequestHandler.timeOutInMilliSeconds = TIMEOUT_FOR_TEST
setupLogger()
}
@@ -156,12 +139,10 @@ class NetworkCmProxyControllerSpec extends Specification {
def 'Get Resource Data from pass-through operational.'() {
given: 'resource data url'
def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child&options=(a=1,b=2)"
- and: 'the expected cm resource address'
- def expectedCmResourceAddress = new CmResourceAddress(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'parent/child')
when: 'get data resource request is performed'
def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
then: 'the NCMP data service is called with correct parameters'
- 1 * mockNetworkCmProxyDataService.getResourceDataForCmHandle(expectedCmResourceAddress, '(a=1,b=2)', NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER)
+ 1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(_, '(a=1,b=2)', NO_TOPIC, false, NO_AUTH_HEADER) >> Mono.just(new ResponseEntity<Object>(HttpStatus.OK))
and: 'response status is Ok'
assert response.status == HttpStatus.OK.value()
}
@@ -170,21 +151,19 @@ class NetworkCmProxyControllerSpec extends Specification {
given: 'resource data url'
def getUrl = "$ncmpBasePathV1/ch/h123/data/ds/ncmp-datastore:operational?resourceIdentifier=parent/child${additionalUrlParam}"
and: 'the expected cm resource address'
- def expectedCmResourceAddress = new CmResourceAddress('ncmp-datastore:operational', 'h123', 'parent/child')
when: 'get data resource request is performed'
def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
then: 'the NCMP data service is called with correct parameters'
- 1 * mockNetworkCmProxyDataService.getResourceDataForCmHandle(expectedCmResourceAddress, expectedIncludeDescendants)
+ 1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(_, NO_OPTIONS, NO_TOPIC, expectedIncludeDescendants, NO_AUTH_HEADER)
and: 'response status is OK'
assert response.status == HttpStatus.OK.value()
where: 'the following parameters are used'
scenario | additionalUrlParam || expectedIncludeDescendants
- 'no additional param' | '' || OMIT_DESCENDANTS
- 'include descendants true' | '&include-descendants=true' || INCLUDE_ALL_DESCENDANTS
- 'include descendants TRUE' | '&include-descendants=true' || INCLUDE_ALL_DESCENDANTS
- 'include descendants false' | '&include-descendants=false' || OMIT_DESCENDANTS
- 'include descendants FALSE' | '&include-descendants=FALSE' || OMIT_DESCENDANTS
- 'options (ignored)' | '&options=(a-=1)' || OMIT_DESCENDANTS
+ 'no additional param' | '' || false
+ 'include descendants true' | '&include-descendants=true' || true
+ 'include descendants TRUE' | '&include-descendants=true' || true
+ 'include descendants false' | '&include-descendants=false' || false
+ 'include descendants FALSE' | '&include-descendants=FALSE' || false
}
def 'Execute (async) data operation to read data from dmi service.'() {
@@ -195,45 +174,19 @@ class NetworkCmProxyControllerSpec extends Specification {
def response = mvc.perform(post(getUrl).contentType(MediaType.APPLICATION_JSON).content(dataOperationRequestJsonData)).andReturn().response
then: 'response status is Ok'
assert response.status == HttpStatus.OK.value()
- and: 'async request id is generated'
- assert response.contentAsString.contains('requestId')
- then: 'the request is handled asynchronously'
- 1 * mockCpsTaskExecutor.executeTaskWithErrorHandling(*_)
+ then: 'the request for (async) data operation invoked once'
+ 1 * mockNetworkCmProxyFacade.executeDataOperationForCmHandles('my-topic-name', _, NO_AUTH_HEADER)
where: 'the following data stores are used'
datastore << [PASSTHROUGH_RUNNING, PASSTHROUGH_OPERATIONAL]
}
- def 'Execute (async) data operation with some validation error.'() {
- given: 'data operation url'
- def getUrl = "$ncmpBasePathV1/data?topic=my-topic-name"
- def dataOperationRequestJsonData = jsonObjectMapper.asJsonString(getDataOperationRequest('read', 'invalid datastore'))
- when: 'post data resource request is performed'
- def response = mvc.perform(post(getUrl).contentType(MediaType.APPLICATION_JSON).content(dataOperationRequestJsonData)).andReturn().response
- then: 'response status is BAD_REQUEST'
- assert response.status == HttpStatus.BAD_REQUEST.value()
- }
-
- def 'Get data operation resource data when notification feature is disabled for datastore: #datastore.'() {
- given: 'data operation url'
- def getUrl = "$ncmpBasePathV1/data?topic=my-topic-name"
- def dataOperationRequestJsonData = jsonObjectMapper.asJsonString(getDataOperationRequest("read", PASSTHROUGH_RUNNING.datastoreName))
- ncmpPassthroughResourceRequestHandler.notificationFeatureEnabled = false
- when: 'post data resource request is performed'
- def response = mvc.perform(post(getUrl).contentType(MediaType.APPLICATION_JSON).content(dataOperationRequestJsonData)
- ).andReturn().response
- then: 'response status is Ok'
- assert response.status == HttpStatus.OK.value()
- and: 'async request id is unavailable'
- assert response.contentAsString == '{"status":"Asynchronous request is unavailable as notification feature is currently disabled."}'
- }
-
def 'Query Resource Data from operational.'() {
given: 'the query resource data url'
- def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:operational/query?cps-path=/cps/path"
+ def getUrl = "$ncmpBasePathV1/ch/ch-1/data/ds/ncmp-datastore:operational/query?cps-path=/cps/path"
when: 'the query data resource request is performed'
def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
then: 'the NCMP query service is called with queryResourceDataOperationalForCmHandle'
- 1 * mockNetworkCmProxyQueryService.queryResourceDataOperational('testCmHandle','/cps/path',FetchDescendantsOption.OMIT_DESCENDANTS)
+ 1 * mockNetworkCmProxyFacade.queryResourceDataForCmHandle('ch-1','/cps/path', false)
and: 'response status is Ok'
assert response.status == HttpStatus.OK.value()
}
@@ -251,16 +204,17 @@ class NetworkCmProxyControllerSpec extends Specification {
def 'Get Resource Data from pass-through running with #scenario value in resource identifier param.'() {
given: 'resource data url'
- def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=$resourceIdentifier&options=(a=1,b=2)"
+ def getUrl = "$ncmpBasePathV1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=$resourceIdentifier&options=(a=1)"
and: 'ncmp service returns json object'
- def expectedCmResourceAddress = new CmResourceAddress(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', resourceIdentifier)
- mockNetworkCmProxyDataService.getResourceDataForCmHandle(expectedCmResourceAddress,'(a=1,b=2)', NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) >> '{valid-json}'
+ 1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(_, '(a=1)', NO_TOPIC, false, NO_AUTH_HEADER)
+ >> new ResponseEntity<Object>('{valid-json}', HttpStatus.OK)
when: 'get data resource request is performed'
def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
then: 'response status is Ok'
- response.status == HttpStatus.OK.value()
- and: 'response contains valid object body'
- response.getContentAsString() == '{valid-json}'
+ assert response.status == 200
+ and: 'response contains the object returned by the service'
+ def responseAsJsonObject = new JsonSlurper().parseText(response.getContentAsString())
+ assert responseAsJsonObject.body == '{valid-json}'
where: 'tokens are used in the resource identifier parameter'
scenario | resourceIdentifier
'/' | 'id/with/slashes'
@@ -277,7 +231,7 @@ class NetworkCmProxyControllerSpec extends Specification {
when: 'update data resource request is performed'
def response = mvc.perform(put(updateUrl).contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody)).andReturn().response
then: 'ncmp service method to update resource is called'
- 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle','parent/child', UPDATE, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
+ 1 * mockNetworkCmProxyFacade.writeResourceDataPassThroughRunningForCmHandle('testCmHandle','parent/child', UPDATE, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
and: 'the response status is OK'
assert response.status == HttpStatus.OK.value()
}
@@ -288,7 +242,7 @@ class NetworkCmProxyControllerSpec extends Specification {
when: 'create resource request is performed'
def response = mvc.perform(post(url).contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody)).andReturn().response
then: 'ncmp service method to create resource called'
- 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'parent/child', CREATE, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
+ 1 * mockNetworkCmProxyFacade.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'parent/child', CREATE, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
and: 'resource is created'
assert response.status == HttpStatus.CREATED.value()
}
@@ -299,7 +253,7 @@ class NetworkCmProxyControllerSpec extends Specification {
when: 'get module resource request is performed'
def response = mvc.perform(get(getUrl)).andReturn().response
then: 'ncmp service method to get yang resource module references is called'
- mockNetworkCmProxyDataService.getYangResourcesModuleReferences('some-cmhandle') >> [new ModuleReference(moduleName: 'some-name1', revision: '2021-10-03')]
+ mockNetworkCmProxyInventoryFacade.getYangResourcesModuleReferences('some-cmhandle') >> [new ModuleReference(moduleName: 'some-name1', revision: '2021-10-03')]
and: 'response contains an array with the module name and revision'
response.getContentAsString() == '[{"moduleName":"some-name1","revision":"2021-10-03"}]'
and: 'response returns an OK http code'
@@ -314,15 +268,14 @@ class NetworkCmProxyControllerSpec extends Specification {
def cmHandle1 = new NcmpServiceCmHandle()
cmHandle1.cmHandleId = 'ch-1'
cmHandle1.publicProperties = [color: 'yellow']
+ cmHandle1.currentTrustLevel = TrustLevel.NONE
def cmHandle2 = new NcmpServiceCmHandle()
cmHandle2.cmHandleId = 'ch-2'
cmHandle2.publicProperties = [color: 'green']
cmHandle2.alternateId = 'someAlternateId'
cmHandle2.moduleSetTag = 'someModuleSetTag'
cmHandle2.dataProducerIdentifier = 'someDataProducerIdentifier'
- mockNetworkCmProxyDataService.executeCmHandleSearch(_) >> [cmHandle1, cmHandle2]
- and: 'map for trust level per cmHandle has value for only one cm handle'
- trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE)
+ mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> [cmHandle1, cmHandle2]
when: 'the searches api is invoked'
def response = mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content(jsonString)).andReturn().response
then: 'response status returns OK'
@@ -331,19 +284,18 @@ class NetworkCmProxyControllerSpec extends Specification {
assert response.contentAsString == '[{"cmHandle":"ch-1","publicCmHandleProperties":[{"color":"yellow"}],"state":null,"trustLevel":"NONE","moduleSetTag":null,"alternateId":null,"dataProducerIdentifier":null},{"cmHandle":"ch-2","publicCmHandleProperties":[{"color":"green"}],"state":null,"trustLevel":null,"moduleSetTag":"someModuleSetTag","alternateId":"someAlternateId","dataProducerIdentifier":"someDataProducerIdentifier"}]'
}
- def 'Get complete Cm Handle details by Cm Handle id.'() {
- given: 'an endpoint and a cm handle'
- def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/some-cm-handle"
+ def 'Get complete Cm Handle details by Cm Handle Reference.'() {
+ given: 'an endpoint and a cm handle reference'
+ def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/some-cm-handle-reference"
and: 'an existing ncmp service cm handle'
def cmHandleId = 'some-cm-handle'
+ def alternateId = 'some-alternate-id'
def dmiProperties = [prop: 'some DMI property']
def publicProperties = ["public prop": 'some public property']
def compositeState = compositeStateTestObject()
- def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
- and: 'the service method is invoked with the cm handle id'
- 1 * mockNetworkCmProxyDataService.getNcmpServiceCmHandle('some-cm-handle') >> ncmpServiceCmHandle
- and: 'map for trust level per cmHandle has values'
- trustLevelPerCmHandle.get('some-cm-handle') >> { TrustLevel.COMPLETE }
+ def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: alternateId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState, currentTrustLevel: TrustLevel.COMPLETE)
+ and: 'the service method is invoked with the cm handle reference'
+ 1 * mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('some-cm-handle-reference') >> ncmpServiceCmHandle
when: 'the cm handle details api is invoked'
def response = mvc.perform(
get(cmHandleDetailsEndpoint)).andReturn().response
@@ -357,13 +309,13 @@ class NetworkCmProxyControllerSpec extends Specification {
assert !response.contentAsString.contains("some DMI property")
}
- def 'Get Cm Handle public properties by Cm Handle id.'() {
+ def 'Get Cm Handle public properties by Cm Handle Reference.'() {
given: 'a cm handle properties endpoint'
- def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle/properties"
+ def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle-reference/properties"
and: 'some cm handle public properties'
def publicProperties = ['public prop': 'some public property']
and: 'the service method is invoked with the cm handle id returning the cm handle public properties'
- 1 * mockNetworkCmProxyDataService.getCmHandlePublicProperties('some-cm-handle') >> publicProperties
+ 1 * mockNetworkCmProxyInventoryFacade.getCmHandlePublicProperties('some-cm-handle-reference') >> publicProperties
when: 'the cm handle properties api is invoked'
def response = mvc.perform(get(cmHandlePropertiesEndpoint)).andReturn().response
then: 'the correct response is returned'
@@ -372,13 +324,13 @@ class NetworkCmProxyControllerSpec extends Specification {
assertContainsPublicProperties(response)
}
- def 'Get Cm Handle composite state by Cm Handle id.'() {
+ def 'Get Cm Handle composite state by Cm Handle Reference.'() {
given: 'a cm handle state endpoint'
- def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle/state"
+ def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle-reference/state"
and: 'some cm handle composite state'
def compositeState = compositeStateTestObject()
and: 'the service method is invoked with the cm handle id returning the cm handle composite state'
- 1 * mockNetworkCmProxyDataService.getCmHandleCompositeState('some-cm-handle') >> compositeState
+ 1 * mockNetworkCmProxyInventoryFacade.getCmHandleCompositeState('some-cm-handle-reference') >> compositeState
when: 'the cm handle state api is invoked'
def response = mvc.perform(get(cmHandlePropertiesEndpoint)).andReturn().response
then: 'the correct response is returned'
@@ -392,16 +344,15 @@ class NetworkCmProxyControllerSpec extends Specification {
def searchesEndpoint = "$ncmpBasePathV1/ch/searches"
String jsonString = TestUtils.getResourceFileContent('invalid-cmhandle-search.json')
and: 'the service method is invoked with module names and returns two cm handles'
- def cmHandel1 = new NcmpServiceCmHandle()
- cmHandel1.cmHandleId = 'ch-1'
- cmHandel1.publicProperties = [color: 'yellow']
- def cmHandel2 = new NcmpServiceCmHandle()
- cmHandel2.cmHandleId = 'ch-2'
- cmHandel2.publicProperties = [color: 'green']
- mockNetworkCmProxyDataService.executeCmHandleSearch(_) >> [cmHandel1, cmHandel2]
- and: 'map for trust level per cmHandle has values'
- trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
- trustLevelPerCmHandle.put('ch-2', TrustLevel.NONE)
+ def cmHandle1 = new NcmpServiceCmHandle()
+ cmHandle1.cmHandleId = 'ch-1'
+ cmHandle1.publicProperties = [color: 'yellow']
+ cmHandle1.currentTrustLevel = TrustLevel.COMPLETE
+ def cmHandle2 = new NcmpServiceCmHandle()
+ cmHandle2.cmHandleId = 'ch-2'
+ cmHandle2.publicProperties = [color: 'green']
+ cmHandle2.currentTrustLevel = TrustLevel.NONE
+ mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> [cmHandle1, cmHandle2]
when: 'the searches api is invoked'
def response = mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content(jsonString)).andReturn().response
then: 'an empty cm handle identifier is returned'
@@ -412,7 +363,7 @@ class NetworkCmProxyControllerSpec extends Specification {
given: 'an endpoint and json data'
def searchesEndpoint = "$ncmpBasePathV1/ch/id-searches"
and: 'the service method is invoked with module names and returns cm handle ids'
- 1 * mockNetworkCmProxyDataService.executeCmHandleIdSearch(_) >> ['ch-1', 'ch-2']
+ 1 * mockNetworkCmProxyInventoryFacade.executeCmHandleIdSearch(_) >> ['ch-1', 'ch-2']
when: 'the searches api is invoked'
def response = mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content('{}')).andReturn().response
then: 'cm handle ids are returned'
@@ -434,7 +385,7 @@ class NetworkCmProxyControllerSpec extends Specification {
when: 'patch data resource request is performed'
def response = mvc.perform(patch(url).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).content(requestBody)).andReturn().response
then: 'ncmp service method to update resource is called'
- 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'parent/child', PATCH, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
+ 1 * mockNetworkCmProxyFacade.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'parent/child', PATCH, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
and: 'the response status is OK'
assert response.status == HttpStatus.OK.value()
}
@@ -445,29 +396,16 @@ class NetworkCmProxyControllerSpec extends Specification {
when: 'delete data resource request is performed'
def response = mvc.perform(delete(url).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andReturn().response
then: 'the ncmp service method to delete resource is called (with null as body)'
- 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'parent/child', DELETE, null, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
+ 1 * mockNetworkCmProxyFacade.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'parent/child', DELETE, null, 'application/json;charset=UTF-8', NO_AUTH_HEADER)
and: 'the response is No Content'
assert response.status == HttpStatus.NO_CONTENT.value()
}
- def 'Get resource data from DMI with valid topic i.e. async request for #scenario'() {
- given: 'resource data url'
- def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:${datastoreInUrl}?resourceIdentifier=parent/child&options=(a=1,b=2)&topic=my-topic-name"
- when: 'get data resource request is performed'
- def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON_VALUE)).andReturn().response
- then: 'async request id is generated'
- assert response.contentAsString.contains("requestId")
- where: 'the following parameters are used'
- scenario | datastoreInUrl
- ':passthrough-operational' | 'passthrough-operational'
- ':passthrough-running' | 'passthrough-running'
- }
-
def 'Getting module definitions for a module'() {
when: 'get module definition request is performed with module name'
def response = mvc.perform(get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=sampleModuleName")).andReturn().response
then: 'ncmp service method is invoked with correct parameters'
- mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', 'sampleModuleName', _)
+ mockNetworkCmProxyInventoryFacade.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', 'sampleModuleName', _)
>> [new ModuleDefinition('sampleModuleName', '2021-10-03','module sampleModuleName{ sample module content }')]
and: 'response contains an array with the module name, revision and content'
response.getContentAsString() == '[{"moduleName":"sampleModuleName","revision":"2021-10-03","content":"module sampleModuleName{ sample module content }"}]'
@@ -478,12 +416,12 @@ class NetworkCmProxyControllerSpec extends Specification {
def 'Getting module definitions filtering on #scenario'() {
when: 'get module definition request is performed'
def response = mvc.perform(
- get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=" + moduleName + "&revision=" + revision))
+ get("$ncmpBasePathV1/ch/some-cmhandle-reference/modules/definitions?module-name=" + moduleName + "&revision=" + revision))
.andReturn().response
- then: 'ncmp service method to get definitions by cm handle is invoked when needed'
- numberOfCallsToByCmHandleId * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle') >> []
+ then: 'ncmp service method to get definitions by cm handle reference is invoked when needed'
+ numberOfCallsToByCmHandleId * mockNetworkCmProxyInventoryFacade.getModuleDefinitionsByCmHandleReference('some-cmhandle-reference') >> []
and: 'ncmp service method to get definitions by module is invoked when needed'
- numberOfCallsToByModule * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', moduleName, revision) >> []
+ numberOfCallsToByModule * mockNetworkCmProxyInventoryFacade.getModuleDefinitionsByCmHandleAndModule('some-cmhandle-reference', moduleName, revision) >> []
and: 'response returns an OK http code'
response.status == HttpStatus.OK.value()
and: 'the correct message is logged when needed'
@@ -506,7 +444,7 @@ class NetworkCmProxyControllerSpec extends Specification {
put("$ncmpBasePathV1/ch/some-cm-handle-id/data-sync?dataSyncEnabled=" + dataSyncEnabledFlag))
.andReturn().response
then: 'method to set data sync enabled is called'
- 1 * mockNetworkCmProxyDataService.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
+ 1 * mockNetworkCmProxyInventoryFacade.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
and: 'the response returns an OK http code'
response.status == HttpStatus.OK.value()
where: 'the following parameters are used'
@@ -515,23 +453,6 @@ class NetworkCmProxyControllerSpec extends Specification {
'disabled' | false
}
- def 'Get Resource Data from operational with or without descendants'() {
- given: 'resource data url with descendants #enabled'
- def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:operational?resourceIdentifier=parent/child&include-descendants=${booleanValue}"
- and: 'the expected target'
- def expectedCmResourceAddress = new CmResourceAddress(OPERATIONAL.datastoreName, 'testCmHandle', 'parent/child')
- when: 'get data resource request is performed'
- def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
- then: 'the NCMP data service is called with getResourceDataOperational with #descendantsOption'
- 1 * mockNetworkCmProxyDataService.getResourceDataForCmHandle(expectedCmResourceAddress, descendantsOption)
- and: 'response status is Ok'
- assert response.status == HttpStatus.OK.value()
- where: 'the following parameters are used'
- booleanValue | descendantsOption
- false | OMIT_DESCENDANTS
- true | INCLUDE_ALL_DESCENDANTS
- }
-
def 'Attempt execute #operation rest operation on resource data with #scenario'() {
given: 'resource data url'
def url = "$ncmpBasePathV1/ch/testCmHandle/data/ds/${datastoreInUrl}?resourceIdentifier=parent/child"
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
index 7b850a7fff..97c68f08f3 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
@@ -23,15 +23,16 @@ package org.onap.cps.ncmp.rest.controller
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.TestUtils
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters
import org.onap.cps.ncmp.rest.model.CmHandlerRegistrationErrorResponse
import org.onap.cps.ncmp.rest.model.DmiPluginRegistrationErrorResponse
import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters
+import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
@@ -54,7 +55,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
MockMvc mvc
@SpringBean
- NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
+ NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
@SpringBean
NcmpRestInputMapper ncmpRestInputMapper = Mock()
@@ -83,7 +84,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
.content(jsonData)
).andReturn().response
then: 'the converted object is forwarded to the registration service'
- 1 * mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(mockDmiPluginRegistration) >> new DmiPluginRegistrationResponse()
+ 1 * mockNetworkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(mockDmiPluginRegistration) >> new DmiPluginRegistrationResponse()
and: 'response status is no content'
response.status == HttpStatus.OK.value()
where: 'the following registration json is used'
@@ -112,7 +113,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
and: 'the mapper service returns a converted object'
ncmpRestInputMapper.toCmHandleQueryServiceParameters(_) >> cmHandleQueryServiceParameters
and: 'the service returns the desired results'
- mockNetworkCmProxyDataService.executeCmHandleIdSearchForInventory(cmHandleQueryServiceParameters) >> serviceMockResponse
+ mockNetworkCmProxyInventoryFacade.executeParameterizedCmHandleIdSearch(cmHandleQueryServiceParameters) >> serviceMockResponse
when: 'post request is performed & search is called with the given request parameters'
def response = mvc.perform(
post("$ncmpBasePathV1/ch/searches")
@@ -135,7 +136,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
and: 'the mapper service returns a converted object'
ncmpRestInputMapper.toCmHandleQueryServiceParameters(_) >> cmHandleQueryServiceParameters
and: 'the service returns the desired results'
- mockNetworkCmProxyDataService.executeCmHandleIdSearchForInventory(cmHandleQueryServiceParameters) >> serviceMockResponse
+ mockNetworkCmProxyInventoryFacade.executeParameterizedCmHandleIdSearch(cmHandleQueryServiceParameters) >> serviceMockResponse
when: 'post request is performed & search is called with the given request parameters'
def response = mvc.perform(
post("$ncmpBasePathV1/ch/searches")
@@ -156,7 +157,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
given: 'the mapper service returns a converted object'
ncmpRestInputMapper.toCmHandleQueryServiceParameters(_) >> cmHandleQueryServiceParameters
and: 'the service returns the desired results'
- mockNetworkCmProxyDataService.executeCmHandleIdSearchForInventory(cmHandleQueryServiceParameters) >> []
+ mockNetworkCmProxyInventoryFacade.executeParameterizedCmHandleIdSearch(cmHandleQueryServiceParameters) >> []
when: 'post request is performed & search is called with the given request parameters'
def response = mvc.perform(
post("$ncmpBasePathV1/ch/searches")
@@ -180,7 +181,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
updatedCmHandles: [CmHandleRegistrationResponse.createSuccessResponse('cm-handle-2')],
removedCmHandles: [CmHandleRegistrationResponse.createSuccessResponse('cm-handle-3')]
)
- mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(*_) >> dmiRegistrationResponse
+ mockNetworkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(*_) >> dmiRegistrationResponse
when: 'registration endpoint is invoked'
def response = mvc.perform(
post("$ncmpBasePathV1/ch")
@@ -204,7 +205,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
removedCmHandles: [removeCmHandleResponse],
upgradedCmHandles: [upgradeCmHandleResponse]
)
- mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(*_) >> dmiRegistrationResponse
+ mockNetworkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(*_) >> dmiRegistrationResponse
when: 'registration endpoint is invoked'
def response = mvc.perform(
post("$ncmpBasePathV1/ch")
@@ -237,7 +238,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
given: 'an endpoint for returning cm handle IDs for a registered dmi plugin'
def getUrl = "$ncmpBasePathV1/ch/cmHandles?dmi-plugin-identifier=some-dmi-plugin-identifier"
and: 'a collection of cm handle IDs are returned'
- 1 * mockNetworkCmProxyDataService.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
+ 1 * mockNetworkCmProxyInventoryFacade.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
>> ['cm-handle-id-1','cm-handle-id-2']
when: 'the endpoint is invoked'
def response = mvc.perform(
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
index ea472cd931..9d36d106c7 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
@@ -19,34 +19,28 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.exceptions
-
-import static org.springframework.http.HttpStatus.BAD_GATEWAY
-import static org.springframework.http.HttpStatus.BAD_REQUEST
-import static org.springframework.http.HttpStatus.CONFLICT
-import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR
-import static org.springframework.http.HttpStatus.NOT_FOUND
-import static org.springframework.http.HttpStatus.PAYLOAD_TOO_LARGE
-import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMP
-import static org.onap.cps.ncmp.rest.exceptions.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMPINVENTORY
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
+package org.onap.cps.ncmp.rest.controller
import groovy.json.JsonSlurper
import org.mapstruct.factory.Mappers
import org.onap.cps.TestUtils
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.exception.DmiRequestException
-import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException
-import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException
-import org.onap.cps.ncmp.rest.controller.NcmpRestInputMapper
-import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandler
-import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler
-import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
-import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper
-import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper
+import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException
+import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException
+import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException
+import org.onap.cps.ncmp.api.exceptions.DmiRequestException
+import org.onap.cps.ncmp.api.exceptions.PayloadTooLargeException
+import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException
+import org.onap.cps.ncmp.api.exceptions.ServerNcmpException
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.data.NcmpCachedResourceRequestHandler
+import org.onap.cps.ncmp.impl.data.NcmpPassthroughResourceRequestHandler
+import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
+import org.onap.cps.ncmp.impl.data.policyexecutor.PolicyExecutor
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.rest.util.CmHandleStateMapper
+import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper
import org.onap.cps.ncmp.rest.util.DeprecationHelper
+import org.onap.cps.ncmp.rest.util.NcmpRestInputMapper
import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.exceptions.CpsException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
@@ -61,6 +55,18 @@ import org.springframework.test.web.servlet.MockMvc
import spock.lang.Shared
import spock.lang.Specification
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
+import static org.onap.cps.ncmp.rest.controller.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMP
+import static org.onap.cps.ncmp.rest.controller.NetworkCmProxyRestExceptionHandlerSpec.ApiType.NCMPINVENTORY
+import static org.springframework.http.HttpStatus.BAD_GATEWAY
+import static org.springframework.http.HttpStatus.BAD_REQUEST
+import static org.springframework.http.HttpStatus.CONFLICT
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR
+import static org.springframework.http.HttpStatus.NOT_FOUND
+import static org.springframework.http.HttpStatus.PAYLOAD_TOO_LARGE
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+
@WebMvcTest
class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
@@ -68,7 +74,13 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
MockMvc mvc
@SpringBean
- NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
+ NetworkCmProxyFacade mockNetworkCmProxyFacade = Mock()
+
+ @SpringBean
+ NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
+
+ @SpringBean
+ InventoryPersistence mockInventoryPersistence = Mock()
@SpringBean
JsonObjectMapper stubbedJsonObjectMapper = Stub()
@@ -83,9 +95,6 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
DataOperationRequestMapper dataOperationRequestMapper = Mappers.getMapper(DataOperationRequestMapper)
@SpringBean
- CpsNcmpTaskExecutor stubbedCpsTaskExecutor = Stub()
-
- @SpringBean
DeprecationHelper stubbedDeprecationHelper = Stub()
@SpringBean
@@ -113,23 +122,26 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
dataNodeBaseEndpointNcmpInventory = "$basePathNcmpInventory/v1"
}
- def 'Get request with #scenario exception returns correct HTTP Status with #scenario'() {
+ def 'Get request with #scenario exception returns correct HTTP Status with #scenario exception'() {
when: 'an exception is thrown by the service'
setupTestException(exception, NCMP)
def response = performTestRequest(NCMP)
then: 'an HTTP response is returned with correct message and details'
assertTestResponse(response, expectedErrorCode, expectedErrorMessage, expectedErrorDetails)
where:
- scenario | exception || expectedErrorCode | expectedErrorMessage | expectedErrorDetails
- 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | sampleErrorDetails
- 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
- 'NCMP-client' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || BAD_REQUEST | sampleErrorMessage | null
- 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | null
- 'other' | new IllegalStateException(sampleErrorMessage) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
- 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | 'DataNode not found'
- 'Existing entry' | new AlreadyDefinedException('name',null) || CONFLICT | 'Already defined exception' | 'name already exists'
- 'Existing entries' | AlreadyDefinedException.forDataNodes(['A', 'B'], 'myAnchorName') || CONFLICT | 'Already defined exception' | '2 data node(s) already exist'
- 'Operation too large' | new PayloadTooLargeException(sampleErrorMessage) || PAYLOAD_TOO_LARGE | sampleErrorMessage | 'Check logs'
+ scenario | exception || expectedErrorCode | expectedErrorMessage | expectedErrorDetails
+ 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | sampleErrorDetails
+ 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
+ 'DMI Request' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || BAD_REQUEST | sampleErrorMessage | null
+ 'Invalid Operation' | new InvalidOperationException('some reason') || BAD_REQUEST | 'some reason' | null
+ 'Unsupported Operation' | new OperationNotSupportedException('not yet') || BAD_REQUEST | 'not yet' | null
+ 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | null
+ 'other' | new IllegalStateException(sampleErrorMessage) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
+ 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | 'DataNode not found'
+ 'Existing entry' | new AlreadyDefinedException('name',null) || CONFLICT | 'Already defined exception' | 'name already exists'
+ 'Existing entries' | AlreadyDefinedException.forDataNodes(['A', 'B'], 'myAnchorName') || CONFLICT | 'Already defined exception' | '2 data node(s) already exist'
+ 'Operation too large' | new PayloadTooLargeException(sampleErrorMessage) || PAYLOAD_TOO_LARGE | sampleErrorMessage | 'Check logs'
+ 'Policy Executor' | new PolicyExecutorException(sampleErrorMessage, sampleErrorDetails) || CONFLICT | sampleErrorMessage | sampleErrorDetails
}
def 'Post request with exception returns correct HTTP Status.'() {
@@ -156,9 +168,9 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
def setupTestException(exception, apiType) {
if (NCMP == apiType) {
- mockNetworkCmProxyDataService.getYangResourcesModuleReferences(*_) >> { throw exception }
+ mockNetworkCmProxyInventoryFacade.getYangResourcesModuleReferences(*_) >> { throw exception }
}
- mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(*_) >> { throw exception }
+ mockNetworkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(*_) >> { throw exception }
}
def performTestRequest(apiType) {
@@ -177,8 +189,5 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
assert expectedErrorDetails == null || content['details'].toString().contains(expectedErrorDetails)
}
- enum ApiType {
- NCMP,
- NCMPINVENTORY;
- }
+ enum ApiType { NCMP, NCMPINVENTORY }
}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutorSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutorSpec.groovy
deleted file mode 100644
index 4c8c40f4e6..0000000000
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/executor/CpsNcmpTaskExecutorSpec.groovy
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * 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.
- * 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.rest.executor
-
-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 spock.lang.Specification
-import spock.util.concurrent.PollingConditions
-
-class CpsNcmpTaskExecutorSpec extends Specification {
-
- def objectUnderTest = new CpsNcmpTaskExecutor()
- def logger = Spy(ListAppender<ILoggingEvent>)
- def enoughTime = 100
- def notEnoughTime = 10
-
- void setup() {
- ((Logger) LoggerFactory.getLogger(CpsNcmpTaskExecutor.class)).addAppender(logger)
- logger.start()
- }
-
- void cleanup() {
- ((Logger) LoggerFactory.getLogger(CpsNcmpTaskExecutor.class)).detachAndStopAllAppenders()
- }
-
- def 'Execute successful task.'() {
- when: 'task is executed'
- objectUnderTest.executeTask(taskSupplier(), enoughTime)
- then: 'an event is logged with level INFO'
- new PollingConditions().within(1) {
- def loggingEvent = getLoggingEvent()
- assert loggingEvent.level == Level.INFO
- }
- and: 'the log indicates the task completed successfully'
- assert loggingEvent.formattedMessage == 'Async task completed successfully.'
- }
-
- def 'Execute failing task.'() {
- when: 'task is executed'
- objectUnderTest.executeTask(taskSupplierForFailingTask(), enoughTime)
- then: 'an event is logged with level ERROR'
- new PollingConditions().within(1) {
- def loggingEvent = getLoggingEvent()
- assert loggingEvent.level == Level.ERROR
- }
- and: 'the original error message is logged'
- assert loggingEvent.formattedMessage.contains('original exception message')
- }
-
- def 'Task times out.'() {
- when: 'task is executed without enough time to complete'
- objectUnderTest.executeTask(taskSupplierForLongRunningTask(), notEnoughTime)
- then: 'an event is logged with level ERROR'
- new PollingConditions().within(1) {
- def loggingEvent = getLoggingEvent()
- assert loggingEvent.level == Level.ERROR
- }
- and: 'a timeout error message is logged'
- assert loggingEvent.formattedMessage.contains('java.util.concurrent.TimeoutException')
- }
-
- def taskSupplier() {
- return () -> 'hello world'
- }
-
- def taskSupplierForFailingTask() {
- return () -> { throw new RuntimeException('original exception message') }
- }
-
- def taskSupplierForLongRunningTask() {
- return () -> { sleep(enoughTime) }
- }
-
- def getLoggingEvent() {
- return logger.list[0]
- }
-
-}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleStateMapperSpec.groovy
index b5f7f0edeb..24f45ad8a1 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/CmHandleStateMapperSpec.groovy
@@ -18,21 +18,22 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.mapper
-
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.LOCKED_MISBEHAVING
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_SYNC_FAILED
+package org.onap.cps.ncmp.rest.util
import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
import org.onap.cps.ncmp.rest.model.CmHandleCompositeState
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
import spock.lang.Specification
+
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.LOCKED_MISBEHAVING
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED
+
class CmHandleStateMapperSpec extends Specification {
def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy
index 8c212d3531..b63cd7a802 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/DeprecationHelperSpec.groovy
@@ -21,8 +21,8 @@
package org.onap.cps.ncmp.rest.util
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
-import org.onap.cps.ncmp.api.models.ConditionApiProperties
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters
+import org.onap.cps.ncmp.api.inventory.models.ConditionApiProperties
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters
import org.onap.cps.ncmp.rest.model.ConditionProperties
import org.onap.cps.ncmp.rest.model.ModuleNameAsJsonObject
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/NcmpRestInputMapperSpec.groovy
index b5f61adc58..3fd7e40345 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/NcmpRestInputMapperSpec.groovy
@@ -18,18 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.controller
+package org.onap.cps.ncmp.rest.util
import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters
import org.onap.cps.ncmp.rest.model.ConditionProperties
import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration
import org.onap.cps.ncmp.rest.model.RestInputCmHandle
import org.onap.cps.ncmp.rest.model.RestModuleDefinition
import org.onap.cps.ncmp.rest.model.RestModuleReference
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
import spock.lang.Specification
diff --git a/cps-ncmp-rest/src/test/resources/application.yml b/cps-ncmp-rest/src/test/resources/application.yml
index 9df1e580f6..aa5716716b 100644
--- a/cps-ncmp-rest/src/test/resources/application.yml
+++ b/cps-ncmp-rest/src/test/resources/application.yml
@@ -26,4 +26,4 @@ notification:
enabled: true
async:
executor:
- time-out-value-in-ms: 2000 \ No newline at end of file
+ time-out-value-in-ms: 2000
diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml
index 77e13dbae8..7871aafd6b 100644
--- a/cps-ncmp-service/pom.xml
+++ b/cps-ncmp-service/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -38,6 +38,22 @@
</properties>
<dependencies>
<dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-exporter-otlp</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-sdk-extension-jaeger-remote-sampler</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.opentelemetry.instrumentation</groupId>
+ <artifactId>opentelemetry-kafka-clients-2.6</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
@@ -58,6 +74,10 @@
<artifactId>cps-path-parser</artifactId>
</dependency>
<dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>annotations</artifactId>
+ </dependency>
+ <dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-spring</artifactId>
</dependency>
@@ -104,5 +124,13 @@
<artifactId>spock</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-actuator-autoconfigure</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
+ </dependency>
</dependencies>
</project>
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 bdc3dee772..8cfad7dbf6 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
@@ -26,14 +26,12 @@ import lombok.Getter;
public enum NcmpResponseStatus {
SUCCESS("0", "Successfully applied changes"),
- SUCCESSFULLY_APPLIED_SUBSCRIPTION("1", "successfully applied subscription"),
+ CM_DATA_SUBSCRIPTION_ACCEPTED("1", "ACCEPTED"),
CM_HANDLES_NOT_FOUND("100", "cm handle id(s) not found"),
CM_HANDLES_NOT_READY("101", "cm handle(s) not ready"),
DMI_SERVICE_NOT_RESPONDING("102", "dmi plugin service is not responding"),
UNABLE_TO_READ_RESOURCE_DATA("103", "dmi plugin service is not able to read resource data"),
- PARTIALLY_APPLIED_SUBSCRIPTION("104", "partially applied subscription"),
- SUBSCRIPTION_NOT_APPLICABLE("105", "subscription not applicable for all cm handles"),
- SUBSCRIPTION_PENDING("106", "subscription pending for all cm handles"),
+ CM_DATA_SUBSCRIPTION_REJECTED("104", "REJECTED"),
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"),
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
deleted file mode 100644
index 20545d711d..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021 highstreet technologies GmbH
- * Modifications Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2022 Bell Canada
- * ================================================================================
- * 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 java.util.Collection;
-import java.util.Map;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.operations.OperationType;
-import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
-import org.onap.cps.ncmp.api.models.CmResourceAddress;
-import org.onap.cps.ncmp.api.models.DataOperationRequest;
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
-import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
-import org.onap.cps.spi.FetchDescendantsOption;
-import org.onap.cps.spi.model.ModuleDefinition;
-import org.onap.cps.spi.model.ModuleReference;
-
-/*
- * Datastore interface for handling CPS data.
- */
-public interface NetworkCmProxyDataService {
-
- /**
- * Registration of New CM Handles.
- *
- * @param dmiPluginRegistration Dmi Plugin Registration
- * @return dmiPluginRegistrationResponse
- */
- DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(DmiPluginRegistration dmiPluginRegistration);
-
- /**
- * Get resource data for given data store using dmi.
- *
- * @param cmResourceAddress target datastore, cm handle and resource identifier
- * @param optionsParamInQuery options query
- * @param topicParamInQuery topic name for (triggering) async responses
- * @param requestId unique requestId for async request
- * @param authorization contents of Authorization header, or null if not present
- * @return {@code Object} resource data
- */
- Object getResourceDataForCmHandle(CmResourceAddress cmResourceAddress,
- String optionsParamInQuery,
- String topicParamInQuery,
- String requestId,
- String authorization);
-
- /**
- * Get resource data for operational.
- *
- * @param cmResourceAddress target datastore, cm handle and resource identifier
- * @Link FetchDescendantsOption fetch descendants option
- * @return {@code Object} resource data
- */
- Object getResourceDataForCmHandle(CmResourceAddress cmResourceAddress,
- FetchDescendantsOption fetchDescendantsOption);
-
- /**
- * Execute (async) data operation for group of cm handles using dmi.
- *
- * @param topicParamInQuery topic name for (triggering) async responses
- * @param dataOperationRequest contains a list of operation definitions(multiple operations)
- * @param requestId request ID
- * @param authorization contents of Authorization header, or null if not present
- */
- void executeDataOperationForCmHandles(String topicParamInQuery,
- DataOperationRequest dataOperationRequest,
- String requestId,
- String authorization);
-
-
- /**
- * Write resource data for data store pass-through running using dmi for given cm-handle.
- *
- * @param cmHandleId cm handle identifier
- * @param resourceIdentifier resource identifier
- * @param operationType required operation type
- * @param requestBody request body to create resource
- * @param contentType content type in body
- * @param authorization contents of Authorization header, or null if not present
- * @return {@code Object} return data
- */
- Object writeResourceDataPassThroughRunningForCmHandle(String cmHandleId,
- String resourceIdentifier,
- OperationType operationType,
- String requestBody,
- String contentType,
- String authorization);
-
- /**
- * Retrieve module references for the given cm handle.
- *
- * @param cmHandleId cm handle identifier
- * @return a collection of modules names and revisions
- */
- Collection<ModuleReference> getYangResourcesModuleReferences(String cmHandleId);
-
- /**
- * Retrieve module definitions for the given cm handle.
- *
- * @param cmHandleId cm handle identifier
- * @return a collection of module definition (moduleName, revision and yang resource content)
- */
- Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(String cmHandleId);
-
- /**
- * Get module definitions for the given parameters.
- *
- * @param cmHandleId cm-handle identifier
- * @param moduleName module name
- * @param moduleRevision the revision of the module
- * @return list of module definitions (module name, revision, yang resource content)
- */
- Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(String cmHandleId,
- String moduleName,
- String moduleRevision);
-
- /**
- * Query cm handle details by cm handle's name.
- *
- * @param cmHandleId cm handle identifier
- * @return a collection of cm handle details.
- */
- NcmpServiceCmHandle getNcmpServiceCmHandle(String cmHandleId);
-
- /**
- * Get cm handle public properties by cm handle id.
- *
- * @param cmHandleId cm handle identifier
- * @return a collection of cm handle public properties.
- */
- Map<String, String> getCmHandlePublicProperties(String cmHandleId);
-
- /**
- * Get cm handle composite state by cm handle id.
- *
- * @param cmHandleId cm handle identifier
- * @return a cm handle composite state
- */
- CompositeState getCmHandleCompositeState(String cmHandleId);
-
- /**
- * Query and return cm handles that match the given query parameters.
- *
- * @param cmHandleQueryApiParameters the cm handle query parameters
- * @return collection of cm handles
- */
- Collection<NcmpServiceCmHandle> executeCmHandleSearch(CmHandleQueryApiParameters cmHandleQueryApiParameters);
-
- /**
- * Query and return cm handle ids that match the given query parameters.
- *
- * @param cmHandleQueryApiParameters the cm handle query parameters
- * @return collection of cm handle ids
- */
- Collection<String> executeCmHandleIdSearch(CmHandleQueryApiParameters cmHandleQueryApiParameters);
-
- /**
- * Set the data sync enabled flag, along with the data sync state to true or false based on the cm handle id.
- *
- * @param cmHandleId cm handle id
- * @param dataSyncEnabled data sync enabled flag
- */
- void setDataSyncEnabled(String cmHandleId, Boolean dataSyncEnabled);
-
- /**
- * Get all cm handle IDs by DMI plugin identifier.
- *
- * @param dmiPluginIdentifier DMI plugin identifier
- * @return collection of cm handle IDs
- */
- Collection<String> getAllCmHandleIdsByDmiPluginIdentifier(String dmiPluginIdentifier);
-
- /**
- * Get all cm handle IDs by various search criteria.
- *
- * @param cmHandleQueryServiceParameters cm handle query parameters
- * @return collection of cm handle IDs
- */
- Collection<String> executeCmHandleIdSearchForInventory(CmHandleQueryServiceParameters
- cmHandleQueryServiceParameters);
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDatastoreException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidDatastoreException.java
index 6cfa159b20..740785e3be 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDatastoreException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidDatastoreException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.api.data.exceptions;
public class InvalidDatastoreException extends RuntimeException {
/**
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidOperationException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidOperationException.java
index 17069098cb..7669dd05f6 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidOperationException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/InvalidOperationException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.api.data.exceptions;
public class InvalidOperationException extends RuntimeException {
/**
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/OperationNotSupportedException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/OperationNotSupportedException.java
index e1daf3df6f..eea846a0f6 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/OperationNotSupportedException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/exceptions/OperationNotSupportedException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.exceptions;
+package org.onap.cps.ncmp.api.data.exceptions;
public class OperationNotSupportedException extends RuntimeException {
/**
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java
new file mode 100644
index 0000000000..98a343b92e
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java
@@ -0,0 +1,41 @@
+/*
+ * ============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.data.models;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.config.CpsApplicationContext;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
+
+@Getter
+@RequiredArgsConstructor
+public class CmResourceAddress {
+
+ private final String datastoreName;
+ @Getter(AccessLevel.NONE)
+ private final String cmHandleReference;
+ private final String resourceIdentifier;
+
+ public String getResolvedCmHandleId() {
+ return CpsApplicationContext.getCpsBean(AlternateIdMatcher.class).getCmHandleId(cmHandleReference);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationDefinition.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java
index 366d845832..d1ff1a5815 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationDefinition.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationDefinition.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.data.models;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationRequest.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationRequest.java
index a4d070c38d..b104f587fb 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DataOperationRequest.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DataOperationRequest.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.data.models;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DatastoreType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DatastoreType.java
index 6520c05c08..a483341b65 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DatastoreType.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/DatastoreType.java
@@ -18,14 +18,14 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.api.data.models;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
-import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException;
+import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException;
@Getter
public enum DatastoreType {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/OperationType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/OperationType.java
index fa00d1a15e..870e24fac4 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/OperationType.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/OperationType.java
@@ -18,14 +18,12 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.api.data.models;
import com.fasterxml.jackson.annotation.JsonValue;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Locale;
import lombok.Getter;
-import org.onap.cps.ncmp.api.impl.exception.InvalidOperationException;
+import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException;
@Getter
public enum OperationType {
@@ -48,13 +46,6 @@ public enum OperationType {
return String.valueOf(operationName);
}
- private static final Map<String, OperationType> operationNameToOperationEnum = new HashMap<>();
-
- static {
- Arrays.stream(OperationType.values()).forEach(
- operationType -> operationNameToOperationEnum.put(operationType.getOperationName(), operationType));
- }
-
/**
* From operation name get operation enum type.
*
@@ -62,10 +53,10 @@ public enum OperationType {
* @return the operation enum type
*/
public static OperationType fromOperationName(final String operationName) {
- final OperationType operationType = operationNameToOperationEnum.get(operationName);
- if (null == operationType) {
+ try {
+ return OperationType.valueOf(operationName.toUpperCase(Locale.ENGLISH));
+ } catch (final IllegalArgumentException e) {
throw new InvalidOperationException(operationName + " is an invalid operation name");
}
- return operationType;
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobResultService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobResultService.java
new file mode 100644
index 0000000000..c6b7a8bd04
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobResultService.java
@@ -0,0 +1,45 @@
+/*
+ * ============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.datajobs;
+
+/**
+ * Service interface to retrieve the result of a data job.
+ * The operations interact with a DMI Plugin to retrieve data job results.
+ */
+public interface DataJobResultService {
+
+ /**
+ * Retrieves the result of a specific data job.
+ *
+ * @param authorization The authorization header from the REST request.
+ * @param dmiServiceName The name of the DMI Service relevant to the data job.
+ * @param dataProducerId The ID of the producer registered by DMI, used for operations related to this request.
+ * This could include alternate IDs or specific identifiers.
+ * @param dataProducerJobId The identifier of the data producer job within the DMI system.
+ * @param destination The destination of the results: Kafka topic name or S3 bucket name.
+ * @return The result of the data job.
+ */
+ String getDataJobResult(final String authorization,
+ final String dmiServiceName,
+ final String dataProducerId,
+ final String dataProducerJobId,
+ final String destination);
+}
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/datajobs/DataJobService.java
index 6122afc808..255b3847eb 100644
--- 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/datajobs/DataJobService.java
@@ -18,29 +18,40 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api;
+package org.onap.cps.ncmp.api.datajobs;
-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;
+import java.util.List;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobReadRequest;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest;
+import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse;
public interface DataJobService {
/**
* process read data job operations.
*
- * @param dataJobId Unique identifier of the job within the request
+ * @param authorization the authorization header from the REST request
+ * @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);
+ void readDataJob(String authorization,
+ String dataJobId,
+ DataJobMetadata dataJobMetadata,
+ DataJobReadRequest dataJobReadRequest);
/**
* process write data job operations.
*
- * @param dataJobId Unique identifier of the job within the request
+ * @param authorization the authorization header from the REST request
+ * @param dataJobId unique identifier of the job within the request
* @param dataJobMetadata data job request headers
* @param dataJobWriteRequest write data job request
+ * @return a list of sub-job write responses
*/
- void writeDataJob(String dataJobId, DataJobMetadata dataJobMetadata, DataJobWriteRequest dataJobWriteRequest);
+ List<SubJobWriteResponse> writeDataJob(String authorization,
+ 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/datajobs/DataJobStatusService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobStatusService.java
new file mode 100644
index 0000000000..9cfc49f1d4
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/DataJobStatusService.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.datajobs;
+
+/**
+ * Service interface to check the status of a data job.
+ * The operations interact with a DMI Plugin to retrieve data job statuses.
+ */
+public interface DataJobStatusService {
+
+ /**
+ * Retrieves the current status of a specific data job.
+ *
+ * @param authorization The authorization header from the REST request.
+ * @param dmiServiceName The name of the DMI Service relevant to the data job.
+ * @param dataProducerId The ID of the producer registered by DMI, used for operations related to this request.
+ * This could include alternate IDs or specific identifiers.
+ * @param dataProducerJobId The identifier of the data producer job within the DMI system.
+ * @return The current status of the data job as a String.
+ */
+ String getDataJobStatus(final String authorization,
+ final String dmiServiceName,
+ final String dataProducerId,
+ final String dataProducerJobId);
+}
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/datajobs/models/DataJobMetadata.java
index dc8037b86f..564352d8db 100644
--- 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/datajobs/models/DataJobMetadata.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models.datajob;
+package org.onap.cps.ncmp.api.datajobs.models;
/**
* Metadata of read/write data job request.
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/datajobs/models/DataJobReadRequest.java
index f861c3d498..19408b1da1 100644
--- 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/datajobs/models/DataJobReadRequest.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models.datajob;
+package org.onap.cps.ncmp.api.datajobs.models;
import java.util.List;
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/datajobs/models/DataJobWriteRequest.java
index 254e198b81..d8961b17c0 100644
--- 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/datajobs/models/DataJobWriteRequest.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models.datajob;
+package org.onap.cps.ncmp.api.datajobs.models;
import java.util.List;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DmiWriteOperation.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DmiWriteOperation.java
new file mode 100644
index 0000000000..7e9ca7988b
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/DmiWriteOperation.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.datajobs.models;
+
+import java.util.Map;
+
+/**
+ * Describes the write data job operation to be forwarded to dmi.
+ *
+ * @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 moduleSetTag The module set tag of the CM Handle.
+ * @param value The value to be written depends on the type of operation.
+ * @param operationId Unique identifier of the operation within the request.
+ * @param privateProperties Contains the private properties of a Cm Handle.
+ */
+public record DmiWriteOperation(
+ String path,
+ String op,
+ String moduleSetTag,
+ Object value,
+ String operationId,
+ Map<String, String> privateProperties) {}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ProducerKey.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ProducerKey.java
new file mode 100644
index 0000000000..ac6b7f8622
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/ProducerKey.java
@@ -0,0 +1,36 @@
+/*
+ * ============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.datajobs.models;
+
+/**
+ * Composite key created from the DMI Service name and a data producer identifier.
+ * Helps to group of the sub job request for a given DMI Plugin.
+ *
+ * @param dmiServiceName Describes the name of the relevant DMI service.
+ * @param dataProducerIdentifier The name of a data producer identifier from a Cm Handle.
+ */
+public record ProducerKey(String dmiServiceName, String dataProducerIdentifier) {
+
+ @Override
+ public String toString() {
+ return dmiServiceName + "#" + dataProducerIdentifier;
+ }
+} \ No newline at end of file
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/datajobs/models/ReadOperation.java
index d2b0738969..2459e4cc2e 100644
--- 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/datajobs/models/ReadOperation.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models.datajob;
+package org.onap.cps.ncmp.api.datajobs.models;
import java.util.List;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/SubJobWriteRequest.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/SubJobWriteRequest.java
new file mode 100644
index 0000000000..a7a6573279
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/SubJobWriteRequest.java
@@ -0,0 +1,44 @@
+/*
+ * ============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.datajobs.models;
+
+import java.util.Collection;
+
+/**
+ * Request data for a write operation by the DMI Plugin.
+ *
+ * @param destination The destination of the results. ( e.g. S3 Bucket)
+ * @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.
+ * @param dataProducerId Identifier of the data producer.
+ * @param dataJobId Identifier for the overall Datajob
+ * @param data A collection of outgoing write operations.
+ */
+public record SubJobWriteRequest (
+ String destination,
+ String dataAcceptType,
+ String dataContentType,
+ String dataProducerId,
+ String dataJobId,
+ Collection<DmiWriteOperation> data) {} \ No newline at end of file
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmResourceAddress.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/SubJobWriteResponse.java
index 21d82fcf56..9cdd8e0590 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmResourceAddress.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/datajobs/models/SubJobWriteResponse.java
@@ -1,12 +1,12 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2024 Nordix Foundation
+ * 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
+ * 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,
@@ -18,8 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.datajobs.models;
-public record CmResourceAddress(String datastoreName, String cmHandleId, String resourceIdentifier) {
-
-}
+/**
+ * Request data for a write operation towards DMI Plugin.
+ *
+ * @param subJobId Identifier of the sub-job from DMI.
+ * @param dmiServiceName The provided name of the DMI service from the request.
+ * @param dataProducerId Identifier of the data producer.
+ */
+public record SubJobWriteResponse(String subJobId, String dmiServiceName, String dataProducerId) {} \ No newline at end of file
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/datajobs/models/WriteOperation.java
index c2f6504ce2..807e03f06f 100644
--- 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/datajobs/models/WriteOperation.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models.datajob;
+package org.onap.cps.ncmp.api.datajobs.models;
/**
* Holds information of write data job operation.
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiClientRequestException.java
index ab0fa68938..65ccba8018 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiClientRequestException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.api.exceptions;
import lombok.Getter;
import org.onap.cps.ncmp.api.NcmpResponseStatus;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiRequestException.java
index d41ca70bca..b2cfbc01be 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiRequestException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiRequestException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.api.exceptions;
/**
* Client Based Network CM Proxy exception.
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/InvalidTopicException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/InvalidTopicException.java
index 6a52d5861e..07b186dae4 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/InvalidTopicException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/InvalidTopicException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.exceptions;
+package org.onap.cps.ncmp.api.exceptions;
import lombok.Getter;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java
index 2c75b5d992..6754965866 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.api.exceptions;
import lombok.Getter;
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/PayloadTooLargeException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PayloadTooLargeException.java
index cddbd08379..edb295dbbf 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/PayloadTooLargeException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PayloadTooLargeException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.exceptions;
+package org.onap.cps.ncmp.api.exceptions;
public class PayloadTooLargeException extends RuntimeException {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java
index 270988b63b..333c12271b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java
@@ -18,20 +18,25 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.api.exceptions;
import lombok.Getter;
+/**
+ * Exception to be used when policy execution fails or does not allow to proceed.
+ */
@Getter
-public class InvalidDmiResourceUrlException extends RuntimeException {
-
- private static final long serialVersionUID = 2928476384584894968L;
+public class PolicyExecutorException extends NcmpException {
- private static final String INVALID_DMI_URL = "Invalid dmi resource url";
- final Integer httpStatus;
+ private static final long serialVersionUID = 6659897770659834798L;
- public InvalidDmiResourceUrlException(final String details, final Integer httpStatus) {
- super(String.format(INVALID_DMI_URL + ": %s", details));
- this.httpStatus = httpStatus;
+ /**
+ * Constructor to form exception for policy executor responses.
+ *
+ * @param message response message
+ * @param details response details
+ */
+ public PolicyExecutorException(final String message, final String details) {
+ super(message, details);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/ServerNcmpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/ServerNcmpException.java
index a03a2d3e6c..03dc3bc8dd 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/ServerNcmpException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/ServerNcmpException.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.api.exceptions;
/**
* Server Based Network CM Proxy exception.
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
deleted file mode 100644
index b4377b84f2..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/DataJobServiceImpl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * ============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/client/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
deleted file mode 100644
index 97ae677c5e..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2022 Bell Canada
- * ================================================================================
- * 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.client;
-
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING;
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA;
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR;
-import static org.springframework.http.HttpStatus.BAD_REQUEST;
-import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Locale;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
-import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException;
-import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException;
-import org.onap.cps.ncmp.api.impl.operations.OperationType;
-import org.onap.cps.utils.JsonObjectMapper;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.HttpServerErrorException;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.WebClient;
-import org.springframework.web.reactive.function.client.WebClientResponseException;
-
-@Component
-@RequiredArgsConstructor
-@Slf4j
-public class DmiRestClient {
-
- private static final String HEALTH_CHECK_URL_EXTENSION = "/actuator/health";
- private static final String NOT_SPECIFIED = "";
- private static final String NO_AUTHORIZATION = null;
- private final WebClient webClient;
- private final DmiProperties dmiProperties;
- private final JsonObjectMapper jsonObjectMapper;
-
- /**
- * Sends POST operation to DMI with json body containing module references.
- *
- * @param dmiResourceUrl dmi resource url
- * @param requestBodyAsJsonString json data body
- * @param operationType the type of operation being executed (for error reporting only)
- * @param authorization contents of Authorization header, or null if not present
- * @return response entity of type String
- */
- public ResponseEntity<Object> postOperationWithJsonData(final String dmiResourceUrl,
- final String requestBodyAsJsonString,
- final OperationType operationType,
- final String authorization) {
- try {
- return ResponseEntity.ok(webClient.post().uri(toUri(dmiResourceUrl))
- .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization))
- .body(BodyInserters.fromValue(requestBodyAsJsonString))
- .retrieve()
- .bodyToMono(Object.class)
- .onErrorMap(httpError -> handleDmiClientException(httpError, operationType.getOperationName()))
- .block());
- } catch (final HttpServerErrorException e) {
- throw handleDmiClientException(e, operationType.getOperationName());
- }
- }
-
- /**
- * Get DMI plugin health status.
- *
- * @param dmiPluginBaseUrl the base URL of the dmi-plugin
- * @return plugin health status ("UP" is all OK, "" (not-specified) in case of any exception)
- */
- public String getDmiHealthStatus(final String dmiPluginBaseUrl) {
- try {
- final JsonNode responseHealthStatus = webClient.get()
- .uri(toUri(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION))
- .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
- .retrieve()
- .bodyToMono(JsonNode.class).block();
- return responseHealthStatus == null ? NOT_SPECIFIED :
- responseHealthStatus.get("status").asText();
- } catch (final Exception e) {
- log.warn("Failed to retrieve health status from {}. Error Message: {}", dmiPluginBaseUrl, e.getMessage());
- return NOT_SPECIFIED;
- }
- }
-
- private HttpHeaders configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) {
- if (dmiProperties.isDmiBasicAuthEnabled()) {
- httpHeaders.setBasicAuth(dmiProperties.getAuthUsername(), dmiProperties.getAuthPassword());
- } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) {
- httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization);
- }
- return httpHeaders;
- }
-
- private static URI toUri(final String dmiResourceUrl) {
- try {
- return new URI(dmiResourceUrl);
- } catch (final URISyntaxException e) {
- throw new InvalidDmiResourceUrlException(dmiResourceUrl, BAD_REQUEST.value());
- }
- }
-
- private DmiClientRequestException handleDmiClientException(final Throwable e, final String operationType) {
- final String exceptionMessage = "Unable to " + operationType + " resource data.";
- if (e instanceof WebClientResponseException wcre) {
- if (wcre.getStatusCode().isSameCodeAs(HttpStatus.REQUEST_TIMEOUT)) {
- throw new DmiClientRequestException(wcre.getStatusCode().value(), wcre.getMessage(),
- jsonObjectMapper.asJsonString(wcre.getResponseBodyAsString()), DMI_SERVICE_NOT_RESPONDING);
- }
- throw new DmiClientRequestException(wcre.getStatusCode().value(), wcre.getMessage(),
- jsonObjectMapper.asJsonString(wcre.getResponseBodyAsString()), UNABLE_TO_READ_RESOURCE_DATA);
-
- }
- if (e instanceof HttpServerErrorException httpServerErrorException) {
- throw new DmiClientRequestException(httpServerErrorException.getStatusCode().value(), exceptionMessage,
- httpServerErrorException.getResponseBodyAsString(), DMI_SERVICE_NOT_RESPONDING);
- }
- throw new DmiClientRequestException(INTERNAL_SERVER_ERROR.value(), exceptionMessage, e.getMessage(),
- UNKNOWN_ERROR);
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java
deleted file mode 100644
index 21271665fd..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * ============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.config;
-
-import io.netty.channel.ChannelOption;
-import io.netty.handler.timeout.ReadTimeoutHandler;
-import io.netty.handler.timeout.WriteTimeoutHandler;
-import java.util.concurrent.TimeUnit;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.client.reactive.ReactorClientHttpConnector;
-import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.netty.http.client.HttpClient;
-import reactor.netty.resources.ConnectionProvider;
-
-@Configuration
-@RequiredArgsConstructor
-public class DmiWebClientConfiguration {
-
- @Value("${ncmp.dmi.httpclient.connectionTimeoutInSeconds:20000}")
- private Integer connectionTimeoutInSeconds;
-
- @Value("${ncmp.dmi.httpclient.maximumInMemorySizeInMegabytes:1}")
- private Integer maximumInMemorySizeInMegabytes;
-
- @Value("${ncmp.dmi.httpclient.maximumConnectionsTotal:100}")
- private Integer maximumConnectionsTotal;
-
- @Getter
- @Component
- public static class DmiProperties {
- @Value("${ncmp.dmi.auth.username}")
- private String authUsername;
- @Value("${ncmp.dmi.auth.password}")
- private String authPassword;
- @Value("${ncmp.dmi.api.base-path}")
- private String dmiBasePath;
- @Value("${ncmp.dmi.auth.enabled}")
- private boolean dmiBasicAuthEnabled;
- }
-
- /**
- * Configures and create a WebClient bean that triggers an initialization (warmup) of the host name resolver and
- * loads the necessary native libraries to avoid the extra time needed to load resources for first request.
- *
- * @return a WebClient instance.
- */
- @Bean
- public WebClient webClient() {
-
- final ConnectionProvider dmiWebClientConnectionProvider
- = ConnectionProvider.create("dmiWebClientConnectionPool", maximumConnectionsTotal);
-
- final HttpClient httpClient = HttpClient.create(dmiWebClientConnectionProvider)
- .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeoutInSeconds * 1000)
- .doOnConnected(connection ->
- connection
- .addHandlerLast(new ReadTimeoutHandler(connectionTimeoutInSeconds, TimeUnit.SECONDS))
- .addHandlerLast(new WriteTimeoutHandler(connectionTimeoutInSeconds, TimeUnit.SECONDS)));
- httpClient.warmup().block();
- return WebClient.builder()
- .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
- .defaultHeaders(header -> header.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
- .clientConnector(new ReactorClientHttpConnector(httpClient))
- .codecs(configurer -> configurer
- .defaultCodecs()
- .maxInMemorySize(maximumInMemorySizeInMegabytes * 1024 * 1024))
- .build();
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDelta.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDelta.java
deleted file mode 100644
index 8a4beb9560..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDelta.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * ============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 java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
-import org.springframework.stereotype.Component;
-
-@Component
-@RequiredArgsConstructor
-public class CmNotificationSubscriptionDelta {
-
- private final CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService;
-
- /**
- * Get the delta for a given predicates list.
- *
- * @param dmiCmNotificationSubscriptionPredicates list of DmiCmNotificationSubscriptionPredicates
- * @return delta list of DmiCmNotificationSubscriptionPredicates
- */
- public List<DmiCmNotificationSubscriptionPredicate> getDelta(
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) {
- final List<DmiCmNotificationSubscriptionPredicate> delta = new ArrayList<>();
-
- for (final DmiCmNotificationSubscriptionPredicate cmNotificationSubscriptionPredicate:
- dmiCmNotificationSubscriptionPredicates) {
-
- final Set<String> targetCmHandleIds = new HashSet<>();
- final Set<String> xpaths = new HashSet<>();
- final DatastoreType datastoreType = cmNotificationSubscriptionPredicate.getDatastoreType();
-
- for (final String cmHandleId : cmNotificationSubscriptionPredicate.getTargetCmHandleIds()) {
- for (final String xpath : cmNotificationSubscriptionPredicate.getXpaths()) {
- if (!cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType,
- cmHandleId, xpath)) {
- xpaths.add(xpath);
- targetCmHandleIds.add(cmHandleId);
-
- }
- }
- }
-
- final DmiCmNotificationSubscriptionPredicate predicateDelta =
- new DmiCmNotificationSubscriptionPredicate(targetCmHandleIds, datastoreType, xpaths);
-
- delta.add(predicateDelta);
- }
- return delta;
- }
-
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java
deleted file mode 100644
index 50a5df537d..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * ============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 lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionDmiInEventProducer;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionNcmpOutEventProducer;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
-import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
-import org.springframework.stereotype.Component;
-
-@Component
-@RequiredArgsConstructor
-public class CmNotificationSubscriptionEventsHandler {
- private final CmNotificationSubscriptionNcmpOutEventProducer cmNotificationSubscriptionNcmpOutEventProducer;
- private final CmNotificationSubscriptionDmiInEventProducer cmNotificationSubscriptionDmiInEventProducer;
-
- /**
- * 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 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 boolean isScheduledEvent) {
- cmNotificationSubscriptionNcmpOutEventProducer.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- eventType, cmNotificationSubscriptionNcmpOutEvent, isScheduledEvent);
- }
-
- /**
- * Publish the event to the provided dmi plugin with key as subscription id and the event is in Cloud Event format.
- *
- * @param subscriptionId Cm Subscription id
- * @param dmiPluginName Dmi Plugin Name
- * @param eventType Type of event
- * @param cmNotificationSubscriptionDmiInEvent Cm Notification Subscription event for Dmi
- */
- public void publishCmNotificationSubscriptionDmiInEvent(final String subscriptionId, final String dmiPluginName,
- final String eventType,
- final CmNotificationSubscriptionDmiInEvent
- cmNotificationSubscriptionDmiInEvent) {
- cmNotificationSubscriptionDmiInEventProducer.publishCmNotificationSubscriptionDmiInEvent(subscriptionId,
- dmiPluginName, eventType, cmNotificationSubscriptionDmiInEvent);
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java
deleted file mode 100644
index 73f9563ecf..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandler.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ============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 java.util.List;
-import java.util.Map;
-import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionDmiInEventMapper;
-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.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
-import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
-import org.springframework.stereotype.Component;
-
-@Component
-@RequiredArgsConstructor
-public class CmNotificationSubscriptionMappersHandler {
-
- private final CmNotificationSubscriptionDmiInEventMapper cmNotificationSubscriptionDmiInEventMapper;
- private final CmNotificationSubscriptionNcmpOutEventMapper cmNotificationSubscriptionNcmpOutEventMapper;
-
- /**
- * Mapper to form a request for the DMI Plugin for the Cm Notification Subscription.
- *
- * @param dmiCmNotificationSubscriptionPredicates Collection of Cm Notification Subscription predicates
- * @return cm notification subscription dmi in event
- */
- public CmNotificationSubscriptionDmiInEvent toCmNotificationSubscriptionDmiInEvent(
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) {
- return cmNotificationSubscriptionDmiInEventMapper.toCmNotificationSubscriptionDmiInEvent(
- dmiCmNotificationSubscriptionPredicates);
- }
-
- /**
- * Mapper to form a response for the client for the Cm Notification Subscription.
- *
- * @param subscriptionId Cm Notification Subscription id
- * @param dmiCmNotificationSubscriptionDetailsMap contains CmNotificationSubscriptionDetails per dmi plugin
- * @return CmNotificationSubscriptionNcmpOutEvent to sent back to the client
- */
- public CmNotificationSubscriptionNcmpOutEvent toCmNotificationSubscriptionNcmpOutEvent(final String subscriptionId,
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap) {
- return cmNotificationSubscriptionNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- dmiCmNotificationSubscriptionDetailsMap);
- }
-
- /**
- * Mapper to form a rejected response for the client for the Cm Notification Subscription Request.
- *
- * @param subscriptionId subscription id
- * @param rejectedTargetFilters list of rejected target filters for the subscription request
- * @return to sent back to the client
- */
- public CmNotificationSubscriptionNcmpOutEvent toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
- final String subscriptionId, final List<String> rejectedTargetFilters) {
- return cmNotificationSubscriptionNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
- subscriptionId, rejectedTargetFilters);
- }
-}
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
deleted file mode 100644
index f7dd51e637..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventPublishingTask.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * ============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.producer.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.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 CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
- private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
-
- /**
- * 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 =
- dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId);
- final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
- cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- dmiCmNotificationSubscriptionDetailsMap);
- eventsPublisher.publishCloudEvent(topicName, subscriptionId,
- buildAndGetCmNotificationNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType,
- cmNotificationSubscriptionNcmpOutEvent));
- dmiCmNotificationSubscriptionCacheHandler
- .removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId);
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java
deleted file mode 100644
index b5370bf1ed..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandler.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * ============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.model.CmNotificationSubscriptionStatus.PENDING;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.Predicate;
-import org.springframework.stereotype.Component;
-
-@Component
-@RequiredArgsConstructor
-public class DmiCmNotificationSubscriptionCacheHandler {
-
- private final CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService;
- private final Map<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache;
- private final InventoryPersistence inventoryPersistence;
-
- /**
- * Adds new subscription to the subscription cache.
- *
- * @param subscriptionId subscription id
- * @param predicates subscription request predicates
- */
- public void add(final String subscriptionId, final List<Predicate> predicates) {
- cmNotificationSubscriptionCache.put(subscriptionId, createDmiCmNotificationSubscriptionsPerDmi(predicates));
- }
-
- /**
- * Get cm notification subscription cache entry via subscription id.
- *
- * @param subscriptionId subscription id
- * @return map of dmi cm notification subscriptions per dmi
- */
- public Map<String, DmiCmNotificationSubscriptionDetails> get(final String subscriptionId) {
- return cmNotificationSubscriptionCache.get(subscriptionId);
- }
-
-
- /**
- * Remove cache entries with CmNotificationSubscriptionStatus ACCEPTED/REJECTED via subscription id.
- *
- * @param subscriptionId subscription id as key in CM notification Subscription cache.
- */
- public void removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(final String subscriptionId) {
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionsPerDmi =
- cmNotificationSubscriptionCache.get(subscriptionId);
- final Map<String, DmiCmNotificationSubscriptionDetails> updatedDmiCmNotificationSubscriptionsPerDmi =
- dmiCmNotificationSubscriptionsPerDmi.entrySet().stream().filter(
- dmiCmNotificationSubscription ->
- !isAcceptedOrRejected(dmiCmNotificationSubscription.getValue()))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
- cmNotificationSubscriptionCache.put(subscriptionId, updatedDmiCmNotificationSubscriptionsPerDmi);
- }
-
- /**
- * Creates map of subscription details per DMI.
- *
- * @param predicates CM Subscription Create Request Predicates
- * @return Map of DmiCmNotificationSubscription per DMI plugin
- */
- public Map<String, DmiCmNotificationSubscriptionDetails> createDmiCmNotificationSubscriptionsPerDmi(
- final List<Predicate> predicates) {
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi =
- new HashMap<>();
- for (final Predicate requestPredicate : predicates) {
- final List<String> targetFilter = requestPredicate.getTargetFilter();
- final DatastoreType datastoreType = DatastoreType.fromDatastoreName(
- requestPredicate.getScopeFilter().getDatastore().toString());
- final Set<String> xpaths = new HashSet<>(requestPredicate.getScopeFilter().getXpathFilter());
- final Map<String, Set<String>> targetCmHandlesByDmiMap = groupTargetCmHandleIdsByDmi(targetFilter);
- for (final Map.Entry<String, Set<String>> targetCmHandlesByDmi: targetCmHandlesByDmiMap.entrySet()) {
- final DmiCmNotificationSubscriptionPredicate dmiCmNotificationSubscriptionPredicate =
- new DmiCmNotificationSubscriptionPredicate(targetCmHandlesByDmi.getValue(),
- datastoreType, xpaths);
- updateDmiCmNotificationSubscriptionDetailsPerDmi(targetCmHandlesByDmi.getKey(),
- dmiCmNotificationSubscriptionPredicate,
- dmiCmNotificationSubscriptionDetailsPerDmi);
- }
- }
- return dmiCmNotificationSubscriptionDetailsPerDmi;
- }
-
- /**
- * Update status in map of subscription details per DMI.
- *
- * @param subscriptionId String of subscription Id
- * @param dmiServiceName String of dmiServiceName
- * @param status String of status
- *
- */
- public void updateDmiCmNotificationSubscriptionStatusPerDmi(final String subscriptionId,
- final String dmiServiceName, final CmNotificationSubscriptionStatus status) {
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi =
- cmNotificationSubscriptionCache.get(subscriptionId);
- dmiCmNotificationSubscriptionDetailsPerDmi.get(dmiServiceName).setCmNotificationSubscriptionStatus(status);
- cmNotificationSubscriptionCache.put(subscriptionId, dmiCmNotificationSubscriptionDetailsPerDmi);
-
- }
-
- /**
- * Persist map of subscription details per DMI.
- *
- * @param subscriptionId String of subscription Id
- * @param dmiServiceName String of dmiServiceName
- *
- */
- public void persistIntoDatabasePerDmi(final String subscriptionId, final String dmiServiceName) {
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicateList =
- cmNotificationSubscriptionCache.get(subscriptionId).get(dmiServiceName)
- .getDmiCmNotificationSubscriptionPredicates();
- for (final DmiCmNotificationSubscriptionPredicate dmiCmNotificationSubscriptionPredicate:
- dmiCmNotificationSubscriptionPredicateList) {
- final DatastoreType datastoreType = dmiCmNotificationSubscriptionPredicate.getDatastoreType();
- final Set<String> cmHandles = dmiCmNotificationSubscriptionPredicate.getTargetCmHandleIds();
- final Set<String> xpaths = dmiCmNotificationSubscriptionPredicate.getXpaths();
-
- for (final String cmHandle: cmHandles) {
- for (final String xpath: xpaths) {
- cmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(datastoreType, cmHandle,
- xpath, subscriptionId);
- }
- }
- }
- }
-
- private void updateDmiCmNotificationSubscriptionDetailsPerDmi(
- final String dmiServiceName,
- final DmiCmNotificationSubscriptionPredicate dmiCmNotificationSubscriptionPredicate,
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi) {
- if (dmiCmNotificationSubscriptionDetailsPerDmi.containsKey(dmiServiceName)) {
- dmiCmNotificationSubscriptionDetailsPerDmi.get(dmiServiceName)
- .getDmiCmNotificationSubscriptionPredicates().add(dmiCmNotificationSubscriptionPredicate);
- } else {
- dmiCmNotificationSubscriptionDetailsPerDmi.put(dmiServiceName,
- new DmiCmNotificationSubscriptionDetails(
- new ArrayList<>(List.of(dmiCmNotificationSubscriptionPredicate)),
- PENDING));
- }
- }
-
- private Map<String, Set<String>> groupTargetCmHandleIdsByDmi(final List<String> targetCmHandleIds) {
- final Map<String, Set<String>> targetCmHandlesByDmiServiceNames = new HashMap<>();
- final Collection<YangModelCmHandle> yangModelCmHandles =
- inventoryPersistence.getYangModelCmHandles(targetCmHandleIds);
-
- for (final YangModelCmHandle yangModelCmHandle : yangModelCmHandles) {
- final String dmiServiceName = yangModelCmHandle.getDmiServiceName();
- targetCmHandlesByDmiServiceNames.putIfAbsent(dmiServiceName, new HashSet<>());
- targetCmHandlesByDmiServiceNames.get(dmiServiceName).add(yangModelCmHandle.getId());
- }
- return targetCmHandlesByDmiServiceNames;
- }
-
- private boolean isAcceptedOrRejected(
- final DmiCmNotificationSubscriptionDetails dmiCmNotificationSubscription) {
- return dmiCmNotificationSubscription.getCmNotificationSubscriptionStatus().toString().equals("ACCEPTED")
- || dmiCmNotificationSubscription.getCmNotificationSubscriptionStatus().toString().equals("REJECTED");
- }
-} \ No newline at end of file
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java
deleted file mode 100644
index 3e072b0f91..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * ============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.consumer;
-
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent;
-
-import io.cloudevents.CloudEvent;
-import java.util.Map;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionEventsHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionMappersHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent;
-import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
-import org.springframework.kafka.annotation.KafkaListener;
-import org.springframework.stereotype.Component;
-
-@Component
-@Slf4j
-@RequiredArgsConstructor
-public class CmNotificationSubscriptionDmiOutEventConsumer {
-
- private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
- private final CmNotificationSubscriptionEventsHandler cmNotificationSubscriptionEventsHandler;
- private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
-
- /**
- * Consume the Cm Notification Subscription event from the dmi-plugin.
- *
- * @param cmNotificationSubscriptionDmiOutEventConsumerRecord the event to be consumed
- */
- @KafkaListener(topics = "${app.ncmp.avc.cm-subscription-dmi-out}",
- containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory")
- public void consumeCmNotificationSubscriptionDmiOutEvent(
- final ConsumerRecord<String, CloudEvent> cmNotificationSubscriptionDmiOutEventConsumerRecord) {
- final CloudEvent cloudEvent = cmNotificationSubscriptionDmiOutEventConsumerRecord.value();
- final CmNotificationSubscriptionDmiOutEvent cmNotificationSubscriptionDmiOutEvent =
- toTargetEvent(cloudEvent, CmNotificationSubscriptionDmiOutEvent.class);
- final String correlationId = String.valueOf(cloudEvent.getExtension("correlationid"));
- if ("subscriptionCreateResponse".equals(cloudEvent.getType()) && cmNotificationSubscriptionDmiOutEvent != null
- && correlationId != null) {
- handleCmSubscriptionCreate(correlationId, cmNotificationSubscriptionDmiOutEvent);
- }
- }
-
- private void handleCmSubscriptionCreate(final String correlationId,
- final CmNotificationSubscriptionDmiOutEvent cmNotificationSubscriptionDmiOutEvent) {
- final String subscriptionId = correlationId.split("#")[0];
- final String dmiPluginName = correlationId.split("#")[1];
-
- if ("ACCEPTED".equals(cmNotificationSubscriptionDmiOutEvent.getData().getStatusMessage())) {
- handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmNotificationSubscriptionStatus.ACCEPTED);
- dmiCmNotificationSubscriptionCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName);
- handleEventsStatusPerDmi(subscriptionId);
- }
-
- if ("REJECTED".equals(cmNotificationSubscriptionDmiOutEvent.getData().getStatusMessage())) {
- handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmNotificationSubscriptionStatus.REJECTED);
- handleEventsStatusPerDmi(subscriptionId);
- }
-
- log.info("Cm Subscription with id : {} handled by the dmi-plugin : {} has the status : {}", subscriptionId,
- dmiPluginName, cmNotificationSubscriptionDmiOutEvent.getData().getStatusMessage());
- }
-
- private void handleCacheStatusPerDmi(final String subscriptionId, final String dmiPluginName,
- final CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus) {
- dmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi(subscriptionId,
- dmiPluginName, cmNotificationSubscriptionStatus);
- }
-
- private void handleEventsStatusPerDmi(final String subscriptionId) {
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsPerDmi =
- dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId);
- final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
- cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- dmiCmNotificationSubscriptionDetailsPerDmi);
- cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- "subscriptionCreateResponse", cmNotificationSubscriptionNcmpOutEvent, false);
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapper.java
deleted file mode 100644
index ea21751691..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapper.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * ============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.mapper;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
-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;
-import org.springframework.stereotype.Component;
-
-@Component
-@RequiredArgsConstructor
-public class CmNotificationSubscriptionNcmpOutEventMapper {
-
- /**
- * Mapper to form a response for the client for the Cm Notification Subscription.
- *
- * @param subscriptionId Cm Notification Subscription Id
- * @param dmiCmNotificationSubscriptionDetailsMap contains CmNotificationSubscriptionDetails per dmi plugin
- * @return CmNotificationSubscriptionNcmpOutEvent to sent back to the client
- */
- public CmNotificationSubscriptionNcmpOutEvent toCmNotificationSubscriptionNcmpOutEvent(final String subscriptionId,
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap) {
-
- final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
- new CmNotificationSubscriptionNcmpOutEvent();
- final Data cmSubscriptionData = new Data();
- cmSubscriptionData.setSubscriptionId(subscriptionId);
- populateCmNotificationSubscriptionNcmpOutEventWithCmHandleIds(dmiCmNotificationSubscriptionDetailsMap,
- cmSubscriptionData);
- cmNotificationSubscriptionNcmpOutEvent.setData(cmSubscriptionData);
-
- return cmNotificationSubscriptionNcmpOutEvent;
- }
-
- /**
- * Mapper to form a rejected response for the client for the Cm Notification Subscription Request.
- *
- * @param subscriptionId subscription id
- * @param rejectedTargetFilters list of rejected target filters for the subscription request
- * @return to sent back to the client
- */
- public CmNotificationSubscriptionNcmpOutEvent toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
- final String subscriptionId, final List<String> rejectedTargetFilters) {
- final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
- new CmNotificationSubscriptionNcmpOutEvent();
- final Data cmSubscriptionData = new Data();
- cmSubscriptionData.setSubscriptionId(subscriptionId);
- cmSubscriptionData.setRejectedTargets(rejectedTargetFilters);
- cmNotificationSubscriptionNcmpOutEvent.setData(cmSubscriptionData);
- return cmNotificationSubscriptionNcmpOutEvent;
- }
-
- private void populateCmNotificationSubscriptionNcmpOutEventWithCmHandleIds(
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap,
- final Data cmSubscriptionData) {
-
- final List<String> acceptedCmHandleIds = new ArrayList<>();
- final List<String> pendingCmHandleIds = new ArrayList<>();
- final List<String> rejectedCmHandleIds = new ArrayList<>();
-
- dmiCmNotificationSubscriptionDetailsMap.forEach((dmiPluginName, dmiCmNotificationSubscriptionDetails) -> {
- final CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus =
- dmiCmNotificationSubscriptionDetails.getCmNotificationSubscriptionStatus();
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates =
- dmiCmNotificationSubscriptionDetails.getDmiCmNotificationSubscriptionPredicates();
-
- switch (cmNotificationSubscriptionStatus) {
- case ACCEPTED -> acceptedCmHandleIds.addAll(
- extractCmHandleIds(dmiCmNotificationSubscriptionPredicates));
- case PENDING -> pendingCmHandleIds.addAll(extractCmHandleIds(dmiCmNotificationSubscriptionPredicates));
- default -> rejectedCmHandleIds.addAll(extractCmHandleIds(dmiCmNotificationSubscriptionPredicates));
- }
- });
-
- cmSubscriptionData.setAcceptedTargets(acceptedCmHandleIds);
- cmSubscriptionData.setPendingTargets(pendingCmHandleIds);
- cmSubscriptionData.setRejectedTargets(rejectedCmHandleIds);
-
- }
-
- private List<String> extractCmHandleIds(
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) {
- final List<String> cmHandleIds = new ArrayList<>();
- dmiCmNotificationSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> cmHandleIds.addAll(
- dmiCmNotificationSubscriptionPredicate.getTargetCmHandleIds()));
-
- return cmHandleIds;
- }
-
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java
deleted file mode 100644
index ed7ed2a0ba..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * ============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.producer;
-
-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.CmNotificationSubscriptionMappersHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionNcmpOutEventPublishingTask;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler;
-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;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.stereotype.Component;
-
-@Component
-@Slf4j
-@RequiredArgsConstructor
-@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true)
-public class CmNotificationSubscriptionNcmpOutEventProducer {
-
- @Value("${app.ncmp.avc.cm-subscription-ncmp-out}")
- 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 CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
- private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
- 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 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 boolean isScheduledEvent) {
-
- 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,
- cmNotificationSubscriptionMappersHandler, dmiCmNotificationSubscriptionCacheHandler);
- 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 void publishCmNotificationSubscriptionNcmpOutEventNow(final String subscriptionId, final String eventType,
- final CmNotificationSubscriptionNcmpOutEvent
- cmNotificationSubscriptionNcmpOutEvent) {
- final CloudEvent cmNotificationSubscriptionNcmpOutEventAsCloudEvent =
- buildAndGetCmNotificationNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType,
- cmNotificationSubscriptionNcmpOutEvent);
- eventsPublisher.publishCloudEvent(cmNotificationSubscriptionNcmpOutEventTopic, subscriptionId,
- cmNotificationSubscriptionNcmpOutEventAsCloudEvent);
- dmiCmNotificationSubscriptionCacheHandler
- .removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId);
- }
-
- /**
- * Get an NCMP out event as cloud event.
- *
- * @param jsonObjectMapper JSON object mapper
- * @param subscriptionId subscription id
- * @param eventType event type
- * @param cmNotificationSubscriptionNcmpOutEvent cm notification subscription NCMP out event
- * @return cm notification subscription NCMP out event as cloud event
- */
- public 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();
- }
-
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java
deleted file mode 100644
index 7872ba0a34..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImpl.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * ============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.service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionDelta;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionEventsHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionMappersHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.Predicate;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
-import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent;
-import org.springframework.stereotype.Service;
-
-@Service
-@RequiredArgsConstructor
-public class CmNotificationSubscriptionHandlerServiceImpl implements CmNotificationSubscriptionHandlerService {
-
- private final CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService;
- private final CmNotificationSubscriptionDelta cmNotificationSubscriptionDelta;
- private final CmNotificationSubscriptionMappersHandler cmNotificationSubscriptionMappersHandler;
- private final CmNotificationSubscriptionEventsHandler cmNotificationSubscriptionEventsHandler;
- private final DmiCmNotificationSubscriptionCacheHandler dmiCmNotificationSubscriptionCacheHandler;
-
- @Override
- public void processSubscriptionCreateRequest(
- final CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent) {
- final String subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId();
- final List<Predicate> predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates();
-
- if (cmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId(subscriptionId)) {
- dmiCmNotificationSubscriptionCacheHandler.add(subscriptionId, predicates);
- sendSubscriptionCreateRequestToDmi(subscriptionId);
- scheduleCmNotificationSubscriptionNcmpOutEventResponse(subscriptionId);
- } else {
- rejectAndPublishCmNotificationSubscriptionCreateRequest(subscriptionId,
- predicates);
- }
- }
-
- private void scheduleCmNotificationSubscriptionNcmpOutEventResponse(final String subscriptionId) {
- cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- "subscriptionCreateResponse", null, true);
- }
-
- private void rejectAndPublishCmNotificationSubscriptionCreateRequest(final String subscriptionId,
- final List<Predicate> predicates) {
- final Set<String> subscriptionTargetFilters =
- predicates.stream().flatMap(predicate -> predicate.getTargetFilter().stream())
- .collect(Collectors.toSet());
- final CmNotificationSubscriptionNcmpOutEvent cmNotificationSubscriptionNcmpOutEvent =
- cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
- subscriptionId, new ArrayList<>(subscriptionTargetFilters));
- cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(subscriptionId,
- "subscriptionCreateResponse", cmNotificationSubscriptionNcmpOutEvent, false);
- }
-
- private void sendSubscriptionCreateRequestToDmi(final String subscriptionId) {
- final Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap =
- dmiCmNotificationSubscriptionCacheHandler.get(subscriptionId);
- dmiCmNotificationSubscriptionDetailsMap.forEach((dmiPluginName, dmiCmNotificationSubscriptionDetails) -> {
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates =
- cmNotificationSubscriptionDelta.getDelta(
- dmiCmNotificationSubscriptionDetails.getDmiCmNotificationSubscriptionPredicates());
- final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent =
- cmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionDmiInEvent(
- dmiCmNotificationSubscriptionPredicates);
- cmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(subscriptionId,
- dmiPluginName, "subscriptionCreateRequest", cmNotificationSubscriptionDmiInEvent);
- });
- }
-} \ No newline at end of file
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceService.java
deleted file mode 100644
index 3bb40c3b7e..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceService.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * ============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.service;
-
-import java.util.Collection;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
-
-public interface CmNotificationSubscriptionPersistenceService {
-
- String NCMP_DATASPACE_NAME = "NCMP-Admin";
- String CM_SUBSCRIPTIONS_ANCHOR_NAME = "cm-data-subscriptions";
-
- /**
- * Check if we have an ongoing cm subscription based on the parameters.
- *
- * @param datastoreType the susbcription target datastore type
- * @param cmHandleId the id of the cm handle for the susbcription
- * @param xpath the target xpath
- * @return true for ongoing cmsubscription , otherwise false
- */
- boolean isOngoingCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath);
-
- /**
- * Check if the subscription ID is unique against ongoing subscriptions.
- *
- * @param subscriptionId subscription ID
- * @return true if subscriptionId is not used in active subscriptions, otherwise false
- */
- boolean isUniqueSubscriptionId(final String subscriptionId);
-
- /**
- * Get all ongoing cm notification subscription based on the parameters.
- *
- * @param datastoreType the susbcription target datastore type
- * @param cmHandleId the id of the cm handle for the susbcription
- * @param xpath the target xpath
- * @return collection of subscription ids of ongoing cm notification subscription
- */
- Collection<String> getOngoingCmNotificationSubscriptionIds(final DatastoreType datastoreType,
- final String cmHandleId, final String xpath);
-
- /**
- * Add cm notification subscription.
- *
- * @param datastoreType the susbcription target datastore type
- * @param cmHandleId the id of the cm handle for the susbcription
- * @param xpath the target xpath
- * @param newSubscriptionId subscription id to be added
- */
- void addCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath, final String newSubscriptionId);
-
- /**
- * Remove cm notification Subscription.
- *
- * @param datastoreType the susbcription target datastore type
- * @param cmHandleId the id of the cm handle for the susbcription
- * @param xpath the target xpath
- * @param subscriptionId subscription id to remove
- */
- void removeCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath, final String subscriptionId);
-
-}
-
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
deleted file mode 100644
index 92f3459187..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImpl.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * ============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.service;
-
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
-
-import java.io.Serializable;
-import java.time.OffsetDateTime;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.api.CpsDataService;
-import org.onap.cps.api.CpsQueryService;
-import org.onap.cps.cpspath.parser.CpsPathUtil;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
-import org.onap.cps.spi.model.DataNode;
-import org.onap.cps.utils.ContentType;
-import org.onap.cps.utils.JsonObjectMapper;
-import org.springframework.stereotype.Service;
-
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class CmNotificationSubscriptionPersistenceServiceImpl implements CmNotificationSubscriptionPersistenceService {
-
- private static final String SUBSCRIPTION_ANCHOR_NAME = "cm-data-subscriptions";
- private static final String CM_SUBSCRIPTION_CPS_PATH_QUERY = """
- /datastores/datastore[@name='%s']/cm-handles/cm-handle[@id='%s']/filters/filter[@xpath='%s']
- """.trim();
- private static final String SUBSCRIPTION_IDS_CPS_PATH_QUERY = """
- //filter/subscriptionIds[text()='%s']
- """.trim();
-
- private final JsonObjectMapper jsonObjectMapper;
- private final CpsQueryService cpsQueryService;
- private final CpsDataService cpsDataService;
-
- @Override
- public boolean isOngoingCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath) {
- return !getOngoingCmNotificationSubscriptionIds(datastoreType, cmHandleId, xpath).isEmpty();
- }
-
- @Override
- public boolean isUniqueSubscriptionId(final String subscriptionId) {
- return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
- SUBSCRIPTION_IDS_CPS_PATH_QUERY.formatted(subscriptionId),
- OMIT_DESCENDANTS).isEmpty();
- }
-
- @Override
- public Collection<String> getOngoingCmNotificationSubscriptionIds(final DatastoreType datastoreType,
- final String cmHandleId, final String xpath) {
-
- final String isOngoingCmSubscriptionCpsPathQuery =
- CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted(datastoreType.getDatastoreName(), cmHandleId,
- escapeQuotesByDoublingThem(xpath));
- final Collection<DataNode> existingNodes =
- cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME,
- isOngoingCmSubscriptionCpsPathQuery, OMIT_DESCENDANTS);
- if (existingNodes.isEmpty()) {
- return Collections.emptyList();
- }
- return (List<String>) existingNodes.iterator().next().getLeaves().get("subscriptionIds");
- }
-
- @Override
- public void addCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath, final String subscriptionId) {
- if (isOngoingCmNotificationSubscription(datastoreType, cmHandleId, xpath)
- && (!getOngoingCmNotificationSubscriptionIds(datastoreType, cmHandleId, xpath)
- .contains(subscriptionId))) {
- final DataNode subscriptionAsDataNode = getSubscriptionAsDataNode(datastoreType, cmHandleId, xpath);
- final Collection<String> subscriptionIds = getOngoingCmNotificationSubscriptionIds(datastoreType,
- cmHandleId, xpath);
- subscriptionIds.add(subscriptionId);
- saveSubscriptionDetails(subscriptionAsDataNode, subscriptionIds);
- } else {
- addNewSubscriptionViaDatastore(datastoreType, cmHandleId, xpath, subscriptionId);
- }
- }
-
- @Override
- public void removeCmNotificationSubscription(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath, final String subscriptionId) {
- final DataNode subscriptionAsDataNode = getSubscriptionAsDataNode(datastoreType, cmHandleId, xpath);
- final Collection<String> subscriptionIds = getOngoingCmNotificationSubscriptionIds(datastoreType,
- cmHandleId, xpath);
- subscriptionIds.remove(subscriptionId);
- saveSubscriptionDetails(subscriptionAsDataNode, subscriptionIds);
- if (isOngoingCmNotificationSubscription(datastoreType, cmHandleId, xpath)) {
- log.info("There are subscribers left for the following cps path {} :",
- CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted(datastoreType.getDatastoreName(), cmHandleId,
- escapeQuotesByDoublingThem(xpath)));
- } else {
- log.info("No subscribers left for the following cps path {} :",
- CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted(datastoreType.getDatastoreName(), cmHandleId,
- escapeQuotesByDoublingThem(xpath)));
- deleteListOfSubscriptionsFor(datastoreType, cmHandleId, xpath);
- }
- }
-
- private void deleteListOfSubscriptionsFor(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath) {
- cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
- CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted(datastoreType.getDatastoreName(), cmHandleId,
- escapeQuotesByDoublingThem(xpath)),
- OffsetDateTime.now());
- }
-
- private DataNode getSubscriptionAsDataNode(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath) {
- return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
- CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted(datastoreType.getDatastoreName(), cmHandleId,
- escapeQuotesByDoublingThem(xpath)),
- OMIT_DESCENDANTS).iterator().next();
- }
-
- private void addNewSubscriptionViaDatastore(final DatastoreType datastoreType, final String cmHandleId,
- final String xpath, final String newSubscriptionId) {
- final String parentXpath = "/datastores/datastore[@name='%s']/cm-handles"
- .formatted(datastoreType.getDatastoreName());
- final String subscriptionAsJson = String.format("{\"cm-handle\":[{\"id\":\"%s\",\"filters\":{\"filter\":"
- + "[{\"xpath\":\"%s\",\"subscriptionIds\":[\"%s\"]}]}}]}", cmHandleId, xpath, newSubscriptionId);
- cpsDataService.saveData(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, parentXpath, subscriptionAsJson,
- OffsetDateTime.now(), ContentType.JSON);
- }
-
- private void saveSubscriptionDetails(final DataNode subscriptionDetailsAsDataNode,
- final Collection<String> subscriptionIds) {
- final Map<String, Serializable> subscriptionDetailsAsMap = new HashMap<>();
- subscriptionDetailsAsMap.put("xpath", subscriptionDetailsAsDataNode.getLeaves().get("xpath"));
- subscriptionDetailsAsMap.put("subscriptionIds", (Serializable) subscriptionIds);
- final String parentXpath = CpsPathUtil.getNormalizedParentXpath(subscriptionDetailsAsDataNode.getXpath());
- final String subscriptionDetailsAsJson = "{\"filter\":["
- + jsonObjectMapper.asJsonString(subscriptionDetailsAsMap).replace("'", "\"") + "]}";
- cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, parentXpath,
- subscriptionDetailsAsJson, OffsetDateTime.now());
- }
-
- private static String escapeQuotesByDoublingThem(final String inputXpath) {
- return inputXpath.replace("'", "''");
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
deleted file mode 100644
index c9e193dab1..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2022 Bell Canada
- * ================================================================================
- * 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.operations;
-
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING;
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ;
-
-import io.micrometer.core.annotation.Timed;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.NcmpResponseStatus;
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
-import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
-import org.onap.cps.ncmp.api.impl.utils.data.operation.ResourceDataOperationRequestUtils;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.CmResourceAddress;
-import org.onap.cps.ncmp.api.models.DataOperationRequest;
-import org.onap.cps.spi.exceptions.CpsException;
-import org.onap.cps.utils.JsonObjectMapper;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.util.UriComponentsBuilder;
-
-/**
- * Operations class for DMI data.
- */
-@Component
-@Slf4j
-public class DmiDataOperations extends DmiOperations {
-
- public DmiDataOperations(final InventoryPersistence inventoryPersistence,
- final JsonObjectMapper jsonObjectMapper,
- final DmiProperties dmiProperties,
- final DmiRestClient dmiRestClient,
- final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
- super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
- }
-
- /**
- * This method fetches the resource data from operational data store for given cm handle
- * identifier on given resource using dmi client.
- *
- * @param cmResourceAddress target datastore, cm handle and resource identifier
- * @param optionsParamInQuery options query
- * @param topicParamInQuery topic name for (triggering) async responses
- * @param requestId requestId for async responses
- * @param authorization contents of Authorization header, or null if not present
- * @return {@code ResponseEntity} response entity
- */
- @Timed(value = "cps.ncmp.dmi.get",
- description = "Time taken to fetch the resource data from operational data store for given cm handle "
- + "identifier on given resource using dmi client")
- public ResponseEntity<Object> getResourceDataFromDmi(final CmResourceAddress cmResourceAddress,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final String requestId,
- final String authorization) {
- final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmResourceAddress.cmHandleId());
- final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
- validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
- final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
-
- final MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap(
- cmResourceAddress.resourceIdentifier(), optionsParamInQuery,
- topicParamInQuery, yangModelCmHandle.getModuleSetTag());
- final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(cmResourceAddress.datastoreName(),
- yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmResourceAddress.cmHandleId());
- final String dmiResourceDataUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap);
-
- return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, authorization);
- }
-
- /**
- * This method fetches all the resource data from operational data store for given cm handle
- * identifier using dmi client.
- *
- * @param dataStoreName data store name
- * @param cmHandleId network resource identifier
- * @param requestId requestId for async responses
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<Object> getResourceDataFromDmi(final String dataStoreName,
- final String cmHandleId,
- final String requestId) {
- final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId);
- final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null,
- yangModelCmHandle);
-
- final MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap("/", null,
- null, yangModelCmHandle.getModuleSetTag());
- final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(dataStoreName,
- yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmHandleId);
- final String dmiResourceDataUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap);
-
- final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
- validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
- return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, null);
- }
-
- /**
- * This method requests the resource data by data store for given list of cm handles using dmi client.
- * The data wil be returned as message on the topic specified.
- *
- * @param topicParamInQuery topic name for (triggering) async responses
- * @param dataOperationRequest data operation request to execute operations
- * @param requestId requestId for as a response
- * @param authorization contents of Authorization header, or null if not present
- */
- public void requestResourceDataFromDmi(final String topicParamInQuery,
- final DataOperationRequest dataOperationRequest,
- final String requestId,
- final String authorization) {
-
- final Set<String> cmHandlesIds
- = getDistinctCmHandleIdsFromDataOperationRequest(dataOperationRequest);
-
- final Collection<YangModelCmHandle> yangModelCmHandles
- = inventoryPersistence.getYangModelCmHandles(cmHandlesIds);
-
- final Map<String, List<DmiDataOperation>> operationsOutPerDmiServiceName
- = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(topicParamInQuery,
- requestId, dataOperationRequest, yangModelCmHandles);
-
- buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName,
- authorization);
- }
-
- /**
- * This method creates the resource data from pass-through running data store for given cm handle
- * identifier on given resource using dmi client.
- *
- * @param cmHandleId network resource identifier
- * @param resourceId resource identifier
- * @param operationType operation enum
- * @param requestData the request data
- * @param dataType data type
- * @param authorization contents of Authorization header, or null if not present
- * @return {@code ResponseEntity} response entity
- */
- public ResponseEntity<Object> writeResourceDataPassThroughRunningFromDmi(final String cmHandleId,
- final String resourceId,
- final OperationType operationType,
- final String requestData,
- final String dataType,
- final String authorization) {
- final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId);
- final String jsonRequestBody = getDmiRequestBody(operationType, null, requestData, dataType,
- yangModelCmHandle);
-
- final MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap(resourceId, null,
- null, yangModelCmHandle.getModuleSetTag());
- final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(PASSTHROUGH_RUNNING.getDatastoreName(),
- yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmHandleId);
- final String dmiUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap);
-
- final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
- validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
- return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType, authorization);
- }
-
- private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
- return inventoryPersistence.getYangModelCmHandle(cmHandleId);
- }
-
- private String getDmiRequestBody(final OperationType operationType,
- final String requestId,
- final String requestData,
- final String dataType,
- final YangModelCmHandle yangModelCmHandle) {
- final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
- .operationType(operationType)
- .requestId(requestId)
- .data(requestData)
- .dataType(dataType)
- .build();
- dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties());
- return jsonObjectMapper.asJsonString(dmiRequestBody);
- }
-
- private String getDmiRequestUrl(final MultiValueMap<String, String> uriQueryParamsMap,
- final Map<String, Object> uriVariableParamsMap) {
- return dmiServiceUrlBuilder.getDmiDatastoreUrl(uriQueryParamsMap, uriVariableParamsMap);
- }
-
- private MultiValueMap<String, String> getUriQueryParamsMap(final String resourceId,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final String moduleSetTagParamInQuery) {
- return dmiServiceUrlBuilder.populateQueryParams(resourceId, optionsParamInQuery,
- topicParamInQuery, moduleSetTagParamInQuery);
- }
-
- private Map<String, Object> getUriVariableParamsMap(final String dataStoreName,
- final String dmiServiceName,
- final String cmHandleId) {
- return dmiServiceUrlBuilder.populateUriVariables(dataStoreName, dmiServiceName, cmHandleId);
- }
-
- private String getDmiServiceDataOperationRequestUrl(final String dmiServiceName,
- final String topicParamInQuery,
- final String requestId) {
- final MultiValueMap<String, String> dataOperationRequestQueryParams = dmiServiceUrlBuilder
- .getDataOperationRequestQueryParams(topicParamInQuery, requestId);
- return dmiServiceUrlBuilder.getDataOperationRequestUrl(dataOperationRequestQueryParams,
- dmiServiceUrlBuilder.populateDataOperationRequestUriVariables(dmiServiceName));
- }
-
- private void validateIfCmHandleStateReady(final YangModelCmHandle yangModelCmHandle,
- final CmHandleState cmHandleState) {
- if (cmHandleState != CmHandleState.READY) {
- throw new CpsException("State mismatch exception.", "Cm-Handle not in READY state. "
- + "cm handle state is "
- + yangModelCmHandle.getCompositeState().getCmHandleState());
- }
- }
-
- private static Set<String> getDistinctCmHandleIdsFromDataOperationRequest(final DataOperationRequest
- dataOperationRequest) {
- return dataOperationRequest.getDataOperationDefinitions().stream()
- .flatMap(dataOperationDefinition ->
- dataOperationDefinition.getCmHandleIds().stream()).collect(Collectors.toSet());
- }
-
- private void buildDataOperationRequestUrlAndSendToDmiService(final String topicParamInQuery,
- final String requestId,
- final Map<String, List<DmiDataOperation>>
- groupsOutPerDmiServiceName,
- final String authorization) {
-
- groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> {
- final String dmiDataOperationResourceUrl =
- getDmiServiceDataOperationRequestUrl(dmiServiceName, topicParamInQuery, requestId);
- sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies,
- authorization);
- });
- }
-
- private void sendDataOperationRequestToDmiService(final String dataOperationResourceUrl,
- final List<DmiDataOperation> dmiDataOperationRequestBodies,
- final String authorization) {
- final DmiDataOperationRequest dmiDataOperationRequest = DmiDataOperationRequest.builder()
- .operations(dmiDataOperationRequestBodies).build();
- final String dmiDataOperationRequestAsJsonString =
- jsonObjectMapper.asJsonString(dmiDataOperationRequest);
- try {
- dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, dmiDataOperationRequestAsJsonString, READ,
- authorization);
- } catch (final DmiClientRequestException e) {
- handleTaskCompletionException(e, dataOperationResourceUrl, dmiDataOperationRequestBodies);
- }
- }
-
- private void handleTaskCompletionException(final DmiClientRequestException dmiClientRequestException,
- final String dataOperationResourceUrl,
- final List<DmiDataOperation> dmiDataOperationRequestBodies) {
- final MultiValueMap<String, String> dataOperationResourceUrlParameters =
- UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams();
- final String topicName = dataOperationResourceUrlParameters.get("topic").get(0);
- final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0);
-
- final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>>
- cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
-
- dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> {
- final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream()
- .map(DmiOperationCmHandle::getId).toList();
- cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody,
- Map.of(dmiClientRequestException.getNcmpResponseStatus(), cmHandleIds));
- });
- ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId,
- cmHandleIdsPerResponseCodesPerOperation);
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
deleted file mode 100644
index f4166d41bb..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2022 Bell Canada
- * ================================================================================
- * 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.operations;
-
-import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
-import org.onap.cps.utils.JsonObjectMapper;
-import org.springframework.stereotype.Service;
-
-@RequiredArgsConstructor
-@Service
-public class DmiOperations {
-
- protected final InventoryPersistence inventoryPersistence;
- protected final JsonObjectMapper jsonObjectMapper;
- protected final DmiProperties dmiProperties;
- protected final DmiRestClient dmiRestClient;
- protected final DmiServiceUrlBuilder dmiServiceUrlBuilder;
-
- String getDmiResourceUrl(final String dmiServiceName, final String cmHandle, final String resourceName) {
- return dmiServiceUrlBuilder.getResourceDataBasePathUriBuilder()
- .pathSegment("{resourceName}")
- .buildAndExpand(dmiServiceName, dmiProperties.getDmiBasePath(), cmHandle, resourceName).toUriString();
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java
deleted file mode 100644
index 60f39fcea0..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * ============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.utils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
-import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
-import org.springframework.stereotype.Service;
-
-@Service
-@Slf4j
-@RequiredArgsConstructor
-public class AlternateIdChecker {
-
- public enum Operation {
- CREATE, UPDATE
- }
-
- private final InventoryPersistence inventoryPersistence;
-
- private static final String NO_CURRENT_ALTERNATE_ID = "";
-
- /**
- * Check if the alternate can be applied to the given cm handle (id).
- * Conditions:
- * - proposed alternate is blank (it wil be ignored)
- * - proposed alternate is same as current (no change)
- * - proposed alternate is not in use for a different cm handle (in the DB)
- *
- * @param cmHandleId cm handle id
- * @param proposedAlternateId proposed alternate id
- * @return true if the new alternate id not in use or equal to current alternate id, false otherwise
- */
- public boolean canApplyAlternateId(final String cmHandleId, final String proposedAlternateId) {
- String currentAlternateId = "";
- try {
- final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
- currentAlternateId = yangModelCmHandle.getAlternateId();
- } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
- // work with blank current alternate id
- }
- return this.canApplyAlternateId(cmHandleId, currentAlternateId, proposedAlternateId);
- }
-
- /**
- * Check if the alternate can be applied to the given cm handle.
- * Conditions:
- * - proposed alternate is blank (it wil be ignored)
- * - proposed alternate is same as current (no change)
- * - proposed alternate is not in use for a different cm handle (in the DB)
- *
- * @param cmHandleId cm handle id
- * @param currentAlternateId current alternate id
- * @param proposedAlternateId new alternate id
- * @return true if the new alternate id not in use or equal to current alternate id, false otherwise
- */
- public boolean canApplyAlternateId(final String cmHandleId,
- final String currentAlternateId,
- final String proposedAlternateId) {
- if (StringUtils.isBlank(currentAlternateId)) {
- if (alternateIdAlreadyInDb(proposedAlternateId)) {
- log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already "
- + "assigned to a different cm handle", cmHandleId);
- return false;
- }
- return true;
- }
- if (currentAlternateId.equals(proposedAlternateId)) {
- return true;
- }
- log.warn("Alternate id update ignored, cannot update cm handle {}, already has an alternate id of {}",
- cmHandleId, currentAlternateId);
- return false;
- }
-
- /**
- * Check all alternate ids of a batch of cm handles.
- * Includes cross-checks in the batch itself for duplicates. Only the first entry encountered wil be accepted.
- *
- * @param newNcmpServiceCmHandles the proposed new cm handles
- * @param operation type of operation being executed
- * @return collection of cm handles ids which are acceptable
- */
- public Collection<String> getIdsOfCmHandlesWithRejectedAlternateId(
- final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles,
- final Operation operation) {
- final Set<String> acceptedAlternateIds = new HashSet<>(newNcmpServiceCmHandles.size());
- final Collection<String> rejectedCmHandleIds = new ArrayList<>();
- for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) {
- final String cmHandleId = ncmpServiceCmHandle.getCmHandleId();
- final String proposedAlternateId = ncmpServiceCmHandle.getAlternateId();
- if (isProposedAlternateIdAcceptable(proposedAlternateId, operation, acceptedAlternateIds, cmHandleId)) {
- acceptedAlternateIds.add(proposedAlternateId);
- } else {
- rejectedCmHandleIds.add(cmHandleId);
- }
- }
- return rejectedCmHandleIds;
- }
-
- private boolean isProposedAlternateIdAcceptable(final String proposedAlternateId, final Operation operation,
- final Set<String> acceptedAlternateIds, final String cmHandleId) {
- if (StringUtils.isEmpty(proposedAlternateId)) {
- return true;
- }
- if (acceptedAlternateIds.contains(proposedAlternateId)) {
- log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already "
- + "assigned to a different cm handle (in this batch)", cmHandleId);
- return false;
- }
- if (Operation.CREATE.equals(operation)) {
- return canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId);
- }
- return canApplyAlternateId(cmHandleId, proposedAlternateId);
- }
-
- private boolean alternateIdAlreadyInDb(final String alternateId) {
- try {
- inventoryPersistence.getCmHandleDataNodeByAlternateId(alternateId);
- } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
- return false;
- }
- return true;
- }
-
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java
deleted file mode 100644
index c032d1e8a4..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * ============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.api.impl.utils;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-import org.onap.cps.spi.model.DataNode;
-
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class DataNodeHelper {
-
- /**
- * The nested DataNode object is being flattened.
- *
- * @param dataNode object.
- * @return DataNode as stream.
- */
- public static Stream<DataNode> flatten(final DataNode dataNode) {
- return Stream.concat(Stream.of(dataNode),
- dataNode.getChildDataNodes().stream().flatMap(DataNodeHelper::flatten));
- }
-
- /**
- * The leaves for each DataNode is listed as map.
- *
- * @param dataNodes as collection
- * @return list of map for the all leaves
- */
- public static List<Map<String, Serializable>> getDataNodeLeaves(final Collection<DataNode> dataNodes) {
- return dataNodes.stream()
- .flatMap(DataNodeHelper::flatten)
- .map(DataNode::getLeaves)
- .collect(Collectors.toList());
- }
-
- /**
- * Extracts the mapping of cm handle id to status with details from nodes leaves.
- *
- * @param dataNodeLeaves as a list of map
- * @return cm handle id to status and details mapping
- */
- public static Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMap(
- final List<Map<String, Serializable>> dataNodeLeaves) {
- return dataNodeLeaves.stream()
- .filter(entryset -> entryset.values().contains("PENDING")
- || entryset.values().contains("ACCEPTED")
- || entryset.values().contains("REJECTED"))
- .collect(
- HashMap<String, Map<String, String>>::new,
- (result, entry) -> {
- final String cmHandleId = (String) entry.get("cmHandleId");
- final String status = (String) entry.get("status");
- final String details = (String) entry.get("details");
-
- if (cmHandleId != null && status != null) {
- result.put(cmHandleId, new HashMap<>());
- result.get(cmHandleId).put("status", status);
- result.get(cmHandleId).put("details", details == null ? "" : details);
- }
- },
- HashMap::putAll
- );
- }
-
- /**
- * Extracts the mapping of cm handle id to status with details from data node collection.
- *
- * @param dataNodes as a collection
- * @return cm handle id to status and details mapping
- */
- public static Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMapFromDataNode(
- final Collection<DataNode> dataNodes) {
- return cmHandleIdToStatusAndDetailsAsMap(getDataNodeLeaves(dataNodes));
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java
deleted file mode 100644
index ac6d093721..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022-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.api.impl.utils;
-
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-import lombok.RequiredArgsConstructor;
-import org.apache.logging.log4j.util.Strings;
-import org.apache.logging.log4j.util.TriConsumer;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
-import org.onap.cps.spi.utils.CpsValidator;
-import org.springframework.stereotype.Component;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.util.UriComponentsBuilder;
-
-@Component
-@RequiredArgsConstructor
-public class DmiServiceUrlBuilder {
- private final DmiProperties dmiProperties;
- private final CpsValidator cpsValidator;
-
- /**
- * This method creates the dmi service url.
- *
- * @param queryParams query param map as key,value pair
- * @param uriVariables uri param map as key (placeholder),value pair
- * @return {@code String} dmi service url as string
- */
- public String getDmiDatastoreUrl(final MultiValueMap<String, String> queryParams,
- final Map<String, Object> uriVariables) {
- return getUriComponentsBuilder(getResourceDataBasePathUriBuilder(), queryParams, uriVariables)
- .buildAndExpand().toUriString();
- }
-
- /**
- * This method builds data operation request url.
- *
- * @param dataoperationRequestQueryParams query param map as key, value pair
- * @param dataoperationRequestUriVariables uri param map as key (placeholder), value pair
- * @return {@code String} data operation request url as string
- */
- public String getDataOperationRequestUrl(final MultiValueMap<String, String> dataoperationRequestQueryParams,
- final Map<String, Object> dataoperationRequestUriVariables) {
- return getDataOperationResourceDataBasePathUriBuilder()
- .queryParams(dataoperationRequestQueryParams)
- .uriVariables(dataoperationRequestUriVariables)
- .buildAndExpand().toUriString();
- }
-
- /**
- * This method creates the dmi service url builder object with path variables.
- *
- * @return {@code UriComponentsBuilder} dmi service url builder object
- */
- public UriComponentsBuilder getResourceDataBasePathUriBuilder() {
- return UriComponentsBuilder.newInstance()
- .path("{dmiServiceName}")
- .pathSegment("{dmiBasePath}")
- .pathSegment("v1")
- .pathSegment("ch")
- .pathSegment("{cmHandleId}");
- }
-
- /**
- * This method creates the dmi service url builder object with path variables for data operation request.
- *
- * @return {@code UriComponentsBuilder} dmi service url builder object
- */
- public UriComponentsBuilder getDataOperationResourceDataBasePathUriBuilder() {
- return UriComponentsBuilder.newInstance()
- .path("{dmiServiceName}")
- .pathSegment("{dmiBasePath}")
- .pathSegment("v1")
- .pathSegment("data");
- }
-
- /**
- * This method populates uri variables.
- *
- * @param dataStoreName data store name
- * @param dmiServiceName dmi service name
- * @param cmHandleId cm handle id for dmi registration
- * @return {@code String} dmi service url as string
- */
- public Map<String, Object> populateUriVariables(final String dataStoreName,
- final String dmiServiceName,
- final String cmHandleId) {
- cpsValidator.validateNameCharacters(cmHandleId);
- final Map<String, Object> uriVariables = new HashMap<>();
- final String dmiBasePath = dmiProperties.getDmiBasePath();
- uriVariables.put("dmiServiceName", dmiServiceName);
- uriVariables.put("dmiBasePath", dmiBasePath);
- uriVariables.put("cmHandleId", cmHandleId);
- uriVariables.put("dataStore", dataStoreName);
- return uriVariables;
- }
-
- /**
- * This method populates uri variables for data operation request.
- *
- * @param dmiServiceName dmi service name
- * @return {@code Map<String, Object>} uri variables as map
- */
- public Map<String, Object> populateDataOperationRequestUriVariables(final String dmiServiceName) {
- final Map<String, Object> uriVariables = new HashMap<>();
- final String dmiBasePath = dmiProperties.getDmiBasePath();
- uriVariables.put("dmiServiceName", dmiServiceName);
- uriVariables.put("dmiBasePath", dmiBasePath);
- return uriVariables;
- }
-
- /**
- * This method is used to populate map from query params.
- *
- * @param resourceId unique id of response for valid topic
- * @param optionsParamInQuery options as provided by client
- * @param topicParamInQuery topic as provided by client
- * @param moduleSetTag module set tag associated with the given cm handle
- * @return all valid query params as map
- */
- public MultiValueMap<String, String> populateQueryParams(final String resourceId,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final String moduleSetTag) {
- final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
- getQueryParamConsumer().accept("resourceIdentifier", resourceId, queryParams);
- getQueryParamConsumer().accept("options", optionsParamInQuery, queryParams);
- if (Strings.isNotEmpty(topicParamInQuery)) {
- getQueryParamConsumer().accept("topic", topicParamInQuery, queryParams);
- }
- if (Strings.isNotEmpty(moduleSetTag)) {
- getQueryParamConsumer().accept("moduleSetTag", moduleSetTag, queryParams);
- }
- return queryParams;
- }
-
- /**
- * This method is used to populate map from query params for data operation request.
- *
- * @param topicParamInQuery topic into url param
- * @param requestId unique id of response for valid topic
- * @return all valid query params as map
- */
- public MultiValueMap<String, String> getDataOperationRequestQueryParams(final String topicParamInQuery,
- final String requestId) {
- final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
- getQueryParamConsumer().accept("topic", topicParamInQuery, queryParams);
- getQueryParamConsumer().accept("requestId", requestId, queryParams);
- return queryParams;
- }
-
- private TriConsumer<String, String, MultiValueMap<String, String>> getQueryParamConsumer() {
- return (paramName, paramValue, paramMap) -> {
- if (Strings.isNotEmpty(paramValue)) {
- paramMap.add(paramName, URLEncoder.encode(paramValue, StandardCharsets.UTF_8));
- }
- };
- }
-
- private UriComponentsBuilder getUriComponentsBuilder(final UriComponentsBuilder uriComponentsBuilder,
- final MultiValueMap<String, String> queryParams,
- final Map<String, Object> uriVariables) {
- return uriComponentsBuilder
- .pathSegment("data")
- .pathSegment("ds")
- .pathSegment("{dataStore}")
- .queryParams(queryParams)
- .uriVariables(uriVariables);
- }
-}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmDataSubscriptionEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmDataSubscriptionEvent.java
deleted file mode 100644
index e527d99f2f..0000000000
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmDataSubscriptionEvent.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * ============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.api.impl.yangmodels;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.List;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-
-/**
- * Subscription event model to persist data into DB.
- * Yang model subscription event
- */
-@Getter
-@Setter
-@NoArgsConstructor
-@JsonInclude(Include.NON_NULL)
-@EqualsAndHashCode(onlyExplicitlyIncluded = true)
-public class YangModelCmDataSubscriptionEvent {
-
- @EqualsAndHashCode.Include
- @JsonProperty("name")
- private String name;
-
- private List<CmHandle> cmHandles;
-
- @AllArgsConstructor
- @Data
- @JsonInclude(JsonInclude.Include.NON_NULL)
- public static class CmHandle {
-
- @JsonProperty()
- private final String id;
-
- private final List<Filter> filters;
- }
-
- @AllArgsConstructor
- @Data
- @JsonInclude(JsonInclude.Include.NON_NULL)
- public static class Filter {
-
- @JsonProperty()
- private final String id;
-
- @JsonProperty()
- private final List<String> subscribers;
- }
-}
-
-
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java
new file mode 100644
index 0000000000..cde4eacbf2
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java
@@ -0,0 +1,228 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 highstreet technologies GmbH
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2021 Pantheon.tech
+ * Modifications Copyright (C) 2021-2022 Bell Canada
+ * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * ================================================================================
+ * 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.inventory;
+
+import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateCmHandleQueryParameters;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService;
+import org.onap.cps.ncmp.impl.inventory.CmHandleRegistrationService;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.ParameterizedCmHandleQueryService;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions;
+import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager;
+import org.onap.cps.ncmp.impl.models.RequiredDmiService;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
+import org.onap.cps.spi.model.ModuleDefinition;
+import org.onap.cps.spi.model.ModuleReference;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class NetworkCmProxyInventoryFacade {
+
+ private final CmHandleRegistrationService cmHandleRegistrationService;
+ private final CmHandleQueryService cmHandleQueryService;
+ private final ParameterizedCmHandleQueryService parameterizedCmHandleQueryService;
+ private final InventoryPersistence inventoryPersistence;
+ private final JsonObjectMapper jsonObjectMapper;
+ private final TrustLevelManager trustLevelManager;
+ private final AlternateIdMatcher alternateIdMatcher;
+
+ /**
+ * Registration of Created, Removed, Updated or Upgraded CM Handles.
+ *
+ * @param dmiPluginRegistration Dmi Plugin Registration details
+ * @return dmiPluginRegistrationResponse
+ */
+ public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
+ final DmiPluginRegistration dmiPluginRegistration) {
+ return cmHandleRegistrationService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
+ }
+
+ /**
+ * Get all cm handle IDs by DMI plugin identifier.
+ *
+ * @param dmiPluginIdentifier DMI plugin identifier
+ * @return collection of cm handle IDs
+ */
+ public Collection<String> getAllCmHandleIdsByDmiPluginIdentifier(final String dmiPluginIdentifier) {
+ return cmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifier);
+ }
+
+ /**
+ * Get all cm handle IDs by various properties.
+ *
+ * @param cmHandleQueryServiceParameters cm handle query parameters
+ * @return collection of cm handle IDs
+ */
+ public Collection<String> executeParameterizedCmHandleIdSearch(
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
+ validateCmHandleQueryParameters(cmHandleQueryServiceParameters, InventoryQueryConditions.ALL_CONDITION_NAMES);
+ return parameterizedCmHandleQueryService.queryCmHandleIdsForInventory(cmHandleQueryServiceParameters);
+ }
+
+
+ /**
+ * Retrieve module references for the given cm handle reference.
+ *
+ * @param cmHandleReference cm handle or alternate id identifier
+ * @return a collection of modules names and revisions
+ */
+ public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getYangResourcesModuleReferences(cmHandleId);
+ }
+
+ /**
+ * Retrieve module definitions for the given cm handle.
+ *
+ * @param cmHandleReference cm handle or alternate id identifier
+ * @return a collection of module definition (moduleName, revision and yang resource content)
+ */
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleReference(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId);
+ }
+
+ /**
+ * Get module definitions for the given parameters.
+ *
+ * @param cmHandleReference cm handle or alternate id identifier
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return list of module definitions (module name, revision, yang resource content)
+ */
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleReference,
+ final String moduleName,
+ final String moduleRevision) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, moduleRevision);
+ }
+
+ /**
+ * Retrieve cm handles with details for the given query parameters.
+ *
+ * @param cmHandleQueryApiParameters cm handle query parameters
+ * @return cm handles with details
+ */
+ public Collection<NcmpServiceCmHandle> executeCmHandleSearch(
+ final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
+ cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
+ validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
+ final Collection<YangModelCmHandle> yangModelCmHandles =
+ parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters);
+ final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles = new ArrayList<>(yangModelCmHandles.size());
+ for (final YangModelCmHandle yangModelCmHandle : yangModelCmHandles) {
+ final NcmpServiceCmHandle ncmpServiceCmHandle = toNcmpServiceCmHandleWithTrustLevel(yangModelCmHandle);
+ ncmpServiceCmHandles.add(ncmpServiceCmHandle);
+ }
+ return ncmpServiceCmHandles;
+ }
+
+ /**
+ * Retrieve cm handle ids for the given query parameters.
+ *
+ * @param cmHandleQueryApiParameters cm handle query parameters
+ * @return cm handle ids
+ */
+ public Collection<String> executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
+ cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
+ validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
+ return parameterizedCmHandleQueryService.queryCmHandleIds(cmHandleQueryServiceParameters);
+ }
+
+ /**
+ * Set the data sync enabled flag, along with the data sync state
+ * based on the data sync enabled boolean for the cm handle id provided.
+ *
+ * @param cmHandleId cm handle id
+ * @param dataSyncEnabledTargetValue data sync enabled flag
+ */
+ public void setDataSyncEnabled(final String cmHandleId, final Boolean dataSyncEnabledTargetValue) {
+ cmHandleRegistrationService.setDataSyncEnabled(cmHandleId, dataSyncEnabledTargetValue);
+ }
+
+ /**
+ * Retrieve cm handle details for a given cm handle reference.
+ *
+ * @param cmHandleReference cm handle or alternate identifier
+ * @return cm handle details
+ */
+ public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
+ return toNcmpServiceCmHandleWithTrustLevel(yangModelCmHandle);
+ }
+
+ /**
+ * Get cm handle public properties for a given cm handle or alternate id.
+ *
+ * @param cmHandleReference cm handle or alternate identifier
+ * @return cm handle public properties
+ */
+ public Map<String, String> getCmHandlePublicProperties(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
+ return YangDataConverter.toPropertiesMap(yangModelCmHandle.getPublicProperties());
+ }
+
+ /**
+ * Get cm handle composite state for a given cm handle id.
+ *
+ * @param cmHandleReference cm handle or alternate identifier
+ * @return cm handle state
+ */
+ public CompositeState getCmHandleCompositeState(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState();
+ }
+
+ private NcmpServiceCmHandle toNcmpServiceCmHandleWithTrustLevel(final YangModelCmHandle yangModelCmHandle) {
+ final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle);
+ final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA);
+ ncmpServiceCmHandle.setCurrentTrustLevel(
+ trustLevelManager.getEffectiveTrustLevel(dmiServiceName, ncmpServiceCmHandle.getCmHandleId()));
+ return ncmpServiceCmHandle;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleQueryApiParameters.java
index dd8dcd60ac..596fb94a36 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryApiParameters.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleQueryApiParameters.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryServiceParameters.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleQueryServiceParameters.java
index 5eeafaca33..13915918e5 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleQueryServiceParameters.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleQueryServiceParameters.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponse.java
index 52b8d6926a..7523f77af2 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponse.java
@@ -19,7 +19,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR;
@@ -31,7 +31,7 @@ import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.api.NcmpResponseStatus;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
@Data
@Builder
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeState.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CompositeState.java
index 5b88f560eb..ca4fde2b62 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeState.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CompositeState.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.api.inventory.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -29,6 +29,9 @@ import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory;
/**
* State Model to store state corresponding to the Yang resource dmi-registry model.
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilder.java
index 2fbe2b2f78..59d7aa2b44 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateBuilder.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilder.java
@@ -19,11 +19,14 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.api.inventory.models;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState.LockReason;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState.DataStores;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState.LockReason;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState.Operational;
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory;
import org.onap.cps.spi.model.DataNode;
public class CompositeStateBuilder {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/ConditionApiProperties.java
index 5cb2ed376c..61d9f4a250 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/ConditionApiProperties.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/ConditionApiProperties.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistration.java
index 7d6a8e1407..44e2ebe320 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistration.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -27,8 +27,8 @@ import java.util.Collections;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
-import org.onap.cps.ncmp.api.impl.exception.DmiRequestException;
-import org.onap.cps.ncmp.api.impl.exception.NcmpException;
+import org.onap.cps.ncmp.api.exceptions.DmiRequestException;
+import org.onap.cps.ncmp.api.exceptions.NcmpException;
/**
* Dmi Registry request object.
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistrationResponse.java
index ee034176e3..736ca620d0 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistrationResponse.java
@@ -19,7 +19,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import java.util.Collections;
import java.util.List;
@@ -33,4 +33,4 @@ public class DmiPluginRegistrationResponse {
private List<CmHandleRegistrationResponse> updatedCmHandles = Collections.emptyList();
private List<CmHandleRegistrationResponse> removedCmHandles = Collections.emptyList();
private List<CmHandleRegistrationResponse> upgradedCmHandles = Collections.emptyList();
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/NcmpServiceCmHandle.java
index 676eebc4d6..3ebceed9d7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/NcmpServiceCmHandle.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
@@ -27,8 +27,6 @@ import java.util.Map;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel;
import org.springframework.validation.annotation.Validated;
/**
@@ -59,6 +57,9 @@ public class NcmpServiceCmHandle {
private TrustLevel registrationTrustLevel;
@JsonSetter(nulls = Nulls.AS_EMPTY)
+ private TrustLevel currentTrustLevel;
+
+ @JsonSetter(nulls = Nulls.AS_EMPTY)
private String alternateId;
@JsonSetter(nulls = Nulls.AS_EMPTY)
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/TrustLevel.java
index f130604a64..83e6ecf912 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/TrustLevel.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel;
+package org.onap.cps.ncmp.api.inventory.models;
import lombok.Getter;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/UpgradedCmHandles.java
index 61cd99ac8f..9f48ae968c 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/UpgradedCmHandles.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.Collections;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/YangResource.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/YangResource.java
index 7975777aa5..1c0ca5d8cd 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/YangResource.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/YangResource.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models;
+package org.onap.cps.ncmp.api.inventory.models;
import lombok.Data;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContext.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/CpsApplicationContext.java
index b14cf0d0db..fbc31adcf3 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContext.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/CpsApplicationContext.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils.context;
+package org.onap.cps.ncmp.config;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -48,4 +48,4 @@ public class CpsApplicationContext implements ApplicationContextAware {
private static synchronized void setCpsApplicationContext(final ApplicationContext cpsApplicationContext) {
CpsApplicationContext.applicationContext = cpsApplicationContext;
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/DmiHttpClientConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/DmiHttpClientConfig.java
new file mode 100644
index 0000000000..8eebb89a0a
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/DmiHttpClientConfig.java
@@ -0,0 +1,57 @@
+/*
+ * ============LICENSE_START=======================================================
+ * 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.
+ * 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.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Getter
+@Setter
+@Configuration
+@ConfigurationProperties(prefix = "ncmp.dmi.httpclient")
+public class DmiHttpClientConfig {
+
+ private final DataServices dataServices = new DataServices();
+ private final ModelServices modelServices = new ModelServices();
+ private final HealthCheckServices healthCheckServices = new HealthCheckServices();
+
+ @Getter
+ @Setter
+ public static class DataServices extends ServiceConfig {
+ private String connectionProviderName = "dataConnectionPool";
+ }
+
+ @Getter
+ @Setter
+ public static class ModelServices extends ServiceConfig {
+ private String connectionProviderName = "modelConnectionPool";
+ }
+
+ @Getter
+ @Setter
+ public static class HealthCheckServices extends ServiceConfig {
+ private String connectionProviderName = "healthConnectionPool";
+ private int maximumConnectionsTotal = 10;
+ private int pendingAcquireMaxCount = 5;
+ }
+}
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/config/KafkaConfig.java
index 167df5a98d..3d3c3db482 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/config/KafkaConfig.java
@@ -18,13 +18,17 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.kafka;
+package org.onap.cps.ncmp.config;
import io.cloudevents.CloudEvent;
+import io.opentelemetry.instrumentation.kafkaclients.v2_6.TracingConsumerInterceptor;
+import io.opentelemetry.instrumentation.kafkaclients.v2_6.TracingProducerInterceptor;
import java.time.Duration;
import java.util.Map;
import lombok.RequiredArgsConstructor;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.context.annotation.Bean;
@@ -52,6 +56,9 @@ public class KafkaConfig<T> {
private final KafkaProperties kafkaProperties;
+ @Value("${cps.tracing.enabled:false}")
+ private boolean tracingEnabled;
+
private static final SslBundles NO_SSL = null;
/**
@@ -64,6 +71,10 @@ public class KafkaConfig<T> {
public ProducerFactory<String, T> legacyEventProducerFactory() {
final Map<String, Object> producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL);
producerConfigProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
+ if (tracingEnabled) {
+ producerConfigProperties.put(
+ ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingProducerInterceptor.class.getName());
+ }
return new DefaultKafkaProducerFactory<>(producerConfigProperties);
}
@@ -77,6 +88,10 @@ public class KafkaConfig<T> {
public ConsumerFactory<String, T> legacyEventConsumerFactory() {
final Map<String, Object> consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL);
consumerConfigProperties.put("spring.deserializer.value.delegate.class", JsonDeserializer.class);
+ if (tracingEnabled) {
+ consumerConfigProperties.put(
+ ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingConsumerInterceptor.class.getName());
+ }
return new DefaultKafkaConsumerFactory<>(consumerConfigProperties);
}
@@ -90,6 +105,9 @@ public class KafkaConfig<T> {
public KafkaTemplate<String, T> legacyEventKafkaTemplate() {
final KafkaTemplate<String, T> kafkaTemplate = new KafkaTemplate<>(legacyEventProducerFactory());
kafkaTemplate.setConsumerFactory(legacyEventConsumerFactory());
+ if (tracingEnabled) {
+ kafkaTemplate.setObservationEnabled(true);
+ }
return kafkaTemplate;
}
@@ -104,6 +122,9 @@ public class KafkaConfig<T> {
new ConcurrentKafkaListenerContainerFactory<>();
containerFactory.setConsumerFactory(legacyEventConsumerFactory());
containerFactory.getContainerProperties().setAuthExceptionRetryInterval(Duration.ofSeconds(10));
+ if (tracingEnabled) {
+ containerFactory.getContainerProperties().setObservationEnabled(true);
+ }
return containerFactory;
}
@@ -116,6 +137,10 @@ public class KafkaConfig<T> {
@Bean
public ProducerFactory<String, CloudEvent> cloudEventProducerFactory() {
final Map<String, Object> producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL);
+ if (tracingEnabled) {
+ producerConfigProperties.put(
+ ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingProducerInterceptor.class.getName());
+ }
return new DefaultKafkaProducerFactory<>(producerConfigProperties);
}
@@ -128,6 +153,10 @@ public class KafkaConfig<T> {
@Bean
public ConsumerFactory<String, CloudEvent> cloudEventConsumerFactory() {
final Map<String, Object> consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL);
+ if (tracingEnabled) {
+ consumerConfigProperties.put(
+ ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingConsumerInterceptor.class.getName());
+ }
return new DefaultKafkaConsumerFactory<>(consumerConfigProperties);
}
@@ -142,6 +171,9 @@ public class KafkaConfig<T> {
final KafkaTemplate<String, CloudEvent> kafkaTemplate =
new KafkaTemplate<>(cloudEventProducerFactory());
kafkaTemplate.setConsumerFactory(cloudEventConsumerFactory());
+ if (tracingEnabled) {
+ kafkaTemplate.setObservationEnabled(true);
+ }
return kafkaTemplate;
}
@@ -157,6 +189,9 @@ public class KafkaConfig<T> {
new ConcurrentKafkaListenerContainerFactory<>();
containerFactory.setConsumerFactory(cloudEventConsumerFactory());
containerFactory.getContainerProperties().setAuthExceptionRetryInterval(Duration.ofSeconds(10));
+ if (tracingEnabled) {
+ containerFactory.getContainerProperties().setObservationEnabled(true);
+ }
return containerFactory;
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java
new file mode 100644
index 0000000000..a6a82b7936
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java
@@ -0,0 +1,141 @@
+/*
+ * ============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.config;
+
+import io.micrometer.observation.ObservationPredicate;
+import io.micrometer.observation.ObservationRegistry;
+import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
+import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
+import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler;
+import io.opentelemetry.sdk.trace.samplers.Sampler;
+import jakarta.annotation.PostConstruct;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryCustomizer;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.server.observation.ServerRequestObservationContext;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.PathMatcher;
+
+/**
+ * Configuration class for setting up OpenTelemetry tracing in a Spring Boot application.
+ * This class provides beans for OTLP exporters (gRPC and HTTP), a Jaeger remote sampler,
+ * and customizes the ObservationRegistry to exclude certain endpoints from being observed.
+ */
+@Configuration
+public class OpenTelemetryConfig {
+
+ @Value("${spring.application.name:cps-application}")
+ private String serviceId;
+
+ @Value("${cps.tracing.exporter.endpoint:http://onap-otel-collector:4317}")
+ private String tracingExporterEndpointUrl;
+
+ @Value("${cps.tracing.sampler.jaeger_remote.endpoint:http://onap-otel-collector:14250}")
+ private String jaegerRemoteSamplerUrl;
+
+ @Value("${cps.tracing.excluded-observation-names:tasks.scheduled.execution}")
+ private String excludedObservationNamesAsCsv;
+
+ private static final int JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECONDS = 30;
+
+ private List<String> excludedObservationNames;
+
+ /**
+ * Initializes the excludedObservationNames after the bean's properties have been set.
+ * This method is called by the Spring container during bean initialization.
+ */
+ @PostConstruct
+ public void init() {
+ excludedObservationNames = Arrays.stream(excludedObservationNamesAsCsv.split(","))
+ .map(String::trim)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Creates an OTLP Exporter with gRPC protocol.
+ *
+ * @return OtlpGrpcSpanExporter bean if tracing is enabled and the exporter protocol is gRPC
+ */
+ @Bean
+ @ConditionalOnExpression(
+ "${cps.tracing.enabled} && 'grpc'.equals('${cps.tracing.exporter.protocol}')")
+ public OtlpGrpcSpanExporter createOtlpExporterGrpc() {
+ return OtlpGrpcSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build();
+ }
+
+ /**
+ * Creates an OTLP Exporter with HTTP protocol.
+ *
+ * @return OtlpHttpSpanExporter bean if tracing is enabled and the exporter protocol is HTTP
+ */
+ @Bean
+ @ConditionalOnExpression(
+ "${cps.tracing.enabled} && 'http'.equals('${cps.tracing.exporter.protocol}')")
+ public OtlpHttpSpanExporter createOtlpExporterHttp() {
+ return OtlpHttpSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build();
+ }
+
+ /**
+ * Creates a Jaeger Remote Sampler.
+ *
+ * @return JaegerRemoteSampler bean if tracing is enabled
+ */
+ @Bean
+ @ConditionalOnProperty("cps.tracing.enabled")
+ public JaegerRemoteSampler createJaegerRemoteSampler() {
+ return JaegerRemoteSampler.builder()
+ .setEndpoint(jaegerRemoteSamplerUrl)
+ .setPollingInterval(Duration.ofSeconds(JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECONDS))
+ .setInitialSampler(Sampler.alwaysOff())
+ .setServiceName(serviceId)
+ .build();
+ }
+
+ /**
+ * Customizes the ObservationRegistry to exclude /actuator/** endpoints from being observed.
+ *
+ * @return ObservationRegistryCustomizer bean if tracing is enabled
+ */
+ @Bean
+ @ConditionalOnProperty("cps.tracing.enabled")
+ public ObservationRegistryCustomizer<ObservationRegistry> skipActuatorEndpointsFromObservation() {
+ final PathMatcher pathMatcher = new AntPathMatcher("/");
+ return registry ->
+ registry.observationConfig().observationPredicate(observationPredicate(pathMatcher));
+ }
+
+ private ObservationPredicate observationPredicate(final PathMatcher pathMatcher) {
+ return (observationName, context) -> {
+ if (context instanceof ServerRequestObservationContext observationContext) {
+ return !pathMatcher.match("/actuator/**", observationContext.getCarrier().getRequestURI());
+ } else {
+ return !excludedObservationNames.contains(observationName);
+ }
+ };
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfig.java
index d547e31c68..0903c671b5 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfig.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * 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.
@@ -18,40 +18,24 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config;
+package org.onap.cps.ncmp.config;
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.convert.DurationUnit;
+import org.springframework.context.annotation.Configuration;
@Getter
@Setter
-@ConfigurationProperties(prefix = "ncmp.dmi.httpclient", ignoreUnknownFields = true)
-public class HttpClientConfiguration {
+@Configuration
+@ConfigurationProperties(prefix = "ncmp.policy-executor.httpclient")
+public class PolicyExecutorHttpClientConfig {
- /**
- * The maximum time to establish a connection.
- */
- @DurationUnit(ChronoUnit.SECONDS)
- private Duration connectionTimeoutInSeconds = Duration.ofSeconds(180);
-
- /**
- * The maximum number of open connections per route.
- */
- private int maximumConnectionsPerRoute = 50;
-
- /**
- * The maximum total number of open connections.
- */
- private int maximumConnectionsTotal = maximumConnectionsPerRoute * 2;
-
- /**
- * The duration after which idle connections are evicted.
- */
- @DurationUnit(ChronoUnit.SECONDS)
- private Duration idleConnectionEvictionThresholdInSeconds = Duration.ofSeconds(5);
+ private final AllServices allServices = new AllServices();
+ @Getter
+ @Setter
+ public static class AllServices extends ServiceConfig {
+ private String connectionProviderName = "policyExecutorConfig";
+ }
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/ServiceConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/ServiceConfig.java
new file mode 100644
index 0000000000..f1fce0c7c6
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/ServiceConfig.java
@@ -0,0 +1,36 @@
+/*
+ * ============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.config;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public abstract class ServiceConfig {
+ private String connectionProviderName = "";
+ private int maximumInMemorySizeInMegabytes = 1;
+ private int maximumConnectionsTotal = 1;
+ private int pendingAcquireMaxCount = 1;
+ private Integer connectionTimeoutInSeconds = 1;
+ private long readTimeoutInSeconds = 1;
+ private long writeTimeoutInSeconds = 1;
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpStartUpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NcmpStartUpException.java
index 7ac26f54fd..7ffbe2e5cb 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpStartUpException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NcmpStartUpException.java
@@ -18,7 +18,9 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.exceptions;
+
+import org.onap.cps.ncmp.api.exceptions.NcmpException;
/**
* NCMP start up exception.
@@ -34,4 +36,4 @@ public class NcmpStartUpException extends NcmpException {
public NcmpStartUpException(final String message, final String details) {
super(message, details);
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NoAlternateIdParentFoundException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NoAlternateIdMatchFoundException.java
index 2e6cd3308c..7c5fc3be2b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NoAlternateIdParentFoundException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NoAlternateIdMatchFoundException.java
@@ -18,22 +18,23 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.exception;
+package org.onap.cps.ncmp.exceptions;
import java.io.Serial;
+import org.onap.cps.ncmp.api.exceptions.NcmpException;
-public class NoAlternateIdParentFoundException extends NcmpException {
+public class NoAlternateIdMatchFoundException extends NcmpException {
@Serial
private static final long serialVersionUID = -2412915490233422945L;
- private static final String ALTERNATE_ID_NOT_FOUND = "No matching (parent) cm handle found using alternate ids";
+ private static final String ALTERNATE_ID_NOT_FOUND = "No matching cm handle found using alternate ids";
/**
* Constructor.
*
* @param cpsPath datanode cpsPath
*/
- public NoAlternateIdParentFoundException(final String cpsPath) {
+ public NoAlternateIdMatchFoundException(final String cpsPath) {
super(ALTERNATE_ID_NOT_FOUND, String.format("cannot find a datanode with alternate id %s", cpsPath));
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfig.java
index 1d6da90a9a..a4f9be357f 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfig.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfig.java
@@ -18,18 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.embeddedcache;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.cache;
import com.hazelcast.config.MapConfig;
import com.hazelcast.map.IMap;
import java.util.Map;
import org.onap.cps.cache.HazelcastCacheConfig;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
-public class CmNotificationSubscriptionCacheConfig extends HazelcastCacheConfig {
+public class CmSubscriptionConfig extends HazelcastCacheConfig {
private static final MapConfig cmNotificationSubscriptionCacheMapConfig =
createMapConfig("cmNotificationSubscriptionCacheMapConfig");
@@ -42,7 +42,7 @@ public class CmNotificationSubscriptionCacheConfig extends HazelcastCacheConfig
* @return configured map of subscription events.
*/
@Bean
- public IMap<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache() {
+ public IMap<String, Map<String, DmiCmSubscriptionDetails>> cmNotificationSubscriptionCache() {
return createHazelcastInstance("hazelCastInstanceCmNotificationSubscription",
cmNotificationSubscriptionCacheMapConfig).getMap("cmNotificationSubscriptionCache");
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandler.java
new file mode 100644
index 0000000000..b5ab7f6525
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandler.java
@@ -0,0 +1,227 @@
+/*
+ * ============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.impl.cmnotificationsubscription.cache;
+
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.PENDING;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class DmiCacheHandler {
+
+ private final CmSubscriptionPersistenceService cmSubscriptionPersistenceService;
+ private final Map<String, Map<String, DmiCmSubscriptionDetails>> cmNotificationSubscriptionCache;
+ private final InventoryPersistence inventoryPersistence;
+
+ /**
+ * Adds subscription to the subscription cache.
+ *
+ * @param subscriptionId subscription id
+ * @param predicates subscription request predicates
+ */
+ public void add(final String subscriptionId, final List<Predicate> predicates) {
+ cmNotificationSubscriptionCache.put(subscriptionId, createDmiSubscriptionsPerDmi(predicates));
+ }
+
+ /**
+ * Adds subscription to the subscription cache.
+ *
+ * @param subscriptionId subscription id
+ * @param dmiCmSubscriptionDetailsPerDmi map of dmi cm notification subscription details per dmi
+ */
+ public void add(final String subscriptionId,
+ final Map<String, DmiCmSubscriptionDetails>
+ dmiCmSubscriptionDetailsPerDmi) {
+ cmNotificationSubscriptionCache.put(subscriptionId, dmiCmSubscriptionDetailsPerDmi);
+ }
+
+ /**
+ * Get cm notification subscription cache entry via subscription id.
+ *
+ * @param subscriptionId subscription id
+ * @return map of dmi cm notification subscriptions per dmi
+ */
+ public Map<String, DmiCmSubscriptionDetails> get(final String subscriptionId) {
+ return cmNotificationSubscriptionCache.get(subscriptionId);
+ }
+
+
+ /**
+ * Remove cache entries with CmNotificationSubscriptionStatus ACCEPTED/REJECTED via subscription id.
+ *
+ * @param subscriptionId subscription id as key in CM notification Subscription cache.
+ */
+ public void removeAcceptedAndRejectedDmiSubscriptionEntries(final String subscriptionId) {
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi =
+ cmNotificationSubscriptionCache.get(subscriptionId);
+ final Map<String, DmiCmSubscriptionDetails> updatedDmiSubscriptionsPerDmi =
+ dmiSubscriptionsPerDmi.entrySet().stream()
+ .filter(dmiCmNotificationSubscription -> !isAcceptedOrRejected(
+ dmiCmNotificationSubscription.getValue()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ cmNotificationSubscriptionCache.put(subscriptionId, updatedDmiSubscriptionsPerDmi);
+ }
+
+ /**
+ * Creates map of subscription details per DMI.
+ *
+ * @param predicates CM Subscription Create Request Predicates
+ * @return Map of DmiCmNotificationSubscription per DMI plugin
+ */
+ public Map<String, DmiCmSubscriptionDetails> createDmiSubscriptionsPerDmi(
+ final List<Predicate> predicates) {
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi =
+ new HashMap<>();
+ for (final Predicate requestPredicate : predicates) {
+ final List<String> targetFilter = requestPredicate.getTargetFilter();
+ final DatastoreType datastoreType = DatastoreType.fromDatastoreName(
+ requestPredicate.getScopeFilter().getDatastore().toString());
+ final Set<String> xpaths = new HashSet<>(requestPredicate.getScopeFilter().getXpathFilter());
+ final Map<String, Set<String>> targetCmHandlesByDmiMap = groupTargetCmHandleIdsByDmi(targetFilter);
+ for (final Map.Entry<String, Set<String>> targetCmHandlesByDmi: targetCmHandlesByDmiMap.entrySet()) {
+ final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate =
+ new DmiCmSubscriptionPredicate(targetCmHandlesByDmi.getValue(),
+ datastoreType, xpaths);
+ updateDmiSubscriptionDetailsPerDmi(targetCmHandlesByDmi.getKey(),
+ dmiCmSubscriptionPredicate,
+ dmiSubscriptionsPerDmi);
+ }
+ }
+ return dmiSubscriptionsPerDmi;
+ }
+
+ /**
+ * Update status in map of subscription details per DMI.
+ *
+ * @param subscriptionId String of subscription Id
+ * @param dmiServiceName String of dmiServiceName
+ * @param status String of status
+ *
+ */
+ public void updateDmiSubscriptionStatus(final String subscriptionId, final String dmiServiceName,
+ final CmSubscriptionStatus status) {
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi =
+ cmNotificationSubscriptionCache.get(subscriptionId);
+ dmiSubscriptionsPerDmi.get(dmiServiceName).setCmSubscriptionStatus(status);
+ cmNotificationSubscriptionCache.put(subscriptionId, dmiSubscriptionsPerDmi);
+ }
+
+ /**
+ * Persist map of subscription details per DMI.
+ *
+ * @param subscriptionId String of subscription Id
+ * @param dmiServiceName String of dmiServiceName
+ *
+ */
+ public void persistIntoDatabasePerDmi(final String subscriptionId, final String dmiServiceName) {
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates =
+ cmNotificationSubscriptionCache.get(subscriptionId).get(dmiServiceName)
+ .getDmiCmSubscriptionPredicates();
+ for (final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate : dmiCmSubscriptionPredicates) {
+ final DatastoreType datastoreType = dmiCmSubscriptionPredicate.getDatastoreType();
+ final Set<String> cmHandles = dmiCmSubscriptionPredicate.getTargetCmHandleIds();
+ final Set<String> xpaths = dmiCmSubscriptionPredicate.getXpaths();
+
+ for (final String cmHandle: cmHandles) {
+ for (final String xpath: xpaths) {
+ cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandle,
+ xpath, subscriptionId);
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove subscription from database per DMI service name.
+ *
+ * @param subscriptionId String of subscription id
+ * @param dmiServiceName String of dmiServiceName
+ *
+ */
+ public void removeFromDatabase(final String subscriptionId, final String dmiServiceName) {
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates =
+ cmNotificationSubscriptionCache.get(subscriptionId).get(dmiServiceName)
+ .getDmiCmSubscriptionPredicates();
+ for (final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate : dmiCmSubscriptionPredicates) {
+ final DatastoreType datastoreType = dmiCmSubscriptionPredicate.getDatastoreType();
+ final Set<String> cmHandles = dmiCmSubscriptionPredicate.getTargetCmHandleIds();
+ final Set<String> xpaths = dmiCmSubscriptionPredicate.getXpaths();
+
+ for (final String cmHandle: cmHandles) {
+ for (final String xpath: xpaths) {
+ cmSubscriptionPersistenceService.removeCmSubscription(datastoreType,
+ cmHandle, xpath, subscriptionId);
+ }
+ }
+ }
+ }
+
+ private void updateDmiSubscriptionDetailsPerDmi(
+ final String dmiServiceName,
+ final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate,
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi) {
+ if (dmiSubscriptionsPerDmi.containsKey(dmiServiceName)) {
+ dmiSubscriptionsPerDmi.get(dmiServiceName)
+ .getDmiCmSubscriptionPredicates().add(dmiCmSubscriptionPredicate);
+ } else {
+ dmiSubscriptionsPerDmi.put(dmiServiceName,
+ new DmiCmSubscriptionDetails(
+ new ArrayList<>(List.of(dmiCmSubscriptionPredicate)),
+ PENDING));
+ }
+ }
+
+ private Map<String, Set<String>> groupTargetCmHandleIdsByDmi(final List<String> targetCmHandleIds) {
+ final Map<String, Set<String>> targetCmHandlesByDmiServiceNames = new HashMap<>();
+ final Collection<YangModelCmHandle> yangModelCmHandles =
+ inventoryPersistence.getYangModelCmHandles(targetCmHandleIds);
+
+ for (final YangModelCmHandle yangModelCmHandle : yangModelCmHandles) {
+ final String dmiServiceName = yangModelCmHandle.getDmiServiceName();
+ targetCmHandlesByDmiServiceNames.putIfAbsent(dmiServiceName, new HashSet<>());
+ targetCmHandlesByDmiServiceNames.get(dmiServiceName).add(yangModelCmHandle.getId());
+ }
+ return targetCmHandlesByDmiServiceNames;
+ }
+
+ private boolean isAcceptedOrRejected(final DmiCmSubscriptionDetails dmiCmSubscription) {
+ return dmiCmSubscription.getCmSubscriptionStatus().toString().equals("ACCEPTED")
+ || dmiCmSubscription.getCmSubscriptionStatus().toString().equals("REJECTED");
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumer.java
index f635f1a80b..9e90eabbc4 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumer.java
@@ -18,11 +18,9 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.avc;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.cmavc;
import io.cloudevents.CloudEvent;
-import io.cloudevents.core.builder.CloudEventBuilder;
-import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
@@ -33,13 +31,13 @@ import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
/**
- * Listener for AVC events.
+ * Listener for AVC events based on Cm Subscriptions.
*/
@Component
@Slf4j
@RequiredArgsConstructor
@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true)
-public class AvcEventConsumer {
+public class CmAvcEventConsumer {
@Value("${app.ncmp.avc.cm-events-topic}")
@@ -50,15 +48,14 @@ public class AvcEventConsumer {
/**
* Incoming AvcEvent in the form of Consumer Record.
*
- * @param avcEventConsumerRecord Incoming raw consumer record
+ * @param cmAvcEventAsConsumerRecord Incoming raw consumer record
*/
@KafkaListener(topics = "${app.dmi.cm-events.topic}",
containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory")
- public void consumeAndForward(final ConsumerRecord<String, CloudEvent> avcEventConsumerRecord) {
- log.debug("Consuming AVC event {} ...", avcEventConsumerRecord.value());
- final String newEventId = UUID.randomUUID().toString();
- final CloudEvent outgoingAvcEvent =
- CloudEventBuilder.from(avcEventConsumerRecord.value()).withId(newEventId).build();
- eventsPublisher.publishCloudEvent(cmEventsTopicName, newEventId, outgoingAvcEvent);
+ public void consumeAndForward(
+ final ConsumerRecord<String, CloudEvent> cmAvcEventAsConsumerRecord) {
+ final CloudEvent outgoingAvcEvent = cmAvcEventAsConsumerRecord.value();
+ log.debug("Consuming AVC event {} ...", outgoingAvcEvent);
+ eventsPublisher.publishCloudEvent(cmEventsTopicName, outgoingAvcEvent.getId(), outgoingAvcEvent);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapper.java
new file mode 100644
index 0000000000..423c603a92
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapper.java
@@ -0,0 +1,103 @@
+/*
+ * ============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.impl.cmnotificationsubscription.dmi;
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.fromDatastoreName;
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.PENDING;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionKey;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate;
+import org.springframework.stereotype.Component;
+
+@Component
+public class DmiCmSubscriptionDetailsPerDmiMapper {
+
+ /**
+ * Maps Dmi Subscription Keys grouped by Dmi Plugin to DmiCmSubscriptionDetails per Dmi plugin.
+ *
+ * @param subscribersPerDmi Details managed by each dmi plugin
+ * @return Grouped Dmi Subscription details per dmi plugin
+ */
+ public Map<String, DmiCmSubscriptionDetails> toDmiCmSubscriptionsPerDmi(
+ final Map<String, Collection<DmiCmSubscriptionKey>> subscribersPerDmi) {
+
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = new HashMap<>();
+
+ subscribersPerDmi.forEach((dmiPluginName, dmiCmSubscriptionKeys) -> {
+ final Map<DatastoreTypeAndXpath, List<DmiCmSubscriptionKey>> groupedByDatastoreTypeAndXpath =
+ groupByDatastoreTypeAndXpath(dmiCmSubscriptionKeys);
+
+ final List<DmiCmSubscriptionPredicate> dmiSubscriptionPredicates =
+ createDmiCmSubscriptionPredicates(groupedByDatastoreTypeAndXpath);
+
+ final DmiCmSubscriptionDetails dmiCmSubscriptionDetails =
+ new DmiCmSubscriptionDetails(dmiSubscriptionPredicates, PENDING);
+
+ dmiSubscriptionsPerDmi.put(dmiPluginName, dmiCmSubscriptionDetails);
+ });
+
+ return dmiSubscriptionsPerDmi;
+ }
+
+ private static Map<DatastoreTypeAndXpath, List<DmiCmSubscriptionKey>> groupByDatastoreTypeAndXpath(
+ final Collection<DmiCmSubscriptionKey> dmiCmSubscriptionKeys) {
+ return dmiCmSubscriptionKeys.stream().collect(Collectors.groupingBy(
+ datastoreTypeAndXpath -> new DatastoreTypeAndXpath(
+ fromDatastoreName(datastoreTypeAndXpath.datastoreName()), datastoreTypeAndXpath.xpath())));
+ }
+
+ private static List<DmiCmSubscriptionPredicate> createDmiCmSubscriptionPredicates(
+ final Map<DatastoreTypeAndXpath, List<DmiCmSubscriptionKey>> groupedByDatastoreTypeAndXpath) {
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates = new ArrayList<>();
+
+ for (final Map.Entry<DatastoreTypeAndXpath, List<DmiCmSubscriptionKey>> datastoreTypeXpathGroupEntry :
+ groupedByDatastoreTypeAndXpath.entrySet()) {
+ final DatastoreTypeAndXpath datastoreTypeAndXpath = datastoreTypeXpathGroupEntry.getKey();
+ final Set<String> cmHandleIds = new HashSet<>();
+
+ for (final DmiCmSubscriptionKey dmiCmSubscriptionKey : datastoreTypeXpathGroupEntry.getValue()) {
+ cmHandleIds.add(dmiCmSubscriptionKey.cmHandleId());
+ }
+
+ final Set<String> xpaths = Collections.singleton(datastoreTypeAndXpath.xpath());
+ dmiCmSubscriptionPredicates.add(
+ new DmiCmSubscriptionPredicate(cmHandleIds, datastoreTypeAndXpath.datastoreType(), xpaths));
+ }
+
+ return dmiCmSubscriptionPredicates;
+ }
+
+
+ private record DatastoreTypeAndXpath(DatastoreType datastoreType, String xpath) { }
+
+}
+
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapper.java
index 489401f26e..4ce4ef36cf 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapper.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi;
import java.util.ArrayList;
import java.util.HashSet;
@@ -27,46 +27,44 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Cmhandle;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Data;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Predicate;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.ScopeFilter;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.CmHandle;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.Data;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.Predicate;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.ScopeFilter;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
-public class CmNotificationSubscriptionDmiInEventMapper {
+public class DmiInEventMapper {
private final InventoryPersistence inventoryPersistence;
/**
* Mapper to form a request for the DMI Plugin for the Cm Notification Subscription.
*
- * @param dmiCmNotificationSubscriptionPredicates Collection of Cm Notification Subscription predicates
- * @return CmNotificationSubscriptionDmiInEvent to be sent to DMI Plugin
+ * @param dmiCmSubscriptionPredicates Collection of Cm Notification Subscription predicates
+ * @return DmiInEvent to be sent to DMI Plugin
*/
- public CmNotificationSubscriptionDmiInEvent toCmNotificationSubscriptionDmiInEvent(
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) {
- final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent =
- new CmNotificationSubscriptionDmiInEvent();
+ public DmiInEvent toDmiInEvent(final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) {
+ final DmiInEvent dmiInEvent = new DmiInEvent();
final Data cmSubscriptionData = new Data();
- cmSubscriptionData.setPredicates(mapToDmiInEventPredicates(dmiCmNotificationSubscriptionPredicates));
- cmSubscriptionData.setCmhandles(mapToCmSubscriptionCmhandleWithPrivateProperties(
- extractUniqueCmHandleIds(dmiCmNotificationSubscriptionPredicates)));
- cmNotificationSubscriptionDmiInEvent.setData(cmSubscriptionData);
- return cmNotificationSubscriptionDmiInEvent;
+ cmSubscriptionData.setPredicates(mapToDmiInEventPredicates(dmiCmSubscriptionPredicates));
+ cmSubscriptionData.setCmHandles(mapToCmSubscriptionCmHandleWithPrivateProperties(
+ extractUniqueCmHandleIds(dmiCmSubscriptionPredicates)));
+ dmiInEvent.setData(cmSubscriptionData);
+ return dmiInEvent;
}
private List<Predicate> mapToDmiInEventPredicates(
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) {
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) {
final List<Predicate> predicates = new ArrayList<>();
- dmiCmNotificationSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> {
+ dmiCmSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> {
final Predicate predicate = new Predicate();
final ScopeFilter scopeFilter = new ScopeFilter();
scopeFilter.setDatastore(ScopeFilter.Datastore.fromValue(
@@ -81,12 +79,12 @@ public class CmNotificationSubscriptionDmiInEventMapper {
}
- private List<Cmhandle> mapToCmSubscriptionCmhandleWithPrivateProperties(final Set<String> cmHandleIds) {
+ private List<CmHandle> mapToCmSubscriptionCmHandleWithPrivateProperties(final Set<String> cmHandleIds) {
- final List<Cmhandle> cmSubscriptionCmHandles = new ArrayList<>();
+ final List<CmHandle> cmSubscriptionCmHandles = new ArrayList<>();
inventoryPersistence.getYangModelCmHandles(cmHandleIds).forEach(yangModelCmHandle -> {
- final Cmhandle cmhandle = new Cmhandle();
+ final CmHandle cmhandle = new CmHandle();
final Map<String, String> cmhandleDmiProperties = new LinkedHashMap<>();
yangModelCmHandle.getDmiProperties()
.forEach(dmiProperty -> cmhandleDmiProperties.put(dmiProperty.getName(), dmiProperty.getValue()));
@@ -99,11 +97,10 @@ public class CmNotificationSubscriptionDmiInEventMapper {
}
- private Set<String> extractUniqueCmHandleIds(
- final List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates) {
+ private Set<String> extractUniqueCmHandleIds(final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) {
final Set<String> cmHandleIds = new HashSet<>();
- dmiCmNotificationSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> cmHandleIds.addAll(
+ dmiCmSubscriptionPredicates.forEach(dmiCmNotificationSubscriptionPredicate -> cmHandleIds.addAll(
dmiCmNotificationSubscriptionPredicate.getTargetCmHandleIds()));
return cmHandleIds;
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducer.java
index 3273c556c6..c62916f05c 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducer.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.producer;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
@@ -26,7 +26,7 @@ import java.net.URI;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.onap.cps.events.EventsPublisher;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -35,38 +35,36 @@ import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true)
-public class CmNotificationSubscriptionDmiInEventProducer {
+public class DmiInEventProducer {
private final EventsPublisher<CloudEvent> eventsPublisher;
private final JsonObjectMapper jsonObjectMapper;
@Value("${app.ncmp.avc.cm-subscription-dmi-in}")
- private String cmNotificationSubscriptionDmiInEventTopic;
+ private String dmiInEventTopic;
/**
* Publish the event to the provided dmi plugin with key as subscription id and the event is in Cloud Event format.
*
- * @param subscriptionId Cm Subscription Id
- * @param dmiPluginName Dmi Plugin Name
- * @param eventType Type of event
- * @param cmNotificationSubscriptionDmiInEvent Cm Notification Subscription event for Dmi
+ * @param subscriptionId Cm Subscription Id
+ * @param dmiPluginName Dmi Plugin Name
+ * @param eventType Type of event
+ * @param dmiInEvent Cm Notification Subscription event for Dmi
*/
- public void publishCmNotificationSubscriptionDmiInEvent(final String subscriptionId, final String dmiPluginName,
- final String eventType, final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent) {
- eventsPublisher.publishCloudEvent(cmNotificationSubscriptionDmiInEventTopic, subscriptionId,
- buildAndGetCmNotificationDmiInEventAsCloudEvent(subscriptionId, dmiPluginName, eventType,
- cmNotificationSubscriptionDmiInEvent));
+ public void publishDmiInEvent(final String subscriptionId, final String dmiPluginName,
+ final String eventType, final DmiInEvent dmiInEvent) {
+ eventsPublisher.publishCloudEvent(dmiInEventTopic, subscriptionId,
+ buildAndGetDmiInEventAsCloudEvent(subscriptionId, dmiPluginName, eventType, dmiInEvent));
}
- private CloudEvent buildAndGetCmNotificationDmiInEventAsCloudEvent(final String subscriptionId,
- final String dmiPluginName, final String eventType,
- final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent) {
+ private CloudEvent buildAndGetDmiInEventAsCloudEvent(final String subscriptionId,
+ final String dmiPluginName, final String eventType, final DmiInEvent dmiInEvent) {
return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withType(eventType)
.withSource(URI.create("NCMP"))
.withDataSchema(URI.create("org.onap.ncmp.dmi.cm.subscription:1.0.0"))
.withExtension("correlationid", subscriptionId.concat("#").concat(dmiPluginName))
- .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionDmiInEvent)).build();
+ .withData(jsonObjectMapper.asJsonBytes(dmiInEvent)).build();
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumer.java
new file mode 100644
index 0000000000..20c7c7b13d
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumer.java
@@ -0,0 +1,115 @@
+/*
+ * ============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.impl.cmnotificationsubscription.dmi;
+
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_ACCEPTED;
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_DATA_SUBSCRIPTION_REJECTED;
+import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent;
+
+import io.cloudevents.CloudEvent;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.onap.cps.ncmp.api.NcmpResponseStatus;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventMapper;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventProducer;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.Data;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.DmiOutEvent;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class DmiOutEventConsumer {
+
+ private final DmiCacheHandler dmiCacheHandler;
+ private final NcmpOutEventProducer ncmpOutEventProducer;
+ private final NcmpOutEventMapper ncmpOutEventMapper;
+
+ private static final String CM_SUBSCRIPTION_CORRELATION_ID_SEPARATOR = "#";
+
+ /**
+ * Consume the Cm Notification Subscription event from the dmi-plugin.
+ *
+ * @param dmiOutEventAsConsumerRecord the event to be consumed
+ */
+ @KafkaListener(topics = "${app.ncmp.avc.cm-subscription-dmi-out}",
+ containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory")
+ public void consumeDmiOutEvent(final ConsumerRecord<String, CloudEvent> dmiOutEventAsConsumerRecord) {
+ final CloudEvent cloudEvent = dmiOutEventAsConsumerRecord.value();
+ final DmiOutEvent dmiOutEvent = toTargetEvent(cloudEvent, DmiOutEvent.class);
+ final String correlationId = String.valueOf(cloudEvent.getExtension("correlationid"));
+ if (dmiOutEvent != null && correlationId != null) {
+ final String eventType = cloudEvent.getType();
+ handleDmiOutEvent(correlationId, eventType, dmiOutEvent);
+ }
+ }
+
+ private void handleDmiOutEvent(final String correlationId, final String eventType,
+ final DmiOutEvent dmiOutEvent) {
+ final String subscriptionId = correlationId.split(CM_SUBSCRIPTION_CORRELATION_ID_SEPARATOR)[0];
+ final String dmiPluginName = correlationId.split(CM_SUBSCRIPTION_CORRELATION_ID_SEPARATOR)[1];
+
+ if (checkStatusCodeAndMessage(CM_DATA_SUBSCRIPTION_ACCEPTED, dmiOutEvent.getData())) {
+ handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmSubscriptionStatus.ACCEPTED);
+ if (eventType.equals("subscriptionCreateResponse")) {
+ dmiCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName);
+ }
+ if (eventType.equals("subscriptionDeleteResponse")) {
+ dmiCacheHandler.removeFromDatabase(subscriptionId, dmiPluginName);
+ }
+ handleEventsStatusPerDmi(subscriptionId, eventType);
+ }
+
+ if (checkStatusCodeAndMessage(CM_DATA_SUBSCRIPTION_REJECTED, dmiOutEvent.getData())) {
+ handleCacheStatusPerDmi(subscriptionId, dmiPluginName, CmSubscriptionStatus.REJECTED);
+ handleEventsStatusPerDmi(subscriptionId, eventType);
+ }
+
+ log.info("Cm Subscription with id : {} handled by the dmi-plugin : {} has the status : {}", subscriptionId,
+ dmiPluginName, dmiOutEvent.getData().getStatusMessage());
+ }
+
+ private void handleCacheStatusPerDmi(final String subscriptionId, final String dmiPluginName,
+ final CmSubscriptionStatus cmSubscriptionStatus) {
+ dmiCacheHandler.updateDmiSubscriptionStatus(subscriptionId, dmiPluginName,
+ cmSubscriptionStatus);
+ }
+
+ private void handleEventsStatusPerDmi(final String subscriptionId, final String eventType) {
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi = dmiCacheHandler.get(subscriptionId);
+ final NcmpOutEvent ncmpOutEvent = ncmpOutEventMapper.toNcmpOutEvent(subscriptionId, dmiSubscriptionsPerDmi);
+ ncmpOutEventProducer.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, false);
+ }
+
+ private boolean checkStatusCodeAndMessage(final NcmpResponseStatus ncmpResponseStatus,
+ final Data dmiOutData) {
+ return ncmpResponseStatus.getCode().equals(dmiOutData.getStatusCode())
+ && ncmpResponseStatus.getMessage()
+ .equals(dmiOutData.getStatusMessage());
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/CmNotificationSubscriptionStatus.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/CmSubscriptionStatus.java
index 68d54fac95..5b7c46ed00 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/CmNotificationSubscriptionStatus.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/CmSubscriptionStatus.java
@@ -18,15 +18,15 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.model;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.models;
-public enum CmNotificationSubscriptionStatus {
+public enum CmSubscriptionStatus {
ACCEPTED("ACCEPTED"), REJECTED("REJECTED"), PENDING("PENDING");
private final String cmNotificationSubscriptionStatusValue;
- CmNotificationSubscriptionStatus(final String cmNotificationSubscriptionStatusValue) {
+ CmSubscriptionStatus(final String cmNotificationSubscriptionStatusValue) {
this.cmNotificationSubscriptionStatusValue = cmNotificationSubscriptionStatusValue;
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionDetails.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionDetails.java
index 95757e7240..dbc607ad27 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionDetails.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionDetails.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.model;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.models;
import java.util.List;
import lombok.AllArgsConstructor;
@@ -28,8 +28,8 @@ import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
-public class DmiCmNotificationSubscriptionDetails {
+public class DmiCmSubscriptionDetails {
- private List<DmiCmNotificationSubscriptionPredicate> dmiCmNotificationSubscriptionPredicates;
- private CmNotificationSubscriptionStatus cmNotificationSubscriptionStatus;
+ private List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates;
+ private CmSubscriptionStatus cmSubscriptionStatus;
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionKey.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionKey.java
new file mode 100644
index 0000000000..edc3c566be
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionKey.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.impl.cmnotificationsubscription.models;
+
+/**
+ * Key used to find the records to be sent to the DMI plugin.
+ *
+ * @param datastoreName datastore name
+ * @param cmHandleId cmhandle id
+ * @param xpath xpath
+ */
+public record DmiCmSubscriptionKey(String datastoreName, String cmHandleId, String xpath) { }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionPredicate.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionPredicate.java
index 9c4c3f64e3..84d3aead8c 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/model/DmiCmNotificationSubscriptionPredicate.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionPredicate.java
@@ -18,18 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.model;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.models;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
@Getter
@Setter
@AllArgsConstructor
-public class DmiCmNotificationSubscriptionPredicate {
+public class DmiCmSubscriptionPredicate {
private Set<String> targetCmHandleIds;
private DatastoreType datastoreType;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionTuple.java
index 340806b892..cd4a15af47 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyQueryService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/models/DmiCmSubscriptionTuple.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * 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.
@@ -15,27 +15,20 @@
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
+ * ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.models;
-import org.onap.cps.spi.FetchDescendantsOption;
+import java.util.Collection;
+import java.util.Map;
-/*
- * Datastore interface for handling cached CPS data query requests.
+/**
+ * Tuple to be used during for to delete usecase.
+ *
+ * @param lastRemainingSubscriptionsPerDmi subscriptions that are used by only one subscriber grouped per dmi
+ * @param overlappingSubscriptionsPerDmi subscriptions that are shared by multiple subscribers grouped per dmi
*/
-public interface NetworkCmProxyQueryService {
-
- /**
- * Get resource data for operational.
- *
- * @param cmHandleId cm handle identifier
- * @param cpsPath cps path
- * @Link FetchDescendantsOption fetch descendants option
- * @return {@code Object} resource data
- */
- Object queryResourceDataOperational(String cmHandleId,
- String cpsPath,
- FetchDescendantsOption fetchDescendantsOption);
+public record DmiCmSubscriptionTuple(Map<String, Collection<DmiCmSubscriptionKey>> lastRemainingSubscriptionsPerDmi,
+ Map<String, Collection<DmiCmSubscriptionKey>> overlappingSubscriptionsPerDmi) {
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java
new file mode 100644
index 0000000000..d7f15a2c72
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java
@@ -0,0 +1,83 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class CmSubscriptionComparator {
+
+ private final CmSubscriptionPersistenceService cmSubscriptionPersistenceService;
+
+ /**
+ * Get the new Dmi Predicates for a given predicates list.
+ *
+ * @param existingDmiCmSubscriptionPredicates list of DmiCmNotificationSubscriptionPredicates
+ * @return new list of DmiCmNotificationSubscriptionPredicates
+ */
+ public List<DmiCmSubscriptionPredicate> getNewDmiSubscriptionPredicates(
+ final List<DmiCmSubscriptionPredicate> existingDmiCmSubscriptionPredicates) {
+ final List<DmiCmSubscriptionPredicate> newDmiCmSubscriptionPredicates =
+ new ArrayList<>();
+
+ for (final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate : existingDmiCmSubscriptionPredicates) {
+
+ final Set<String> targetCmHandleIds = new HashSet<>();
+ final Set<String> xpaths = new HashSet<>();
+ final DatastoreType datastoreType = dmiCmSubscriptionPredicate.getDatastoreType();
+
+ for (final String cmHandleId : dmiCmSubscriptionPredicate.getTargetCmHandleIds()) {
+ for (final String xpath : dmiCmSubscriptionPredicate.getXpaths()) {
+ if (!cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType,
+ cmHandleId, xpath)) {
+ xpaths.add(xpath);
+ targetCmHandleIds.add(cmHandleId);
+
+ }
+ }
+ }
+
+ populateValidDmiSubscriptionPredicates(targetCmHandleIds, xpaths, datastoreType,
+ newDmiCmSubscriptionPredicates);
+ }
+ return newDmiCmSubscriptionPredicates;
+ }
+
+ private void populateValidDmiSubscriptionPredicates(final Set<String> targetCmHandleIds,
+ final Set<String> xpaths, final DatastoreType datastoreType,
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) {
+ if (!(targetCmHandleIds.isEmpty() || xpaths.isEmpty())) {
+ final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate =
+ new DmiCmSubscriptionPredicate(targetCmHandleIds, datastoreType, xpaths);
+ dmiCmSubscriptionPredicates.add(dmiCmSubscriptionPredicate);
+ }
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandler.java
index 536693ee4e..90c5c575e6 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandler.java
@@ -18,18 +18,26 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.service;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent;
+import java.util.List;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate;
-public interface CmNotificationSubscriptionHandlerService {
+public interface CmSubscriptionHandler {
/**
- * Process cm notification subscription request.
+ * Process cm notification subscription create request.
*
- * @param cmNotificationSubscriptionNcmpInEvent CM Notification Subscription event
+ * @param subscriptionId subscription id
+ * @param predicates subscription predicates
*/
- void processSubscriptionCreateRequest(
- final CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent);
+ void processSubscriptionCreateRequest(final String subscriptionId, final List<Predicate> predicates);
-}
+ /**
+ * Process cm notification subscription delete request.
+ *
+ * @param subscriptionId subscription id
+ */
+ void processSubscriptionDeleteRequest(final String subscriptionId);
+
+} \ No newline at end of file
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImpl.java
new file mode 100644
index 0000000000..1cdc7ed3e0
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImpl.java
@@ -0,0 +1,229 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiCmSubscriptionDetailsPerDmiMapper;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventMapper;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventProducer;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionKey;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionTuple;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.spi.model.DataNode;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class CmSubscriptionHandlerImpl implements CmSubscriptionHandler {
+
+ private static final Pattern SUBSCRIPTION_KEY_FROM_XPATH_PATTERN = Pattern.compile(
+ "^/datastores/datastore\\[@name='([^']*)']/cm-handles/cm-handle\\[@id='([^']*)']/"
+ + "filters/filter\\[@xpath='(.*)']$");
+
+ private final CmSubscriptionPersistenceService cmSubscriptionPersistenceService;
+ private final CmSubscriptionComparator cmSubscriptionComparator;
+ private final NcmpOutEventMapper ncmpOutEventMapper;
+ private final DmiInEventMapper dmiInEventMapper;
+ private final DmiCmSubscriptionDetailsPerDmiMapper dmiCmSubscriptionDetailsPerDmiMapper;
+ private final NcmpOutEventProducer ncmpOutEventProducer;
+ private final DmiInEventProducer dmiInEventProducer;
+ private final DmiCacheHandler dmiCacheHandler;
+ private final InventoryPersistence inventoryPersistence;
+
+ @Override
+ public void processSubscriptionCreateRequest(final String subscriptionId, final List<Predicate> predicates) {
+ if (cmSubscriptionPersistenceService.isUniqueSubscriptionId(subscriptionId)) {
+ dmiCacheHandler.add(subscriptionId, predicates);
+ handleNewCmSubscription(subscriptionId);
+ scheduleNcmpOutEventResponse(subscriptionId, "subscriptionCreateResponse");
+ } else {
+ rejectAndPublishCreateRequest(subscriptionId, predicates);
+ }
+ }
+
+ @Override
+ public void processSubscriptionDeleteRequest(final String subscriptionId) {
+ final Collection<DataNode> subscriptionDataNodes =
+ cmSubscriptionPersistenceService.getAllNodesForSubscriptionId(subscriptionId);
+ final DmiCmSubscriptionTuple dmiCmSubscriptionTuple =
+ getLastRemainingAndOverlappingSubscriptionsPerDmi(subscriptionDataNodes);
+ dmiCacheHandler.add(subscriptionId, mergeDmiCmSubscriptionDetailsPerDmiMaps(dmiCmSubscriptionTuple));
+ if (dmiCmSubscriptionTuple.lastRemainingSubscriptionsPerDmi().isEmpty()) {
+ acceptAndPublishDeleteRequest(subscriptionId);
+ } else {
+ sendSubscriptionDeleteRequestToDmi(subscriptionId,
+ dmiCmSubscriptionDetailsPerDmiMapper.toDmiCmSubscriptionsPerDmi(
+ dmiCmSubscriptionTuple.lastRemainingSubscriptionsPerDmi()));
+ scheduleNcmpOutEventResponse(subscriptionId, "subscriptionDeleteResponse");
+ }
+ }
+
+ private Map<String, DmiCmSubscriptionDetails> mergeDmiCmSubscriptionDetailsPerDmiMaps(
+ final DmiCmSubscriptionTuple dmiCmSubscriptionTuple) {
+ final Map<String, DmiCmSubscriptionDetails> lastRemainingDmiSubscriptionsPerDmi =
+ dmiCmSubscriptionDetailsPerDmiMapper.toDmiCmSubscriptionsPerDmi(
+ dmiCmSubscriptionTuple.lastRemainingSubscriptionsPerDmi());
+ final Map<String, DmiCmSubscriptionDetails> overlappingDmiSubscriptionsPerDmi =
+ dmiCmSubscriptionDetailsPerDmiMapper.toDmiCmSubscriptionsPerDmi(
+ dmiCmSubscriptionTuple.overlappingSubscriptionsPerDmi());
+ final Map<String, DmiCmSubscriptionDetails> mergedDmiSubscriptionsPerDmi =
+ new HashMap<>(lastRemainingDmiSubscriptionsPerDmi);
+ overlappingDmiSubscriptionsPerDmi.forEach((dmiServiceName, dmiCmSubscriptionDetails) ->
+ mergedDmiSubscriptionsPerDmi.merge(dmiServiceName, dmiCmSubscriptionDetails,
+ this::mergeDmiCmSubscriptionDetails));
+ return mergedDmiSubscriptionsPerDmi;
+ }
+
+ private DmiCmSubscriptionDetails mergeDmiCmSubscriptionDetails(
+ final DmiCmSubscriptionDetails dmiCmSubscriptionDetails,
+ final DmiCmSubscriptionDetails otherDmiCmSubscriptionDetails) {
+ final List<DmiCmSubscriptionPredicate> mergedDmiCmSubscriptionPredicates =
+ new ArrayList<>(dmiCmSubscriptionDetails.getDmiCmSubscriptionPredicates());
+ mergedDmiCmSubscriptionPredicates.addAll(otherDmiCmSubscriptionDetails.getDmiCmSubscriptionPredicates());
+ return new DmiCmSubscriptionDetails(mergedDmiCmSubscriptionPredicates, CmSubscriptionStatus.PENDING);
+ }
+
+ private void scheduleNcmpOutEventResponse(final String subscriptionId, final String eventType) {
+ ncmpOutEventProducer.publishNcmpOutEvent(subscriptionId, eventType, null, true);
+ }
+
+ private void rejectAndPublishCreateRequest(final String subscriptionId, final List<Predicate> predicates) {
+ final Set<String> subscriptionTargetFilters =
+ predicates.stream().flatMap(predicate -> predicate.getTargetFilter().stream())
+ .collect(Collectors.toSet());
+ final NcmpOutEvent ncmpOutEvent = ncmpOutEventMapper.toNcmpOutEventForRejectedRequest(subscriptionId,
+ new ArrayList<>(subscriptionTargetFilters));
+ ncmpOutEventProducer.publishNcmpOutEvent(subscriptionId, "subscriptionCreateResponse", ncmpOutEvent, false);
+ }
+
+ private void acceptAndPublishDeleteRequest(final String subscriptionId) {
+ final Set<String> dmiServiceNames = dmiCacheHandler.get(subscriptionId).keySet();
+ for (final String dmiServiceName : dmiServiceNames) {
+ dmiCacheHandler.updateDmiSubscriptionStatus(subscriptionId, dmiServiceName,
+ CmSubscriptionStatus.ACCEPTED);
+ dmiCacheHandler.removeFromDatabase(subscriptionId, dmiServiceName);
+ }
+ final NcmpOutEvent ncmpOutEvent = ncmpOutEventMapper.toNcmpOutEvent(subscriptionId,
+ dmiCacheHandler.get(subscriptionId));
+ ncmpOutEventProducer.publishNcmpOutEvent(subscriptionId, "subscriptionDeleteResponse", ncmpOutEvent,
+ false);
+ }
+
+ private void handleNewCmSubscription(final String subscriptionId) {
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi =
+ dmiCacheHandler.get(subscriptionId);
+ dmiSubscriptionsPerDmi.forEach((dmiPluginName, dmiSubscriptionDetails) -> {
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates =
+ cmSubscriptionComparator.getNewDmiSubscriptionPredicates(
+ dmiSubscriptionDetails.getDmiCmSubscriptionPredicates());
+
+ if (dmiCmSubscriptionPredicates.isEmpty()) {
+ acceptAndPersistCmSubscriptionPerDmi(subscriptionId, dmiPluginName);
+ } else {
+ publishDmiInEventPerDmi(subscriptionId, dmiPluginName, dmiCmSubscriptionPredicates);
+ }
+ });
+ }
+
+ private void publishDmiInEventPerDmi(final String subscriptionId, final String dmiPluginName,
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) {
+ final DmiInEvent dmiInEvent = dmiInEventMapper.toDmiInEvent(dmiCmSubscriptionPredicates);
+ dmiInEventProducer.publishDmiInEvent(subscriptionId, dmiPluginName,
+ "subscriptionCreateRequest", dmiInEvent);
+ }
+
+ private void acceptAndPersistCmSubscriptionPerDmi(final String subscriptionId, final String dmiPluginName) {
+ dmiCacheHandler.updateDmiSubscriptionStatus(subscriptionId, dmiPluginName,
+ CmSubscriptionStatus.ACCEPTED);
+ dmiCacheHandler.persistIntoDatabasePerDmi(subscriptionId, dmiPluginName);
+ }
+
+ private void sendSubscriptionDeleteRequestToDmi(final String subscriptionId,
+ final Map<String, DmiCmSubscriptionDetails>
+ dmiCmSubscriptionsPerDmi) {
+ dmiCmSubscriptionsPerDmi.forEach((dmiPluginName, dmiCmSubscriptionDetails) -> {
+ final DmiInEvent dmiInEvent =
+ dmiInEventMapper.toDmiInEvent(
+ dmiCmSubscriptionDetails.getDmiCmSubscriptionPredicates());
+ dmiInEventProducer.publishDmiInEvent(subscriptionId,
+ dmiPluginName, "subscriptionDeleteRequest", dmiInEvent);
+ });
+ }
+
+
+ private DmiCmSubscriptionTuple getLastRemainingAndOverlappingSubscriptionsPerDmi(
+ final Collection<DataNode> subscriptionNodes) {
+ final Map<String, Collection<DmiCmSubscriptionKey>> lastRemainingSubscriptionsPerDmi = new HashMap<>();
+ final Map<String, Collection<DmiCmSubscriptionKey>> overlappingSubscriptionsPerDmi = new HashMap<>();
+
+ for (final DataNode subscriptionNode : subscriptionNodes) {
+ final DmiCmSubscriptionKey dmiCmSubscriptionKey = extractCmSubscriptionKey(subscriptionNode.getXpath());
+ final String dmiServiceName = inventoryPersistence.getYangModelCmHandle(
+ dmiCmSubscriptionKey.cmHandleId()).getDmiServiceName();
+ final List<String> subscribers = (List<String>) subscriptionNode.getLeaves().get("subscriptionIds");
+ populateDmiCmSubscriptionTuple(subscribers, overlappingSubscriptionsPerDmi,
+ lastRemainingSubscriptionsPerDmi, dmiServiceName, dmiCmSubscriptionKey);
+ }
+ return new DmiCmSubscriptionTuple(lastRemainingSubscriptionsPerDmi, overlappingSubscriptionsPerDmi);
+ }
+
+ private static void populateDmiCmSubscriptionTuple(final List<String> subscribers,
+ final Map<String, Collection<DmiCmSubscriptionKey>>
+ overlappingSubscriptionsPerDmi,
+ final Map<String, Collection<DmiCmSubscriptionKey>>
+ lastRemainingSubscriptionsPerDmi,
+ final String dmiServiceName,
+ final DmiCmSubscriptionKey dmiCmSubscriptionKey) {
+ final Map<String, Collection<DmiCmSubscriptionKey>> targetMap =
+ subscribers.size() > 1 ? overlappingSubscriptionsPerDmi : lastRemainingSubscriptionsPerDmi;
+ targetMap.computeIfAbsent(dmiServiceName, dmiName -> new HashSet<>()).add(dmiCmSubscriptionKey);
+ }
+
+ private DmiCmSubscriptionKey extractCmSubscriptionKey(final String xpath) {
+ final Matcher matcher = SUBSCRIPTION_KEY_FROM_XPATH_PATTERN.matcher(xpath);
+ if (matcher.find()) {
+ final String datastoreName = matcher.group(1);
+ final String cmHandleId = matcher.group(2);
+ final String filterXpath = matcher.group(3);
+ return new DmiCmSubscriptionKey(datastoreName, cmHandleId, filterXpath);
+ }
+ throw new IllegalArgumentException("DataNode xpath does not represent a subscription key");
+ }
+
+} \ No newline at end of file
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumer.java
index 2c544b7b6a..cba64e0e94 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumer.java
@@ -18,45 +18,52 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer;
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp;
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent;
+import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent;
import io.cloudevents.CloudEvent;
+import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionHandlerService;
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Predicate;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
-public class CmNotificationSubscriptionNcmpInEventConsumer {
+public class NcmpInEventConsumer {
- private final CmNotificationSubscriptionHandlerService cmNotificationSubscriptionHandlerService;
+ private final CmSubscriptionHandler cmSubscriptionHandler;
/**
* Consume the specified event.
*
- * @param subscriptionEventConsumerRecord the event to be consumed
+ * @param ncmpInEventAsConsumerRecord the event to be consumed
*/
@KafkaListener(topics = "${app.ncmp.avc.cm-subscription-ncmp-in}",
containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory")
- public void consumeSubscriptionEvent(final ConsumerRecord<String, CloudEvent> subscriptionEventConsumerRecord) {
- final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value();
- final CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent =
- toTargetEvent(cloudEvent, CmNotificationSubscriptionNcmpInEvent.class);
+ public void consumeSubscriptionEvent(final ConsumerRecord<String, CloudEvent> ncmpInEventAsConsumerRecord) {
+ final CloudEvent cloudEvent = ncmpInEventAsConsumerRecord.value();
+ final NcmpInEvent ncmpInEvent =
+ toTargetEvent(cloudEvent, NcmpInEvent.class);
log.info("Subscription with name {} to be mapped to hazelcast object...",
- cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId());
+ ncmpInEvent.getData().getSubscriptionId());
- final String subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId();
+ final String subscriptionId = ncmpInEvent.getData().getSubscriptionId();
+ final List<Predicate> predicates = ncmpInEvent.getData().getPredicates();
if ("subscriptionCreateRequest".equals(cloudEvent.getType())) {
- log.info("Subscription for source {} with subscription id {} ...", cloudEvent.getSource(), subscriptionId);
- cmNotificationSubscriptionHandlerService.processSubscriptionCreateRequest(
- cmNotificationSubscriptionNcmpInEvent);
+ log.info("Subscription create request for source {} with subscription id {} ...",
+ cloudEvent.getSource(), subscriptionId);
+ cmSubscriptionHandler.processSubscriptionCreateRequest(subscriptionId, predicates);
+ }
+ if ("subscriptionDeleteRequest".equals(cloudEvent.getType())) {
+ log.info("Subscription delete request for source {} with subscription id {} ...",
+ cloudEvent.getSource(), subscriptionId);
+ cmSubscriptionHandler.processSubscriptionDeleteRequest(subscriptionId);
}
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapper.java
new file mode 100644
index 0000000000..afff9d1298
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapper.java
@@ -0,0 +1,114 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.Data;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class NcmpOutEventMapper {
+
+ /**
+ * Mapper to form a response for the client for the Cm Notification Subscription.
+ *
+ * @param subscriptionId Cm Notification Subscription Id
+ * @param dmiSubscriptionsPerDmi contains CmNotificationSubscriptionDetails per dmi plugin
+ * @return CmNotificationSubscriptionNcmpOutEvent to sent back to the client
+ */
+ public NcmpOutEvent toNcmpOutEvent(final String subscriptionId,
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi) {
+
+ final NcmpOutEvent ncmpOutEvent = new NcmpOutEvent();
+ final Data cmSubscriptionData = new Data();
+ cmSubscriptionData.setSubscriptionId(subscriptionId);
+ populateNcmpOutEventWithCmHandleIds(dmiSubscriptionsPerDmi,
+ cmSubscriptionData);
+ ncmpOutEvent.setData(cmSubscriptionData);
+
+ return ncmpOutEvent;
+ }
+
+ /**
+ * Mapper to form a rejected response for the client for the Cm Notification Subscription Request.
+ *
+ * @param subscriptionId subscription id
+ * @param rejectedTargetFilters list of rejected target filters for the subscription request
+ * @return to sent back to the client
+ */
+ public NcmpOutEvent toNcmpOutEventForRejectedRequest(final String subscriptionId,
+ final List<String> rejectedTargetFilters) {
+ final NcmpOutEvent ncmpOutEvent = new NcmpOutEvent();
+ final Data cmSubscriptionData = new Data();
+ cmSubscriptionData.setSubscriptionId(subscriptionId);
+ cmSubscriptionData.setRejectedTargets(rejectedTargetFilters);
+ ncmpOutEvent.setData(cmSubscriptionData);
+ return ncmpOutEvent;
+ }
+
+ private void populateNcmpOutEventWithCmHandleIds(
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi,
+ final Data cmSubscriptionData) {
+
+ final Collection<String> acceptedCmHandleIds = new HashSet<>();
+ final Collection<String> pendingCmHandleIds = new HashSet<>();
+ final Collection<String> rejectedCmHandleIds = new HashSet<>();
+
+ dmiSubscriptionsPerDmi.forEach((dmiPluginName, dmiSubscriptionDetails) -> {
+ final CmSubscriptionStatus cmSubscriptionStatus =
+ dmiSubscriptionDetails.getCmSubscriptionStatus();
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates =
+ dmiSubscriptionDetails.getDmiCmSubscriptionPredicates();
+
+ switch (cmSubscriptionStatus) {
+ case ACCEPTED -> acceptedCmHandleIds.addAll(
+ extractCmHandleIds(dmiCmSubscriptionPredicates));
+ case PENDING -> pendingCmHandleIds.addAll(extractCmHandleIds(dmiCmSubscriptionPredicates));
+ default -> rejectedCmHandleIds.addAll(extractCmHandleIds(dmiCmSubscriptionPredicates));
+ }
+ });
+
+ cmSubscriptionData.setAcceptedTargets(acceptedCmHandleIds);
+ cmSubscriptionData.setPendingTargets(pendingCmHandleIds);
+ cmSubscriptionData.setRejectedTargets(rejectedCmHandleIds);
+
+ }
+
+ private List<String> extractCmHandleIds(
+ final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) {
+ final List<String> cmHandleIds = new ArrayList<>();
+ dmiCmSubscriptionPredicates.forEach(dmiSubscriptionPredicate -> cmHandleIds.addAll(
+ dmiSubscriptionPredicate.getTargetCmHandleIds()));
+
+ return cmHandleIds;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducer.java
new file mode 100644
index 0000000000..3371d59f7a
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducer.java
@@ -0,0 +1,139 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp;
+
+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.impl.cmnotificationsubscription.cache.DmiCacheHandler;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true)
+public class NcmpOutEventProducer {
+
+ @Value("${app.ncmp.avc.cm-subscription-ncmp-out}")
+ private String ncmpOutEventTopic;
+
+ @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms}")
+ private Integer dmiOutEventTimeoutInMs;
+
+ private final EventsPublisher<CloudEvent> eventsPublisher;
+ private final JsonObjectMapper jsonObjectMapper;
+ private final NcmpOutEventMapper ncmpOutEventMapper;
+ private final DmiCacheHandler dmiCacheHandler;
+ private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+ private static final Map<String, ScheduledFuture<?>> scheduledTasksPerSubscriptionIdAndEventType =
+ 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 ncmpOutEvent Cm Notification Subscription Event for the
+ * client
+ * @param isScheduledEvent Determines if the event is to be scheduled
+ * or published now
+ */
+ public void publishNcmpOutEvent(final String subscriptionId, final String eventType,
+ final NcmpOutEvent ncmpOutEvent, final boolean isScheduledEvent) {
+
+ final String taskKey = subscriptionId.concat(eventType);
+
+ if (isScheduledEvent && !scheduledTasksPerSubscriptionIdAndEventType.containsKey(taskKey)) {
+ final ScheduledFuture<?> scheduledFuture = scheduleAndPublishNcmpOutEvent(subscriptionId, eventType);
+ scheduledTasksPerSubscriptionIdAndEventType.putIfAbsent(taskKey, scheduledFuture);
+ log.debug("Scheduled the Cm Subscription Event for subscriptionId : {} and eventType : {}", subscriptionId,
+ eventType);
+ } else {
+ cancelScheduledTask(taskKey);
+ if (ncmpOutEvent != null) {
+ publishNcmpOutEventNow(subscriptionId, eventType, ncmpOutEvent);
+ log.debug("Published Cm Subscription Event on demand for subscriptionId : {} and eventType : {}",
+ subscriptionId, eventType);
+ }
+ }
+ }
+
+ private ScheduledFuture<?> scheduleAndPublishNcmpOutEvent(final String subscriptionId, final String eventType) {
+ final NcmpOutEventPublishingTask ncmpOutEventPublishingTask =
+ new NcmpOutEventPublishingTask(ncmpOutEventTopic, subscriptionId, eventType, eventsPublisher,
+ jsonObjectMapper, ncmpOutEventMapper, dmiCacheHandler);
+ return scheduledExecutorService.schedule(ncmpOutEventPublishingTask, dmiOutEventTimeoutInMs,
+ TimeUnit.MILLISECONDS);
+ }
+
+ private void cancelScheduledTask(final String taskKey) {
+
+ final ScheduledFuture<?> scheduledFuture = scheduledTasksPerSubscriptionIdAndEventType.get(taskKey);
+ if (scheduledFuture != null) {
+ scheduledFuture.cancel(true);
+ scheduledTasksPerSubscriptionIdAndEventType.remove(taskKey);
+ }
+
+ }
+
+
+ private void publishNcmpOutEventNow(final String subscriptionId, final String eventType,
+ final NcmpOutEvent ncmpOutEvent) {
+ final CloudEvent ncmpOutEventAsCloudEvent =
+ buildAndGetNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType, ncmpOutEvent);
+ eventsPublisher.publishCloudEvent(ncmpOutEventTopic, subscriptionId, ncmpOutEventAsCloudEvent);
+ dmiCacheHandler.removeAcceptedAndRejectedDmiSubscriptionEntries(subscriptionId);
+ }
+
+ /**
+ * Get an NCMP out event as cloud event.
+ *
+ * @param jsonObjectMapper JSON object mapper
+ * @param subscriptionId subscription id
+ * @param eventType event type
+ * @param ncmpOutEvent cm notification subscription NCMP out event
+ * @return cm notification subscription NCMP out event as cloud event
+ */
+ public static CloudEvent buildAndGetNcmpOutEventAsCloudEvent(final JsonObjectMapper jsonObjectMapper,
+ final String subscriptionId, final String eventType, final NcmpOutEvent ncmpOutEvent) {
+
+ 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(ncmpOutEvent)).build();
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventPublishingTask.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventPublishingTask.java
new file mode 100644
index 0000000000..f8f253d275
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventPublishingTask.java
@@ -0,0 +1,62 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp;
+
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventProducer.buildAndGetNcmpOutEventAsCloudEvent;
+
+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.impl.cmnotificationsubscription.cache.DmiCacheHandler;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails;
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent;
+import org.onap.cps.utils.JsonObjectMapper;
+
+@Slf4j
+@RequiredArgsConstructor
+public class NcmpOutEventPublishingTask 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 NcmpOutEventMapper ncmpOutEventMapper;
+ private final DmiCacheHandler dmiCacheHandler;
+
+ /**
+ * Delegating the responsibility of publishing NcmpOutEvent as a separate task which will
+ * be called after a specified delay.
+ */
+ @Override
+ public void run() {
+ final Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi =
+ dmiCacheHandler.get(subscriptionId);
+ final NcmpOutEvent ncmpOutEvent = ncmpOutEventMapper.toNcmpOutEvent(subscriptionId,
+ dmiSubscriptionsPerDmi);
+ eventsPublisher.publishCloudEvent(topicName, subscriptionId,
+ buildAndGetNcmpOutEventAsCloudEvent(jsonObjectMapper, subscriptionId, eventType,
+ ncmpOutEvent));
+ dmiCacheHandler.removeAcceptedAndRejectedDmiSubscriptionEntries(subscriptionId);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceService.java
new file mode 100644
index 0000000000..6b5ed908b8
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceService.java
@@ -0,0 +1,244 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
+ * ================================================================================
+ * 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.impl.cmnotificationsubscription.utils;
+
+import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY;
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
+
+import java.io.Serializable;
+import java.time.OffsetDateTime;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.api.CpsDataService;
+import org.onap.cps.api.CpsQueryService;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.spi.model.DataNode;
+import org.onap.cps.utils.ContentType;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class CmSubscriptionPersistenceService {
+
+ private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
+ private static final String CM_SUBSCRIPTIONS_ANCHOR_NAME = "cm-data-subscriptions";
+
+ private static final String SUBSCRIPTION_ANCHOR_NAME = "cm-data-subscriptions";
+ private static final String CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_AND_CMHANDLE = """
+ /datastores/datastore[@name='%s']/cm-handles/cm-handle[@id='%s']
+ """.trim();
+ private static final String CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE =
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_AND_CMHANDLE + "/filters";
+
+ private static final String CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH =
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE + "/filter[@xpath='%s']";
+
+
+ private static final String CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID = """
+ //filter/subscriptionIds[text()='%s']
+ """.trim();
+
+ private final JsonObjectMapper jsonObjectMapper;
+ private final CpsQueryService cpsQueryService;
+ private final CpsDataService cpsDataService;
+
+ /**
+ * Check if we have an ongoing cm subscription based on the parameters.
+ *
+ * @param datastoreType the susbcription target datastore type
+ * @param cmHandleId the id of the cm handle for the susbcription
+ * @param xpath the target xpath
+ * @return true for ongoing cmsubscription , otherwise false
+ */
+ public boolean isOngoingCmSubscription(final DatastoreType datastoreType, final String cmHandleId,
+ final String xpath) {
+ return !getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).isEmpty();
+ }
+
+ /**
+ * Check if the subscription ID is unique against ongoing subscriptions.
+ *
+ * @param subscriptionId subscription ID
+ * @return true if subscriptionId is not used in active subscriptions, otherwise false
+ */
+ public boolean isUniqueSubscriptionId(final String subscriptionId) {
+ return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID.formatted(subscriptionId), OMIT_DESCENDANTS).isEmpty();
+ }
+
+ /**
+ * Get all ongoing cm notification subscription based on the parameters.
+ *
+ * @param datastoreType the susbcription target datastore type
+ * @param cmHandleId the id of the cm handle for the susbcription
+ * @param xpath the target xpath
+ * @return collection of subscription ids of ongoing cm notification subscription
+ */
+ public Collection<String> getOngoingCmSubscriptionIds(final DatastoreType datastoreType,
+ final String cmHandleId, final String xpath) {
+
+ final String isOngoingCmSubscriptionCpsPathQuery =
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted(
+ datastoreType.getDatastoreName(), cmHandleId, escapeQuotesByDoublingThem(xpath));
+ final Collection<DataNode> existingNodes =
+ cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME,
+ isOngoingCmSubscriptionCpsPathQuery, OMIT_DESCENDANTS);
+ if (existingNodes.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return (List<String>) existingNodes.iterator().next().getLeaves().get("subscriptionIds");
+ }
+
+ /**
+ * Add cm notification subscription.
+ *
+ * @param datastoreType the susbcription target datastore type
+ * @param cmHandleId the id of the cm handle for the susbcription
+ * @param xpath the target xpath
+ * @param newSubscriptionId subscription id to be added
+ */
+ public void addCmSubscription(final DatastoreType datastoreType, final String cmHandleId,
+ final String xpath, final String newSubscriptionId) {
+ final Collection<String> subscriptionIds =
+ getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath);
+ if (subscriptionIds.isEmpty()) {
+ addFirstSubscriptionForDatastoreCmHandleAndXpath(datastoreType, cmHandleId, xpath, newSubscriptionId);
+ } else if (!subscriptionIds.contains(newSubscriptionId)) {
+ subscriptionIds.add(newSubscriptionId);
+ saveSubscriptionDetails(datastoreType, cmHandleId, xpath, subscriptionIds);
+ }
+ }
+
+ /**
+ * Remove cm notification Subscription.
+ *
+ * @param datastoreType the susbcription target datastore type
+ * @param cmHandleId the id of the cm handle for the susbcription
+ * @param xpath the target xpath
+ * @param subscriptionId subscription id to remove
+ */
+ public void removeCmSubscription(final DatastoreType datastoreType, final String cmHandleId,
+ final String xpath, final String subscriptionId) {
+ final Collection<String> subscriptionIds =
+ getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath);
+ if (subscriptionIds.remove(subscriptionId)) {
+ saveSubscriptionDetails(datastoreType, cmHandleId, xpath, subscriptionIds);
+ log.info("There are subscribers left for the following cps path {} :",
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted(
+ datastoreType.getDatastoreName(), cmHandleId, escapeQuotesByDoublingThem(xpath)));
+ if (subscriptionIds.isEmpty()) {
+ log.info("No subscribers left for the following cps path {} :",
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted(
+ datastoreType.getDatastoreName(), cmHandleId, escapeQuotesByDoublingThem(xpath)));
+ deleteListOfSubscriptionsFor(datastoreType, cmHandleId, xpath);
+ }
+ }
+ }
+
+ /**
+ * Retrieve all existing dataNodes for given subscription id.
+ *
+ * @param subscriptionId subscription id
+ * @return collection of DataNodes
+ */
+ public Collection<DataNode> getAllNodesForSubscriptionId(final String subscriptionId) {
+ return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID.formatted(subscriptionId),
+ OMIT_DESCENDANTS);
+ }
+
+ private void deleteListOfSubscriptionsFor(final DatastoreType datastoreType, final String cmHandleId,
+ final String xpath) {
+ cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted(
+ datastoreType.getDatastoreName(), cmHandleId, escapeQuotesByDoublingThem(xpath)),
+ OffsetDateTime.now());
+ final Collection<DataNode> existingFiltersForCmHandle =
+ cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted(
+ datastoreType.getDatastoreName(), cmHandleId),
+ DIRECT_CHILDREN_ONLY).iterator().next()
+ .getChildDataNodes();
+ if (existingFiltersForCmHandle.isEmpty()) {
+ removeCmHandleFromDatastore(datastoreType.getDatastoreName(), cmHandleId);
+ }
+ }
+
+ private void removeCmHandleFromDatastore(final String datastoreName, final String cmHandleId) {
+ cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_AND_CMHANDLE.formatted(datastoreName, cmHandleId),
+ OffsetDateTime.now());
+ }
+
+ private boolean isFirstSubscriptionForCmHandle(final DatastoreType datastoreType, final String cmHandleId) {
+ return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted(
+ datastoreType.getDatastoreName(), cmHandleId), OMIT_DESCENDANTS).isEmpty();
+ }
+
+ private void addFirstSubscriptionForDatastoreCmHandleAndXpath(final DatastoreType datastoreType,
+ final String cmHandleId, final String xpath, final String subscriptionId) {
+ final Collection<String> newSubscriptionList = Collections.singletonList(subscriptionId);
+ final String subscriptionDetailsAsJson = getSubscriptionDetailsAsJson(xpath, newSubscriptionList);
+ if (isFirstSubscriptionForCmHandle(datastoreType, cmHandleId)) {
+ final String parentXpath =
+ "/datastores/datastore[@name='%s']/cm-handles".formatted(datastoreType.getDatastoreName());
+ final String subscriptionAsJson =
+ String.format("{\"cm-handle\":[{\"id\":\"%s\",\"filters\":%s}]}", cmHandleId,
+ subscriptionDetailsAsJson);
+ cpsDataService.saveData(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME, parentXpath, subscriptionAsJson,
+ OffsetDateTime.now(), ContentType.JSON);
+ } else {
+ cpsDataService.saveListElements(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted(
+ datastoreType.getDatastoreName(), cmHandleId), subscriptionDetailsAsJson,
+ OffsetDateTime.now(), ContentType.JSON);
+ }
+ }
+
+ private void saveSubscriptionDetails(final DatastoreType datastoreType, final String cmHandleId, final String xpath,
+ final Collection<String> subscriptionIds) {
+ final String subscriptionDetailsAsJson = getSubscriptionDetailsAsJson(xpath, subscriptionIds);
+ cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, CM_SUBSCRIPTIONS_ANCHOR_NAME,
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted(
+ datastoreType.getDatastoreName(), cmHandleId), subscriptionDetailsAsJson, OffsetDateTime.now(),
+ ContentType.JSON);
+ }
+
+ private String getSubscriptionDetailsAsJson(final String xpath, final Collection<String> subscriptionIds) {
+ final Map<String, Serializable> subscriptionDetailsAsMap =
+ Map.of("xpath", xpath, "subscriptionIds", (Serializable) subscriptionIds);
+ return "{\"filter\":[" + jsonObjectMapper.asJsonString(subscriptionDetailsAsMap) + "]}";
+ }
+
+ private static String escapeQuotesByDoublingThem(final String inputXpath) {
+ return inputXpath.replace("'", "''");
+ }
+
+}
+
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java
new file mode 100644
index 0000000000..301b8195e4
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java
@@ -0,0 +1,310 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2022 Bell Canada
+ * ================================================================================
+ * 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.impl.data;
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL;
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING;
+import static org.onap.cps.ncmp.api.data.models.OperationType.READ;
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA;
+
+import io.micrometer.core.annotation.Timed;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.NcmpResponseStatus;
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress;
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException;
+import org.onap.cps.ncmp.impl.data.models.DmiDataOperation;
+import org.onap.cps.ncmp.impl.data.models.DmiDataOperationRequest;
+import org.onap.cps.ncmp.impl.data.models.DmiOperationCmHandle;
+import org.onap.cps.ncmp.impl.data.policyexecutor.PolicyExecutor;
+import org.onap.cps.ncmp.impl.data.utils.DmiDataOperationsHelper;
+import org.onap.cps.ncmp.impl.dmi.DmiProperties;
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.models.DmiRequestBody;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.onap.cps.spi.exceptions.CpsException;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.util.UriComponentsBuilder;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * Operations class for DMI data.
+ */
+@RequiredArgsConstructor
+@Service
+public class DmiDataOperations {
+
+ private final InventoryPersistence inventoryPersistence;
+ private final JsonObjectMapper jsonObjectMapper;
+ private final DmiProperties dmiProperties;
+ private final DmiRestClient dmiRestClient;
+ private final PolicyExecutor policyExecutor;
+
+ /**
+ * This method fetches the resource data from the operational data store for a given CM handle
+ * identifier on the specified resource using the DMI client.
+ *
+ * @param cmResourceAddress Target datastore, CM handle, and resource identifier.
+ * @param options Options query string.
+ * @param topic Topic name for triggering asynchronous responses.
+ * @param requestId Request ID for asynchronous responses.
+ * @param authorization Contents of the Authorization header, or null if not present.
+ * @return {@code Mono<ResponseEntity<Object>>} A reactive type representing the response entity.
+ */
+ @Timed(value = "cps.ncmp.dmi.get",
+ description = "Time taken to fetch the resource data from operational data store for given cm handle "
+ + "identifier on given resource using dmi client")
+ public Mono<ResponseEntity<Object>> getResourceDataFromDmi(final CmResourceAddress cmResourceAddress,
+ final String options,
+ final String topic,
+ final String requestId,
+ final String authorization) {
+ final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmResourceAddress.getResolvedCmHandleId());
+ final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
+ validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
+ final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
+ final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(cmResourceAddress
+ .getDatastoreName(), yangModelCmHandle, cmResourceAddress.getResourceIdentifier(), options, topic);
+ return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, READ,
+ authorization);
+ }
+
+ /**
+ * This method fetches all the resource data from operational data store for given cm handle
+ * identifier using dmi client.
+ * Note: this method is only used for DataSync
+ *
+ * @param cmHandleId network resource identifier
+ * @param requestId requestId for async responses
+ * @return {@code ResponseEntity} response entity
+ */
+ public ResponseEntity<Object> getAllResourceDataFromDmi(final String cmHandleId, final String requestId) {
+ final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId);
+ final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
+ validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
+
+ final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
+ final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(
+ PASSTHROUGH_OPERATIONAL.getDatastoreName(), yangModelCmHandle, "/", null,
+ null);
+ return dmiRestClient.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, READ,
+ null);
+ }
+
+ /**
+ * This method requests the resource data by data store for given list of cm handles using dmi client.
+ * The data wil be returned as message on the topic specified.
+ *
+ * @param topicParamInQuery topic name for (triggering) async responses
+ * @param dataOperationRequest data operation request to execute operations
+ * @param requestId requestId for as a response
+ * @param authorization contents of Authorization header, or null if not present
+ */
+ public void requestResourceDataFromDmi(final String topicParamInQuery,
+ final DataOperationRequest dataOperationRequest,
+ final String requestId,
+ final String authorization) {
+
+ final Set<String> cmHandlesIds = getDistinctCmHandleIds(dataOperationRequest);
+
+ final Collection<YangModelCmHandle> yangModelCmHandles
+ = inventoryPersistence.getYangModelCmHandles(cmHandlesIds);
+
+ final Map<String, List<DmiDataOperation>> operationsOutPerDmiServiceName
+ = DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(topicParamInQuery,
+ requestId, dataOperationRequest, yangModelCmHandles);
+
+ asyncSendMultipleRequest(requestId, topicParamInQuery, operationsOutPerDmiServiceName,
+ authorization);
+ }
+
+ /**
+ * This method creates the resource data from pass-through running data store for given cm handle
+ * identifier on given resource using dmi client.
+ *
+ * @param cmHandleId network resource identifier
+ * @param resourceId resource identifier
+ * @param operationType operation enum
+ * @param requestData the request data
+ * @param dataType data type
+ * @param authorization contents of Authorization header, or null if not present
+ * @return {@code ResponseEntity} response entity
+ */
+ public ResponseEntity<Object> writeResourceDataPassThroughRunningFromDmi(final String cmHandleId,
+ final String resourceId,
+ final OperationType operationType,
+ final String requestData,
+ final String dataType,
+ final String authorization) {
+ final CmResourceAddress cmResourceAddress =
+ new CmResourceAddress(PASSTHROUGH_RUNNING.getDatastoreName(), cmHandleId, resourceId);
+
+ final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmResourceAddress.getResolvedCmHandleId());
+
+ policyExecutor.checkPermission(yangModelCmHandle, operationType, authorization, resourceId, requestData);
+
+ final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
+ validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
+
+ final String jsonRequestBody = getDmiRequestBody(operationType, null, requestData, dataType,
+ yangModelCmHandle);
+ final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(
+ PASSTHROUGH_RUNNING.getDatastoreName(), yangModelCmHandle, resourceId, null,
+ null);
+ return dmiRestClient.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody,
+ operationType, authorization);
+ }
+
+ private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
+ return inventoryPersistence.getYangModelCmHandle(cmHandleId);
+ }
+
+ private String getDmiRequestBody(final OperationType operationType,
+ final String requestId,
+ final String requestData,
+ final String dataType,
+ final YangModelCmHandle yangModelCmHandle) {
+ final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
+ .operationType(operationType)
+ .requestId(requestId)
+ .data(requestData)
+ .dataType(dataType)
+ .moduleSetTag(yangModelCmHandle.getModuleSetTag())
+ .build();
+ dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties());
+ return jsonObjectMapper.asJsonString(dmiRequestBody);
+ }
+
+ private UrlTemplateParameters getUrlTemplateParameters(final String datastoreName,
+ final YangModelCmHandle yangModelCmHandle,
+ final String resourceIdentifier,
+ final String optionsParamInQuery,
+ final String topicParamInQuery) {
+ final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(DATA);
+ return RestServiceUrlTemplateBuilder.newInstance()
+ .fixedPathSegment("ch")
+ .variablePathSegment("cmHandleId", yangModelCmHandle.getId())
+ .fixedPathSegment("data")
+ .fixedPathSegment("ds")
+ .variablePathSegment("datastore", datastoreName)
+ .queryParameter("resourceIdentifier", resourceIdentifier)
+ .queryParameter("options", optionsParamInQuery)
+ .queryParameter("topic", topicParamInQuery)
+ .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath());
+ }
+
+ private UrlTemplateParameters getUrlTemplateParameters(final String dmiServiceName,
+ final String requestId,
+ final String topicParamInQuery) {
+ return RestServiceUrlTemplateBuilder.newInstance()
+ .fixedPathSegment("data")
+ .queryParameter("requestId", requestId)
+ .queryParameter("topic", topicParamInQuery)
+ .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath());
+ }
+
+ private void validateIfCmHandleStateReady(final YangModelCmHandle yangModelCmHandle,
+ final CmHandleState cmHandleState) {
+ if (cmHandleState != CmHandleState.READY) {
+ throw new CpsException("State mismatch exception.", "Cm-Handle not in READY state. "
+ + "cm handle state is "
+ + yangModelCmHandle.getCompositeState().getCmHandleState());
+ }
+ }
+
+ private static Set<String> getDistinctCmHandleIds(final DataOperationRequest dataOperationRequest) {
+ return dataOperationRequest.getDataOperationDefinitions().stream()
+ .flatMap(dataOperationDefinition ->
+ dataOperationDefinition.getCmHandleIds().stream()).collect(Collectors.toSet());
+ }
+
+ private void asyncSendMultipleRequest(final String requestId, final String topicParamInQuery,
+ final Map<String, List<DmiDataOperation>> dmiDataOperationsPerDmi,
+ final String authorization) {
+
+ Flux.fromIterable(dmiDataOperationsPerDmi.entrySet())
+ .flatMap(entry -> {
+ final String dmiServiceName = entry.getKey();
+ final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(dmiServiceName,
+ requestId, topicParamInQuery);
+ final List<DmiDataOperation> dmiDataOperations = entry.getValue();
+ final String dmiDataOperationRequestAsJsonString
+ = createDmiDataOperationRequestAsJsonString(dmiDataOperations);
+ return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, urlTemplateParameters,
+ dmiDataOperationRequestAsJsonString, READ, authorization)
+ .then()
+ .onErrorResume(DmiClientRequestException.class, dmiClientRequestException -> {
+ final String dataOperationResourceUrl = UriComponentsBuilder
+ .fromUriString(urlTemplateParameters.urlTemplate())
+ .buildAndExpand(urlTemplateParameters.urlVariables())
+ .toUriString();
+ handleTaskCompletionException(dmiClientRequestException, dataOperationResourceUrl,
+ dmiDataOperations);
+ return Mono.empty();
+ });
+ }).subscribe();
+ }
+
+ private String createDmiDataOperationRequestAsJsonString(
+ final List<DmiDataOperation> dmiDataOperationRequestBodies) {
+ final DmiDataOperationRequest dmiDataOperationRequest = DmiDataOperationRequest.builder()
+ .operations(dmiDataOperationRequestBodies)
+ .build();
+ return jsonObjectMapper.asJsonString(dmiDataOperationRequest);
+ }
+
+ private void handleTaskCompletionException(final DmiClientRequestException dmiClientRequestException,
+ final String dataOperationResourceUrl,
+ final List<DmiDataOperation> dmiDataOperations) {
+ final MultiValueMap<String, String> dataOperationResourceUrlParameters =
+ UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams();
+ final String topicName = dataOperationResourceUrlParameters.get("topic").get(0);
+ final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0);
+
+ final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>>
+ cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
+
+ dmiDataOperations.forEach(dmiDataOperationRequestBody -> {
+ final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream()
+ .map(DmiOperationCmHandle::getId).toList();
+ cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody,
+ Map.of(dmiClientRequestException.getNcmpResponseStatus(), cmHandleIds));
+ });
+ DmiDataOperationsHelper.publishErrorMessageToClientTopic(topicName, requestId,
+ cmHandleIdsPerResponseCodesPerOperation);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java
new file mode 100644
index 0000000000..01022cc03e
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java
@@ -0,0 +1,75 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022-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.impl.data;
+
+import java.util.Collection;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.api.CpsDataService;
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress;
+import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.model.DataNode;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+@RequiredArgsConstructor
+public class NcmpCachedResourceRequestHandler extends NcmpDatastoreRequestHandler {
+
+ private final CpsDataService cpsDataService;
+ private final NetworkCmProxyQueryService networkCmProxyQueryService;
+
+ /**
+ * Executes a synchronous query request for given cm handle.
+ * Note. Currently only ncmp-datastore:operational supports query operations.
+ *
+ * @param cmHandleId the cm handle
+ * @param resourceIdentifier the resource identifier
+ * @param includeDescendants whether include descendants
+ * @return a collection of data nodes
+ */
+ public Collection<DataNode> executeRequest(final String cmHandleId, final String resourceIdentifier,
+ final boolean includeDescendants) {
+ final FetchDescendantsOption fetchDescendantsOption = getFetchDescendantsOption(includeDescendants);
+ return networkCmProxyQueryService.queryResourceDataOperational(cmHandleId, resourceIdentifier,
+ fetchDescendantsOption);
+ }
+
+ @Override
+ protected Mono<Object> getResourceDataForCmHandle(final CmResourceAddress cmResourceAddress,
+ final String optionsParamInQuery,
+ final String topicParamInQuery,
+ final String requestId,
+ final boolean includeDescendants,
+ final String authorization) {
+ final FetchDescendantsOption fetchDescendantsOption = getFetchDescendantsOption(includeDescendants);
+
+ final DataNode dataNode = cpsDataService.getDataNodes(cmResourceAddress.getDatastoreName(),
+ cmResourceAddress.getResolvedCmHandleId(),
+ cmResourceAddress.getResourceIdentifier(),
+ fetchDescendantsOption).iterator().next();
+ return Mono.justOrEmpty(dataNode);
+ }
+
+ private static FetchDescendantsOption getFetchDescendantsOption(final boolean includeDescendants) {
+ return includeDescendants ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+ : FetchDescendantsOption.OMIT_DESCENDANTS;
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandler.java
new file mode 100644
index 0000000000..f0a8c6c5d2
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandler.java
@@ -0,0 +1,96 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022-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.impl.data;
+
+import java.util.Map;
+import java.util.UUID;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress;
+import org.onap.cps.ncmp.utils.events.TopicValidator;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Slf4j
+@Service
+public abstract class NcmpDatastoreRequestHandler {
+
+ private static final String NO_REQUEST_ID = null;
+ private static final String NO_TOPIC = null;
+
+ @Value("${notification.async.executor.time-out-value-in-ms:60000}")
+ protected int timeOutInMilliSeconds;
+ @Value("${notification.enabled:true}")
+ protected boolean notificationFeatureEnabled;
+
+ /**
+ * Executes synchronous/asynchronous get request for given cm handle.
+ *
+ * @param cmResourceAddress the name of the datastore, cm handle and resource identifier
+ * @param options options to pass through to dmi client
+ * @param topic topic (optional) for asynchronous responses
+ * @param includeDescendants whether include descendants
+ * @param authorization contents of Authorization header, or null if not present
+ * @return the result object, depends on use op topic. With topic a map object with request id is returned
+ * otherwise the result of the request.
+ */
+ public Object executeRequest(final CmResourceAddress cmResourceAddress,
+ final String options,
+ final String topic,
+ final boolean includeDescendants,
+ final String authorization) {
+
+ final boolean asyncResponseRequested = topic != null;
+ if (asyncResponseRequested && notificationFeatureEnabled) {
+ return getResourceDataAsynchronously(cmResourceAddress, options, topic, includeDescendants, authorization);
+ }
+
+ if (asyncResponseRequested) {
+ log.warn("Asynchronous request is unavailable as notification feature is currently disabled, "
+ + "will use synchronous operation.");
+ }
+ final Mono<Object> resourceDataMono = getResourceDataForCmHandle(cmResourceAddress, options,
+ NO_TOPIC, NO_REQUEST_ID, includeDescendants, authorization);
+ return resourceDataMono.block();
+ }
+
+ private Map<String, String> getResourceDataAsynchronously(final CmResourceAddress cmResourceAddress,
+ final String options,
+ final String topic,
+ final boolean includeDescendants,
+ final String authorization) {
+ TopicValidator.validateTopicName(topic);
+ final String requestId = UUID.randomUUID().toString();
+ getResourceDataForCmHandle(cmResourceAddress, options, topic, requestId, includeDescendants, authorization)
+ .doOnSuccess(result ->
+ log.debug("Async operation succeeded for request id {}: {}", requestId, result))
+ .subscribe();
+ log.debug("Received Async request with id {}", requestId);
+ return Map.of("requestId", requestId);
+ }
+
+ protected abstract Mono<Object> getResourceDataForCmHandle(final CmResourceAddress cmResourceAddress,
+ final String optionsParamInQuery,
+ final String topicParamInQuery,
+ final String requestId,
+ final boolean includeDescendant,
+ final String authorization);
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java
new file mode 100644
index 0000000000..a21210c376
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java
@@ -0,0 +1,102 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022-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.impl.data;
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL;
+import static org.onap.cps.ncmp.api.data.models.OperationType.READ;
+
+import java.util.Map;
+import java.util.UUID;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException;
+import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException;
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress;
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.api.exceptions.PayloadTooLargeException;
+import org.onap.cps.ncmp.utils.events.TopicValidator;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+@RequiredArgsConstructor
+public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestHandler {
+
+ private final DmiDataOperations dmiDataOperations;
+
+ private static final int MAXIMUM_CM_HANDLES_PER_OPERATION = 200;
+ private static final String PAYLOAD_TOO_LARGE_TEMPLATE = "Operation '%s' affects too many (%d) cm handles";
+
+ /**
+ * Executes asynchronous request for group of cm handles to resource data.
+ *
+ * @param topic the topic param in query
+ * @param dataOperationRequest data operation request details for resource data
+ * @param authorization contents of Authorization header, or null if not present
+ * @return a map with one entry of request Id for success or status and error when async feature is disabled
+ */
+ public Map<String, String> executeAsynchronousRequest(final String topic,
+ final DataOperationRequest dataOperationRequest,
+ final String authorization) {
+ validateDataOperationRequest(topic, dataOperationRequest);
+ if (!notificationFeatureEnabled) {
+ return Map.of("status",
+ "Asynchronous request is unavailable as notification feature is currently disabled.");
+ }
+ final String requestId = UUID.randomUUID().toString();
+ dmiDataOperations.requestResourceDataFromDmi(topic, dataOperationRequest, requestId, authorization);
+ return Map.of("requestId", requestId);
+ }
+
+ @Override
+ protected Mono<Object> getResourceDataForCmHandle(final CmResourceAddress cmResourceAddress,
+ final String options,
+ final String topic,
+ final String requestId,
+ final boolean includeDescendants,
+ final String authorization) {
+
+ return dmiDataOperations.getResourceDataFromDmi(cmResourceAddress, options, topic, requestId, authorization)
+ .flatMap(responseEntity -> Mono.justOrEmpty(responseEntity.getBody()));
+ }
+
+ private void validateDataOperationRequest(final String topicParamInQuery,
+ final DataOperationRequest dataOperationRequest) {
+ TopicValidator.validateTopicName(topicParamInQuery);
+ dataOperationRequest.getDataOperationDefinitions().forEach(dataOperationDefinition -> {
+ if (OperationType.fromOperationName(dataOperationDefinition.getOperation()) != READ) {
+ throw new OperationNotSupportedException(
+ dataOperationDefinition.getOperation() + " operation not yet supported");
+ }
+ if (DatastoreType.fromDatastoreName(dataOperationDefinition.getDatastore()) == OPERATIONAL) {
+ throw new InvalidDatastoreException(dataOperationDefinition.getDatastore()
+ + " datastore is not supported");
+ }
+ if (dataOperationDefinition.getCmHandleIds().size() > MAXIMUM_CM_HANDLES_PER_OPERATION) {
+ final String errorMessage = String.format(PAYLOAD_TOO_LARGE_TEMPLATE,
+ dataOperationDefinition.getOperationId(),
+ dataOperationDefinition.getCmHandleIds().size());
+ throw new PayloadTooLargeException(errorMessage);
+ }
+ });
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java
new file mode 100644
index 0000000000..5343a2e131
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java
@@ -0,0 +1,129 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 highstreet technologies GmbH
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2021 Pantheon.tech
+ * Modifications Copyright (C) 2021-2022 Bell Canada
+ * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * ================================================================================
+ * 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.impl.data;
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL;
+
+import java.util.Collection;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress;
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
+import org.onap.cps.spi.model.DataNode;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class NetworkCmProxyFacade {
+
+ private final NcmpCachedResourceRequestHandler ncmpCachedResourceRequestHandler;
+ private final NcmpPassthroughResourceRequestHandler ncmpPassthroughResourceRequestHandler;
+ private final DmiDataOperations dmiDataOperations;
+ private final AlternateIdMatcher alternateIdMatcher;
+
+ /**
+ * Fetches resource data for a given data store using DMI (Data Management Interface).
+ * This method retrieves data based on the provided CmResourceAddress and additional query parameters.
+ * It supports asynchronous processing and handles authorization if required.
+ *
+ * @param cmResourceAddress The target data store, including the CM handle and resource identifier.
+ * This parameter must not be null.
+ * @param optionsParamInQuery Additional query parameters that may influence the data retrieval process,
+ * such as filters or limits. This parameter can be null.
+ * @param topicParamInQuery The topic name for triggering asynchronous responses. If specified,
+ * the response will be sent to this topic. This parameter can be null.
+ * @param includeDescendants include (all) descendants or not
+ * @param authorization The contents of the Authorization header. This parameter can be null
+ * if authorization is not required.
+ * @return the result object, depends on use op topic. With topic a map object with request id is returned
+ * otherwise the result of the request.
+ */
+ public Object getResourceDataForCmHandle(final CmResourceAddress cmResourceAddress,
+ final String optionsParamInQuery,
+ final String topicParamInQuery,
+ final Boolean includeDescendants,
+ final String authorization) {
+
+ final NcmpDatastoreRequestHandler ncmpDatastoreRequestHandler
+ = getNcmpDatastoreRequestHandler(cmResourceAddress.getDatastoreName());
+ return ncmpDatastoreRequestHandler.executeRequest(cmResourceAddress, optionsParamInQuery,
+ topicParamInQuery, includeDescendants, authorization);
+ }
+
+ /**
+ * Executes asynchronous request for group of cm handles to resource data.
+ *
+ * @param topic the topic param in query
+ * @param dataOperationRequest data operation request details for resource data
+ * @param authorization contents of Authorization header, or null if not present
+ * @return a map with one entry of request Id for success or status and error when async feature is disabled
+ */
+ public Object executeDataOperationForCmHandles(final String topic,
+ final DataOperationRequest dataOperationRequest,
+ final String authorization) {
+ return ncmpPassthroughResourceRequestHandler.executeAsynchronousRequest(topic,
+ dataOperationRequest,
+ authorization);
+ }
+
+ public Collection<DataNode> queryResourceDataForCmHandle(final String cmHandle,
+ final String cpsPath,
+ final Boolean includeDescendants) {
+ return ncmpCachedResourceRequestHandler.executeRequest(cmHandle, cpsPath, includeDescendants);
+ }
+
+ /**
+ * Write resource data for data store pass-through running using dmi for given cm-handle.
+ *
+ * @param cmHandleReference cm handle or alternate identifier
+ * @param resourceIdentifier resource identifier
+ * @param operationType required operation type
+ * @param requestData request body to create resource
+ * @param dataType content type in body
+ * @param authorization contents of Authorization header, or null if not present
+ * @return {@code Object} return data
+ */
+ public Object writeResourceDataPassThroughRunningForCmHandle(final String cmHandleReference,
+ final String resourceIdentifier,
+ final OperationType operationType,
+ final String requestData,
+ final String dataType,
+ final String authorization) {
+ return dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(cmHandleReference, resourceIdentifier,
+ operationType, requestData, dataType, authorization);
+ }
+
+ private NcmpDatastoreRequestHandler getNcmpDatastoreRequestHandler(final String datastoreName) {
+ if (OPERATIONAL.equals(DatastoreType.fromDatastoreName(datastoreName))) {
+ return ncmpCachedResourceRequestHandler;
+ }
+ return ncmpPassthroughResourceRequestHandler;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryService.java
new file mode 100644
index 0000000000..39abdc56a0
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryService.java
@@ -0,0 +1,50 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022-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.impl.data;
+
+import java.util.Collection;
+import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.model.DataNode;
+
+/*
+ * Datastore interface for handling cached CPS data query requests.
+ */
+public interface NetworkCmProxyQueryService {
+
+ /**
+ * Fetches operational resource data based on the provided CM handle identifier and CPS path.
+ * This method retrieves data nodes from the specified path within the context of a given CM handle.
+ * It supports options for fetching descendant nodes.
+ *
+ * @param cmHandleId The CM handle identifier, which uniquely identifies the CM handle.
+ * This parameter must not be null.
+ * @param cpsPath The CPS (Control Plane Service) path specifying the location of the
+ * resource data within the CM handle. This parameter must not be null.
+ * @param fetchDescendantsOption The option specifying whether to fetch descendant nodes along with the specified
+ * resource data.
+ * @return {@code Collection<DataNode>} A collection of DataNode objects representing the resource data
+ * retrieved from the specified path. The collection may include descendant nodes based on the
+ * fetchDescendantsOption.
+ */
+ Collection<DataNode> queryResourceDataOperational(String cmHandleId,
+ String cpsPath,
+ FetchDescendantsOption fetchDescendantsOption);
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImpl.java
index d8353f3029..021924a616 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImpl.java
@@ -18,15 +18,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl;
+package org.onap.cps.ncmp.impl.data;
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+import java.util.Collection;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.api.CpsQueryService;
-import org.onap.cps.ncmp.api.NetworkCmProxyQueryService;
import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.model.DataNode;
import org.springframework.stereotype.Service;
@Slf4j
@@ -37,9 +38,9 @@ public class NetworkCmProxyQueryServiceImpl implements NetworkCmProxyQueryServic
private final CpsQueryService cpsQueryService;
@Override
- public Object queryResourceDataOperational(final String cmHandleId,
- final String cpsPath,
- final FetchDescendantsOption fetchDescendantsOption) {
+ public Collection<DataNode> queryResourceDataOperational(final String cmHandleId,
+ final String cpsPath,
+ final FetchDescendantsOption fetchDescendantsOption) {
return cpsQueryService.queryDataNodes(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId, cpsPath,
fetchDescendantsOption);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/AsyncRestRequestResponseEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/AsyncRestRequestResponseEventConsumer.java
index 993e3d63db..f14bb15842 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/AsyncRestRequestResponseEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/AsyncRestRequestResponseEventConsumer.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async;
+package org.onap.cps.ncmp.impl.data.async;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumer.java
index 9bb7fae4d9..6f368da2d0 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumer.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async;
+package org.onap.cps.ncmp.impl.data.async;
import io.cloudevents.CloudEvent;
import io.cloudevents.kafka.impl.KafkaHeaders;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapper.java
index 46a11b82a0..21d40339b2 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapper.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async;
+package org.onap.cps.ncmp.impl.data.async;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategies.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategies.java
index 0404790408..2615672374 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategies.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategies.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async;
+package org.onap.cps.ncmp.impl.data.async;
import io.cloudevents.CloudEvent;
import io.cloudevents.kafka.impl.KafkaHeaders;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperation.java
index 7baac34b1f..649d3ad374 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperation.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.impl.data.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@@ -26,7 +26,9 @@ import java.util.ArrayList;
import java.util.List;
import lombok.Builder;
import lombok.Getter;
-import org.onap.cps.ncmp.api.models.DataOperationDefinition;
+import org.onap.cps.ncmp.api.data.models.DataOperationDefinition;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.api.data.models.OperationType;
@JsonInclude(JsonInclude.Include.NON_NULL)
@Getter
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationRequest.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperationRequest.java
index 8ee1d905bf..f342f04a1a 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationRequest.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiDataOperationRequest.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.impl.data.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperationCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiOperationCmHandle.java
index 1bf2b77dcc..6926b6890e 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperationCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/models/DmiOperationCmHandle.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.impl.data.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
new file mode 100644
index 0000000000..96771e30f1
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
@@ -0,0 +1,185 @@
+/*
+ * ============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.impl.data.policyexecutor;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.api.exceptions.NcmpException;
+import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException;
+import org.onap.cps.ncmp.api.exceptions.ServerNcmpException;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class PolicyExecutor {
+
+ @Value("${ncmp.policy-executor.enabled:false}")
+ private boolean enabled;
+
+ @Value("${ncmp.policy-executor.server.address:http://policy-executor}")
+ private String serverAddress;
+
+ @Value("${ncmp.policy-executor.server.port:8080}")
+ private String serverPort;
+
+ @Qualifier("policyExecutorWebClient")
+ private final WebClient policyExecutorWebClient;
+
+ private final ObjectMapper objectMapper;
+
+ /**
+ * Use the Policy Executor to check permission for a cm write operation.
+ * Wil throw an exception when the operation is not permitted (work in progress)
+ *
+ * @param yangModelCmHandle the cm handle involved
+ * @param operationType the write operation
+ * @param authorization the original rest authorization token (can be used to determine the client)
+ * @param resourceIdentifier the resource identifier (can be blank)
+ * @param changeRequestAsJson the change details from the original rest request in json format
+ */
+ public void checkPermission(final YangModelCmHandle yangModelCmHandle,
+ final OperationType operationType,
+ final String authorization,
+ final String resourceIdentifier,
+ final String changeRequestAsJson) {
+ log.trace("Policy Executor Enabled: {}", enabled);
+ if (enabled) {
+ final ResponseEntity<JsonNode> responseEntity =
+ getPolicyExecutorResponse(yangModelCmHandle, operationType, authorization, resourceIdentifier,
+ changeRequestAsJson);
+
+ if (responseEntity == null) {
+ log.warn("No valid response from policy, ignored");
+ return;
+ }
+
+ if (responseEntity.getStatusCode().is2xxSuccessful()) {
+ if (responseEntity.getBody() == null) {
+ log.warn("No valid response body from policy, ignored");
+ return;
+ }
+ processResponse(responseEntity.getBody());
+ } else {
+ log.warn("Policy Executor invocation failed with status {}",
+ responseEntity.getStatusCode().value());
+ throw new ServerNcmpException("Policy Executor invocation failed", "HTTP status code: "
+ + responseEntity.getStatusCode().value());
+ }
+ }
+ }
+
+ private Map<String, Object> getSingleRequestAsMap(final YangModelCmHandle yangModelCmHandle,
+ final OperationType operationType,
+ final String resourceIdentifier,
+ final String changeRequestAsJson) {
+ final Map<String, Object> data = new HashMap<>(4);
+ data.put("cmHandleId", yangModelCmHandle.getId());
+ data.put("resourceIdentifier", resourceIdentifier);
+ data.put("targetIdentifier", yangModelCmHandle.getAlternateId());
+ if (!OperationType.DELETE.equals(operationType)) {
+ try {
+ final Object changeRequestAsObject = objectMapper.readValue(changeRequestAsJson, Object.class);
+ data.put("cmChangeRequest", changeRequestAsObject);
+ } catch (final JsonProcessingException e) {
+ throw new NcmpException("Cannot convert Change Request data to Object",
+ "Invalid Json: " + changeRequestAsJson);
+ }
+ }
+ final Map<String, Object> request = new HashMap<>(2);
+ request.put("schema", getAssociatedPolicyDataSchemaName(operationType));
+ request.put("data", data);
+ return request;
+ }
+
+ private static String getAssociatedPolicyDataSchemaName(final OperationType operationType) {
+ return "urn:cps:org.onap.cps.ncmp.policy-executor.ncmp-" + operationType.getOperationName() + "-schema:1.0.0";
+ }
+
+ private Object createBodyAsObject(final List<Object> requests) {
+ final Map<String, Object> bodyAsMap = new HashMap<>(2);
+ bodyAsMap.put("decisionType", "allow");
+ bodyAsMap.put("requests", requests);
+ return bodyAsMap;
+ }
+
+ private ResponseEntity<JsonNode> getPolicyExecutorResponse(final YangModelCmHandle yangModelCmHandle,
+ final OperationType operationType,
+ final String authorization,
+ final String resourceIdentifier,
+ final String changeRequestAsJson) {
+
+
+ final Map<String, Object> requestAsMap = getSingleRequestAsMap(yangModelCmHandle,
+ operationType,
+ resourceIdentifier,
+ changeRequestAsJson);
+
+ final Object bodyAsObject = createBodyAsObject(Collections.singletonList(requestAsMap));
+
+ final UrlTemplateParameters urlTemplateParameters = RestServiceUrlTemplateBuilder.newInstance()
+ .fixedPathSegment("execute")
+ .createUrlTemplateParameters(String.format("%s:%s", serverAddress, serverPort),
+ "policy-executor/api");
+
+ return policyExecutorWebClient.post()
+ .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
+ .header(HttpHeaders.AUTHORIZATION, authorization)
+ .body(BodyInserters.fromValue(bodyAsObject))
+ .retrieve()
+ .toEntity(JsonNode.class)
+ .block();
+ }
+
+ private static void processResponse(final JsonNode responseBody) {
+ final String decisionId = responseBody.path("decisionId").asText("unknown id");
+ log.trace("Policy Executor Decision ID: {} ", decisionId);
+ final String decision = responseBody.path("decision").asText("unknown");
+ if ("allow".equals(decision)) {
+ log.trace("Policy Executor allows the operation");
+ } else {
+ log.warn("Policy Executor decision: {}", decision);
+ final String details = responseBody.path("message").asText();
+ log.warn("Policy Executor message: {}", details);
+ final String message = "Policy Executor did not allow request. Decision #"
+ + decisionId + " : " + decision;
+ throw new PolicyExecutorException(message, details);
+ }
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DataOperationEventCreator.java
index 42bad89f52..d74abb9935 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DataOperationEventCreator.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils.data.operation;
+package org.onap.cps.ncmp.impl.data.utils;
import io.cloudevents.CloudEvent;
import java.util.ArrayList;
@@ -29,11 +29,11 @@ import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.api.NcmpResponseStatus;
-import org.onap.cps.ncmp.api.impl.events.NcmpEvent;
-import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation;
import org.onap.cps.ncmp.events.async1_0_0.Data;
import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent;
import org.onap.cps.ncmp.events.async1_0_0.Response;
+import org.onap.cps.ncmp.impl.data.models.DmiDataOperation;
+import org.onap.cps.ncmp.utils.events.NcmpEvent;
import org.springframework.util.MultiValueMap;
@Slf4j
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java
index dc4108cac0..3104be5539 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils.data.operation;
+package org.onap.cps.ncmp.impl.data.utils;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_READY;
@@ -31,27 +31,26 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.events.EventsPublisher;
import org.onap.cps.ncmp.api.NcmpResponseStatus;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation;
-import org.onap.cps.ncmp.api.impl.operations.DmiOperationCmHandle;
-import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer;
-import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.DataOperationDefinition;
-import org.onap.cps.ncmp.api.models.DataOperationRequest;
+import org.onap.cps.ncmp.api.data.models.DataOperationDefinition;
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest;
+import org.onap.cps.ncmp.config.CpsApplicationContext;
+import org.onap.cps.ncmp.impl.data.models.DmiDataOperation;
+import org.onap.cps.ncmp.impl.data.models.DmiOperationCmHandle;
+import org.onap.cps.ncmp.impl.dmi.DmiServiceNameOrganizer;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
-@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class ResourceDataOperationRequestUtils {
+@Slf4j
+public class DmiDataOperationsHelper {
private static final String UNKNOWN_SERVICE_NAME = null;
@@ -126,58 +125,6 @@ public class ResourceDataOperationRequestUtils {
}
/**
- * Handles the async task completion for an entire data, publishing errors to client topic on task failure.
- *
- * @param topicParamInQuery client given topic
- * @param requestId unique identifier per request
- * @param dataOperationRequest incoming data operation request details
- * @param throwable error cause, or null if task completed with no exception
- */
- public static void handleAsyncTaskCompletionForDataOperationsRequest(
- final String topicParamInQuery,
- final String requestId,
- final DataOperationRequest dataOperationRequest,
- final Throwable throwable) {
- if (throwable == null) {
- log.info("Data operations request {} completed.", requestId);
- } else if (throwable instanceof TimeoutException) {
- log.error("Data operations request {} timed out.", requestId);
- ResourceDataOperationRequestUtils.publishErrorMessageToClientTopicForEntireOperation(topicParamInQuery,
- requestId, dataOperationRequest, NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING);
- } else {
- log.error("Data operations request {} failed.", requestId, throwable);
- ResourceDataOperationRequestUtils.publishErrorMessageToClientTopicForEntireOperation(topicParamInQuery,
- requestId, dataOperationRequest, NcmpResponseStatus.UNKNOWN_ERROR);
- }
- }
-
- /**
- * Creates data operation cloud event for when the entire data operation fails and publishes it to client topic.
- *
- * @param topicParamInQuery client given topic
- * @param requestId unique identifier per request
- * @param dataOperationRequestIn incoming data operation request details
- * @param ncmpResponseStatus response code to be sent for all cm handle ids in all operations
- */
- private static void publishErrorMessageToClientTopicForEntireOperation(
- final String topicParamInQuery,
- final String requestId,
- final DataOperationRequest dataOperationRequestIn,
- final NcmpResponseStatus ncmpResponseStatus) {
-
- final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>>
- cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
-
- for (final DataOperationDefinition dataOperationDefinitionIn :
- dataOperationRequestIn.getDataOperationDefinitions()) {
- cmHandleIdsPerResponseCodesPerOperation.add(
- DmiDataOperation.buildDmiDataOperationRequestBodyWithoutCmHandles(dataOperationDefinitionIn),
- Map.of(ncmpResponseStatus, dataOperationDefinitionIn.getCmHandleIds()));
- }
- publishErrorMessageToClientTopic(topicParamInQuery, requestId, cmHandleIdsPerResponseCodesPerOperation);
- }
-
- /**
* Creates data operation cloud event and publish it to client topic.
*
* @param clientTopic client given topic
@@ -193,6 +140,8 @@ public class ResourceDataOperationRequestUtils {
final CloudEvent dataOperationCloudEvent = DataOperationEventCreator.createDataOperationEvent(clientTopic,
requestId, cmHandleIdsPerResponseCodesPerOperation);
final EventsPublisher<CloudEvent> eventsPublisher = CpsApplicationContext.getCpsBean(EventsPublisher.class);
+ log.warn("publishing error message to client topic: {} ,requestId: {}, data operation cloud event id: {}",
+ clientTopic, requestId, dataOperationCloudEvent.getId());
eventsPublisher.publishCloudEvent(clientTopic, requestId, dataOperationCloudEvent);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImpl.java
new file mode 100644
index 0000000000..8934c088a1
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImpl.java
@@ -0,0 +1,55 @@
+/*
+ * ============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.impl.datajobs;
+
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.datajobs.DataJobResultService;
+import org.onap.cps.ncmp.impl.dmi.DmiProperties;
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class DataJobResultServiceImpl implements DataJobResultService {
+
+ private final DmiRestClient dmiRestClient;
+ private final DmiProperties dmiProperties;
+
+ @Override
+ public String getDataJobResult(final String authorization,
+ final String dmiServiceName,
+ final String dataProducerId,
+ final String dataProducerJobId,
+ final String destination) {
+ final UrlTemplateParameters urlTemplateParameters = RestServiceUrlTemplateBuilder.newInstance()
+ .fixedPathSegment("cmwriteJob")
+ .fixedPathSegment("dataProducer")
+ .variablePathSegment("dataProducerId", dataProducerId)
+ .fixedPathSegment("dataProducerJob")
+ .variablePathSegment("dataProducerJobId", dataProducerJobId)
+ .fixedPathSegment("result")
+ .queryParameter("destination", destination)
+ .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath());
+ return dmiRestClient.getDataJobResult(urlTemplateParameters, authorization).block();
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImpl.java
new file mode 100644
index 0000000000..04c3ad2fc6
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImpl.java
@@ -0,0 +1,67 @@
+/*
+ * ============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.impl.datajobs;
+
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.datajobs.DataJobService;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobReadRequest;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest;
+import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation;
+import org.onap.cps.ncmp.api.datajobs.models.ProducerKey;
+import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DataJobServiceImpl implements DataJobService {
+
+ private final DmiSubJobRequestHandler dmiSubJobClient;
+ private final WriteRequestExaminer writeRequestExaminer;
+
+ @Override
+ public void readDataJob(final String authorization,
+ final String dataJobId,
+ final DataJobMetadata dataJobMetadata,
+ final DataJobReadRequest dataJobReadRequest) {
+ log.info("data job id for read operation is: {}", dataJobId);
+ }
+
+ @Override
+ public List<SubJobWriteResponse> writeDataJob(final String authorization,
+ final String dataJobId,
+ final DataJobMetadata dataJobMetadata,
+ final DataJobWriteRequest dataJobWriteRequest) {
+ log.info("data job id for write operation is: {}", dataJobId);
+
+ final Map<ProducerKey, List<DmiWriteOperation>> dmiWriteOperationsPerProducerKey =
+ writeRequestExaminer.splitDmiWriteOperationsFromRequest(dataJobId, dataJobWriteRequest);
+
+ return dmiSubJobClient.sendRequestsToDmi(authorization,
+ dataJobId,
+ dataJobMetadata,
+ dmiWriteOperationsPerProducerKey);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobStatusServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobStatusServiceImpl.java
new file mode 100644
index 0000000000..1cfb8a9dff
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DataJobStatusServiceImpl.java
@@ -0,0 +1,66 @@
+/*
+ * ============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.impl.datajobs;
+
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.datajobs.DataJobStatusService;
+import org.onap.cps.ncmp.impl.dmi.DmiProperties;
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.springframework.stereotype.Service;
+
+/**
+ * Implementation of {@link DataJobStatusService} interface.
+ * The operations interact with a DMI Plugin to retrieve data job statuses.
+ */
+@Service
+@RequiredArgsConstructor
+public class DataJobStatusServiceImpl implements DataJobStatusService {
+
+ private final DmiRestClient dmiRestClient;
+ private final DmiProperties dmiProperties;
+
+ @Override
+ public String getDataJobStatus(final String authorization,
+ final String dmiServiceName,
+ final String dataProducerId,
+ final String dataProducerJobId) {
+
+ final UrlTemplateParameters urlTemplateParameters = buildUrlParameters(dmiServiceName,
+ dataProducerId,
+ dataProducerJobId);
+ return dmiRestClient.getDataJobStatus(urlTemplateParameters, authorization).block();
+ }
+
+ private UrlTemplateParameters buildUrlParameters(final String dmiServiceName,
+ final String dataProducerId,
+ final String dataProducerJobId) {
+ return RestServiceUrlTemplateBuilder.newInstance()
+ .fixedPathSegment("cmwriteJob")
+ .fixedPathSegment("dataProducer")
+ .variablePathSegment("dataProducerId", dataProducerId)
+ .fixedPathSegment("dataProducerJob")
+ .variablePathSegment("dataProducerJobId", dataProducerJobId)
+ .fixedPathSegment("status")
+ .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath());
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java
new file mode 100644
index 0000000000..a118d53e7e
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java
@@ -0,0 +1,96 @@
+/*
+ * ============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.impl.datajobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata;
+import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation;
+import org.onap.cps.ncmp.api.datajobs.models.ProducerKey;
+import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteRequest;
+import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse;
+import org.onap.cps.ncmp.impl.dmi.DmiProperties;
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient;
+import org.onap.cps.ncmp.impl.models.RequiredDmiService;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DmiSubJobRequestHandler {
+
+ private final DmiRestClient dmiRestClient;
+ private final DmiProperties dmiProperties;
+ private final JsonObjectMapper jsonObjectMapper;
+
+ /**
+ * Sends sub-job write requests to the DMI Plugin.
+ *
+ * @param authorization the authorization header from the REST request
+ * @param dataJobId data job identifier
+ * @param dataJobMetadata the data job's metadata
+ * @param dmiWriteOperationsPerProducerKey a collection of write requests per producer key
+ * @return a list of sub-job write responses
+ */
+ public List<SubJobWriteResponse> sendRequestsToDmi(final String authorization,
+ final String dataJobId,
+ final DataJobMetadata dataJobMetadata,
+ final Map<ProducerKey, List<DmiWriteOperation>> dmiWriteOperationsPerProducerKey) {
+ final List<SubJobWriteResponse> subJobWriteResponses = new ArrayList<>(dmiWriteOperationsPerProducerKey.size());
+ dmiWriteOperationsPerProducerKey.forEach((producerKey, dmi3ggpWriteOperations) -> {
+ final SubJobWriteRequest subJobWriteRequest = new SubJobWriteRequest(dataJobMetadata.destination(),
+ dataJobMetadata.dataAcceptType(),
+ dataJobMetadata.dataContentType(),
+ producerKey.dataProducerIdentifier(),
+ dataJobId,
+ dmi3ggpWriteOperations);
+
+ final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(dataJobMetadata.destination(),
+ producerKey);
+ final ResponseEntity<Object> responseEntity = dmiRestClient.synchronousPostOperationWithJsonData(
+ RequiredDmiService.DATA,
+ urlTemplateParameters,
+ jsonObjectMapper.asJsonString(subJobWriteRequest),
+ OperationType.CREATE,
+ authorization);
+ final SubJobWriteResponse subJobWriteResponse = jsonObjectMapper
+ .convertToValueType(responseEntity.getBody(), SubJobWriteResponse.class);
+ log.debug("Sub job write response: {}", subJobWriteResponse);
+ subJobWriteResponses.add(subJobWriteResponse);
+ });
+ return subJobWriteResponses;
+ }
+
+ private UrlTemplateParameters getUrlTemplateParameters(final String destination, final ProducerKey producerKey) {
+ return RestServiceUrlTemplateBuilder.newInstance()
+ .fixedPathSegment("cmwriteJob")
+ .queryParameter("destination", destination)
+ .createUrlTemplateParameters(producerKey.dmiServiceName(), dmiProperties.getDmiBasePath());
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java
new file mode 100644
index 0000000000..70d08dccdc
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java
@@ -0,0 +1,109 @@
+/*
+ * ============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.impl.datajobs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest;
+import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation;
+import org.onap.cps.ncmp.api.datajobs.models.ProducerKey;
+import org.onap.cps.ncmp.api.datajobs.models.WriteOperation;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
+import org.onap.cps.spi.model.DataNode;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class WriteRequestExaminer {
+
+ private final AlternateIdMatcher alternateIdMatcher;
+ private static final String PATH_SEPARATOR = "/";
+
+ /**
+ * Splitting incoming data job write request into Dmi Write Operations by ProducerKey.
+ *
+ * @param dataJobId data job identifier
+ * @param dataJobWriteRequest incoming data job write request
+ * @return {@code Map} map of Dmi Write Operations per Producer Key
+ */
+ public Map<ProducerKey, List<DmiWriteOperation>> splitDmiWriteOperationsFromRequest(
+ final String dataJobId,
+ final DataJobWriteRequest dataJobWriteRequest) {
+ final Map<ProducerKey, List<DmiWriteOperation>> dmiWriteOperationsPerProducerKey = new HashMap<>();
+ for (final WriteOperation writeOperation : dataJobWriteRequest.data()) {
+ examineWriteOperation(dataJobId, dmiWriteOperationsPerProducerKey, writeOperation);
+ }
+ return dmiWriteOperationsPerProducerKey;
+ }
+
+ private void examineWriteOperation(final String dataJobId,
+ final Map<ProducerKey, List<DmiWriteOperation>> dmiWriteOperationsPerProducerKey,
+ final WriteOperation writeOperation) {
+ log.debug("data job id for write operation is: {}", dataJobId);
+ final DataNode dataNode = alternateIdMatcher
+ .getCmHandleDataNodeByLongestMatchingAlternateId(writeOperation.path(), PATH_SEPARATOR);
+
+ final DmiWriteOperation dmiWriteOperation = createDmiWriteOperation(writeOperation, dataNode);
+
+ final ProducerKey producerKey = createProducerKey(dataNode);
+ final List<DmiWriteOperation> dmiWriteOperations;
+ if (dmiWriteOperationsPerProducerKey.containsKey(producerKey)) {
+ dmiWriteOperations = dmiWriteOperationsPerProducerKey.get(producerKey);
+ } else {
+ dmiWriteOperations = new ArrayList<>();
+ dmiWriteOperationsPerProducerKey.put(producerKey, dmiWriteOperations);
+ }
+ dmiWriteOperations.add(dmiWriteOperation);
+ }
+
+ private ProducerKey createProducerKey(final DataNode dataNode) {
+ return new ProducerKey((String) dataNode.getLeaves().get("dmi-service-name"),
+ (String) dataNode.getLeaves().get("data-producer-identifier"));
+ }
+
+ private DmiWriteOperation createDmiWriteOperation(final WriteOperation writeOperation,
+ final DataNode dataNode) {
+ return new DmiWriteOperation(
+ writeOperation.path(),
+ writeOperation.op(),
+ (String) dataNode.getLeaves().get("module-set-tag"),
+ writeOperation.value(),
+ writeOperation.operationId(),
+ getPrivatePropertiesFromDataNode(dataNode));
+ }
+
+ private Map<String, String> getPrivatePropertiesFromDataNode(final DataNode dataNode) {
+ final YangModelCmHandle yangModelCmHandle = YangDataConverter.toYangModelCmHandle(dataNode);
+ final Map<String, String> cmHandleDmiProperties = new LinkedHashMap<>();
+ yangModelCmHandle.getDmiProperties()
+ .forEach(dmiProperty -> cmHandleDmiProperties.put(dmiProperty.getName(), dmiProperty.getValue()));
+ return cmHandleDmiProperties;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java
new file mode 100644
index 0000000000..2f60460da3
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java
@@ -0,0 +1,55 @@
+/*
+ * ============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.impl.dmi;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Getter
+@Component
+public class DmiProperties {
+ @Value("${ncmp.dmi.auth.username}")
+ private String authUsername;
+ @Value("${ncmp.dmi.auth.password}")
+ private String authPassword;
+ @Getter(AccessLevel.NONE)
+ @Value("${ncmp.dmi.api.base-path}")
+ private String dmiBasePath;
+ @Value("${ncmp.dmi.auth.enabled}")
+ private boolean dmiBasicAuthEnabled;
+
+ /**
+ * Removes both leading and trailing slashes if they are present.
+ *
+ * @return dmi base path without any slashes ("/")
+ */
+ public String getDmiBasePath() {
+ if (dmiBasePath.startsWith("/")) {
+ dmiBasePath = dmiBasePath.substring(1);
+ }
+ if (dmiBasePath.endsWith("/")) {
+ dmiBasePath = dmiBasePath.substring(0, dmiBasePath.length() - 1);
+ }
+ return dmiBasePath;
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java
new file mode 100644
index 0000000000..a177272dff
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java
@@ -0,0 +1,225 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2022 Bell Canada
+ * ================================================================================
+ * 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.impl.dmi;
+
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING;
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA;
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.REQUEST_TIMEOUT;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.util.Locale;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException;
+import org.onap.cps.ncmp.impl.models.RequiredDmiService;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClientRequestException;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+import reactor.core.publisher.Mono;
+
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class DmiRestClient {
+
+ private static final String NOT_SPECIFIED = "";
+ private static final String NO_AUTHORIZATION = null;
+
+ private final DmiProperties dmiProperties;
+ private final JsonObjectMapper jsonObjectMapper;
+ @Qualifier("dataServicesWebClient")
+ private final WebClient dataServicesWebClient;
+ @Qualifier("modelServicesWebClient")
+ private final WebClient modelServicesWebClient;
+ @Qualifier("healthChecksWebClient")
+ private final WebClient healthChecksWebClient;
+
+ /**
+ * Sends a synchronous (blocking) POST operation to the DMI with a JSON body containing module references.
+ *
+ * @param requiredDmiService Determines if the required service is for a data or model operation.
+ * @param urlTemplateParameters The DMI resource URL template with variables.
+ * @param requestBodyAsJsonString JSON data body.
+ * @param operationType The type of operation being executed (for error reporting only).
+ * @param authorization Contents of the Authorization header, or null if not present.
+ * @return ResponseEntity containing the response from the DMI.
+ * @throws DmiClientRequestException If there is an error during the DMI request.
+ */
+ public ResponseEntity<Object> synchronousPostOperationWithJsonData(final RequiredDmiService requiredDmiService,
+ final UrlTemplateParameters
+ urlTemplateParameters,
+ final String requestBodyAsJsonString,
+ final OperationType operationType,
+ final String authorization) {
+ final Mono<ResponseEntity<Object>> responseEntityMono =
+ asynchronousPostOperationWithJsonData(requiredDmiService,
+ urlTemplateParameters,
+ requestBodyAsJsonString,
+ operationType,
+ authorization);
+ return responseEntityMono.block();
+ }
+
+ /**
+ * Asynchronously performs an HTTP POST operation with the given JSON data.
+ *
+ * @param requiredDmiService The service object required for retrieving or configuring the WebClient.
+ * @param urlTemplateParameters The URL template with variables for the POST request.
+ * @param requestBodyAsJsonString The JSON string that will be sent as the request body.
+ * @param operationType An enumeration or object that holds information about the type of operation
+ * being performed.
+ * @param authorization The authorization token to be added to the request headers.
+ * @return A Mono emitting the response entity containing the server's response.
+ */
+ public Mono<ResponseEntity<Object>> asynchronousPostOperationWithJsonData(final RequiredDmiService
+ requiredDmiService,
+ final UrlTemplateParameters
+ urlTemplateParameters,
+ final String requestBodyAsJsonString,
+ final OperationType operationType,
+ final String authorization) {
+ final WebClient webClient = getWebClient(requiredDmiService);
+ return webClient.post()
+ .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
+ .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization))
+ .body(BodyInserters.fromValue(requestBodyAsJsonString))
+ .retrieve()
+ .toEntity(Object.class)
+ .onErrorMap(throwable -> handleDmiClientException(throwable, operationType.getOperationName()));
+ }
+
+ /**
+ * Retrieves the health status of the DMI plugin.
+ * This method performs an HTTP GET request to the DMI health check endpoint specified by the URL template
+ * parameters. If the response status code indicates a client error (4xx) or a server error (5xx), it logs a warning
+ * and returns an empty Mono. In case of an error during the request, it logs the exception and returns a default
+ * value of "NOT_SPECIFIED". If the response body contains a JSON node with a "status" field, the value of this
+ * field is returned.
+ *
+ * @param urlTemplateParameters the URL template parameters for the DMI health check endpoint
+ * @return a Mono emitting the health status as a String, or "NOT_SPECIFIED" if an error occurs
+ */
+ public Mono<String> getDmiHealthStatus(final UrlTemplateParameters urlTemplateParameters) {
+ return healthChecksWebClient.get()
+ .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
+ .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION))
+ .retrieve()
+ .bodyToMono(JsonNode.class)
+ .map(responseHealthStatus -> responseHealthStatus.path("status").asText())
+ .onErrorResume(Exception.class, ex -> {
+ log.warn("Failed to retrieve health status from {}. Status: {}",
+ urlTemplateParameters.urlTemplate(), ex.getMessage());
+ return Mono.empty();
+ })
+ .defaultIfEmpty(NOT_SPECIFIED);
+ }
+
+ /**
+ * Retrieves the status of a data job from the DMI service.
+ *
+ * @param urlTemplateParameters The URL template parameters for the DMI data job status endpoint.
+ * @param authorization The authorization token to be added to the request headers.
+ * @return A Mono emitting the status of the data job as a String.
+ * @throws DmiClientRequestException If there is an error during the DMI request.
+ */
+ public Mono<String> getDataJobStatus(final UrlTemplateParameters urlTemplateParameters,
+ final String authorization) {
+
+ return dataServicesWebClient.get()
+ .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
+ .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization))
+ .retrieve()
+ .bodyToMono(JsonNode.class)
+ .map(jsonNode -> jsonNode.path("status").asText())
+ .onErrorMap(throwable -> handleDmiClientException(throwable, OperationType.READ.getOperationName()));
+ }
+
+ /**
+ * Retrieves the result of a data job from the DMI service.
+ *
+ * @param urlTemplateParameters The URL template parameters for the DMI data job status endpoint.
+ * @param authorization The authorization token to be added to the request headers.
+ * @return A Mono emitting the result of the data job as a String.
+ * @throws DmiClientRequestException If there is an error during the DMI request.
+ */
+ public Mono<String> getDataJobResult(final UrlTemplateParameters urlTemplateParameters,
+ final String authorization) {
+ return dataServicesWebClient.get()
+ .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
+ .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization))
+ .retrieve().bodyToMono(String.class)
+ .onErrorMap(throwable -> handleDmiClientException(throwable,
+ OperationType.READ.getOperationName()));
+ }
+
+ private WebClient getWebClient(final RequiredDmiService requiredDmiService) {
+ return requiredDmiService.equals(RequiredDmiService.DATA) ? dataServicesWebClient : modelServicesWebClient;
+ }
+
+ private void configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) {
+ if (dmiProperties.isDmiBasicAuthEnabled()) {
+ httpHeaders.setBasicAuth(dmiProperties.getAuthUsername(), dmiProperties.getAuthPassword());
+ } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) {
+ httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization);
+ }
+ }
+
+ private DmiClientRequestException handleDmiClientException(final Throwable throwable, final String operationType) {
+ if (throwable instanceof WebClientResponseException webClientResponseException) {
+ if (webClientResponseException.getStatusCode().isSameCodeAs(REQUEST_TIMEOUT)) {
+ throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(),
+ webClientResponseException.getMessage(),
+ jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()),
+ DMI_SERVICE_NOT_RESPONDING);
+ }
+ throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(),
+ webClientResponseException.getMessage(),
+ jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()),
+ UNABLE_TO_READ_RESOURCE_DATA);
+
+ }
+ final String exceptionMessage = "Unable to " + operationType + " resource data.";
+ if (throwable instanceof WebClientRequestException webClientRequestException) {
+ throw new DmiClientRequestException(HttpStatus.SERVICE_UNAVAILABLE.value(),
+ webClientRequestException.getMessage(),
+ exceptionMessage, DMI_SERVICE_NOT_RESPONDING);
+ }
+ if (throwable instanceof HttpServerErrorException httpServerErrorException) {
+ throw new DmiClientRequestException(httpServerErrorException.getStatusCode().value(), exceptionMessage,
+ httpServerErrorException.getResponseBodyAsString(), DMI_SERVICE_NOT_RESPONDING);
+ }
+ throw new DmiClientRequestException(INTERNAL_SERVER_ERROR.value(), exceptionMessage, throwable.getMessage(),
+ UNKNOWN_ERROR);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java
index 26e94866a1..37e982d8cb 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils;
+package org.onap.cps.ncmp.impl.dmi;
import java.util.Collection;
import java.util.HashMap;
@@ -27,8 +27,8 @@ import java.util.Map;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
-import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.models.RequiredDmiService;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DmiServiceNameOrganizer {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfiguration.java
new file mode 100644
index 0000000000..4134a56ead
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfiguration.java
@@ -0,0 +1,68 @@
+/*
+ * ============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.impl.dmi;
+
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.config.DmiHttpClientConfig;
+import org.onap.cps.ncmp.impl.utils.http.WebClientConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Configuration
+@RequiredArgsConstructor
+public class DmiWebClientsConfiguration extends WebClientConfiguration {
+
+ private final DmiHttpClientConfig dmiHttpClientConfig;
+
+ /**
+ * Configures and creates a web client bean for DMI data services.
+ *
+ * @param webClientBuilder The builder instance to create the WebClient.
+ * @return a WebClient instance configured for data services.
+ */
+ @Bean
+ public WebClient dataServicesWebClient(final WebClient.Builder webClientBuilder) {
+ return configureWebClient(webClientBuilder, dmiHttpClientConfig.getDataServices());
+ }
+
+ /**
+ * Configures and creates a web client bean for DMI model services.
+ *
+ * @param webClientBuilder The builder instance to create the WebClient.
+ * @return a WebClient instance configured for model services.
+ */
+ @Bean
+ public WebClient modelServicesWebClient(final WebClient.Builder webClientBuilder) {
+ return configureWebClient(webClientBuilder, dmiHttpClientConfig.getModelServices());
+ }
+
+ /**
+ * Configures and creates a web client bean for DMI health check services.
+ *
+ * @param webClientBuilder The builder instance to create the WebClient.
+ * @return a WebClient instance configured for health check services.
+ */
+ @Bean
+ public WebClient healthChecksWebClient(final WebClient.Builder webClientBuilder) {
+ return configureWebClient(webClientBuilder, dmiHttpClientConfig.getHealthCheckServices());
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/AlternateIdChecker.java
new file mode 100644
index 0000000000..3600d6da32
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/AlternateIdChecker.java
@@ -0,0 +1,115 @@
+/*
+ * ============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.impl.inventory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class AlternateIdChecker {
+
+ public enum Operation {
+ CREATE, UPDATE
+ }
+
+ private final InventoryPersistence inventoryPersistence;
+
+ private static final String NO_CURRENT_ALTERNATE_ID = "";
+
+ /**
+ * Check all alternate ids of a batch of cm handles.
+ * Includes cross-checks in the batch itself for duplicates. Only the first entry encountered wil be accepted.
+ *
+ * @param newNcmpServiceCmHandles the proposed new cm handles
+ * @param operation type of operation being executed
+ * @return collection of cm handles ids which are acceptable
+ */
+ public Collection<String> getIdsOfCmHandlesWithRejectedAlternateId(
+ final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles,
+ final Operation operation) {
+ final Set<String> assignedAlternateIds = getAlternateIdsAlreadyInDb(newNcmpServiceCmHandles);
+ final Collection<String> rejectedCmHandleIds = new ArrayList<>();
+ for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) {
+ final String cmHandleId = ncmpServiceCmHandle.getCmHandleId();
+ final String proposedAlternateId = ncmpServiceCmHandle.getAlternateId();
+ if (isProposedAlternateIdAcceptable(proposedAlternateId, operation, assignedAlternateIds, cmHandleId)) {
+ assignedAlternateIds.add(proposedAlternateId);
+ } else {
+ rejectedCmHandleIds.add(cmHandleId);
+ }
+ }
+ return rejectedCmHandleIds;
+ }
+
+ private boolean isProposedAlternateIdAcceptable(final String proposedAlternateId, final Operation operation,
+ final Set<String> assignedAlternateIds, final String cmHandleId) {
+ if (StringUtils.isBlank(proposedAlternateId)) {
+ return true;
+ }
+ final String currentAlternateId = getCurrentAlternateId(operation, cmHandleId);
+ if (currentAlternateId.equals(proposedAlternateId)) {
+ return true;
+ }
+ if (StringUtils.isNotBlank(currentAlternateId)) {
+ log.warn("Alternate id update ignored, cannot update cm handle {}, already has an alternate id of {}",
+ cmHandleId, currentAlternateId);
+ return false;
+ }
+ if (assignedAlternateIds.contains(proposedAlternateId)) {
+ log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already "
+ + "assigned to a different cm handle", cmHandleId);
+ return false;
+ }
+ return true;
+ }
+
+ private Set<String> getAlternateIdsAlreadyInDb(final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) {
+ final Set<String> alternateIdsToCheck = ncmpServiceCmHandles.stream()
+ .map(NcmpServiceCmHandle::getAlternateId)
+ .filter(StringUtils::isNotBlank)
+ .collect(Collectors.toSet());
+ return inventoryPersistence.getCmHandleDataNodesByAlternateIds(alternateIdsToCheck).stream()
+ .map(dataNode -> (String) dataNode.getLeaves().get("alternate-id"))
+ .collect(Collectors.toSet());
+ }
+
+ private String getCurrentAlternateId(final Operation operation, final String cmHandleId) {
+ if (operation == Operation.UPDATE) {
+ try {
+ return inventoryPersistence.getYangModelCmHandle(cmHandleId).getAlternateId();
+ } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
+ // work with blank current alternate id
+ }
+ }
+ return NO_CURRENT_ALTERNATE_ID;
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/RestQueryParametersValidator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryParametersValidator.java
index 2ef97cab5c..08954024b7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/RestQueryParametersValidator.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryParametersValidator.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils;
+package org.onap.cps.ncmp.impl.inventory;
import com.google.common.base.Strings;
import java.util.Collection;
@@ -26,12 +26,12 @@ import java.util.Map;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
import org.onap.cps.spi.exceptions.DataValidationException;
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class RestQueryParametersValidator {
+public class CmHandleQueryParametersValidator {
/**
* Validate query parameters.
@@ -55,7 +55,7 @@ public class RestQueryParametersValidator {
"Empty 'conditionsParameters' - please supply a valid condition parameter.");
}
cmHandleQueryParameter.getConditionParameters().forEach(
- RestQueryParametersValidator::validateConditionParameter
+ CmHandleQueryParametersValidator::validateConditionParameter
);
}
);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryService.java
index 81467dbb3e..95c3c77b71 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryService.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-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.
@@ -18,26 +18,26 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory;
import java.util.Collection;
-import java.util.List;
import java.util.Map;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.model.DataNode;
-public interface CmHandleQueries {
+public interface CmHandleQueryService {
/**
- * Query CmHandles based on additional (private) properties.
+ * Query Cm Handles based on additional (private) properties.
*
* @param additionalPropertyQueryPairs private properties for query
- * @return Ids of CmHandles which have these private properties
+ * @return Ids of Cm Handles which have these private properties
*/
Collection<String> queryCmHandleAdditionalProperties(Map<String, String> additionalPropertyQueryPairs);
/**
- * Query CmHandles based on public properties.
+ * Query Cm Handles based on public properties.
*
* @param publicPropertyQueryPairs public properties for query
* @return CmHandles which have these public properties
@@ -45,10 +45,10 @@ public interface CmHandleQueries {
Collection<String> queryCmHandlePublicProperties(Map<String, String> publicPropertyQueryPairs);
/**
- * Query CmHandles based on Trust Level.
+ * Query Cm Handles based on Trust Level.
*
* @param trustLevelPropertyQueryPairs trust level properties for query
- * @return CmHandles which have desired trust level
+ * @return Ids of Cm Handles which have desired trust level
*/
Collection<String> queryCmHandlesByTrustLevel(Map<String, String> trustLevelPropertyQueryPairs);
@@ -56,9 +56,9 @@ public interface CmHandleQueries {
* Method which returns cm handles by the cm handles state.
*
* @param cmHandleState cm handle state
- * @return a list of cm handles
+ * @return a list of data nodes representing the cm handles.
*/
- List<DataNode> queryCmHandlesByState(CmHandleState cmHandleState);
+ Collection<DataNode> queryCmHandlesByState(CmHandleState cmHandleState);
/**
* Method to return data nodes with ancestor representing the cm handles.
@@ -66,8 +66,7 @@ public interface CmHandleQueries {
* @param cpsPath cps path for which the cmHandle is requested
* @return a list of data nodes representing the cm handles.
*/
- List<DataNode> queryCmHandleAncestorsByCpsPath(String cpsPath,
- FetchDescendantsOption fetchDescendantsOption);
+ Collection<DataNode> queryCmHandleAncestorsByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption);
/**
* Method to return data nodes representing the cm handles.
@@ -75,7 +74,7 @@ public interface CmHandleQueries {
* @param cpsPath cps path for which the cmHandle is requested
* @return a list of data nodes representing the cm handles.
*/
- List<DataNode> queryNcmpRegistryByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption);
+ Collection<DataNode> queryNcmpRegistryByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption);
/**
* Method to check the state of a cm handle with given id.
@@ -90,15 +89,16 @@ public interface CmHandleQueries {
* Method which returns cm handles by the operational sync state of cm handle.
*
* @param dataStoreSyncState sync state
- * @return a list of cm handles
+ * @return a list of data nodes representing the cm handles.
*/
- List<DataNode> queryCmHandlesByOperationalSyncState(DataStoreSyncState dataStoreSyncState);
+ Collection<DataNode> queryCmHandlesByOperationalSyncState(DataStoreSyncState dataStoreSyncState);
/**
* Get all cm handles ids by DMI plugin identifier.
*
* @param dmiPluginIdentifier DMI plugin identifier
- * @return collection of cm handles
+ * @return collection of cm handle ids
*/
Collection<String> getCmHandleIdsByDmiPluginIdentifier(String dmiPluginIdentifier);
+
}
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/impl/inventory/CmHandleQueryServiceImpl.java
index 6cffb4d274..71e7384208 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/impl/inventory/CmHandleQueryServiceImpl.java
@@ -19,38 +19,42 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory;
-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.NCMP_DMI_REGISTRY_PARENT;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
-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.api.CpsDataService;
+import org.onap.cps.api.CpsQueryService;
+import org.onap.cps.cpspath.parser.CpsPathUtil;
+import org.onap.cps.impl.utils.CpsValidator;
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.ModelledDmiServiceLeaves;
+import org.onap.cps.ncmp.impl.inventory.models.PropertyType;
+import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelCacheConfig;
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
@Component
-public class CmHandleQueriesImpl implements CmHandleQueries {
+public class CmHandleQueryServiceImpl implements CmHandleQueryService {
private static final String DESCENDANT_PATH = "//";
private static final String ANCESTOR_CM_HANDLES = "/ancestor::cm-handles";
- private final CpsDataPersistenceService cpsDataPersistenceService;
+ private final CpsDataService cpsDataService;
+ private final CpsQueryService cpsQueryService;
@Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN)
private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
@@ -79,21 +83,24 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
}
@Override
- public List<DataNode> queryCmHandlesByState(final CmHandleState cmHandleState) {
+ public Collection<DataNode> queryCmHandlesByState(final CmHandleState cmHandleState) {
return queryCmHandleAncestorsByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]",
INCLUDE_ALL_DESCENDANTS);
}
@Override
- public List<DataNode> queryNcmpRegistryByCpsPath(final String cpsPath,
+ public Collection<DataNode> queryNcmpRegistryByCpsPath(final String cpsPath,
final FetchDescendantsOption fetchDescendantsOption) {
- return cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- cpsPath, fetchDescendantsOption);
+ return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cpsPath,
+ fetchDescendantsOption);
}
@Override
- public List<DataNode> queryCmHandleAncestorsByCpsPath(final String cpsPath,
+ public Collection<DataNode> queryCmHandleAncestorsByCpsPath(final String cpsPath,
final FetchDescendantsOption fetchDescendantsOption) {
+ if (CpsPathUtil.getCpsPathQuery(cpsPath).getXpathPrefix().endsWith("/cm-handles")) {
+ return queryNcmpRegistryByCpsPath(cpsPath, fetchDescendantsOption);
+ }
return queryNcmpRegistryByCpsPath(cpsPath + ANCESTOR_CM_HANDLES, fetchDescendantsOption);
}
@@ -105,7 +112,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
}
@Override
- public List<DataNode> queryCmHandlesByOperationalSyncState(final DataStoreSyncState dataStoreSyncState) {
+ public Collection<DataNode> queryCmHandlesByOperationalSyncState(final DataStoreSyncState dataStoreSyncState) {
return queryCmHandleAncestorsByCpsPath("//state/datastores" + "/operational[@sync-state=\""
+ dataStoreSyncState + "\"]", FetchDescendantsOption.OMIT_DESCENDANTS);
}
@@ -174,9 +181,9 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
return cmHandleIds;
}
- private List<DataNode> getCmHandlesByDmiPluginIdentifierAndDmiProperty(final String dmiPluginIdentifier,
- final String dmiProperty) {
- return cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ private Collection<DataNode> getCmHandlesByDmiPluginIdentifierAndDmiProperty(final String dmiPluginIdentifier,
+ final String dmiProperty) {
+ return cpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@" + dmiProperty + "='" + dmiPluginIdentifier + "']",
OMIT_DESCENDANTS);
}
@@ -184,7 +191,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
private DataNode getCmHandleState(final String cmHandleId) {
cpsValidator.validateNameCharacters(cmHandleId);
final String xpath = NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']/state";
- return cpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
xpath, OMIT_DESCENDANTS).iterator().next();
}
}
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/impl/inventory/CmHandleRegistrationService.java
index 6aa09767be..d9f7e38993 100755..100644
--- 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/impl/inventory/CmHandleRegistrationService.java
@@ -1,7 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 highstreet technologies GmbH
- * Modifications Copyright (C) 2021-2024 Nordix Foundation
+ * Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021-2022 Bell Canada
* Modifications Copyright (C) 2023 TechMahindra Ltd.
@@ -22,23 +21,23 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl;
+package org.onap.cps.ncmp.impl.inventory;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_READY;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID;
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE;
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
-import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateCmHandleQueryParameters;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE;
import com.google.common.collect.Lists;
import com.hazelcast.map.IMap;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -49,77 +48,52 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateUtils;
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleOperationsUtils;
-import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
-import org.onap.cps.ncmp.api.impl.operations.OperationType;
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel;
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager;
-import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker;
-import org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions;
-import org.onap.cps.ncmp.api.impl.utils.InventoryQueryConditions;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
-import org.onap.cps.ncmp.api.models.CmResourceAddress;
-import org.onap.cps.ncmp.api.models.DataOperationRequest;
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
-import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
-import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.sync.ModuleOperationsUtils;
+import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler;
+import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.CpsException;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
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;
@Slf4j
@Service
@RequiredArgsConstructor
-public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService {
+public class CmHandleRegistrationService {
private static final int DELETE_BATCH_SIZE = 100;
- private final JsonObjectMapper jsonObjectMapper;
- private final DmiDataOperations dmiDataOperations;
- private final NetworkCmProxyDataServicePropertyHandler networkCmProxyDataServicePropertyHandler;
+
+ private final CmHandleRegistrationServicePropertyHandler cmHandleRegistrationServicePropertyHandler;
private final InventoryPersistence inventoryPersistence;
- private final CmHandleQueries cmHandleQueries;
- private final NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService;
- private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler;
private final CpsDataService cpsDataService;
+ private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler;
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;
- @Override
+ /**
+ * Registration of Created, Removed, Updated or Upgraded CM Handles.
+ *
+ * @param dmiPluginRegistration Dmi Plugin Registration details
+ * @return dmiPluginRegistrationResponse
+ */
public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
final DmiPluginRegistration dmiPluginRegistration) {
dmiPluginRegistration.validateDmiPluginRegistration();
final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
- setTrustLevelPerDmiPlugin(dmiPluginRegistration);
+ trustLevelManager.registerDmiPlugin(dmiPluginRegistration);
processRemovedCmHandles(dmiPluginRegistration, dmiPluginRegistrationResponse);
@@ -132,95 +106,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
return dmiPluginRegistrationResponse;
}
- @Override
- public Object getResourceDataForCmHandle(final CmResourceAddress cmResourceAddress,
- final String optionsParamInQuery,
- final String topicParamInQuery,
- final String requestId,
- final String authorization) {
- final ResponseEntity<?> responseEntity = dmiDataOperations.getResourceDataFromDmi(cmResourceAddress,
- optionsParamInQuery,
- topicParamInQuery,
- requestId,
- authorization);
- return responseEntity.getBody();
- }
-
- @Override
- public Object getResourceDataForCmHandle(final CmResourceAddress cmResourceAddress,
- final FetchDescendantsOption fetchDescendantsOption) {
- return cpsDataService.getDataNodes(cmResourceAddress.datastoreName(),
- cmResourceAddress.cmHandleId(),
- cmResourceAddress.resourceIdentifier(),
- fetchDescendantsOption).iterator().next();
- }
-
- @Override
- public void executeDataOperationForCmHandles(final String topicParamInQuery,
- final DataOperationRequest dataOperationRequest,
- final String requestId,
- final String authorization) {
- dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId,
- authorization);
- }
-
- @Override
- public Object writeResourceDataPassThroughRunningForCmHandle(final String cmHandleId,
- final String resourceIdentifier,
- final OperationType operationType,
- final String requestData,
- final String dataType,
- final String authorization) {
- return dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(cmHandleId, resourceIdentifier,
- operationType, requestData, dataType, authorization);
- }
-
- @Override
- public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleId) {
- return inventoryPersistence.getYangResourcesModuleReferences(cmHandleId);
- }
-
- @Override
- public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(final String cmHandleId) {
- return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId);
- }
-
- @Override
- public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleId,
- final String moduleName,
- final String moduleRevision) {
- return inventoryPersistence.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, moduleRevision);
- }
-
- /**
- * Retrieve cm handles with details for the given query parameters.
- *
- * @param cmHandleQueryApiParameters cm handle query parameters
- * @return cm handles with details
- */
- @Override
- public Collection<NcmpServiceCmHandle> executeCmHandleSearch(
- final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
- cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
- validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
- return networkCmProxyCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters);
- }
-
- /**
- * Retrieve cm handle ids for the given query parameters.
- *
- * @param cmHandleQueryApiParameters cm handle query parameters
- * @return cm handle ids
- */
- @Override
- public Collection<String> executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
- cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
- validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
- return networkCmProxyCmHandleQueryService.queryCmHandleIds(cmHandleQueryServiceParameters);
- }
-
/**
* Set the data sync enabled flag, along with the data sync state
* based on the data sync enabled boolean for the cm handle id provided.
@@ -228,7 +113,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
* @param cmHandleId cm handle id
* @param dataSyncEnabledTargetValue data sync enabled flag
*/
- @Override
public void setDataSyncEnabled(final String cmHandleId, final Boolean dataSyncEnabledTargetValue) {
final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId);
if (dataSyncEnabledTargetValue.equals(compositeState.getDataSyncEnabled())) {
@@ -252,70 +136,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
}
}
- /**
- * Get all cm handle IDs by DMI plugin identifier.
- *
- * @param dmiPluginIdentifier DMI plugin identifier
- * @return set of cm handle IDs
- */
- @Override
- public Collection<String> getAllCmHandleIdsByDmiPluginIdentifier(final String dmiPluginIdentifier) {
- return cmHandleQueries.getCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifier);
- }
-
- /**
- * Get all cm handle IDs by various properties.
- *
- * @param cmHandleQueryServiceParameters cm handle query parameters
- * @return set of cm handle IDs
- */
- @Override
- public Collection<String> executeCmHandleIdSearchForInventory(
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
- validateCmHandleQueryParameters(cmHandleQueryServiceParameters, InventoryQueryConditions.ALL_CONDITION_NAMES);
- return networkCmProxyCmHandleQueryService.queryCmHandleIdsForInventory(cmHandleQueryServiceParameters);
- }
-
- /**
- * Retrieve cm handle details for a given cm handle.
- *
- * @param cmHandleId cm handle identifier
- * @return cm handle details
- */
- @Override
- public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleId) {
- return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(
- inventoryPersistence.getYangModelCmHandle(cmHandleId));
- }
-
- /**
- * Get cm handle public properties for a given cm handle id.
- *
- * @param cmHandleId cm handle identifier
- * @return cm handle public properties
- */
- @Override
- public Map<String, String> getCmHandlePublicProperties(final String cmHandleId) {
- final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
- final List<YangModelCmHandle.Property> yangModelPublicProperties = yangModelCmHandle.getPublicProperties();
- final Map<String, String> cmHandlePublicProperties = new HashMap<>();
- YangDataConverter.asPropertiesMap(yangModelPublicProperties, cmHandlePublicProperties);
- return cmHandlePublicProperties;
- }
-
- /**
- * Get cm handle composite state for a given cm handle id.
- *
- * @param cmHandleId cm handle identifier
- * @return cm handle state
- */
- @Override
- public CompositeState getCmHandleCompositeState(final String cmHandleId) {
- return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState();
- }
-
protected void processRemovedCmHandles(final DmiPluginRegistration dmiPluginRegistration,
- final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
final List<String> tobeRemovedCmHandleIds = dmiPluginRegistration.getRemovedCmHandles();
final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
new ArrayList<>(tobeRemovedCmHandleIds.size());
@@ -326,7 +148,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
final Set<String> notDeletedCmHandles = new HashSet<>();
for (final List<String> tobeRemovedCmHandleBatch : Lists.partition(tobeRemovedCmHandleIds, DELETE_BATCH_SIZE)) {
try {
- batchDeleteCmHandlesFromDbAndModuleSyncMap(tobeRemovedCmHandleBatch);
+ batchDeleteCmHandlesFromDbAndCaches(tobeRemovedCmHandleBatch);
tobeRemovedCmHandleBatch.forEach(cmHandleId ->
cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)));
@@ -348,7 +170,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
}
protected void processCreatedCmHandles(final DmiPluginRegistration dmiPluginRegistration,
- final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
final List<NcmpServiceCmHandle> ncmpServiceCmHandles = dmiPluginRegistration.getCreatedCmHandles();
final List<CmHandleRegistrationResponse> failedCmHandleRegistrationResponses = new ArrayList<>();
@@ -378,8 +200,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
}
protected void processUpdatedCmHandles(final DmiPluginRegistration dmiPluginRegistration,
- final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
- dmiPluginRegistrationResponse.setUpdatedCmHandles(networkCmProxyDataServicePropertyHandler
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse) {
+ dmiPluginRegistrationResponse.setUpdatedCmHandles(cmHandleRegistrationServicePropertyHandler
.updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
}
@@ -405,67 +227,24 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
}
} else {
cmHandleUpgradeResponses.add(
- CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_READY));
+ CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_READY));
}
} catch (final DataNodeNotFoundException dataNodeNotFoundException) {
log.error("Unable to find data node for cm handle id : {} , caused by : {}",
- cmHandleId, dataNodeNotFoundException.getMessage());
+ cmHandleId, dataNodeNotFoundException.getMessage());
cmHandleUpgradeResponses.add(
- CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
+ CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
} catch (final DataValidationException dataValidationException) {
log.error("Unable to upgrade cm handle id: {}, caused by : {}",
- cmHandleId, dataValidationException.getMessage());
+ cmHandleId, dataValidationException.getMessage());
cmHandleUpgradeResponses.add(
- CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID));
+ CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID));
}
}
cmHandleUpgradeResponses.addAll(upgradeCmHandles(acceptedCmHandleStatePerCmHandle));
dmiPluginRegistrationResponse.setUpgradedCmHandles(cmHandleUpgradeResponses);
}
- private Collection<String> checkAlternateIds(
- final List<NcmpServiceCmHandle> cmHandlesToBeCreated,
- final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses) {
- final Collection<String> rejectedCmHandleIds = alternateIdChecker
- .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated, AlternateIdChecker.Operation.CREATE);
- cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses(
- rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED));
- return rejectedCmHandleIds;
- }
-
- private List<String> persistCmHandlesWithState(final DmiPluginRegistration dmiPluginRegistration,
- final DmiPluginRegistrationResponse dmiPluginRegistrationResponse,
- final List<NcmpServiceCmHandle> cmHandlesToBeCreated,
- final Collection<String> rejectedCmHandleIds) {
- final List<String> succeededCmHandleIds = new ArrayList<>(cmHandlesToBeCreated.size());
- final List<YangModelCmHandle> yangModelCmHandlesToRegister = new ArrayList<>(cmHandlesToBeCreated.size());
- final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
- new ArrayList<>(cmHandlesToBeCreated.size());
- for (final NcmpServiceCmHandle ncmpServiceCmHandle: cmHandlesToBeCreated) {
- if (!rejectedCmHandleIds.contains(ncmpServiceCmHandle.getCmHandleId())) {
- yangModelCmHandlesToRegister.add(getYangModelCmHandle(dmiPluginRegistration, ncmpServiceCmHandle));
- cmHandleRegistrationResponses.add(
- CmHandleRegistrationResponse.createSuccessResponse(ncmpServiceCmHandle.getCmHandleId()));
- succeededCmHandleIds.add(ncmpServiceCmHandle.getCmHandleId());
- }
- }
- lcmEventsCmHandleStateHandler.initiateStateAdvised(yangModelCmHandlesToRegister);
- dmiPluginRegistrationResponse.setCreatedCmHandles(cmHandleRegistrationResponses);
- return succeededCmHandleIds;
- }
-
- private YangModelCmHandle getYangModelCmHandle(final DmiPluginRegistration dmiPluginRegistration,
- final NcmpServiceCmHandle ncmpServiceCmHandle) {
- return YangModelCmHandle.toYangModelCmHandle(
- dmiPluginRegistration.getDmiPlugin(),
- dmiPluginRegistration.getDmiDataPlugin(),
- dmiPluginRegistration.getDmiModelPlugin(),
- ncmpServiceCmHandle,
- ncmpServiceCmHandle.getModuleSetTag(),
- ncmpServiceCmHandle.getAlternateId(),
- ncmpServiceCmHandle.getDataProducerIdentifier());
- }
-
private void processTrustLevels(final Collection<NcmpServiceCmHandle> cmHandlesToBeCreated,
final Collection<String> succeededCmHandleIds) {
final Map<String, TrustLevel> initialTrustLevelPerCmHandleId = new HashMap<>(cmHandlesToBeCreated.size());
@@ -475,7 +254,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
ncmpServiceCmHandle.getRegistrationTrustLevel());
}
}
- trustLevelManager.handleInitialRegistrationOfTrustLevels(initialTrustLevelPerCmHandleId);
+ trustLevelManager.registerCmHandles(initialTrustLevelPerCmHandleId);
}
private static boolean moduleUpgradeCanBeSkipped(final YangModelCmHandle yangModelCmHandle,
@@ -489,14 +268,14 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
private static void updateYangModelCmHandleForUpgrade(final YangModelCmHandle yangModelCmHandle,
final String upgradedModuleSetTag) {
final String lockReasonWithModuleSetTag = String.format(ModuleOperationsUtils.MODULE_SET_TAG_MESSAGE_FORMAT,
- upgradedModuleSetTag);
+ upgradedModuleSetTag);
yangModelCmHandle.setCompositeState(new CompositeStateBuilder().withCmHandleState(CmHandleState.READY)
- .withLockReason(MODULE_UPGRADE, lockReasonWithModuleSetTag).build());
+ .withLockReason(MODULE_UPGRADE, lockReasonWithModuleSetTag).build());
}
private CmHandleRegistrationResponse deleteCmHandleAndGetCmHandleRegistrationResponse(final String cmHandleId) {
try {
- deleteCmHandleFromDbAndModuleSyncMap(cmHandleId);
+ deleteCmHandleFromDbAndCaches(cmHandleId);
return CmHandleRegistrationResponse.createSuccessResponse(cmHandleId);
} catch (final DataNodeNotFoundException dataNodeNotFoundException) {
log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}",
@@ -519,15 +298,17 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle);
}
- private void deleteCmHandleFromDbAndModuleSyncMap(final String cmHandleId) {
+ private void deleteCmHandleFromDbAndCaches(final String cmHandleId) {
inventoryPersistence.deleteSchemaSetWithCascade(cmHandleId);
inventoryPersistence.deleteDataNode(NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']");
+ trustLevelManager.removeCmHandles(Collections.singleton(cmHandleId));
removeDeletedCmHandleFromModuleSyncMap(cmHandleId);
}
- private void batchDeleteCmHandlesFromDbAndModuleSyncMap(final Collection<String> cmHandleIds) {
+ private void batchDeleteCmHandlesFromDbAndCaches(final Collection<String> cmHandleIds) {
inventoryPersistence.deleteSchemaSetsWithCascade(cmHandleIds);
inventoryPersistence.deleteDataNodes(mapCmHandleIdsToXpaths(cmHandleIds));
+ trustLevelManager.removeCmHandles(cmHandleIds);
cmHandleIds.forEach(this::removeDeletedCmHandleFromModuleSyncMap);
}
@@ -561,12 +342,48 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
return cmHandleStatePerCmHandle.keySet().stream().map(YangModelCmHandle::getId).toList();
}
- private void setTrustLevelPerDmiPlugin(final DmiPluginRegistration dmiPluginRegistration) {
- if (DmiPluginRegistration.isNullEmptyOrBlank(dmiPluginRegistration.getDmiDataPlugin())) {
- trustLevelPerDmiPlugin.put(dmiPluginRegistration.getDmiPlugin(), TrustLevel.COMPLETE);
- } else {
- trustLevelPerDmiPlugin.put(dmiPluginRegistration.getDmiDataPlugin(), TrustLevel.COMPLETE);
+ private Collection<String> checkAlternateIds(
+ final List<NcmpServiceCmHandle> cmHandlesToBeCreated,
+ final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses) {
+ final Collection<String> rejectedCmHandleIds = alternateIdChecker
+ .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated, AlternateIdChecker.Operation.CREATE);
+ cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses(
+ rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED));
+ return rejectedCmHandleIds;
+ }
+
+ private List<String> persistCmHandlesWithState(final DmiPluginRegistration dmiPluginRegistration,
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse,
+ final List<NcmpServiceCmHandle> cmHandlesToBeCreated,
+ final Collection<String> rejectedCmHandleIds) {
+ final List<String> succeededCmHandleIds = new ArrayList<>(cmHandlesToBeCreated.size());
+ final List<YangModelCmHandle> yangModelCmHandlesToRegister = new ArrayList<>(cmHandlesToBeCreated.size());
+ final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
+ new ArrayList<>(cmHandlesToBeCreated.size());
+ for (final NcmpServiceCmHandle ncmpServiceCmHandle: cmHandlesToBeCreated) {
+ if (!rejectedCmHandleIds.contains(ncmpServiceCmHandle.getCmHandleId())) {
+ yangModelCmHandlesToRegister.add(getYangModelCmHandle(dmiPluginRegistration, ncmpServiceCmHandle));
+ cmHandleRegistrationResponses.add(
+ CmHandleRegistrationResponse.createSuccessResponse(ncmpServiceCmHandle.getCmHandleId()));
+ succeededCmHandleIds.add(ncmpServiceCmHandle.getCmHandleId());
+ }
}
+ lcmEventsCmHandleStateHandler.initiateStateAdvised(yangModelCmHandlesToRegister);
+ dmiPluginRegistrationResponse.setCreatedCmHandles(cmHandleRegistrationResponses);
+ return succeededCmHandleIds;
}
+ private YangModelCmHandle getYangModelCmHandle(final DmiPluginRegistration dmiPluginRegistration,
+ final NcmpServiceCmHandle ncmpServiceCmHandle) {
+ return YangModelCmHandle.toYangModelCmHandle(
+ dmiPluginRegistration.getDmiPlugin(),
+ dmiPluginRegistration.getDmiDataPlugin(),
+ dmiPluginRegistration.getDmiModelPlugin(),
+ ncmpServiceCmHandle,
+ ncmpServiceCmHandle.getModuleSetTag(),
+ ncmpServiceCmHandle.getAlternateId(),
+ ncmpServiceCmHandle.getDataProducerIdentifier());
+ }
+
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java
index f861910024..308ead1270 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,16 +20,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl;
+package org.onap.cps.ncmp.impl.inventory;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID;
-import static org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServicePropertyHandler.PropertyType.DMI_PROPERTY;
-import static org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServicePropertyHandler.PropertyType.PUBLIC_PROPERTY;
-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.NCMP_DMI_REGISTRY_PARENT;
+import static org.onap.cps.ncmp.impl.inventory.CmHandleRegistrationServicePropertyHandler.PropertyType.DMI_PROPERTY;
+import static org.onap.cps.ncmp.impl.inventory.CmHandleRegistrationServicePropertyHandler.PropertyType.PUBLIC_PROPERTY;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
import com.google.common.collect.ImmutableMap;
import java.time.OffsetDateTime;
@@ -44,27 +44,26 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.onap.cps.api.CpsDataService;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
import org.onap.cps.spi.exceptions.DataValidationException;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.DataNodeBuilder;
+import org.onap.cps.utils.ContentType;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
@Slf4j
@Service
@RequiredArgsConstructor
//Accepting the security hotspot as the string checked is generated from inside code and not user input.
@SuppressWarnings("squid:S5852")
-public class NetworkCmProxyDataServicePropertyHandler {
+public class CmHandleRegistrationServicePropertyHandler {
private final InventoryPersistence inventoryPersistence;
private final CpsDataService cpsDataService;
@@ -113,8 +112,7 @@ public class NetworkCmProxyDataServicePropertyHandler {
private void processUpdates(final DataNode existingCmHandleDataNode,
final NcmpServiceCmHandle updatedNcmpServiceCmHandle) {
- setAndUpdateCmHandleField(
- updatedNcmpServiceCmHandle.getCmHandleId(), "alternate-id", updatedNcmpServiceCmHandle.getAlternateId());
+ updateAlternateId(updatedNcmpServiceCmHandle);
updateDataProducerIdentifier(existingCmHandleDataNode, updatedNcmpServiceCmHandle);
if (!updatedNcmpServiceCmHandle.getPublicProperties().isEmpty()) {
updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY,
@@ -125,18 +123,27 @@ public class NetworkCmProxyDataServicePropertyHandler {
}
}
+ private void updateAlternateId(final NcmpServiceCmHandle ncmpServiceCmHandle) {
+ final String newAlternateId = ncmpServiceCmHandle.getAlternateId();
+ if (StringUtils.isNotBlank(newAlternateId)) {
+ setAndUpdateCmHandleField(ncmpServiceCmHandle.getCmHandleId(), "alternate-id", newAlternateId);
+ }
+ }
+
private void updateDataProducerIdentifier(final DataNode cmHandleDataNode,
final NcmpServiceCmHandle ncmpServiceCmHandle) {
final String newDataProducerIdentifier = ncmpServiceCmHandle.getDataProducerIdentifier();
- if (StringUtils.hasText(newDataProducerIdentifier)) {
- final YangModelCmHandle yangModelCmHandle =
- YangDataConverter.convertCmHandleToYangModel(cmHandleDataNode);
+ if (StringUtils.isNotBlank(newDataProducerIdentifier)) {
+ final YangModelCmHandle yangModelCmHandle = YangDataConverter.toYangModelCmHandle(cmHandleDataNode);
final String existingDataProducerIdentifier = yangModelCmHandle.getDataProducerIdentifier();
- if (StringUtils.hasText(existingDataProducerIdentifier)) {
+ if (StringUtils.isNotBlank(existingDataProducerIdentifier)) {
if (!existingDataProducerIdentifier.equals(newDataProducerIdentifier)) {
log.warn("Unable to update dataProducerIdentifier for cmHandle {}. "
+ "Value for dataProducerIdentifier has been set previously.",
ncmpServiceCmHandle.getCmHandleId());
+ } else {
+ log.debug("dataProducerIdentifier for cmHandle {} is already set to {}.",
+ ncmpServiceCmHandle.getCmHandleId(), newDataProducerIdentifier);
}
} else {
setAndUpdateCmHandleField(
@@ -222,7 +229,7 @@ public class NetworkCmProxyDataServicePropertyHandler {
cmHandleData.put(fieldName, newFieldValue);
dmiRegistryData.put("cm-handles", cmHandleData);
cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
- jsonObjectMapper.asJsonString(dmiRegistryData), OffsetDateTime.now());
+ jsonObjectMapper.asJsonString(dmiRegistryData), OffsetDateTime.now(), ContentType.JSON);
log.debug("Updating {} for cmHandle {} with value : {})", fieldName, cmHandleIdToUpdate, newFieldValue);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CompositeStateUtils.java
index 35ad54fdef..685d204633 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CompositeStateUtils.java
@@ -18,11 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
/**
* It will have all the utility method responsible for handling the composite state.
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/DataStoreSyncState.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/DataStoreSyncState.java
index b92d152bfa..a260ce9cbe 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/DataStoreSyncState.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/DataStoreSyncState.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory;
public enum DataStoreSyncState {
SYNCHRONIZED, UNSYNCHRONIZED, NONE_REQUESTED
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java
index 184b12570e..a0d3a3eaee 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java
@@ -19,13 +19,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-import org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.spi.model.ModuleReference;
@@ -130,14 +130,12 @@ public interface InventoryPersistence extends NcmpPersistence {
DataNode getCmHandleDataNodeByAlternateId(String alternateId);
/**
- * Get data node that matches longest alternate id by removing elements (as defined by the separator string)
- * from right to left.
+ * Get data nodes for the given batch of alternate ids.
*
- * @param alternateId alternate ID
- * @param separator a string that separates each element from the next.
- * @return data node
+ * @param alternateIds alternate IDs
+ * @return data nodes
*/
- DataNode getCmHandleDataNodeByLongestMatchAlternateId(final String alternateId, final String separator);
+ Collection<DataNode> getCmHandleDataNodesByAlternateIds(Collection<String> alternateIds);
/**
* Get collection of data nodes of given cm handles.
@@ -154,4 +152,12 @@ public interface InventoryPersistence extends NcmpPersistence {
* @return Collection of CM handle Ids
*/
Collection<String> getCmHandleIdsWithGivenModules(Collection<String> moduleNamesForQuery);
+
+ /**
+ * Check database if cm handle id exists if not return false.
+ *
+ * @param cmHandleId cmHandle Id
+ * @return Boolean
+ */
+ boolean isExistingCmHandleId(String cmHandleId);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
index bf54fe5d96..06c3f8d2f4 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory;
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
@@ -32,21 +32,23 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
import org.onap.cps.api.CpsAnchorService;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsModuleService;
-import org.onap.cps.ncmp.api.impl.exception.NoAlternateIdParentFoundException;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.impl.utils.CpsValidator;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
import org.onap.cps.spi.exceptions.DataValidationException;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.spi.model.ModuleReference;
-import org.onap.cps.spi.utils.CpsValidator;
+import org.onap.cps.utils.ContentType;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Component;
@@ -59,7 +61,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
private final CpsModuleService cpsModuleService;
private final CpsAnchorService cpsAnchorService;
private final CpsValidator cpsValidator;
- private final CmHandleQueries cmHandleQueries;
+ private final CmHandleQueryService cmHandleQueryService;
/**
* initialize an inventory persistence object.
@@ -72,12 +74,13 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
*/
public InventoryPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService,
final CpsModuleService cpsModuleService, final CpsValidator cpsValidator,
- final CpsAnchorService cpsAnchorService, final CmHandleQueries cmHandleQueries) {
+ final CpsAnchorService cpsAnchorService,
+ final CmHandleQueryService cmHandleQueryService) {
super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator);
this.cpsModuleService = cpsModuleService;
this.cpsAnchorService = cpsAnchorService;
this.cpsValidator = cpsValidator;
- this.cmHandleQueries = cmHandleQueries;
+ this.cmHandleQueryService = cmHandleQueryService;
}
@@ -94,7 +97,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
public void saveCmHandleState(final String cmHandleId, final CompositeState compositeState) {
final String cmHandleJsonData = createStateJsonData(jsonObjectMapper.asJsonString(compositeState));
cpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- getXPathForCmHandleById(cmHandleId), cmHandleJsonData, OffsetDateTime.now());
+ getXPathForCmHandleById(cmHandleId), cmHandleJsonData, OffsetDateTime.now(), ContentType.JSON);
}
@Override
@@ -104,14 +107,14 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
getXPathForCmHandleById(cmHandleId),
createStateJsonData(jsonObjectMapper.asJsonString(compositeState))));
cpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- cmHandlesJsonDataMap, OffsetDateTime.now());
+ cmHandlesJsonDataMap, OffsetDateTime.now(), ContentType.JSON);
}
@Override
public YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
cpsValidator.validateNameCharacters(cmHandleId);
final DataNode dataNode = getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next();
- return YangDataConverter.convertCmHandleToYangModel(dataNode);
+ return YangDataConverter.toYangModelCmHandle(dataNode);
}
@Override
@@ -126,7 +129,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
dataValidationException.getMessage());
}
});
- return YangDataConverter.convertDataNodesToYangModelCmHandles(getCmHandleDataNodes(validCmHandleIds));
+ return YangDataConverter.toYangModelCmHandles(getCmHandleDataNodes(validCmHandleIds));
}
@Override
@@ -160,7 +163,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
Lists.partition(yangModelCmHandles, CMHANDLE_BATCH_SIZE)) {
final String cmHandlesJsonData = createCmHandlesJsonData(yangModelCmHandleBatch);
cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- NCMP_DMI_REGISTRY_PARENT, cmHandlesJsonData, NO_TIMESTAMP);
+ NCMP_DMI_REGISTRY_PARENT, cmHandlesJsonData, NO_TIMESTAMP, ContentType.JSON);
}
}
@@ -172,7 +175,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
@Override
public DataNode getCmHandleDataNodeByAlternateId(final String alternateId) {
final String cpsPathForCmHandleByAlternateId = getCpsPathForCmHandleByAlternateId(alternateId);
- final Collection<DataNode> dataNodes = cmHandleQueries
+ final Collection<DataNode> dataNodes = cmHandleQueryService
.queryNcmpRegistryByCpsPath(cpsPathForCmHandleByAlternateId, OMIT_DESCENDANTS);
if (dataNodes.isEmpty()) {
throw new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
@@ -182,16 +185,12 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
}
@Override
- public DataNode getCmHandleDataNodeByLongestMatchAlternateId(final String alternateId, final String separator) {
- String bestMatch = alternateId;
- while (StringUtils.isNotEmpty(bestMatch)) {
- try {
- return getCmHandleDataNodeByAlternateId(bestMatch);
- } catch (final DataNodeNotFoundException ignored) {
- bestMatch = getParentPath(bestMatch, separator);
- }
+ public Collection<DataNode> getCmHandleDataNodesByAlternateIds(final Collection<String> alternateIds) {
+ if (alternateIds.isEmpty()) {
+ return Collections.emptyList();
}
- throw new NoAlternateIdParentFoundException(alternateId);
+ final String cpsPathForCmHandlesByAlternateIds = getCpsPathForCmHandlesByAlternateIds(alternateIds);
+ return cmHandleQueryService.queryNcmpRegistryByCpsPath(cpsPathForCmHandlesByAlternateIds, OMIT_DESCENDANTS);
}
@Override
@@ -206,6 +205,15 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
return cpsAnchorService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery);
}
+ @Override
+ public boolean isExistingCmHandleId(final String cmHandleId) {
+ try {
+ return !getCmHandleDataNodeByCmHandleId(cmHandleId).isEmpty();
+ } catch (final DataNodeNotFoundException exception) {
+ return false;
+ }
+ }
+
private static String getXPathForCmHandleById(final String cmHandleId) {
return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']";
}
@@ -214,6 +222,11 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@alternate-id='" + alternateId + "']";
}
+ private static String getCpsPathForCmHandlesByAlternateIds(final Collection<String> alternateIds) {
+ return alternateIds.stream().collect(Collectors.joining("' or @alternate-id='",
+ NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@alternate-id='", "']"));
+ }
+
private static String createStateJsonData(final String state) {
return "{\"state\":" + state + "}";
}
@@ -221,9 +234,4 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
private String createCmHandlesJsonData(final List<YangModelCmHandle> yangModelCmHandles) {
return "{\"cm-handles\":" + jsonObjectMapper.asJsonString(yangModelCmHandles) + "}";
}
-
- private static String getParentPath(final String path, final String separator) {
- final int lastSeparatorIndex = path.lastIndexOf(separator);
- return lastSeparatorIndex < 0 ? "" : path.substring(0, lastSeparatorIndex);
- }
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/ncmppersistence/NcmpPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/NcmpPersistence.java
index d72b5d58f1..5271485e3b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/ncmppersistence/NcmpPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/NcmpPersistence.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.ncmppersistence;
+package org.onap.cps.ncmp.impl.inventory;
import java.time.OffsetDateTime;
import java.util.Collection;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/NcmpPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/NcmpPersistenceImpl.java
index 6a2d6d810b..905b09ef74 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/NcmpPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/NcmpPersistenceImpl.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory;
import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
@@ -29,11 +29,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsModuleService;
-import org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
import org.onap.cps.spi.model.DataNode;
-import org.onap.cps.spi.utils.CpsValidator;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Component;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandleQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java
index 06522f80cf..03ec30b73b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyCmHandleQueryService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java
@@ -18,13 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api;
+package org.onap.cps.ncmp.impl.inventory;
import java.util.Collection;
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
-public interface NetworkCmProxyCmHandleQueryService {
+public interface ParameterizedCmHandleQueryService {
/**
* Query and return cm handle ids that match the given query parameters.
* Supported query types:
@@ -51,21 +51,14 @@ public interface NetworkCmProxyCmHandleQueryService {
Collection<String> queryCmHandleIdsForInventory(CmHandleQueryServiceParameters cmHandleQueryServiceParameters);
/**
- * Query and return cm handle objects that match the given query parameters.
+ * Query and return yang model cm handle objects that match the given query parameters.
* Supported query types:
* public properties
* modules
* cps-path
*
* @param cmHandleQueryServiceParameters the cm handle query parameters
- * @return collection of cm handles
+ * @return collection of yang model cm handles
*/
- Collection<NcmpServiceCmHandle> queryCmHandles(CmHandleQueryServiceParameters cmHandleQueryServiceParameters);
-
- /**
- * Query and return all cm handle objects.
- *
- * @return collection of cm handles
- */
- Collection<NcmpServiceCmHandle> getAllCmHandles();
+ Collection<YangModelCmHandle> queryCmHandles(CmHandleQueryServiceParameters cmHandleQueryServiceParameters);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java
index 8890d14ae1..84229e2895 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java
@@ -18,16 +18,15 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl;
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
-import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.HAS_ALL_MODULES;
-import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.HAS_ALL_PROPERTIES;
-import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.WITH_CPS_PATH;
-import static org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions.WITH_TRUST_LEVEL;
-import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateCpsPathConditionProperties;
-import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateModuleNameConditionProperties;
-import static org.onap.cps.ncmp.api.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle;
+package org.onap.cps.ncmp.impl.inventory;
+
+import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateCpsPathConditionProperties;
+import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateModuleNameConditionProperties;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HAS_ALL_MODULES;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HAS_ALL_PROPERTIES;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_CPS_PATH;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_TRUST_LEVEL;
import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY;
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
@@ -40,67 +39,58 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
import org.onap.cps.cpspath.parser.PathParsingException;
-import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.inventory.enums.PropertyType;
-import org.onap.cps.ncmp.api.impl.utils.InventoryQueryConditions;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
+import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions;
+import org.onap.cps.ncmp.impl.inventory.models.PropertyType;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.onap.cps.spi.exceptions.DataValidationException;
import org.onap.cps.spi.model.ConditionProperties;
import org.onap.cps.spi.model.DataNode;
import org.springframework.stereotype.Service;
@Service
-@Slf4j
@RequiredArgsConstructor
-public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmHandleQueryService {
+public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHandleQueryService {
private static final Collection<String> NO_QUERY_TO_EXECUTE = null;
- private final CmHandleQueries cmHandleQueries;
+ private final CmHandleQueryService cmHandleQueryService;
private final InventoryPersistence inventoryPersistence;
@Override
public Collection<String> queryCmHandleIds(
final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
return executeQueries(cmHandleQueryServiceParameters,
- this::executeCpsPathQuery,
- this::queryCmHandlesByPublicProperties,
- this::executeModuleNameQuery,
+ this::executeCpsPathQuery,
+ this::queryCmHandlesByPublicProperties,
+ this::executeModuleNameQuery,
this::queryCmHandlesByTrustLevel);
}
@Override
public Collection<String> queryCmHandleIdsForInventory(
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
return executeQueries(cmHandleQueryServiceParameters,
- this::queryCmHandlesByPublicProperties,
- this::queryCmHandlesByPrivateProperties,
- this::queryCmHandlesByDmiPlugin);
+ this::executeCpsPathQuery,
+ this::queryCmHandlesByPublicProperties,
+ this::queryCmHandlesByPrivateProperties,
+ this::queryCmHandlesByDmiPlugin);
}
@Override
- public Collection<NcmpServiceCmHandle> queryCmHandles(
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
-
+ public Collection<YangModelCmHandle> queryCmHandles(
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) {
if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) {
return getAllCmHandles();
}
-
final Collection<String> cmHandleIds = queryCmHandleIds(cmHandleQueryServiceParameters);
-
- return getNcmpServiceCmHandles(cmHandleIds);
+ return inventoryPersistence.getYangModelCmHandles(cmHandleIds);
}
- @Override
- public Collection<NcmpServiceCmHandle> getAllCmHandles() {
+ private Collection<YangModelCmHandle> getAllCmHandles() {
final DataNode dataNode = inventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT).iterator().next();
- return dataNode.getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet());
+ return dataNode.getChildDataNodes().stream().map(YangDataConverter::toYangModelCmHandle).toList();
}
private Collection<String> queryCmHandlesByDmiPlugin(
@@ -115,7 +105,7 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
final String dmiPluginIdentifierValue = dmiPropertyQueryPairs
.get(PropertyType.DMI_PLUGIN.getYangContainerName());
- return cmHandleQueries.getCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifierValue);
+ return cmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifierValue);
}
private Collection<String> queryCmHandlesByPrivateProperties(
@@ -128,7 +118,7 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
if (privatePropertyQueryPairs.isEmpty()) {
return NO_QUERY_TO_EXECUTE;
}
- return cmHandleQueries.queryCmHandleAdditionalProperties(privatePropertyQueryPairs);
+ return cmHandleQueryService.queryCmHandleAdditionalProperties(privatePropertyQueryPairs);
}
private Collection<String> queryCmHandlesByPublicProperties(
@@ -141,7 +131,7 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
if (publicPropertyQueryPairs.isEmpty()) {
return NO_QUERY_TO_EXECUTE;
}
- return cmHandleQueries.queryCmHandlePublicProperties(publicPropertyQueryPairs);
+ return cmHandleQueryService.queryCmHandlePublicProperties(publicPropertyQueryPairs);
}
private Collection<String> queryCmHandlesByTrustLevel(final CmHandleQueryServiceParameters
@@ -154,7 +144,7 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
if (trustLevelPropertyQueryPairs.isEmpty()) {
return NO_QUERY_TO_EXECUTE;
}
- return cmHandleQueries.queryCmHandlesByTrustLevel(trustLevelPropertyQueryPairs);
+ return cmHandleQueryService.queryCmHandlesByTrustLevel(trustLevelPropertyQueryPairs);
}
private Collection<String> executeModuleNameQuery(
@@ -180,7 +170,7 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
}
try {
cpsPathQueryResult = collectCmHandleIdsFromDataNodes(
- cmHandleQueries.queryCmHandleAncestorsByCpsPath(
+ cmHandleQueryService.queryCmHandleAncestorsByCpsPath(
cpsPathCondition.get("cpsPath"), OMIT_DESCENDANTS));
} catch (final PathParsingException pathParsingException) {
throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(),
@@ -228,22 +218,6 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
return collectCmHandleIdsFromDataNodes(dataNode.getChildDataNodes());
}
- private Collection<NcmpServiceCmHandle> getNcmpServiceCmHandles(final Collection<String> cmHandleIds) {
- final Collection<YangModelCmHandle> yangModelcmHandles
- = inventoryPersistence.getYangModelCmHandles(cmHandleIds);
-
- final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles = new ArrayList<>(yangModelcmHandles.size());
-
- yangModelcmHandles.forEach(yangModelcmHandle ->
- ncmpServiceCmHandles.add(YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelcmHandle))
- );
- return ncmpServiceCmHandles;
- }
-
- private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) {
- return convertYangModelCmHandleToNcmpServiceCmHandle(YangDataConverter.convertCmHandleToYangModel(dataNode));
- }
-
private Collection<String> executeQueries(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters,
final Function<CmHandleQueryServiceParameters, Collection<String>>...
queryFunctions) {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditions.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditions.java
index a59776036a..6be5c8ba16 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditions.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditions.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils;
+package org.onap.cps.ncmp.impl.inventory.models;
import java.util.Arrays;
import java.util.Collection;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleState.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleState.java
index 5485ee7e80..9a4b3e2a83 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleState.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/CmHandleState.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory.models;
public enum CmHandleState {
ADVISED, READY, LOCKED, DELETING, DELETED
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/InventoryQueryConditions.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/InventoryQueryConditions.java
index 9437cf0bac..e0b54d2197 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/InventoryQueryConditions.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/InventoryQueryConditions.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils;
+package org.onap.cps.ncmp.impl.inventory.models;
import java.util.Arrays;
import java.util.List;
@@ -32,7 +32,8 @@ public enum InventoryQueryConditions {
HAS_ALL_PROPERTIES("hasAllProperties"),
HAS_ALL_ADDITIONAL_PROPERTIES("hasAllAdditionalProperties"),
- CM_HANDLE_WITH_DMI_PLUGIN("cmHandleWithDmiPlugin");
+ CM_HANDLE_WITH_DMI_PLUGIN("cmHandleWithDmiPlugin"),
+ WITH_CPS_PATH("cmHandleWithCpsPath");
public static final List<String> ALL_CONDITION_NAMES = Arrays.stream(InventoryQueryConditions.values())
.map(InventoryQueryConditions::getName).collect(Collectors.toList());
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/LockReasonCategory.java
index e2b2c6b4ae..1003aeca2d 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/LockReasonCategory.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory.models;
public enum LockReasonCategory {
MODULE_SYNC_FAILED,
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/ModelledDmiServiceLeaves.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/ModelledDmiServiceLeaves.java
index b8a1ba02db..e9c4957d0c 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/ModelledDmiServiceLeaves.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/ModelledDmiServiceLeaves.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory;
+package org.onap.cps.ncmp.impl.inventory.models;
public enum ModelledDmiServiceLeaves {
DMI_SERVICE_NAME("dmi-service-name"),
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/enums/PropertyType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/PropertyType.java
index 08bfe98e5c..cc8b094b4c 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/enums/PropertyType.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/PropertyType.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.enums;
+package org.onap.cps.ncmp.impl.inventory.models;
import lombok.AllArgsConstructor;
import lombok.Getter;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandle.java
index 2ca2b2eb0d..76ee286635 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandle.java
@@ -18,8 +18,7 @@
* ============LICENSE_END=========================================================
*/
-
-package org.onap.cps.ncmp.api.impl.yangmodels;
+package org.onap.cps.ncmp.impl.inventory.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -34,9 +33,9 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.impl.models.RequiredDmiService;
/**
* Cm Handle which follows the Yang resource dmi registry model when persisting data to DMI or the DB.
@@ -126,10 +125,9 @@ public class YangModelCmHandle {
yangModelCmHandle.setDmiServiceName(dmiServiceName);
yangModelCmHandle.setDmiDataServiceName(dmiDataServiceName);
yangModelCmHandle.setDmiModelServiceName(dmiModelServiceName);
- yangModelCmHandle.setModuleSetTag(moduleSetTag == null ? StringUtils.EMPTY : moduleSetTag);
- yangModelCmHandle.setAlternateId(alternateId == null ? StringUtils.EMPTY : alternateId);
- yangModelCmHandle.setDataProducerIdentifier(
- dataProducerIdentifier == null ? StringUtils.EMPTY : dataProducerIdentifier);
+ yangModelCmHandle.setModuleSetTag(StringUtils.trimToEmpty(moduleSetTag));
+ yangModelCmHandle.setAlternateId(StringUtils.trimToEmpty(alternateId));
+ yangModelCmHandle.setDataProducerIdentifier(StringUtils.trimToEmpty(dataProducerIdentifier));
yangModelCmHandle.setDmiProperties(asYangModelCmHandleProperties(ncmpServiceCmHandle.getDmiProperties()));
yangModelCmHandle.setPublicProperties(asYangModelCmHandleProperties(
ncmpServiceCmHandle.getPublicProperties()));
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/executor/AsyncTaskExecutor.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/AsyncTaskExecutor.java
index 2d5e7a1abc..b8bb64f537 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/executor/AsyncTaskExecutor.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/AsyncTaskExecutor.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync.executor;
+package org.onap.cps.ncmp.impl.inventory.sync;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/DataSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DataSyncWatchdog.java
index 6f089a57fb..c3973236f0 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/DataSyncWatchdog.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DataSyncWatchdog.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-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.
@@ -18,9 +18,9 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync;
+package org.onap.cps.ncmp.impl.inventory.sync;
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
import com.hazelcast.map.IMap;
import java.time.OffsetDateTime;
@@ -29,10 +29,9 @@ import java.util.function.Consumer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.api.CpsDataService;
-import org.onap.cps.ncmp.api.impl.config.embeddedcache.SynchronizationCacheConfig;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@@ -61,21 +60,22 @@ public class DataSyncWatchdog {
moduleOperationsUtils.getUnsynchronizedReadyCmHandles().forEach(unSynchronizedReadyCmHandle -> {
final String cmHandleId = unSynchronizedReadyCmHandle.getId();
if (hasPushedIntoSemaphoreMap(cmHandleId)) {
- log.debug("Executing data sync on {}", cmHandleId);
+ log.info("Executing data sync on {}", cmHandleId);
final CompositeState compositeState = inventoryPersistence
.getCmHandleState(cmHandleId);
final String resourceData = moduleOperationsUtils.getResourceData(cmHandleId);
if (resourceData == null) {
- log.debug("Error retrieving resource data for Cm-Handle: {}", cmHandleId);
+ log.error("Error retrieving resource data for Cm-Handle: {}", cmHandleId);
} else {
cpsDataService.saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId,
resourceData, OffsetDateTime.now());
setSyncStateToSynchronized().accept(compositeState);
inventoryPersistence.saveCmHandleState(cmHandleId, compositeState);
updateDataSyncSemaphoreMap(cmHandleId);
+ log.info("Data sync finished for {}", cmHandleId);
}
} else {
- log.debug("{} already processed by another instance", cmHandleId);
+ log.info("{} already processed by another instance", cmHandleId);
}
});
log.debug("No Cm-Handles currently found in READY State and Operational Sync State is UNSYNCHRONIZED");
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/impl/inventory/sync/DmiModelOperations.java
index 2a9248a165..8ba70b3a31 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/impl/inventory/sync/DmiModelOperations.java
@@ -19,48 +19,42 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.impl.inventory.sync;
-import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL;
+import static org.onap.cps.ncmp.api.data.models.OperationType.READ;
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL;
import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.YangResource;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.api.inventory.models.YangResource;
+import org.onap.cps.ncmp.impl.dmi.DmiProperties;
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.models.DmiRequestBody;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
import org.onap.cps.spi.model.ModuleReference;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
/**
* Operations class for DMI Model.
*/
-@Component
-public class DmiModelOperations extends DmiOperations {
+@RequiredArgsConstructor
+@Service
+public class DmiModelOperations {
- /**
- * Constructor for {@code DmiOperations}. This method also manipulates url properties.
- *
- * @param dmiRestClient {@code DmiRestClient}
- */
- public DmiModelOperations(final InventoryPersistence inventoryPersistence,
- final JsonObjectMapper jsonObjectMapper,
- final DmiProperties dmiProperties,
- final DmiRestClient dmiRestClient, final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
- super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
- }
+ private final JsonObjectMapper jsonObjectMapper;
+ private final DmiProperties dmiProperties;
+ private final DmiRestClient dmiRestClient;
/**
* Retrieves module references.
@@ -113,9 +107,13 @@ public class DmiModelOperations extends DmiOperations {
final String jsonRequestBody,
final String cmHandle,
final String resourceName) {
- final String dmiResourceDataUrl = getDmiResourceUrl(dmiServiceName, cmHandle, resourceName);
- return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody,
- OperationType.READ, null);
+ final UrlTemplateParameters urlTemplateParameters = RestServiceUrlTemplateBuilder.newInstance()
+ .fixedPathSegment("ch")
+ .variablePathSegment("cmHandleId", cmHandle)
+ .fixedPathSegment(resourceName)
+ .createUrlTemplateParameters(dmiServiceName, dmiProperties.getDmiBasePath());
+ return dmiRestClient.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, jsonRequestBody, READ,
+ null);
}
private static String getRequestBodyToFetchYangResources(final Collection<ModuleReference> newModuleReferences,
@@ -126,8 +124,7 @@ public class DmiModelOperations extends DmiOperations {
data.add("modules", moduleReferencesAsJson);
final JsonObject jsonRequestObject = new JsonObject();
if (!moduleSetTag.isEmpty()) {
- final JsonElement moduleSetTagAsJson = JsonParser.parseString(moduleSetTag);
- jsonRequestObject.add("moduleSetTag", moduleSetTagAsJson);
+ jsonRequestObject.addProperty("moduleSetTag", moduleSetTag);
}
jsonRequestObject.add("data", data);
jsonRequestObject.add("cmHandleProperties", toJsonObject(dmiProperties));
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java
index 794ca5b1b6..aae1769968 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java
@@ -19,15 +19,11 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync;
-
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL;
+package org.onap.cps.ncmp.impl.inventory.sync;
import com.fasterxml.jackson.databind.JsonNode;
-import java.time.Duration;
-import java.time.OffsetDateTime;
-import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -38,14 +34,14 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState;
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory;
-import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.impl.data.DmiDataOperations;
+import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService;
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.utils.JsonObjectMapper;
@@ -57,14 +53,13 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class ModuleOperationsUtils {
- private final CmHandleQueries cmHandleQueries;
+ private final CmHandleQueryService cmHandleQueryService;
private final DmiDataOperations dmiDataOperations;
private final JsonObjectMapper jsonObjectMapper;
private static final String RETRY_ATTEMPT_KEY = "attempt";
private static final String MODULE_SET_TAG_KEY = "moduleSetTag";
public static final String MODULE_SET_TAG_MESSAGE_FORMAT = "Upgrade to ModuleSetTag: %s";
- private static final String LOCK_REASON_DETAILS_MSG_FORMAT =
- MODULE_SET_TAG_MESSAGE_FORMAT + " Attempt #%d failed: %s";
+ private static final String LOCK_REASON_DETAILS_MSG_FORMAT = " Attempt #%d failed: %s";
private static final Pattern retryAttemptPattern = Pattern.compile("Attempt #(\\d+) failed:.+");
private static final Pattern moduleSetTagPattern = Pattern.compile("Upgrade to ModuleSetTag: (\\S+)");
private static final String CPS_PATH_CM_HANDLES_MODEL_SYNC_FAILED_OR_UPGRADE = """
@@ -77,8 +72,9 @@ public class ModuleOperationsUtils {
*
* @return cm handles (data nodes) in ADVISED state (empty list if none found)
*/
- public List<DataNode> getAdvisedCmHandles() {
- final List<DataNode> advisedCmHandlesAsDataNodes = cmHandleQueries.queryCmHandlesByState(CmHandleState.ADVISED);
+ public Collection<DataNode> getAdvisedCmHandles() {
+ final Collection<DataNode> advisedCmHandlesAsDataNodes =
+ cmHandleQueryService.queryCmHandlesByState(CmHandleState.ADVISED);
log.debug("Total number of fetched advised cm handle(s) is (are) {}", advisedCmHandlesAsDataNodes.size());
return advisedCmHandlesAsDataNodes;
}
@@ -91,13 +87,13 @@ public class ModuleOperationsUtils {
* return empty list if not found
*/
public List<YangModelCmHandle> getUnsynchronizedReadyCmHandles() {
- final List<DataNode> unsynchronizedCmHandles = cmHandleQueries
+ final Collection<DataNode> unsynchronizedCmHandles = cmHandleQueryService
.queryCmHandlesByOperationalSyncState(DataStoreSyncState.UNSYNCHRONIZED);
final List<YangModelCmHandle> yangModelCmHandles = new ArrayList<>();
for (final DataNode unsynchronizedCmHandle : unsynchronizedCmHandles) {
final String cmHandleId = unsynchronizedCmHandle.getLeaves().get("id").toString();
- if (cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY)) {
+ if (cmHandleQueryService.cmHandleHasState(cmHandleId, CmHandleState.READY)) {
yangModelCmHandles.addAll(convertCmHandlesDataNodesToYangModelCmHandles(
Collections.singletonList(unsynchronizedCmHandle)));
}
@@ -111,31 +107,33 @@ public class ModuleOperationsUtils {
*
* @return a random LOCKED yang model cm handle, return null if not found
*/
- public List<YangModelCmHandle> getCmHandlesThatFailedModelSyncOrUpgrade() {
- final List<DataNode> lockedCmHandlesAsDataNodeList
- = cmHandleQueries.queryCmHandleAncestorsByCpsPath(CPS_PATH_CM_HANDLES_MODEL_SYNC_FAILED_OR_UPGRADE,
+ public Collection<YangModelCmHandle> getCmHandlesThatFailedModelSyncOrUpgrade() {
+ final Collection<DataNode> lockedCmHandlesAsDataNodeList
+ = cmHandleQueryService.queryCmHandleAncestorsByCpsPath(CPS_PATH_CM_HANDLES_MODEL_SYNC_FAILED_OR_UPGRADE,
FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
return convertCmHandlesDataNodesToYangModelCmHandles(lockedCmHandlesAsDataNodeList);
}
/**
- * Update Composite State attempts counter and set new lock reason and details.
+ * Updates the lock reason message and attempt counter for the provided CompositeState.
+ * This method increments the attempt counter and updates the lock reason message,
+ * including the module set tag if available.
*
- * @param lockReasonCategory lock reason category
- * @param errorMessage error message
+ * @param compositeState the composite state of the CM handle
+ * @param lockReasonCategory the lock reason category for the CM handle
+ * @param errorMessage the error message to include in the lock reason message
*/
- public void updateLockReasonDetailsAndAttempts(final CompositeState compositeState,
- final LockReasonCategory lockReasonCategory,
- final String errorMessage) {
- int attempt = 1;
- final Map<String, String> compositeStateDetails
- = getLockedCompositeStateDetails(compositeState.getLockReason());
- if (!compositeStateDetails.isEmpty() && compositeStateDetails.containsKey(RETRY_ATTEMPT_KEY)) {
- attempt = 1 + Integer.parseInt(compositeStateDetails.get(RETRY_ATTEMPT_KEY));
- }
- final String moduleSetTag = compositeStateDetails.getOrDefault(MODULE_SET_TAG_KEY, "");
+ public void updateLockReasonWithAttempts(final CompositeState compositeState,
+ final LockReasonCategory lockReasonCategory,
+ final String errorMessage) {
+ final Map<String, String> lockedStateDetails = getLockedCompositeStateDetails(compositeState.getLockReason());
+ final int nextAttemptCount = calculateNextAttemptCount(lockedStateDetails);
+ final String moduleSetTag = lockedStateDetails.getOrDefault(MODULE_SET_TAG_KEY, "");
+
+ final String lockReasonMessage = buildLockReasonDetails(moduleSetTag, nextAttemptCount, errorMessage);
+
compositeState.setLockReason(CompositeState.LockReason.builder()
- .details(String.format(LOCK_REASON_DETAILS_MSG_FORMAT, moduleSetTag, attempt, errorMessage))
+ .details(lockReasonMessage)
.lockReasonCategory(lockReasonCategory)
.build());
}
@@ -166,48 +164,15 @@ public class ModuleOperationsUtils {
return Collections.emptyMap();
}
-
/**
- * Check if a module sync retry is needed.
- *
- * @param compositeState the composite state currently in the locked state
- * @return if the retry mechanism should be attempted
- */
- public boolean needsModuleSyncRetryOrUpgrade(final CompositeState compositeState) {
- final OffsetDateTime time = OffsetDateTime.parse(compositeState.getLastUpdateTime(),
- DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
- final CompositeState.LockReason lockReason = compositeState.getLockReason();
-
- final boolean moduleUpgrade = LockReasonCategory.MODULE_UPGRADE == lockReason.getLockReasonCategory();
- if (moduleUpgrade) {
- log.info("Locked for module upgrade");
- return true;
- }
-
- final boolean failedDuringModuleSync = LockReasonCategory.MODULE_SYNC_FAILED
- == lockReason.getLockReasonCategory();
- final boolean failedDuringModuleUpgrade = LockReasonCategory.MODULE_UPGRADE_FAILED
- == lockReason.getLockReasonCategory();
-
- if (failedDuringModuleSync || failedDuringModuleUpgrade) {
- log.info("Locked for module {} (last attempt failed).", failedDuringModuleSync ? "sync" : "upgrade");
- return isRetryDue(lockReason, time);
- }
- log.info("Locked for other reason");
- return false;
- }
-
- /**
- * Get the Resourece Data from Node through DMI Passthrough service.
+ * Get the Resource Data from Node through DMI Passthrough service.
*
* @param cmHandleId cm handle id
* @return optional string containing the resource data
*/
public String getResourceData(final String cmHandleId) {
- final ResponseEntity<Object> resourceDataResponseEntity = dmiDataOperations.getResourceDataFromDmi(
- PASSTHROUGH_OPERATIONAL.getDatastoreName(),
- cmHandleId,
- UUID.randomUUID().toString());
+ final ResponseEntity<Object> resourceDataResponseEntity = dmiDataOperations.getAllResourceDataFromDmi(
+ cmHandleId, UUID.randomUUID().toString());
if (resourceDataResponseEntity.getStatusCode().is2xxSuccessful()) {
return getFirstResource(resourceDataResponseEntity.getBody());
}
@@ -239,27 +204,23 @@ public class ModuleOperationsUtils {
return jsonObjectMapper.asJsonString(Map.of(firstElement.getKey(), firstElement.getValue()));
}
- private List<YangModelCmHandle> convertCmHandlesDataNodesToYangModelCmHandles(
- final List<DataNode> cmHandlesAsDataNodeList) {
- return cmHandlesAsDataNodeList.stream().map(YangDataConverter::convertCmHandleToYangModel).toList();
+ private Collection<YangModelCmHandle> convertCmHandlesDataNodesToYangModelCmHandles(
+ final Collection<DataNode> cmHandlesAsDataNodeList) {
+ return cmHandlesAsDataNodeList.stream().map(YangDataConverter::toYangModelCmHandle).toList();
}
- private boolean isRetryDue(final CompositeState.LockReason compositeStateLockReason, final OffsetDateTime time) {
- final int timeInMinutesUntilNextAttempt;
- final Map<String, String> compositeStateDetails = getLockedCompositeStateDetails(compositeStateLockReason);
- if (compositeStateDetails.isEmpty()) {
- timeInMinutesUntilNextAttempt = 1;
- log.info("First Attempt: no current attempts found.");
- } else {
- timeInMinutesUntilNextAttempt = (int) Math.pow(2, Integer.parseInt(compositeStateDetails
- .get(RETRY_ATTEMPT_KEY)));
- }
- final int timeSinceLastAttempt = (int) Duration.between(time, OffsetDateTime.now()).toMinutes();
- if (timeInMinutesUntilNextAttempt >= timeSinceLastAttempt) {
- log.info("Time until next attempt is {} minutes: ", timeInMinutesUntilNextAttempt - timeSinceLastAttempt);
- return false;
+ private int calculateNextAttemptCount(final Map<String, String> compositeStateDetails) {
+ return compositeStateDetails.containsKey(RETRY_ATTEMPT_KEY)
+ ? 1 + Integer.parseInt(compositeStateDetails.get(RETRY_ATTEMPT_KEY))
+ : 1;
+ }
+
+ private String buildLockReasonDetails(final String moduleSetTag, final int attempt, final String errorMessage) {
+ if (moduleSetTag.isEmpty()) {
+ return String.format(LOCK_REASON_DETAILS_MSG_FORMAT, attempt, errorMessage);
}
- log.info("Retry due now");
- return true;
+ return String.format(MODULE_SET_TAG_MESSAGE_FORMAT + " " + LOCK_REASON_DETAILS_MSG_FORMAT,
+ moduleSetTag, attempt, errorMessage);
}
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java
index e257112fc3..ca0f1c6a6d 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2022-2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,35 +19,29 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync;
+package org.onap.cps.ncmp.impl.inventory.sync;
-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.NCMP_DMI_REGISTRY_PARENT;
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Collections;
-import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
import org.onap.cps.api.CpsAnchorService;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsModuleService;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
import org.onap.cps.spi.CascadeDeleteAllowed;
-import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
-import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleReference;
+import org.onap.cps.utils.ContentType;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Service;
@@ -57,7 +52,6 @@ public class ModuleSyncService {
private final DmiModelOperations dmiModelOperations;
private final CpsModuleService cpsModuleService;
- private final CmHandleQueries cmHandleQueries;
private final CpsDataService cpsDataService;
private final CpsAnchorService cpsAnchorService;
private final JsonObjectMapper jsonObjectMapper;
@@ -112,40 +106,32 @@ public class ModuleSyncService {
}
private ModuleDelta getModuleDelta(final YangModelCmHandle yangModelCmHandle, final String targetModuleSetTag) {
- final Collection<ModuleReference> allModuleReferences;
final Map<String, String> newYangResources;
-
- final YangModelCmHandle cmHandleWithSameModuleSetTag = getAnyReadyCmHandleByModuleSetTag(targetModuleSetTag);
- if (cmHandleWithSameModuleSetTag == null) {
+ Collection<ModuleReference> allModuleReferences = getModuleReferencesByModuleSetTag(targetModuleSetTag);
+ if (allModuleReferences.isEmpty()) {
allModuleReferences = dmiModelOperations.getModuleReferences(yangModelCmHandle);
newYangResources = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
cpsModuleService.identifyNewModuleReferences(allModuleReferences));
} else {
log.info("Found other cm handle having same module set tag: {}", targetModuleSetTag);
- allModuleReferences = cpsModuleService.getYangResourcesModuleReferences(
- NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleWithSameModuleSetTag.getId());
newYangResources = NO_NEW_MODULES;
}
return new ModuleDelta(allModuleReferences, newYangResources);
}
- private YangModelCmHandle getAnyReadyCmHandleByModuleSetTag(final String moduleSetTag) {
- if (StringUtils.isBlank(moduleSetTag)) {
- return null;
+ private Collection<ModuleReference> getModuleReferencesByModuleSetTag(final String moduleSetTag) {
+ if (moduleSetTag == null || moduleSetTag.trim().isEmpty()) {
+ return Collections.emptyList();
}
- final String escapedModuleSetTag = moduleSetTag.replace("'", "''");
- final List<DataNode> dataNodes = cmHandleQueries.queryNcmpRegistryByCpsPath(
- NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@module-set-tag='" + escapedModuleSetTag + "']",
- FetchDescendantsOption.DIRECT_CHILDREN_ONLY);
- return dataNodes.stream().map(YangDataConverter::convertCmHandleToYangModel)
- .filter(cmHandle -> cmHandle.getCompositeState().getCmHandleState() == CmHandleState.READY)
- .findFirst().orElse(null);
+ return cpsModuleService.getModuleReferencesByAttribute(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ Map.of("module-set-tag", moduleSetTag), Map.of("cm-handle-state", CmHandleState.READY.name()));
}
private void setCmHandleModuleSetTag(final YangModelCmHandle yangModelCmHandle, final String newModuleSetTag) {
final String jsonForUpdate = jsonObjectMapper.asJsonString(Map.of(
"cm-handles", Map.of("id", yangModelCmHandle.getId(), "module-set-tag", newModuleSetTag)));
cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
- jsonForUpdate, OffsetDateTime.now());
+ jsonForUpdate, OffsetDateTime.now(), ContentType.JSON);
}
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java
index 590cb56c48..c6deb79d4d 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java
@@ -18,24 +18,23 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync;
+package org.onap.cps.ncmp.impl.inventory.sync;
import com.hazelcast.map.IMap;
import java.util.Collection;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.onap.cps.spi.model.DataNode;
import org.springframework.stereotype.Component;
@@ -64,8 +63,7 @@ public class ModuleSyncTasks {
= new HashMap<>(cmHandlesAsDataNodes.size());
for (final DataNode cmHandleAsDataNode : cmHandlesAsDataNodes) {
final String cmHandleId = String.valueOf(cmHandleAsDataNode.getLeaves().get("id"));
- final YangModelCmHandle yangModelCmHandle =
- YangDataConverter.convertCmHandleToYangModel(cmHandleAsDataNode);
+ final YangModelCmHandle yangModelCmHandle = YangDataConverter.toYangModelCmHandle(cmHandleAsDataNode);
final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId);
final boolean inUpgrade = ModuleOperationsUtils.inUpgradeOrUpgradeFailed(compositeState);
try {
@@ -81,7 +79,7 @@ public class ModuleSyncTasks {
log.warn("Processing of {} module failed due to reason {}.", cmHandleId, e.getMessage());
final LockReasonCategory lockReasonCategory = inUpgrade ? LockReasonCategory.MODULE_UPGRADE_FAILED
: LockReasonCategory.MODULE_SYNC_FAILED;
- moduleOperationsUtils.updateLockReasonDetailsAndAttempts(compositeState,
+ moduleOperationsUtils.updateLockReasonWithAttempts(compositeState,
lockReasonCategory, e.getMessage());
setCmHandleStateLocked(yangModelCmHandle, compositeState.getLockReason());
cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED);
@@ -97,23 +95,23 @@ public class ModuleSyncTasks {
}
/**
- * Reset state to "ADVISED" for any previously failed cm handles.
+ * Resets the state of failed CM handles and updates their status to ADVISED for retry.
+
+ * This method processes a collection of failed CM handles, logs their lock reason, and resets their state
+ * to ADVISED. Once reset, it updates the CM handle states in a batch to allow for re-attempt by the module-sync
+ * watchdog.
*
- * @param failedCmHandles previously failed (locked) cm handles
+ * @param failedCmHandles a collection of CM handles that have failed and need their state reset
*/
- public void resetFailedCmHandles(final List<YangModelCmHandle> failedCmHandles) {
+ public void resetFailedCmHandles(final Collection<YangModelCmHandle> failedCmHandles) {
final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle = new HashMap<>(failedCmHandles.size());
for (final YangModelCmHandle failedCmHandle : failedCmHandles) {
final CompositeState compositeState = failedCmHandle.getCompositeState();
- final boolean isReadyForRetry = moduleOperationsUtils.needsModuleSyncRetryOrUpgrade(compositeState);
- log.info("Retry for cmHandleId : {} is {}", failedCmHandle.getId(), isReadyForRetry);
- if (isReadyForRetry) {
- final String resetCmHandleId = failedCmHandle.getId();
- log.debug("Reset cm handle {} state to ADVISED to be re-attempted by module-sync watchdog",
- resetCmHandleId);
- cmHandleStatePerCmHandle.put(failedCmHandle, CmHandleState.ADVISED);
- removeResetCmHandleFromModuleSyncMap(resetCmHandleId);
- }
+ final String resetCmHandleId = failedCmHandle.getId();
+ log.debug("Resetting CM handle {} state to ADVISED for retry by the module-sync watchdog. Lock reason: {}",
+ failedCmHandle.getId(), compositeState.getLockReason().getLockReasonCategory().name());
+ cmHandleStatePerCmHandle.put(failedCmHandle, CmHandleState.ADVISED);
+ removeResetCmHandleFromModuleSyncMap(resetCmHandleId);
}
lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java
index 249232d230..bc7d6cdf67 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,21 +19,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync;
+package org.onap.cps.ncmp.impl.inventory.sync;
import com.hazelcast.map.IMap;
import java.util.Collection;
import java.util.HashSet;
-import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.config.embeddedcache.SynchronizationCacheConfig;
-import org.onap.cps.ncmp.api.impl.inventory.sync.executor.AsyncTaskExecutor;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
import org.onap.cps.spi.model.DataNode;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@@ -85,10 +82,10 @@ public class ModuleSyncWatchdog {
/**
* Find any failed (locked) cm handles and change state back to 'ADVISED'.
*/
- @Scheduled(fixedDelayString = "${ncmp.timers.locked-modules-sync.sleep-time-ms:300000}")
+ @Scheduled(fixedDelayString = "${ncmp.timers.locked-modules-sync.sleep-time-ms:15000}")
public void resetPreviouslyFailedCmHandles() {
log.info("Processing module sync retry-watchdog waking up.");
- final List<YangModelCmHandle> failedCmHandles
+ final Collection<YangModelCmHandle> failedCmHandles
= moduleOperationsUtils.getCmHandlesThatFailedModelSyncOrUpgrade();
log.info("Retrying {} cmHandles", failedCmHandles.size());
moduleSyncTasks.resetFailedCmHandles(failedCmHandles);
@@ -105,7 +102,7 @@ public class ModuleSyncWatchdog {
private void populateWorkQueueIfNeeded() {
if (moduleSyncWorkQueue.isEmpty()) {
- final List<DataNode> advisedCmHandles = moduleOperationsUtils.getAdvisedCmHandles();
+ final Collection<DataNode> advisedCmHandles = moduleOperationsUtils.getAdvisedCmHandles();
log.info("Processing module sync fetched {} advised cm handles from DB", advisedCmHandles.size());
for (final DataNode advisedCmHandle : advisedCmHandles) {
if (!moduleSyncWorkQueue.offer(advisedCmHandle)) {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java
index 62a380ca5c..76b33cc8d9 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.embeddedcache;
+package org.onap.cps.ncmp.impl.inventory.sync;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.QueueConfig;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/config/WatchdogSchedulingConfigurer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/WatchdogSchedulingConfigurer.java
index 1aaee2708f..203c5a1a20 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/config/WatchdogSchedulingConfigurer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/WatchdogSchedulingConfigurer.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync.config;
+package org.onap.cps.ncmp.impl.inventory.sync;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
@@ -53,4 +53,4 @@ public class WatchdogSchedulingConfigurer implements SchedulingConfigurer {
taskScheduler.initialize();
return taskScheduler;
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java
index f7707d9f76..7395838306 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventHeaderMapper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventHeaderMapper.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
import org.mapstruct.Mapper;
import org.onap.cps.ncmp.events.lcm.v1.LcmEvent;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java
index a8d00f7e31..4bc2f10218 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventType.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
public enum LcmEventType {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java
index 8274772d2c..6cce153269 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandler.java
@@ -18,12 +18,12 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
import java.util.Collection;
import java.util.Map;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
/**
* The implementation of it should handle the persisting of composite state and delegate the request to publish the
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java
index 3742719e26..cf7921c350 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java
@@ -18,15 +18,15 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
import java.util.Collection;
import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
import org.onap.cps.ncmp.events.lcm.v1.LcmEvent;
import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@@ -74,6 +74,6 @@ public class LcmEventsCmHandleStateHandlerAsyncHelper {
}
private static NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) {
- return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle);
+ return YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java
index 0ed95adff2..b1b7b955f7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java
@@ -18,12 +18,12 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.ADVISED;
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETED;
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.LOCKED;
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.READY;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.LOCKED;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY;
import io.micrometer.core.annotation.Timed;
import java.util.ArrayList;
@@ -37,13 +37,13 @@ import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateUtils;
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.impl.inventory.CompositeStateUtils;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
import org.springframework.stereotype.Service;
@Slf4j
@@ -194,7 +194,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState
}
private NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) {
- return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle);
+ return YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle);
}
@Getter
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java
index fa27be158a..5137515758 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreator.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
import java.util.UUID;
import lombok.Getter;
@@ -26,12 +26,12 @@ import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
import org.onap.cps.ncmp.events.lcm.v1.Event;
import org.onap.cps.ncmp.events.lcm.v1.LcmEvent;
import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader;
import org.onap.cps.ncmp.events.lcm.v1.Values;
+import org.onap.cps.ncmp.impl.utils.EventDateTimeFormatter;
import org.springframework.stereotype.Component;
@@ -128,4 +128,4 @@ public class LcmEventsCreator {
private Values newValues;
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java
index 19d9ba5c0d..348894d1b4 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorHelper.java
@@ -18,12 +18,12 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
-import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.CREATE;
-import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.DELETE;
-import static org.onap.cps.ncmp.api.impl.events.lcm.LcmEventType.UPDATE;
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETED;
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED;
+import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.CREATE;
+import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.DELETE;
+import static org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventType.UPDATE;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
@@ -33,7 +33,7 @@ import java.util.Map;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
import org.onap.cps.ncmp.events.lcm.v1.Values;
/**
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java
index f51b58c3ef..192667175e 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsService.java
@@ -18,15 +18,20 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm;
+package org.onap.cps.ncmp.impl.inventory.sync.lcm;
-import io.micrometer.core.annotation.Timed;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Timer;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.events.EventsPublisher;
import org.onap.cps.ncmp.events.lcm.v1.LcmEvent;
import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader;
+import org.onap.cps.ncmp.events.lcm.v1.Values;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.KafkaException;
@@ -41,8 +46,12 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class LcmEventsService {
+ private static final Tag TAG_METHOD = Tag.of("method", "publishLcmEvent");
+ private static final Tag TAG_CLASS = Tag.of("class", LcmEventsService.class.getName());
+ private static final String UNAVAILABLE_CM_HANDLE_STATE = "N/A";
private final EventsPublisher<LcmEvent> eventsPublisher;
private final JsonObjectMapper jsonObjectMapper;
+ private final MeterRegistry meterRegistry;
@Value("${app.lcm.events.topic:ncmp-events}")
private String topicName;
@@ -51,24 +60,58 @@ public class LcmEventsService {
private boolean notificationsEnabled;
/**
- * Publish the LcmEvent with header to the public topic.
+ * Publishes an LCM event to the dedicated topic with optional notification headers.
+ * Capture and log KafkaException If an error occurs while publishing the event to Kafka
*
- * @param cmHandleId Cm Handle Id
- * @param lcmEvent Lcm Event
- * @param lcmEventHeader Lcm Event Header
+ * @param cmHandleId Cm Handle Id associated with the LCM event
+ * @param lcmEvent The LCM event object to be published
+ * @param lcmEventHeader Optional headers associated with the LCM event
*/
- @Timed(value = "cps.ncmp.lcm.events.publish", description = "Time taken to publish a LCM event")
public void publishLcmEvent(final String cmHandleId, final LcmEvent lcmEvent, final LcmEventHeader lcmEventHeader) {
+
if (notificationsEnabled) {
+ final Timer.Sample timerSample = Timer.start(meterRegistry);
try {
final Map<String, Object> lcmEventHeadersMap =
jsonObjectMapper.convertToValueType(lcmEventHeader, Map.class);
eventsPublisher.publishEvent(topicName, cmHandleId, lcmEventHeadersMap, lcmEvent);
} catch (final KafkaException e) {
log.error("Unable to publish message to topic : {} and cause : {}", topicName, e.getMessage());
+ } finally {
+ recordMetrics(lcmEvent, timerSample);
}
} else {
log.debug("Notifications disabled.");
}
}
+
+ private void recordMetrics(final LcmEvent lcmEvent, final Timer.Sample timerSample) {
+ final List<Tag> tags = new ArrayList<>(4);
+ tags.add(TAG_CLASS);
+ tags.add(TAG_METHOD);
+
+ final String oldCmHandleState = extractCmHandleStateValue(lcmEvent.getEvent().getOldValues());
+ tags.add(Tag.of("oldCmHandleState", oldCmHandleState));
+
+ final String newCmHandleState = extractCmHandleStateValue(lcmEvent.getEvent().getNewValues());
+ tags.add(Tag.of("newCmHandleState", newCmHandleState));
+
+ timerSample.stop(Timer.builder("cps.ncmp.lcm.events.publish")
+ .description("Time taken to publish a LCM event")
+ .tags(tags)
+ .register(meterRegistry));
+ }
+
+ /**
+ * Extracts the CM handle state value from the given Values object.
+ * If the provided Values object or its CM handle state is null, returns a default value.
+ *
+ * @param values The Values object containing CM handle state information.
+ * @return The CM handle state value as a string, or a default value if null.
+ */
+ private String extractCmHandleStateValue(final Values values) {
+ return (values != null && values.getCmHandleState() != null)
+ ? values.getCmHandleState().value()
+ : UNAVAILABLE_CM_HANDLE_STATE;
+ }
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java
index 230a370d65..efcbb78ace 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java
@@ -18,41 +18,41 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel;
+package org.onap.cps.ncmp.impl.inventory.trustlevel;
import io.cloudevents.CloudEvent;
import io.cloudevents.kafka.impl.KafkaHeaders;
import lombok.RequiredArgsConstructor;
import org.apache.kafka.clients.consumer.ConsumerRecord;
-import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper;
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel;
+import org.onap.cps.ncmp.utils.events.CloudEventMapper;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
-public class DeviceHeartbeatConsumer {
+public class DeviceTrustLevelMessageConsumer {
private static final String CLOUD_EVENT_ID_HEADER_NAME = "ce_id";
private final TrustLevelManager trustLevelManager;
/**
- * Listening the device heartbeats.
+ * Listening to the device trust level updates.
*
- * @param deviceHeartbeatConsumerRecord Device Heartbeat record.
+ * @param consumerRecord Device trust level record.
*/
@KafkaListener(topics = "${app.dmi.device-heartbeat.topic}",
containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory")
- public void heartbeatListener(final ConsumerRecord<String, CloudEvent> deviceHeartbeatConsumerRecord) {
+ public void deviceTrustLevelListener(final ConsumerRecord<String, CloudEvent> consumerRecord) {
- final String cmHandleId = KafkaHeaders.getParsedKafkaHeader(deviceHeartbeatConsumerRecord.headers(),
+ final String cmHandleId = KafkaHeaders.getParsedKafkaHeader(consumerRecord.headers(),
CLOUD_EVENT_ID_HEADER_NAME);
final DeviceTrustLevel deviceTrustLevel =
- CloudEventMapper.toTargetEvent(deviceHeartbeatConsumerRecord.value(), DeviceTrustLevel.class);
- final TrustLevel newDeviceTrustLevel = TrustLevel.valueOf(deviceTrustLevel.getData().getTrustLevel());
- trustLevelManager.handleUpdateOfDeviceTrustLevel(cmHandleId, newDeviceTrustLevel);
-
+ CloudEventMapper.toTargetEvent(consumerRecord.value(), DeviceTrustLevel.class);
+ final String trustLevelAsString = deviceTrustLevel.getData().getTrustLevel();
+ trustLevelManager.updateCmHandleTrustLevel(cmHandleId, TrustLevel.valueOf(trustLevelAsString));
}
}
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/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java
index d6d6fd6bc1..7581c4af7a 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/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java
@@ -18,17 +18,17 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel.dmiavailability;
+package org.onap.cps.ncmp.impl.inventory.trustlevel;
import java.util.Collection;
import java.util.Map;
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.onap.cps.ncmp.api.inventory.models.TrustLevel;
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient;
+import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService;
+import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder;
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@@ -36,10 +36,10 @@ import org.springframework.stereotype.Service;
@Slf4j
@RequiredArgsConstructor
@Service
-public class DmiPluginWatchDog {
+public class DmiPluginTrustLevelWatchDog {
private final DmiRestClient dmiRestClient;
- private final NetworkCmProxyDataService networkCmProxyDataService;
+ private final CmHandleQueryService cmHandleQueryService;
private final TrustLevelManager trustLevelManager;
@Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN)
@@ -52,10 +52,8 @@ public class DmiPluginWatchDog {
*/
@Scheduled(fixedDelayString = "${ncmp.timers.trust-level.dmi-availability-watchdog-ms:30000}")
public void checkDmiAvailability() {
- trustLevelPerDmiPlugin.entrySet().forEach(entry -> {
+ trustLevelPerDmiPlugin.forEach((dmiServiceName, oldDmiTrustLevel) -> {
final TrustLevel newDmiTrustLevel;
- final TrustLevel oldDmiTrustLevel = entry.getValue();
- final String dmiServiceName = entry.getKey();
final String dmiHealthStatus = getDmiHealthStatus(dmiServiceName);
log.debug("The health status for dmi-plugin: {} is {}", dmiServiceName, dmiHealthStatus);
@@ -68,13 +66,15 @@ public class DmiPluginWatchDog {
log.debug("The Dmi Plugin: {} has already the same trust level: {}", dmiServiceName, newDmiTrustLevel);
} else {
final Collection<String> cmHandleIds =
- networkCmProxyDataService.getAllCmHandleIdsByDmiPluginIdentifier(dmiServiceName);
- trustLevelManager.handleUpdateOfDmiTrustLevel(dmiServiceName, cmHandleIds, newDmiTrustLevel);
+ cmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier(dmiServiceName);
+ trustLevelManager.updateDmi(dmiServiceName, cmHandleIds, newDmiTrustLevel);
}
});
}
- private String getDmiHealthStatus(final String dmiServiceName) {
- return dmiRestClient.getDmiHealthStatus(dmiServiceName);
+ private String getDmiHealthStatus(final String dmiServiceBaseUrl) {
+ final UrlTemplateParameters urlTemplateParameters = RestServiceUrlTemplateBuilder.newInstance()
+ .createUrlTemplateParametersForHealthCheck(dmiServiceBaseUrl);
+ return dmiRestClient.getDmiHealthStatus(urlTemplateParameters).block();
}
}
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/impl/inventory/trustlevel/TrustLevelCacheConfig.java
index 440cd3ded1..b64d3a24b3 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/impl/inventory/trustlevel/TrustLevelCacheConfig.java
@@ -18,12 +18,12 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.embeddedcache;
+package org.onap.cps.ncmp.impl.inventory.trustlevel;
import com.hazelcast.config.MapConfig;
import java.util.Map;
import org.onap.cps.cache.HazelcastCacheConfig;
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel;
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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/impl/inventory/trustlevel/TrustLevelManager.java
index 9d65a66d8d..aff0e19981 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/impl/inventory/trustlevel/TrustLevelManager.java
@@ -18,17 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel;
+package org.onap.cps.ncmp.impl.inventory.trustlevel;
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.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration;
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.models.RequiredDmiService;
+import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@@ -44,16 +45,31 @@ public class TrustLevelManager {
private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
private final InventoryPersistence inventoryPersistence;
- private final AvcEventPublisher avcEventPublisher;
+ private final CmAvcEventPublisher cmAvcEventPublisher;
private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel";
private static final String AVC_NO_OLD_VALUE = null;
/**
+ * Add dmi plugins to the cache.
+ *
+ * @param dmiPluginRegistration a dmi plugin being registered
+ */
+ public void registerDmiPlugin(final DmiPluginRegistration dmiPluginRegistration) {
+ final String dmiServiceName;
+ if (DmiPluginRegistration.isNullEmptyOrBlank(dmiPluginRegistration.getDmiDataPlugin())) {
+ dmiServiceName = dmiPluginRegistration.getDmiPlugin();
+ } else {
+ dmiServiceName = dmiPluginRegistration.getDmiDataPlugin();
+ }
+ trustLevelPerDmiPlugin.put(dmiServiceName, TrustLevel.COMPLETE);
+ }
+
+ /**
* Add cmHandles to the cache and publish notification for initial trust level of cmHandles if it is NONE.
*
* @param cmHandlesToBeCreated a list of cmHandles being created
*/
- public void handleInitialRegistrationOfTrustLevels(final Map<String, TrustLevel> cmHandlesToBeCreated) {
+ public void registerCmHandles(final Map<String, TrustLevel> cmHandlesToBeCreated) {
for (final Map.Entry<String, TrustLevel> entry : cmHandlesToBeCreated.entrySet()) {
final String cmHandleId = entry.getKey();
if (trustLevelPerCmHandle.containsKey(cmHandleId)) {
@@ -65,7 +81,7 @@ public class TrustLevelManager {
}
trustLevelPerCmHandle.put(cmHandleId, initialTrustLevel);
if (TrustLevel.NONE.equals(initialTrustLevel)) {
- avcEventPublisher.publishAvcEvent(cmHandleId,
+ cmAvcEventPublisher.publishAvcEvent(cmHandleId,
AVC_CHANGED_ATTRIBUTE_NAME,
AVC_NO_OLD_VALUE,
initialTrustLevel.name());
@@ -82,15 +98,15 @@ public class TrustLevelManager {
* @param affectedCmHandleIds cm handle ids belonging to dmi service name
* @param newDmiTrustLevel new trust level of the dmi plugin
*/
- public void handleUpdateOfDmiTrustLevel(final String dmiServiceName,
- final Collection<String> affectedCmHandleIds,
- final TrustLevel newDmiTrustLevel) {
+ public void updateDmi(final String dmiServiceName,
+ final Collection<String> affectedCmHandleIds,
+ final TrustLevel newDmiTrustLevel) {
final TrustLevel oldDmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName);
trustLevelPerDmiPlugin.put(dmiServiceName, newDmiTrustLevel);
for (final String affectedCmHandleId : affectedCmHandleIds) {
- final TrustLevel deviceTrustLevel = trustLevelPerCmHandle.get(affectedCmHandleId);
- final TrustLevel oldEffectiveTrustLevel = deviceTrustLevel.getEffectiveTrustLevel(oldDmiTrustLevel);
- final TrustLevel newEffectiveTrustLevel = deviceTrustLevel.getEffectiveTrustLevel(newDmiTrustLevel);
+ final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandle.get(affectedCmHandleId);
+ final TrustLevel oldEffectiveTrustLevel = cmHandleTrustLevel.getEffectiveTrustLevel(oldDmiTrustLevel);
+ final TrustLevel newEffectiveTrustLevel = cmHandleTrustLevel.getEffectiveTrustLevel(newDmiTrustLevel);
sendAvcNotificationIfRequired(affectedCmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel);
}
}
@@ -100,23 +116,52 @@ public class TrustLevelManager {
* changed.
*
* @param cmHandleId cm handle id
- * @param newDeviceTrustLevel new trust level of the device
+ * @param newCmHandleTrustLevel new trust level of the device
*/
- public void handleUpdateOfDeviceTrustLevel(final String cmHandleId,
- final TrustLevel newDeviceTrustLevel) {
- final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
- final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA);
+ public void updateCmHandleTrustLevel(final String cmHandleId,
+ final TrustLevel newCmHandleTrustLevel) {
+ final String dmiServiceName = getDmiServiceName(cmHandleId);
final TrustLevel dmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName);
- final TrustLevel oldDeviceTrustLevel = trustLevelPerCmHandle.get(cmHandleId);
+ final TrustLevel oldCmHandleTrustLevel = trustLevelPerCmHandle.get(cmHandleId);
- final TrustLevel oldEffectiveTrustLevel = oldDeviceTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
- final TrustLevel newEffectiveTrustLevel = newDeviceTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
+ final TrustLevel oldEffectiveTrustLevel = oldCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
+ final TrustLevel newEffectiveTrustLevel = newCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
- trustLevelPerCmHandle.put(cmHandleId, newDeviceTrustLevel);
+ trustLevelPerCmHandle.put(cmHandleId, newCmHandleTrustLevel);
sendAvcNotificationIfRequired(cmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel);
}
+ /**
+ * Select effective trust level among device and dmi plugin.
+ *
+ * @param cmHandleId cm handle id
+ * @return TrustLevel effective trust level
+ */
+ public TrustLevel getEffectiveTrustLevel(final String dmiServiceName, final String cmHandleId) {
+ final TrustLevel dmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName);
+ final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandle.get(cmHandleId);
+ return dmiTrustLevel.getEffectiveTrustLevel(cmHandleTrustLevel);
+ }
+
+ /**
+ * Remove cm handle trust level from the cache.
+ *
+ * @param cmHandleIds cm handle ids to be removed from the cache
+ */
+ public void removeCmHandles(final Collection<String> cmHandleIds) {
+ for (final String cmHandleId : cmHandleIds) {
+ if (trustLevelPerCmHandle.remove(cmHandleId) == null) {
+ log.debug("Removed Cm handle: {} is not in trust level cache", cmHandleId);
+ }
+ }
+ }
+
+ private String getDmiServiceName(final String cmHandleId) {
+ final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
+ return yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA);
+ }
+
private void sendAvcNotificationIfRequired(final String notificationCandidateCmHandleId,
final TrustLevel oldEffectiveTrustLevel,
final TrustLevel newEffectiveTrustLevel) {
@@ -126,7 +171,7 @@ public class TrustLevelManager {
} else {
log.info("The trust level for Cm Handle: {} is now: {} ", notificationCandidateCmHandleId,
newEffectiveTrustLevel);
- avcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId,
+ cmAvcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId,
AVC_CHANGED_ATTRIBUTE_NAME,
oldEffectiveTrustLevel.name(),
newEffectiveTrustLevel.name());
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/impl/models/DmiRequestBody.java
index f1032f818f..6b05385693 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/impl/models/DmiRequestBody.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.impl.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -28,7 +28,8 @@ import java.util.List;
import java.util.Map;
import lombok.Builder;
import lombok.Getter;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
@JsonInclude(JsonInclude.Include.NON_NULL)
@Getter
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/RequiredDmiService.java
index 7e39766f3f..c0c4f73f2a 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/RequiredDmiService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/models/RequiredDmiService.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.impl.models;
/**
* Enmm to determine if the required service is for a data or model operation.
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/config/NcmpRequestLoggingConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/policyexecutor/PolicyExecutorWebClientConfiguration.java
index e91f48f78a..333030ccd2 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/config/NcmpRequestLoggingConfig.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/policyexecutor/PolicyExecutorWebClientConfiguration.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2024 Nordix Foundation.
+ * 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.
@@ -18,28 +18,29 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.dmi.rest.stub.config;
+package org.onap.cps.ncmp.impl.policyexecutor;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.config.PolicyExecutorHttpClientConfig;
+import org.onap.cps.ncmp.impl.utils.http.WebClientConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.web.filter.CommonsRequestLoggingFilter;
+import org.springframework.web.reactive.function.client.WebClient;
@Configuration
-public class NcmpRequestLoggingConfig {
+@RequiredArgsConstructor
+public class PolicyExecutorWebClientConfiguration extends WebClientConfiguration {
+
+ private final PolicyExecutorHttpClientConfig policyExecutorHttpClientConfig;
/**
- * Configuration class to log NCMP request headers and payload.
- * logged request information before it is processed.
+ * Configures and creates a web client bean for Policy Executor.
+ *
+ * @param webClientBuilder The builder instance to create the WebClient.
+ * @return a WebClient instance configured for Policy Executor.
*/
@Bean
- public CommonsRequestLoggingFilter logNcmpRequestInfo() {
- final CommonsRequestLoggingFilter commonsRequestLoggingFilter = new CommonsRequestLoggingFilter();
- commonsRequestLoggingFilter.setIncludeHeaders(true);
- commonsRequestLoggingFilter.setIncludeQueryString(true);
- commonsRequestLoggingFilter.setIncludePayload(true);
- commonsRequestLoggingFilter.setMaxPayloadLength(1000);
- commonsRequestLoggingFilter.setAfterMessagePrefix("NCMP REQUEST DATA: ");
- return commonsRequestLoggingFilter;
+ public WebClient policyExecutorWebClient(final WebClient.Builder webClientBuilder) {
+ return configureWebClient(webClientBuilder, policyExecutorHttpClientConfig.getAllServices());
}
}
-
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java
new file mode 100644
index 0000000000..c526dfb297
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java
@@ -0,0 +1,78 @@
+/*
+ * ============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.impl.utils;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.ncmp.exceptions.NoAlternateIdMatchFoundException;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
+import org.onap.cps.spi.model.DataNode;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class AlternateIdMatcher {
+
+ private final InventoryPersistence inventoryPersistence;
+
+ /**
+ * Get data node that matches longest alternate id by removing elements (as defined by the separator string)
+ * from right to left.
+ *
+ * @param alternateId alternate ID
+ * @param separator a string that separates each element from the next.
+ * @return data node
+ */
+ public DataNode getCmHandleDataNodeByLongestMatchingAlternateId(final String alternateId, final String separator) {
+ String bestMatch = alternateId;
+ while (StringUtils.isNotEmpty(bestMatch)) {
+ try {
+ return inventoryPersistence.getCmHandleDataNodeByAlternateId(bestMatch);
+ } catch (final DataNodeNotFoundException ignored) {
+ bestMatch = getParentPath(bestMatch, separator);
+ }
+ }
+ throw new NoAlternateIdMatchFoundException(alternateId);
+ }
+
+ /**
+ * Get cm handle Id from given cmHandleReference.
+ *
+ * @param cmHandleReference cm handle or alternate identifier
+ * @return cm handle id string
+ */
+ public String getCmHandleId(final String cmHandleReference) {
+ if (inventoryPersistence.isExistingCmHandleId(cmHandleReference)) {
+ return cmHandleReference;
+ } else {
+ return inventoryPersistence.getCmHandleDataNodeByAlternateId(cmHandleReference)
+ .getLeaves().get("id").toString();
+ }
+ }
+
+ private String getParentPath(final String path, final String separator) {
+ final int lastSeparatorIndex = path.lastIndexOf(separator);
+ return lastSeparatorIndex < 0 ? "" : path.substring(0, lastSeparatorIndex);
+ }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatter.java
index 5dd6827126..9284c0fab7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatter.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatter.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils;
+package org.onap.cps.ncmp.impl.utils;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/YangDataConverter.java
index 07b92892a9..ac0c44e1c3 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/YangDataConverter.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils;
+package org.onap.cps.ncmp.impl.utils;
import java.util.Collection;
import java.util.LinkedHashMap;
@@ -30,10 +30,10 @@ import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
import org.onap.cps.spi.model.DataNode;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@@ -43,12 +43,12 @@ public class YangDataConverter {
private static final Pattern cmHandleIdInXpathPattern = Pattern.compile("\\[@id='(.*?)']");
/**
- * This method convert yang model cm handle to ncmp service cm handle.
+ * This method converts yang model cm handle to ncmp service cm handle.
* @param yangModelCmHandle the yang model of the cm handle
* @return ncmp service cm handle
*/
- public static NcmpServiceCmHandle convertYangModelCmHandleToNcmpServiceCmHandle(
- final YangModelCmHandle yangModelCmHandle) {
+ public static NcmpServiceCmHandle toNcmpServiceCmHandle(
+ final YangModelCmHandle yangModelCmHandle) {
final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
final List<YangModelCmHandle.Property> dmiProperties = yangModelCmHandle.getDmiProperties();
final List<YangModelCmHandle.Property> publicProperties = yangModelCmHandle.getPublicProperties();
@@ -63,23 +63,24 @@ public class YangDataConverter {
}
/**
- * This method convert yang model cm handle properties to simple map.
+ * This method converts yang model cm handle properties to simple map.
* @param properties the yang model cm handle properties
- * @param propertiesMap the String, String map for the results
+ * @return simple map representing the properties
*/
- public static void asPropertiesMap(final List<YangModelCmHandle.Property> properties,
- final Map<String, String> propertiesMap) {
+ public static Map<String, String> toPropertiesMap(final List<YangModelCmHandle.Property> properties) {
+ final Map<String, String> propertiesMap = new LinkedHashMap<>(properties.size());
for (final YangModelCmHandle.Property property : properties) {
propertiesMap.put(property.getName(), property.getValue());
}
+ return propertiesMap;
}
/**
- * This method convert cm handle data node to yang model cm handle.
+ * This method converts cm handle data node to yang model cm handle.
* @param cmHandleDataNode the datanode of the cm handle
* @return yang model cm handle
*/
- public static YangModelCmHandle convertCmHandleToYangModel(final DataNode cmHandleDataNode) {
+ public static YangModelCmHandle toYangModelCmHandle(final DataNode cmHandleDataNode) {
final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
final String cmHandleId = cmHandleDataNode.getLeaves().get("id").toString();
ncmpServiceCmHandle.setCmHandleId(cmHandleId);
@@ -96,18 +97,17 @@ public class YangDataConverter {
}
/**
- * This method convert cm handle data nodes to yang model cm handles.
+ * This method converts cm handle data nodes to yang model cm handles.
* @param cmHandleDataNodes the datanode of the cm handle
* @return yang model cm handles
*/
- public static Collection<YangModelCmHandle> convertDataNodesToYangModelCmHandles(
+ public static Collection<YangModelCmHandle> toYangModelCmHandles(
final Collection<DataNode> cmHandleDataNodes) {
- return cmHandleDataNodes.stream().map(YangDataConverter::convertCmHandleToYangModel)
- .collect(Collectors.toList());
+ return cmHandleDataNodes.stream().map(YangDataConverter::toYangModelCmHandle).collect(Collectors.toList());
}
/**
- * This method extract cm handle id from xpath of data node.
+ * This method extracts cm handle id from xpath of data node.
* @param xpath for data node of the cm handle
* @return cm handle Id
*/
@@ -145,15 +145,11 @@ public class YangDataConverter {
private static void setDmiProperties(final List<YangModelCmHandle.Property> dmiProperties,
final NcmpServiceCmHandle ncmpServiceCmHandle) {
- final Map<String, String> dmiPropertiesMap = new LinkedHashMap<>(dmiProperties.size());
- asPropertiesMap(dmiProperties, dmiPropertiesMap);
- ncmpServiceCmHandle.setDmiProperties(dmiPropertiesMap);
+ ncmpServiceCmHandle.setDmiProperties(toPropertiesMap(dmiProperties));
}
private static void setPublicProperties(final List<YangModelCmHandle.Property> publicProperties,
final NcmpServiceCmHandle ncmpServiceCmHandle) {
- final Map<String, String> publicPropertiesMap = new LinkedHashMap<>();
- asPropertiesMap(publicProperties, publicPropertiesMap);
- ncmpServiceCmHandle.setPublicProperties(publicPropertiesMap);
+ ncmpServiceCmHandle.setPublicProperties(toPropertiesMap(publicProperties));
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java
new file mode 100644
index 0000000000..c850ca94a0
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java
@@ -0,0 +1,134 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022-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.impl.utils.http;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.web.util.UriComponentsBuilder;
+
+@NoArgsConstructor
+public class RestServiceUrlTemplateBuilder {
+
+ private final UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance();
+ private static final String FIXED_PATH_SEGMENT = null;
+ private static final String VERSION_SEGMENT = "v1";
+ private final Map<String, String> pathSegments = new LinkedHashMap<>();
+ private final Map<String, String> queryParameters = new LinkedHashMap<>();
+
+ /**
+ * Static factory method to create a new instance of DmiServiceUrlTemplateBuilder.
+ *
+ * @return a new instance of DmiServiceUrlTemplateBuilder
+ */
+ public static RestServiceUrlTemplateBuilder newInstance() {
+ return new RestServiceUrlTemplateBuilder();
+ }
+
+ /**
+ * Add a fixed pathSegment to the URL.
+ *
+ * @param pathSegment the path segment
+ * @return this builder instance
+ */
+ public RestServiceUrlTemplateBuilder fixedPathSegment(final String pathSegment) {
+ pathSegments.put(pathSegment, FIXED_PATH_SEGMENT);
+ return this;
+ }
+
+ /**
+ * Add a variable pathSegment to the URL.
+ * Do NOT add { } braces. the builder will take care of that
+ *
+ * @param pathSegment the name of the variable path segment (with { and }
+ * @param value the value to be insert in teh URL for the given variable path segment
+ * @return this builder instance
+ */
+ public RestServiceUrlTemplateBuilder variablePathSegment(final String pathSegment, final String value) {
+ pathSegments.put(pathSegment, value);
+ return this;
+ }
+
+ /**
+ * Add a query parameter to the URL.
+ * Do NOT encode as the builder wil take care of encoding
+ *
+ * @param queryParameterName the name of the variable
+ * @param queryParameterValue the value of the variable (only Strings are supported).
+ *
+ * @return this builder instance
+ */
+ public RestServiceUrlTemplateBuilder queryParameter(final String queryParameterName,
+ final String queryParameterValue) {
+ if (Strings.isNotBlank(queryParameterValue)) {
+ queryParameters.put(queryParameterName, queryParameterValue);
+ }
+ return this;
+ }
+
+ /**
+ * Constructs a URL template with variables based on the accumulated path segments and query parameters.
+ *
+ * @param serviceBaseUrl the base URL of the service, e.g., "http://dmi-service.com".
+ * @param basePath the base path of the service
+ * @return a UrlTemplateParameters instance containing the complete URL template and URL variables
+ */
+ public UrlTemplateParameters createUrlTemplateParameters(final String serviceBaseUrl, final String basePath) {
+ this.uriComponentsBuilder.pathSegment(basePath).pathSegment(VERSION_SEGMENT);
+ final Map<String, String> urlTemplateVariables = new HashMap<>();
+
+ pathSegments.forEach((pathSegmentName, variablePathValue) -> {
+ if (StringUtils.equals(variablePathValue, FIXED_PATH_SEGMENT)) {
+ this.uriComponentsBuilder.pathSegment(pathSegmentName);
+ } else {
+ this.uriComponentsBuilder.pathSegment("{" + pathSegmentName + "}");
+ urlTemplateVariables.put(pathSegmentName, variablePathValue);
+ }
+ });
+
+ queryParameters.forEach((paramName, paramValue) -> {
+ this.uriComponentsBuilder.queryParam(paramName, "{" + paramName + "}");
+ urlTemplateVariables.put(paramName, paramValue);
+ });
+
+ final String urlTemplate = serviceBaseUrl + this.uriComponentsBuilder.build().toUriString();
+ return new UrlTemplateParameters(urlTemplate, urlTemplateVariables);
+ }
+
+ /**
+ * Constructs a URL for a spring actuator health check based on the given base URL.
+ *
+ * @param serviceBaseUrl the base URL of the service, e.g., "http://dmi-service.com".
+ * @return a {@link UrlTemplateParameters} instance containing the complete URL template and empty URL variables,
+ * suitable for DMI health check.
+ */
+ public UrlTemplateParameters createUrlTemplateParametersForHealthCheck(final String serviceBaseUrl) {
+ this.uriComponentsBuilder.pathSegment("actuator").pathSegment("health");
+
+ final String urlTemplate = serviceBaseUrl + this.uriComponentsBuilder.build().toUriString();
+ return new UrlTemplateParameters(urlTemplate, Collections.emptyMap());
+ }
+
+}
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DmiOperationCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/UrlTemplateParameters.java
index 5cb24bc398..839af71823 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DmiOperationCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/UrlTemplateParameters.java
@@ -1,6 +1,6 @@
/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
+ * ============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.
@@ -18,17 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.dmi.rest.stub.model.data.operational;
+package org.onap.cps.ncmp.impl.utils.http;
-import java.util.HashMap;
import java.util.Map;
-import lombok.Getter;
-import lombok.Setter;
-@Setter
-@Getter
-public class DmiOperationCmHandle {
- private String id;
- private Map<String, String> cmHandleProperties = new HashMap<>();
- private String moduleSetTag;
+/**
+ * Represents a URL template with associated variables for dynamic substitution.
+ * This record encapsulates a URL template string and a map of variables used for substitution within the template.
+ */
+public record UrlTemplateParameters(String urlTemplate, Map<String, String> urlVariables) {
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/WebClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/WebClientConfiguration.java
new file mode 100644
index 0000000000..d8e8350345
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/WebClientConfiguration.java
@@ -0,0 +1,83 @@
+/*
+ * ============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.impl.utils.http;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import io.netty.channel.ChannelOption;
+import io.netty.handler.timeout.ReadTimeoutHandler;
+import io.netty.handler.timeout.WriteTimeoutHandler;
+import io.netty.resolver.DefaultAddressResolverGroup;
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+import org.onap.cps.ncmp.config.ServiceConfig;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.netty.http.client.HttpClient;
+import reactor.netty.resources.ConnectionProvider;
+
+/**
+ * Configures and creates WebClient beans for various rest services such as DMI and Policy Executor.
+ * The configuration utilizes Netty-based HttpClient with custom connection settings, read and write timeouts,
+ * and initializes WebClient with these settings to ensure optimal performance and resource management.
+ */
+public class WebClientConfiguration {
+
+ private static final Duration DEFAULT_RESPONSE_TIMEOUT = Duration.ofSeconds(30);
+
+ protected WebClient configureWebClient(final WebClient.Builder webClientBuilder,
+ final ServiceConfig serviceConfig) {
+ final ConnectionProvider connectionProvider = getConnectionProvider(serviceConfig);
+ final HttpClient httpClient = createHttpClient(serviceConfig, connectionProvider);
+ return buildAndGetWebClient(webClientBuilder, httpClient, serviceConfig.getMaximumInMemorySizeInMegabytes());
+ }
+
+ private static HttpClient createHttpClient(final ServiceConfig serviceConfig,
+ final ConnectionProvider connectionProvider) {
+ return HttpClient.create(connectionProvider)
+ .responseTimeout(DEFAULT_RESPONSE_TIMEOUT)
+ .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, serviceConfig.getConnectionTimeoutInSeconds() * 1000)
+ .doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler(
+ serviceConfig.getReadTimeoutInSeconds(), TimeUnit.SECONDS)).addHandlerLast(
+ new WriteTimeoutHandler(serviceConfig.getWriteTimeoutInSeconds(), TimeUnit.SECONDS)))
+ .resolver(DefaultAddressResolverGroup.INSTANCE)
+ .compress(true);
+ }
+
+ @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
+ private static ConnectionProvider getConnectionProvider(final ServiceConfig serviceConfig) {
+ return ConnectionProvider.builder(serviceConfig.getConnectionProviderName())
+ .maxConnections(serviceConfig.getMaximumConnectionsTotal())
+ .pendingAcquireMaxCount(serviceConfig.getPendingAcquireMaxCount())
+ .build();
+ }
+
+ private WebClient buildAndGetWebClient(final WebClient.Builder webClientBuilder, final HttpClient httpClient,
+ final int maximumInMemorySizeInMegabytes) {
+ return webClientBuilder
+ .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
+ .defaultHeaders(header -> header.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
+ .clientConnector(new ReactorClientHttpConnector(httpClient))
+ .codecs(configurer -> configurer.defaultCodecs()
+ .maxInMemorySize(maximumInMemorySizeInMegabytes * 1024 * 1024)).build();
+ }
+}
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 4cc8cdaa66..6d51eb48b8 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
@@ -33,13 +33,13 @@ import org.onap.cps.api.CpsAnchorService;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsDataspaceService;
import org.onap.cps.api.CpsModuleService;
-import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException;
+import org.onap.cps.ncmp.exceptions.NcmpStartUpException;
import org.onap.cps.spi.CascadeDeleteAllowed;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
-import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
@Slf4j
@RequiredArgsConstructor
@@ -61,12 +61,12 @@ abstract class AbstractModelLoader implements ModelLoader {
long retryTimeMs;
@Override
- public void onApplicationEvent(@NonNull final ApplicationReadyEvent applicationReadyEvent) {
+ public void onApplicationEvent(@NonNull final ApplicationStartedEvent applicationStartedEvent) {
try {
onboardOrUpgradeModel();
} catch (final NcmpStartUpException ncmpStartUpException) {
log.error("Onboarding model for NCMP failed: {} ", ncmpStartUpException.getMessage());
- SpringApplication.exit(applicationReadyEvent.getApplicationContext(), () -> EXIT_CODE_ON_ERROR);
+ SpringApplication.exit(applicationStartedEvent.getApplicationContext(), () -> EXIT_CODE_ON_ERROR);
}
}
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 a0b7bd5826..780b240b6c 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
@@ -20,7 +20,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.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME;
import static org.onap.cps.utils.ContentType.JSON;
import java.time.OffsetDateTime;
@@ -29,8 +29,8 @@ import org.onap.cps.api.CpsAnchorService;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.api.CpsDataspaceService;
import org.onap.cps.api.CpsModuleService;
-import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException;
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
+import org.onap.cps.ncmp.api.data.models.DatastoreType;
+import org.onap.cps.ncmp.exceptions.NcmpStartUpException;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.springframework.stereotype.Service;
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 7c25953f0d..76d12f290c 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
@@ -20,9 +20,9 @@
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 static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR;
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.api.CpsAnchorService;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/ModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/ModelLoader.java
index c61bf1c9b1..9832ba3f9e 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/ModelLoader.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/ModelLoader.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.
@@ -21,13 +21,13 @@
package org.onap.cps.ncmp.init;
import lombok.NonNull;
-import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
-public interface ModelLoader extends ApplicationListener<ApplicationReadyEvent> {
+public interface ModelLoader extends ApplicationListener<ApplicationStartedEvent> {
@Override
- void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent);
+ void onApplicationEvent(@NonNull ApplicationStartedEvent applicationStartedEvent);
void onboardOrUpgradeModel();
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java
index 4120970e52..4462b169e2 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/mapper/CloudEventMapper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CloudEventMapper.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.mapper;
+package org.onap.cps.ncmp.utils.events;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cloudevents.CloudEvent;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java
index 7afe606f4f..2a9717cc1a 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisher.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/CmAvcEventPublisher.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient;
+package org.onap.cps.ncmp.utils.events;
import io.cloudevents.CloudEvent;
import java.util.Collections;
@@ -26,7 +26,6 @@ import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.onap.cps.events.EventsPublisher;
-import org.onap.cps.ncmp.api.impl.events.NcmpEvent;
import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc;
import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent;
import org.onap.cps.ncmp.events.avc.ncmp_to_client.Data;
@@ -35,7 +34,7 @@ import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
-public class AvcEventPublisher {
+public class CmAvcEventPublisher {
private final EventsPublisher<CloudEvent> eventsPublisher;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java
index 248db9805c..8d3190eb00 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/NcmpEvent.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events;
+package org.onap.cps.ncmp.utils.events;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
@@ -27,8 +27,8 @@ import java.util.Map;
import java.util.UUID;
import lombok.Builder;
import org.apache.commons.lang3.StringUtils;
-import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter;
-import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext;
+import org.onap.cps.ncmp.config.CpsApplicationContext;
+import org.onap.cps.ncmp.impl.utils.EventDateTimeFormatter;
import org.onap.cps.utils.JsonObjectMapper;
@Builder
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/TopicValidator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java
index 6a46fbd638..07da7f76a0 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/util/TopicValidator.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java
@@ -18,12 +18,12 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.util;
+package org.onap.cps.ncmp.utils.events;
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
-import org.onap.cps.ncmp.rest.exceptions.InvalidTopicException;
+import org.onap.cps.ncmp.api.exceptions.InvalidTopicException;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TopicValidator {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/DatastoreTypeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/DatastoreTypeSpec.groovy
new file mode 100644
index 0000000000..3a6737d3ca
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/DatastoreTypeSpec.groovy
@@ -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.data.models
+
+import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException
+import spock.lang.Specification
+
+class DatastoreTypeSpec extends Specification {
+
+ def 'Converting string to enum.'() {
+ expect: 'converting string to enum results in the correct enum value'
+ DatastoreType.fromDatastoreName(datastoreName) == expectedEnum
+ where: 'the following datastore names are used'
+ datastoreName || expectedEnum
+ 'ncmp-datastore:operational' || DatastoreType.OPERATIONAL
+ 'ncmp-datastore:passthrough-running' || DatastoreType.PASSTHROUGH_RUNNING
+ 'ncmp-datastore:passthrough-operational' || DatastoreType.PASSTHROUGH_OPERATIONAL
+ }
+
+ def 'Converting unknown name string to enum.'() {
+ when: 'attempt converting unknown datastore name'
+ DatastoreType.fromDatastoreName('unknown')
+ then: 'an invalid datastore exception is thrown'
+ def thrown = thrown(InvalidDatastoreException)
+ assert thrown.message.contains('unknown is an invalid datastore')
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/OperationTypeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/OperationTypeSpec.groovy
new file mode 100644
index 0000000000..efe67abef5
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/data/models/OperationTypeSpec.groovy
@@ -0,0 +1,48 @@
+/*
+ * ============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.data.models
+
+import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException
+import spock.lang.Specification
+
+class OperationTypeSpec extends Specification {
+
+ def 'Converting string to enum.'() {
+ expect: 'converting string to enum results in the correct enum value'
+ OperationType.fromOperationName(operationName) == expectedEnum
+ where: 'the following datastore names are used'
+ operationName || expectedEnum
+ 'read' || OperationType.READ
+ 'create' || OperationType.CREATE
+ 'update' || OperationType.UPDATE
+ 'patch' || OperationType.PATCH
+ 'delete' || OperationType.DELETE
+ }
+
+ def 'Converting unknown name string to enum.'() {
+ when: 'attempt converting unknown datastore name'
+ OperationType.fromOperationName('unknown')
+ then: 'an invalid operation exception is thrown'
+ def thrown = thrown(InvalidOperationException)
+ assert thrown.message.contains('unknown is an invalid operation')
+ }
+
+}
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
deleted file mode 100644
index 43787640a3..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * ============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
deleted file mode 100644
index 4d0af6f490..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2021-2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
- * ================================================================================
- * 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 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
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
-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
-import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.models.DataOperationDefinition
-import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters
-import org.onap.cps.ncmp.api.models.ConditionApiProperties
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-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
-import org.onap.cps.api.CpsDataService
-import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
-import org.onap.cps.spi.FetchDescendantsOption
-import org.onap.cps.spi.model.DataNode
-import org.springframework.http.HttpStatus
-import org.springframework.http.ResponseEntity
-import spock.lang.Specification
-
-class NetworkCmProxyDataServiceImplSpec extends Specification {
-
- def mockCpsDataService = Mock(CpsDataService)
- def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
- def mockDmiDataOperations = Mock(DmiDataOperations)
- def nullNetworkCmProxyDataServicePropertyHandler = null
- def mockInventoryPersistence = Mock(InventoryPersistence)
- def mockCmHandleQueries = Mock(CmHandleQueries)
- def mockDmiPluginRegistration = Mock(DmiPluginRegistration)
- def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandleQueryService)
- def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
- def stubModuleSyncStartedOnCmHandles = Stub(IMap<String, Object>)
- def stubTrustLevelPerDmiPlugin = Stub(Map<String, TrustLevel>)
- def mockTrustLevelManager = Mock(TrustLevelManager)
- def mockAlternateIdChecker = Mock(AlternateIdChecker)
-
- def NO_TOPIC = null
- def NO_REQUEST_ID = null
- def NO_AUTH_HEADER = null
- def OPTIONS_PARAM = '(a=1,b=2)'
- def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id')
-
- def objectUnderTest = new NetworkCmProxyDataServiceImpl(
- spiedJsonObjectMapper,
- mockDmiDataOperations,
- nullNetworkCmProxyDataServicePropertyHandler,
- mockInventoryPersistence,
- mockCmHandleQueries,
- mockCpsCmHandlerQueryService,
- mockLcmEventsCmHandleStateHandler,
- mockCpsDataService,
- stubModuleSyncStartedOnCmHandles,
- stubTrustLevelPerDmiPlugin,
- mockTrustLevelManager,
- mockAlternateIdChecker)
-
- def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
-
- def dataNode = [new DataNode(leaves: ['id': 'some-cm-handle', 'dmi-service-name': 'testDmiService'])]
-
- def 'Write resource data for pass-through running from DMI using POST.'() {
- given: 'cpsDataService returns valid datanode'
- mockDataNode()
- when: 'write resource data is called'
- objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId', CREATE,
- '{some-json}', 'application/json', null)
- then: 'DMI called with correct data'
- 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
- CREATE, '{some-json}', 'application/json', null)
- >> { new ResponseEntity<>(HttpStatus.CREATED) }
- }
-
- def 'Get resource data for from DMI.'() {
- given: 'cpsDataService returns valid data node'
- mockDataNode()
- and: 'some cm resource address'
- def cmResourceAddress = new CmResourceAddress('some datastore','some CM Handle', 'some resource Id')
- and: 'get resource data from DMI is called'
- mockDmiDataOperations.getResourceDataFromDmi(cmResourceAddress, OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) >>
- new ResponseEntity<>('dmi-response', HttpStatus.OK)
- when: 'get resource data operational for the given cm resource address is called'
- def response = objectUnderTest.getResourceDataForCmHandle(cmResourceAddress, OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER)
- then: 'DMI returns a json response'
- assert response == 'dmi-response'
- }
-
- def 'Get resource data for operational (cached) data.'() {
- given: 'CPS Data service returns some object(s)'
- mockCpsDataService.getDataNodes(OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', FetchDescendantsOption.OMIT_DESCENDANTS) >> ['First Object', 'other Object']
- and: 'a cm resource address for the same datastore, cm handle and resource id'
- def cmResourceAddress = new CmResourceAddress(OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId')
- when: 'get resource data is called'
- def response = objectUnderTest.getResourceDataForCmHandle(cmResourceAddress, FetchDescendantsOption.OMIT_DESCENDANTS)
- then: 'get resource data returns teh first object from the data service'
- assert response == 'First Object'
- }
-
- def 'Execute (async) data operation for #datastoreName from DMI.'() {
- given: 'cpsDataService returns valid data node'
- def dataOperationRequest = getDataOperationRequest(datastoreName)
- when: 'request resource data for data operation is called'
- objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER)
- then: 'request resource data for data operation returns expected response'
- 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER)
- where: 'the following data stores are used'
- datastoreName << [PASSTHROUGH_RUNNING.datastoreName, PASSTHROUGH_OPERATIONAL.datastoreName]
- }
-
- def 'Getting Yang Resources.'() {
- when: 'yang resources is called'
- objectUnderTest.getYangResourcesModuleReferences('some-cm-handle')
- then: 'CPS module services is invoked for the correct dataspace and cm handle'
- 1 * mockInventoryPersistence.getYangResourcesModuleReferences('some-cm-handle')
- }
-
- def 'Get a cm handle.'() {
- given: 'the system returns a yang modelled cm handle'
- def dmiServiceName = 'some service name'
- def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
- lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
- lastUpdateTime: 'some-timestamp',
- dataSyncEnabled: false,
- dataStores: dataStores())
- def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
- def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
- def moduleSetTag = 'some-module-set-tag'
- def alternateId = 'some-alternate-id'
- def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName,
- dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState,
- moduleSetTag: moduleSetTag, alternateId: alternateId)
- 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
- when: 'getting cm handle details for a given cm handle id from ncmp service'
- def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle')
- then: 'the result is a ncmpServiceCmHandle'
- result.class == NcmpServiceCmHandle.class
- and: 'the cm handle contains the cm handle id'
- result.cmHandleId == 'some-cm-handle'
- and: 'the cm handle contains the alternate id'
- result.alternateId == 'some-alternate-id'
- and: 'the cm handle contains the module-set-tag'
- result.moduleSetTag == 'some-module-set-tag'
- and: 'the cm handle contains the DMI Properties'
- result.dmiProperties ==[ Book:'Romance Novel' ]
- and: 'the cm handle contains the public Properties'
- result.publicProperties == [ "Public Book":'Public Romance Novel' ]
- and: 'the cm handle contains the cm handle composite state'
- result.compositeState == compositeState
- }
-
- def 'Get cm handle public properties'() {
- given: 'a yang modelled cm handle'
- def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
- def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
- def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties)
- and: 'the system returns this yang modelled cm handle'
- 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
- when: 'getting cm handle public properties for a given cm handle id from ncmp service'
- def result = objectUnderTest.getCmHandlePublicProperties('some-cm-handle')
- then: 'the result returns the correct data'
- result == [ 'public prop' : 'some public prop' ]
- }
-
- def 'Execute cm handle id search for inventory'() {
- given: 'a ConditionApiProperties object'
- def conditionProperties = new ConditionProperties()
- conditionProperties.conditionName = 'hasAllProperties'
- conditionProperties.conditionParameters = [ [ 'some-key' : 'some-value' ] ]
- def conditionServiceProps = new CmHandleQueryServiceParameters()
- conditionServiceProps.cmHandleQueryParameters = [conditionProperties] as List<ConditionProperties>
- and: 'the system returns an set of cmHandle ids'
- mockCpsCmHandlerQueryService.queryCmHandleIdsForInventory(*_) >> [ 'cmHandle1', 'cmHandle2' ]
- when: 'getting cm handle id set for a given dmi property'
- def result = objectUnderTest.executeCmHandleIdSearchForInventory(conditionServiceProps)
- then: 'the result returns the correct 2 elements'
- assert result.size() == 2
- assert result.contains('cmHandle1')
- assert result.contains('cmHandle2')
- }
-
- def 'Get cm handle composite state'() {
- given: 'a yang modelled cm handle'
- def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
- lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
- lastUpdateTime: 'some-timestamp',
- dataSyncEnabled: false,
- dataStores: dataStores())
- def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
- def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
- def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
- and: 'the system returns this yang modelled cm handle'
- 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
- when: 'getting cm handle composite state for a given cm handle id from ncmp service'
- def result = objectUnderTest.getCmHandleCompositeState('some-cm-handle')
- then: 'the result returns the correct data'
- result == compositeState
- }
-
- def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() {
- given: 'cpsDataService returns valid datanode'
- mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
- when: 'get resource data is called'
- objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceId', UPDATE,
- '{some-json}', 'application/json', NO_AUTH_HEADER)
- then: 'DMI called with correct data'
- 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
- UPDATE, '{some-json}', 'application/json', NO_AUTH_HEADER)
- >> { new ResponseEntity<>(HttpStatus.OK) }
- }
-
- def 'Verify modules and create anchor params.'() {
- given: 'dmi plugin registration return created cm handles'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'service1', dmiModelPlugin: 'service1',
- dmiDataPlugin: 'service2')
- dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
- mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle]
- and: 'no rejected cm handles because of alternate ids'
- mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> []
- when: 'parse and create cm handle in dmi registration then sync module'
- mockDmiPluginRegistration.createdCmHandles = ['test-cm-handle-id']
- objectUnderTest.processCreatedCmHandles(mockDmiPluginRegistration, new DmiPluginRegistrationResponse())
- then: 'system persists the cm handle state'
- 1 * mockLcmEventsCmHandleStateHandler.initiateStateAdvised(_) >> {
- args -> {
- def cmHandleStatePerCmHandle = (args[0] as Collection)
- cmHandleStatePerCmHandle.each {
- assert it.id == 'test-cm-handle-id'
- }
- }
- }
- }
-
- def 'Execute cm handle id search'() {
- given: 'valid CmHandleQueryApiParameters input'
- def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
- def conditionApiProperties = new ConditionApiProperties()
- conditionApiProperties.conditionName = 'hasAllModules'
- conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
- cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
- and: 'query cm handle method return with a data node list'
- mockCpsCmHandlerQueryService.queryCmHandleIds(
- spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
- >> ['cm-handle-id-1']
- when: 'execute cm handle search is called'
- def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters)
- then: 'result is the same collection as returned by the CPS Data Service'
- assert result == ['cm-handle-id-1']
- }
-
- def 'Getting module definitions by module'() {
- when: 'get module definitions is performed with module name'
- objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
- then: 'ncmp inventory persistence service is invoked once with correct parameters'
- 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
- }
-
- def 'Getting module definitions by cm handle id'() {
- when: 'get module definitions is performed with cm handle id'
- objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle')
- then: 'ncmp inventory persistence service is invoked once with correct parameter'
- 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
- }
-
- def 'Execute cm handle search'() {
- given: 'valid CmHandleQueryApiParameters input'
- def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
- def conditionApiProperties = new ConditionApiProperties()
- conditionApiProperties.conditionName = 'hasAllModules'
- conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
- cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
- and: 'query cm handle method return with a data node list'
- mockCpsCmHandlerQueryService.queryCmHandles(
- spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
- >> [new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')]
- when: 'execute cm handle search is called'
- def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters)
- then: 'result is the same collection as returned by the CPS Data Service'
- assert result.stream().map(d -> d.cmHandleId).collect(Collectors.toSet()) == ['cm-handle-id-1'] as Set
- }
-
- def 'Set Cm Handle Data Sync Enabled Flag where data sync flag is #scenario'() {
- given: 'an existing cm handle composite state'
- def compositeState = new CompositeState(cmHandleState: CmHandleState.READY, dataSyncEnabled: initialDataSyncEnabledFlag,
- dataStores: CompositeState.DataStores.builder()
- .operationalDataStore(CompositeState.Operational.builder()
- .dataStoreSyncState(initialDataSyncState)
- .build()).build())
- and: 'get cm handle state returns the composite state for the given cm handle id'
- mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
- when: 'set data sync enabled is called with the data sync enabled flag set to #dataSyncEnabledFlag'
- objectUnderTest.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
- then: 'the data sync enabled flag is set to #dataSyncEnabled'
- compositeState.dataSyncEnabled == dataSyncEnabledFlag
- and: 'the data store sync state is set to #expectedDataStoreSyncState'
- compositeState.dataStores.operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState
- and: 'the cps data service to delete data nodes is invoked the expected number of times'
- deleteDataNodeExpectedNumberOfInvocation * mockCpsDataService.deleteDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'some-cm-handle-id', '/netconf-state', _)
- and: 'the inventory persistence service to update node leaves is called with the correct values'
- saveCmHandleStateExpectedNumberOfInvocations * mockInventoryPersistence.saveCmHandleState('some-cm-handle-id', compositeState)
- where: 'the following data sync enabled flag is used'
- scenario | dataSyncEnabledFlag | initialDataSyncEnabledFlag | initialDataSyncState || expectedDataStoreSyncState | deleteDataNodeExpectedNumberOfInvocation | saveCmHandleStateExpectedNumberOfInvocations
- 'enabled' | true | false | DataStoreSyncState.NONE_REQUESTED || DataStoreSyncState.UNSYNCHRONIZED | 0 | 1
- 'disabled' | false | true | DataStoreSyncState.UNSYNCHRONIZED || DataStoreSyncState.NONE_REQUESTED | 0 | 1
- 'disabled where sync-state is currently SYNCHRONIZED' | false | true | DataStoreSyncState.SYNCHRONIZED || DataStoreSyncState.NONE_REQUESTED | 1 | 1
- 'is set to existing flag state' | true | true | DataStoreSyncState.UNSYNCHRONIZED || DataStoreSyncState.UNSYNCHRONIZED | 0 | 0
- }
-
- def 'Set cm Handle Data Sync Enabled flag with following cm handle not in ready state exception' () {
- given: 'a cm handle composite state'
- def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, dataSyncEnabled: false)
- and: 'get cm handle state returns the composite state for the given cm handle id'
- mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
- when: 'set data sync enabled is called with the data sync enabled flag set to true'
- objectUnderTest.setDataSyncEnabled('some-cm-handle-id', true)
- then: 'the expected exception is thrown'
- thrown(CpsException)
- and: 'the inventory persistence service to update node leaves is not invoked'
- 0 * mockInventoryPersistence.saveCmHandleState(_, _)
- }
-
- def 'Get all cm handle IDs by DMI plugin identifier.' () {
- given: 'cm handle queries service returns cm handles'
- 1 * mockCmHandleQueries.getCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier') >> ['cm-handle-1','cm-handle-2']
- when: 'cm handle Ids are requested with dmi plugin identifier'
- def result = objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
- then: 'the result size is correct'
- assert result.size() == 2
- and: 'the result returns the correct details'
- assert result.containsAll('cm-handle-1','cm-handle-2')
- }
-
- def dataStores() {
- CompositeState.DataStores.builder()
- .operationalDataStore(CompositeState.Operational.builder()
- .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
- .lastSyncTime('some-timestamp').build()).build()
- }
-
- def mockDataNode() {
- mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
- }
-
- def getDataOperationRequest(datastore) {
- def dataOperationRequest = new DataOperationRequest()
- def dataOperationDefinitions = new ArrayList()
- dataOperationDefinitions.add(getDataOperationDefinition(datastore))
- dataOperationRequest.setDataOperationDefinitions(dataOperationDefinitions)
- return dataOperationRequest
- }
-
- def getDataOperationDefinition(datastore) {
- def dataOperationDefinition = new DataOperationDefinition()
- dataOperationDefinition.setOperation("read")
- dataOperationDefinition.setOperationId("operational-12")
- dataOperationDefinition.setDatastore(datastore)
- def targetIds = new ArrayList()
- targetIds.add("some-cm-handle")
- dataOperationDefinition.setCmHandleIds(targetIds)
- return dataOperationDefinition
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
deleted file mode 100644
index 547d08a3e5..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2022 Bell Canada
- * ================================================================================
- * 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.client
-
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
-import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
-
-import com.fasterxml.jackson.databind.JsonNode
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.databind.node.ObjectNode
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
-import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException
-import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException
-import org.onap.cps.ncmp.utils.TestUtils
-import org.onap.cps.utils.JsonObjectMapper
-import org.spockframework.spring.SpringBean
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.http.HttpHeaders
-import org.springframework.http.ResponseEntity
-import org.springframework.test.context.ContextConfiguration
-import org.springframework.web.client.HttpServerErrorException
-import org.springframework.web.reactive.function.client.WebClient
-import reactor.core.publisher.Mono
-import spock.lang.Specification
-import org.springframework.web.reactive.function.client.WebClientResponseException
-
-@SpringBootTest
-@ContextConfiguration(classes = [DmiWebClientConfiguration, DmiRestClient, ObjectMapper])
-class DmiRestClientSpec extends Specification {
-
- static final NO_AUTH_HEADER = null
- static final BASIC_AUTH_HEADER = 'Basic c29tZS11c2VyOnNvbWUtcGFzc3dvcmQ='
- static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token'
-
- @Autowired
- DmiWebClientConfiguration.DmiProperties dmiProperties
-
- @Autowired
- DmiRestClient objectUnderTest
-
- @SpringBean
- WebClient mockWebClient = Mock(WebClient);
-
- @SpringBean
- JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
-
- def mockRequestBodyUriSpec = Mock(WebClient.RequestBodyUriSpec)
- def mockResponseSpec = Mock(WebClient.ResponseSpec)
- def mockResponseEntity = Mock(ResponseEntity)
-
- def setup() {
- mockRequestBodyUriSpec.uri(_) >> mockRequestBodyUriSpec
- mockRequestBodyUriSpec.headers(_) >> mockRequestBodyUriSpec
- mockRequestBodyUriSpec.retrieve() >> mockResponseSpec
- }
-
- def 'DMI POST operation with JSON.'() {
- given: 'the web client returns a valid response entity for the expected parameters'
- mockWebClient.post() >> mockRequestBodyUriSpec
- mockRequestBodyUriSpec.body(_) >> mockRequestBodyUriSpec
- def monoSpec = Mono.just(mockResponseEntity)
- mockResponseSpec.bodyToMono(Object.class) >> monoSpec
- monoSpec.block() >> mockResponseEntity
- when: 'POST operation is invoked'
- def response = objectUnderTest.postOperationWithJsonData('/my/url', 'some json', READ, null)
- then: 'the output of the method is equal to the output from the test template'
- assert response.statusCode.value() == 200
- assert response.hasBody()
- }
-
- def 'Failing DMI POST operation for server error'() {
- given: 'the web client throws an exception'
- mockWebClient.post() >> { throw new HttpServerErrorException(SERVICE_UNAVAILABLE, null, null, null) }
- when: 'POST operation is invoked'
- objectUnderTest.postOperationWithJsonData('/some', 'some json', READ, null)
- then: 'a http client exception is thrown'
- def thrown = thrown(DmiClientRequestException)
- and: 'the exception has the relevant details from the error response'
- assert thrown.ncmpResponseStatus.code == '102'
- assert thrown.httpStatusCode == 503
- }
-
- def 'Failing DMI POST operation due to invalid dmi resource url.'() {
- when: 'POST operation is invoked with invalid dmi resource url'
- objectUnderTest.postOperationWithJsonData('/invalid dmi url', null, null, null)
- then: 'invalid dmi resource url exception is thrown'
- def thrown = thrown(InvalidDmiResourceUrlException)
- and: 'the exception has the relevant details from the error response'
- assert thrown.httpStatus == 400
- assert thrown.message == 'Invalid dmi resource url: /invalid dmi url'
- where: 'the following operations are executed'
- operation << [CREATE, READ, PATCH]
- }
-
- def 'Dmi service sends client error response when #scenario'() {
- given: 'the web client unable to return response entity but error'
- mockWebClient.post() >> mockRequestBodyUriSpec
- mockRequestBodyUriSpec.body(_) >> mockRequestBodyUriSpec
- def monoSpec = Mono.error(new WebClientResponseException('message', httpStatusCode, null, null, null, null))
- mockResponseSpec.bodyToMono(Object.class) >> monoSpec
- when: 'POST operation is invoked'
- objectUnderTest.postOperationWithJsonData('/my/url', 'some json', READ, null)
- then: 'a http client exception is thrown'
- def thrown = thrown(DmiClientRequestException)
- and: 'the exception has the relevant details from the error response'
- assert thrown.ncmpResponseStatus.code == expectedNcmpResponseStatusCode
- assert thrown.httpStatusCode == httpStatusCode
- where: 'the following errors occur'
- scenario | httpStatusCode | expectedNcmpResponseStatusCode
- 'dmi request timeout' | 408 | DMI_SERVICE_NOT_RESPONDING.code
- 'other error code' | 500 | UNABLE_TO_READ_RESOURCE_DATA.code
- }
-
- def 'Dmi trust level is determined by spring boot health status'() {
- given: 'a health check response'
- def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json')
- def jsonNode = jsonObjectMapper.convertJsonString(dmiPluginHealthCheckResponseJsonData, JsonNode.class)
- ((ObjectNode) jsonNode).put('status', 'my status')
- def monoResponse = Mono.just(jsonNode)
- mockWebClient.get() >> mockRequestBodyUriSpec
- mockResponseSpec.bodyToMono(_) >> monoResponse
- monoResponse.block() >> jsonNode
- when: 'get trust level of the dmi plugin'
- def result = objectUnderTest.getDmiHealthStatus('some/url')
- then: 'the status value from the json is return'
- assert result == 'my status'
- }
-
- def 'Failing to get dmi plugin health status #scenario'() {
- given: 'rest template with #scenario'
- mockWebClient.get() >> healthStatusResponse
- when: 'attempt to get health status of the dmi plugin'
- def result = objectUnderTest.getDmiHealthStatus('some url')
- then: 'result will be empty'
- assert result == ''
- where: 'the following responses are used'
- scenario | healthStatusResponse
- 'null' | null
- 'exception' | {throw new Exception()}
- }
-
- def 'DMI auth header #scenario'() {
- when: 'Specific dmi properties are provided'
- dmiProperties.dmiBasicAuthEnabled = authEnabled
- then: 'http headers to conditionally have Authorization header'
- def authHeaderValues = objectUnderTest.configureHttpHeaders(new HttpHeaders(), ncmpAuthHeader).getOrEmpty('Authorization')
- def outputAuthHeader = (authHeaderValues == null ? null : authHeaderValues[0])
- assert outputAuthHeader == expectedAuthHeader
- where: 'the following configurations are used'
- scenario | authEnabled | ncmpAuthHeader || expectedAuthHeader
- 'DMI basic auth enabled, no NCMP bearer token' | true | NO_AUTH_HEADER || BASIC_AUTH_HEADER
- 'DMI basic auth enabled, with NCMP bearer token' | true | BEARER_AUTH_HEADER || BASIC_AUTH_HEADER
- 'DMI basic auth disabled, no NCMP bearer token' | false | NO_AUTH_HEADER || NO_AUTH_HEADER
- 'DMI basic auth disabled, with NCMP bearer token' | false | BEARER_AUTH_HEADER || BEARER_AUTH_HEADER
- 'DMI basic auth disabled, with NCMP basic auth' | false | BASIC_AUTH_HEADER || NO_AUTH_HEADER
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
deleted file mode 100644
index 6a73089e84..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy
+++ /dev/null
@@ -1,64 +0,0 @@
-/*-
- * ============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.config
-
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.test.context.ContextConfiguration
-import org.springframework.test.context.TestPropertySource
-import org.springframework.web.reactive.function.client.WebClient
-import spock.lang.Specification
-
-@SpringBootTest
-@ContextConfiguration(classes = [DmiWebClientConfiguration.DmiProperties])
-@TestPropertySource(properties = ['ncmp.dmi.httpclient.connectionTimeoutInSeconds=1', 'ncmp.dmi.httpclient.maximumInMemorySizeInMegabytes=1'])
-class DmiWebClientConfigurationSpec extends Specification {
-
- @Autowired
- DmiWebClientConfiguration.DmiProperties dmiProperties
-
- def objectUnderTest = new DmiWebClientConfiguration()
-
- def setup() {
- objectUnderTest.connectionTimeoutInSeconds = 10
- objectUnderTest.maximumInMemorySizeInMegabytes = 1
- objectUnderTest.maximumConnectionsTotal = 2
- }
-
- def 'DMI Properties.'() {
- expect: 'properties are set to values in test configuration yaml file'
- dmiProperties.authUsername == 'some-user'
- dmiProperties.authPassword == 'some-password'
- }
-
- def 'Web Client Configuration construction.'() {
- expect: 'the system can create an instance'
- new DmiWebClientConfiguration() != null
- }
-
- def 'Creating a WebClient instance.'() {
- given: 'WebClient configuration invoked'
- def webClientInstance = objectUnderTest.webClient()
- expect: 'the system can create an instance'
- assert webClientInstance != null
- assert webClientInstance instanceof WebClient
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDeltaSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDeltaSpec.groovy
deleted file mode 100644
index e50652689a..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDeltaSpec.groovy
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * ============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 org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType
-import spock.lang.Specification
-
-class CmNotificationSubscriptionDeltaSpec extends Specification {
-
- def mockCmNotificationSubscriptionPersistenceService = Mock(CmNotificationSubscriptionPersistenceService)
- def objectUnderTest = new CmNotificationSubscriptionDelta(mockCmNotificationSubscriptionPersistenceService)
-
- def 'Find Delta of given list of predicates'() {
- given: 'A list of predicates'
- def predicateList = [new DmiCmNotificationSubscriptionPredicate(['ch-1','ch-2'].toSet(), DatastoreType.PASSTHROUGH_OPERATIONAL, ['a/1/','b/2'].toSet())]
- and: '3 positive responses and 1 negative.'
- mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-1', 'a/1/') >>> true
- mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-1', 'b/2') >>> true
- mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-2', 'a/1/') >>> true
- mockCmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_OPERATIONAL, 'ch-2', 'b/2') >>> false
- when: 'getDelta is called'
- def result = objectUnderTest.getDelta(predicateList)
- then: 'verify correct delta is returned'
- assert result.size() == 1
- assert result[0].targetCmHandleIds[0] == 'ch-2'
- assert result[0].xpaths[0] == 'b/2'
-
- }
-
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy
deleted file mode 100644
index 788a7a7da5..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionEventsHandlerSpec.groovy
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * ============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 org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionNcmpOutEventProducer
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.producer.CmNotificationSubscriptionDmiInEventProducer
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent
-import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent
-import spock.lang.Specification
-
-class CmNotificationSubscriptionEventsHandlerSpec extends Specification {
-
- def mockCmNotificationSubscriptionNcmpOutEventProducer = Mock(CmNotificationSubscriptionNcmpOutEventProducer)
- def mockCmNotificationSubscriptionDmiInEventProducer = Mock(CmNotificationSubscriptionDmiInEventProducer)
-
- def objectUnderTest = new CmNotificationSubscriptionEventsHandler(mockCmNotificationSubscriptionNcmpOutEventProducer,
- mockCmNotificationSubscriptionDmiInEventProducer)
-
- def 'Publish cm notification subscription ncmp out event'() {
- given: 'an ncmp out event'
- def cmNotificationSubscriptionNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent()
- when: 'the method to publish cm notification subscription ncmp out event is called'
- objectUnderTest.publishCmNotificationSubscriptionNcmpOutEvent("some-id",
- "some-event", cmNotificationSubscriptionNcmpOutEvent, true)
- then: 'the parameters is delegated to the correct method once'
- 1 * mockCmNotificationSubscriptionNcmpOutEventProducer.publishCmNotificationSubscriptionNcmpOutEvent(
- "some-id", "some-event", cmNotificationSubscriptionNcmpOutEvent, true)
- }
-
- def 'Publish cm notification subscription dmi in event'() {
- given: 'a dmi in event'
- def cmNotificationSubscriptionDmiInEvent = new CmNotificationSubscriptionDmiInEvent()
- when: 'the method to publish cm notification subscription ncmp out event is called'
- objectUnderTest.publishCmNotificationSubscriptionDmiInEvent("some-id",
- "some-dmi", "some-event", cmNotificationSubscriptionDmiInEvent)
- then: 'the parameters is delegated to the correct method once'
- 1 * mockCmNotificationSubscriptionDmiInEventProducer.publishCmNotificationSubscriptionDmiInEvent("some-id",
- "some-dmi", "some-event", cmNotificationSubscriptionDmiInEvent)
- }
-} \ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy
deleted file mode 100644
index bdc54bd1ee..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionMappersHandlerSpec.groovy
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * ============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 org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionDmiInEventMapper
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper
-import spock.lang.Specification
-
-class CmNotificationSubscriptionMappersHandlerSpec extends Specification{
-
- def mockCmNotificationDmiInEventMapper = Mock(CmNotificationSubscriptionDmiInEventMapper)
- def mockCmNotificationNcmpOutEventMapper = Mock(CmNotificationSubscriptionNcmpOutEventMapper)
-
- def objectUnderTest = new CmNotificationSubscriptionMappersHandler(mockCmNotificationDmiInEventMapper,
- mockCmNotificationNcmpOutEventMapper)
-
- def 'Get cm notification subscription DMI in event'() {
- given: 'a list of predicates'
- def testListOfPredicates = []
- when: 'method to create a cm notification subscription dmi in event is called with predicates'
- objectUnderTest.toCmNotificationSubscriptionDmiInEvent(testListOfPredicates)
- then: 'the parameters is delegated to the correct dmi in event mapper method'
- 1 * mockCmNotificationDmiInEventMapper.toCmNotificationSubscriptionDmiInEvent(testListOfPredicates)
- }
-
- def 'Get cm notification subscription ncmp out event'() {
- given: 'a subscription details map'
- def testSubscriptionDetailsMap = [:]
- when: 'method to create cm notification subscription ncmp out event is called with the following parameters'
- objectUnderTest.toCmNotificationSubscriptionNcmpOutEvent("test-id", testSubscriptionDetailsMap)
- then: 'the parameters is delegated to the correct ncmp out event mapper method'
- 1 * mockCmNotificationNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEvent("test-id",
- testSubscriptionDetailsMap)
- }
-
- def 'Get cm notification subscription ncmp out event for a rejected request'() {
- given: 'a list of target filters'
- def testRejectedTargetFilters = []
- when: 'method to create cm notification subscription ncmp out event is called with the following parameters'
- objectUnderTest.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
- "test-id", testRejectedTargetFilters)
- then: 'the parameters is delegated to the correct ncmp out event mapper method'
- 1 * mockCmNotificationNcmpOutEventMapper.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
- "test-id", testRejectedTargetFilters)
- }
-}
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
deleted file mode 100644
index 77bbe7ebc4..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpOutEventProducerSpec.groovy
+++ /dev/null
@@ -1,88 +0,0 @@
-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.producer.CmNotificationSubscriptionNcmpOutEventProducer
-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
-import org.onap.cps.utils.JsonObjectMapper
-import spock.lang.Specification
-
-class CmNotificationSubscriptionNcmpOutEventProducerSpec extends Specification {
-
- def mockEventsPublisher = Mock(EventsPublisher)
- def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler)
- def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler)
-
- def objectUnderTest = new CmNotificationSubscriptionNcmpOutEventProducer(mockEventsPublisher, jsonObjectMapper,
- mockCmNotificationSubscriptionMappersHandler, mockDmiCmNotificationSubscriptionCacheHandler)
-
- def 'Create and #scenario Cm Notification Subscription NCMP out event'() {
- given: 'a cm subscription response for the client'
- def subscriptionId = 'test-subscription-id-2'
- def eventType = 'subscriptionCreateResponse'
- 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, 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 ->
- {
- 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
- }
- }
- then: 'the cache handler is called once to remove accepted and rejected entries in cache'
- 1 * mockDmiCmNotificationSubscriptionCacheHandler.removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries(subscriptionId)
- }
-
-
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapperSpec.groovy
deleted file mode 100644
index f6bb24c2f2..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionNcmpOutEventMapperSpec.groovy
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * ============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.mapper
-
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType
-import spock.lang.Specification
-
-class CmNotificationSubscriptionNcmpOutEventMapperSpec extends Specification {
-
- static Map<String, DmiCmNotificationSubscriptionDetails> dmiCmNotificationSubscriptionDetailsMap
-
- def objectUnderTest = new CmNotificationSubscriptionNcmpOutEventMapper()
-
- def setup() {
- def dmiCmNotificationSubscriptionPredicateA = new DmiCmNotificationSubscriptionPredicate(['ch-A'] as Set, DatastoreType.PASSTHROUGH_RUNNING, ['/a'] as Set)
- def dmiCmNotificationSubscriptionPredicateB = new DmiCmNotificationSubscriptionPredicate(['ch-B'] as Set, DatastoreType.PASSTHROUGH_OPERATIONAL, ['/b'] as Set)
- def dmiCmNotificationSubscriptionPredicateC = new DmiCmNotificationSubscriptionPredicate(['ch-C'] as Set, DatastoreType.PASSTHROUGH_OPERATIONAL, ['/c'] as Set)
- dmiCmNotificationSubscriptionDetailsMap = ['dmi-1': new DmiCmNotificationSubscriptionDetails([dmiCmNotificationSubscriptionPredicateA], CmNotificationSubscriptionStatus.PENDING),
- 'dmi-2': new DmiCmNotificationSubscriptionDetails([dmiCmNotificationSubscriptionPredicateB], CmNotificationSubscriptionStatus.ACCEPTED),
- 'dmi-3': new DmiCmNotificationSubscriptionDetails([dmiCmNotificationSubscriptionPredicateC], CmNotificationSubscriptionStatus.REJECTED)
- ]
- }
-
- def 'Check for Cm Notification Subscription Outgoing event mapping'() {
- when: 'we try to map the event to send it to client'
- def result = objectUnderTest.toCmNotificationSubscriptionNcmpOutEvent('test-subscription', dmiCmNotificationSubscriptionDetailsMap)
- then: 'event is mapped correctly for the subscription'
- result.data.subscriptionId == 'test-subscription'
- and: 'the cm handle ids are part of correct list'
- result.data.pendingTargets == ['ch-A']
- result.data.acceptedTargets == ['ch-B']
- result.data.rejectedTargets == ['ch-C']
- }
-
- def 'Check for Cm Notification Rejected Subscription Outgoing event mapping'() {
- when: 'we try to map the event to send it to client'
- def result = objectUnderTest.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest('test-subscription', ['ch-1', 'ch-2'])
- then: 'event is mapped correctly for the subscription id'
- result.data.subscriptionId == 'test-subscription'
- and: 'the cm handle ids are part of correct list'
- result.data.withRejectedTargets(['ch-1', 'ch-2'])
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy
deleted file mode 100644
index 98b4ee2671..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionHandlerServiceImplSpec.groovy
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * ============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.service
-
-import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionDelta
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionEventsHandler
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.CmNotificationSubscriptionMappersHandler
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.DmiCmNotificationSubscriptionCacheHandler
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionDmiInEventMapper
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper.CmNotificationSubscriptionNcmpOutEventMapper
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent
-import org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent
-import org.onap.cps.ncmp.utils.TestUtils
-import org.onap.cps.utils.JsonObjectMapper
-import spock.lang.Specification
-
-class CmNotificationSubscriptionHandlerServiceImplSpec extends Specification{
-
- def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- def mockCmNotificationSubscriptionPersistenceService = Mock(CmNotificationSubscriptionPersistenceService);
- def mockCmNotificationSubscriptionDelta = Mock(CmNotificationSubscriptionDelta);
- def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler);
- def mockCmNotificationSubscriptionEventsHandler = Mock(CmNotificationSubscriptionEventsHandler);
- def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler);
-
- def objectUnderTest = new CmNotificationSubscriptionHandlerServiceImpl(mockCmNotificationSubscriptionPersistenceService,
- mockCmNotificationSubscriptionDelta, mockCmNotificationSubscriptionMappersHandler,
- mockCmNotificationSubscriptionEventsHandler, mockDmiCmNotificationSubscriptionCacheHandler)
-
- def testSubscriptionDetailsMap = ["dmi-1":new DmiCmNotificationSubscriptionDetails([], CmNotificationSubscriptionStatus.PENDING)]
- def testListOfDeltaPredicates = []
-
- def 'Consume valid and unique CmNotificationSubscriptionNcmpInEvent create message'() {
- given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id'
- def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
- def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class)
- mockCmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId("test-id") >> true
- and: 'the cache handler returns for relevant subscription id'
- 1 * mockDmiCmNotificationSubscriptionCacheHandler.get("test-id") >> testSubscriptionDetailsMap
- and: 'the delta predicates is returned'
- 1 * mockCmNotificationSubscriptionDelta.getDelta(_) >> testListOfDeltaPredicates
- and: 'the DMI in event mapper returns cm notification subscription event'
- def testDmiInEvent = new CmNotificationSubscriptionDmiInEvent()
- 1 * mockCmNotificationSubscriptionMappersHandler
- .toCmNotificationSubscriptionDmiInEvent(testListOfDeltaPredicates) >> testDmiInEvent
- when: 'the valid and unique event is consumed'
- objectUnderTest.processSubscriptionCreateRequest(testEventConsumed)
- then: 'the subscription cache handler is called once'
- 1 * mockDmiCmNotificationSubscriptionCacheHandler.add('test-id',_)
- and: 'the events handler method to publish DMI event is called correct number of times with the correct parameters'
- testSubscriptionDetailsMap.size() * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(
- "test-id", "dmi-1", "subscriptionCreateRequest", testDmiInEvent)
- and: 'we schedule to send the response after configured time from the cache'
- 1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(
- "test-id", "subscriptionCreateResponse", null, true)
- }
-
- def 'Consume valid and but non-unique CmNotificationSubscription create message'() {
- given: 'a cmNotificationSubscriptionNcmp in event'
- def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
- def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class)
- mockCmNotificationSubscriptionPersistenceService.isUniqueSubscriptionId('test-id') >> false
- and: 'the NCMP out in event mapper returns an event for rejected request'
- def testNcmpOutEvent = new CmNotificationSubscriptionNcmpOutEvent()
- 1 * mockCmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEventForRejectedRequest(
- "test-id",_) >> testNcmpOutEvent
- when: 'the valid but non-unique event is consumed'
- objectUnderTest.processSubscriptionCreateRequest(testEventConsumed)
- then: 'the events handler method to publish DMI event is never called'
- 0 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionDmiInEvent(_,_,_,_)
- and: 'the events handler method to publish NCMP out event is called once'
- 1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent(
- 'test-id', 'subscriptionCreateResponse', testNcmpOutEvent, false)
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImplSpec.groovy
deleted file mode 100644
index 13a20a1eb2..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/service/CmNotificationSubscriptionPersistenceServiceImplSpec.groovy
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * ============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.service
-
-import org.onap.cps.api.CpsDataService
-import org.onap.cps.api.CpsQueryService
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType
-import org.onap.cps.spi.FetchDescendantsOption
-import org.onap.cps.spi.model.DataNode
-import org.onap.cps.utils.JsonObjectMapper
-import com.fasterxml.jackson.databind.ObjectMapper
-import spock.lang.Specification
-
-class CmNotificationSubscriptionPersistenceServiceImplSpec extends Specification {
-
- def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- def mockCpsQueryService = Mock(CpsQueryService)
- def mockCpsDataService = Mock(CpsDataService)
-
- def objectUnderTest = new CmNotificationSubscriptionPersistenceServiceImpl(jsonObjectMapper, mockCpsQueryService, mockCpsDataService)
-
- def 'Check ongoing cm subscription #scenario'() {
- given: 'a valid cm subscription query'
- def cpsPathQuery = "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-1']/filters/filter[@xpath='/cps/path']";
- and: 'datanodes optionally returned'
- 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
- cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> dataNode
- when: 'we check for an ongoing cm subscription'
- def response = objectUnderTest.isOngoingCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1', '/cps/path')
- then: 'we get expected response'
- assert response == isOngoingCmSubscription
- where: 'following scenarios are used'
- scenario | dataNode || isOngoingCmSubscription
- 'valid datanodes present' | [new DataNode(xpath: '/cps/path', leaves: ['subscriptionIds': ['sub-1', 'sub-2']])] || true
- 'no datanodes present' | [] || false
- }
-
- def 'Checking uniqueness of incoming subscription ID'() {
- given: 'a cps path with a subscription ID for querying'
- def cpsPathQuery = objectUnderTest.SUBSCRIPTION_IDS_CPS_PATH_QUERY.formatted('some-sub')
- and: 'relevant datanodes are returned'
- 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >>
- dataNodes
- when: 'a subscription ID is tested for uniqueness'
- def result = objectUnderTest.isUniqueSubscriptionId('some-sub')
- then: 'result is as expected'
- assert result == isValidSubscriptionId
- where: 'following scenarios are used'
- scenario | dataNodes || isValidSubscriptionId
- 'datanodes present' | [new DataNode()] || false
- 'no datanodes present' | [] || true
- }
-
- def 'Add new subscriber to an ongoing cm notification subscription'() {
- given: 'a valid cm subscription path query'
- def cpsPathQuery = objectUnderTest.CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y')
- and: 'a dataNode exists for the given cps path query'
- mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
- cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y','subscriptionIds': ['sub-1']])]
- when: 'the method to add/update cm notification subscription is called'
- objectUnderTest.addCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1','/x/y', 'newSubId')
- then: 'data service method to update list of subscribers is called once'
- 1 * mockCpsDataService.updateNodeLeaves(
- 'NCMP-Admin',
- 'cm-data-subscriptions',
- '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters',
- '{"filter":[{"xpath":"/x/y","subscriptionIds":["sub-1","newSubId"]}]}', _)
- }
-
- def 'Add new cm notification subscription for #datastoreType'() {
- given: 'a valid cm subscription path query'
- def cpsPathQuery = objectUnderTest.CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted(datastoreName, 'ch-1', '/x/y')
- and: 'a parent node xpath for given path above'
- def parentNodeXpath = '/datastores/datastore[@name=\'%s\']/cm-handles'
- and: 'a datanode does not exist for the given cps path query'
- mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
- cpsPathQuery.formatted(datastoreName),
- FetchDescendantsOption.OMIT_DESCENDANTS) >> []
- when: 'the method to add/update cm notification subscription is called'
- objectUnderTest.addCmNotificationSubscription(datastoreType, 'ch-1','/x/y', 'newSubId')
- then: 'data service method to update list of subscribers is called once with the correct parameters'
- 1 * mockCpsDataService.saveData(
- 'NCMP-Admin',
- 'cm-data-subscriptions',
- parentNodeXpath.formatted(datastoreName),
- '{"cm-handle":[{"id":"ch-1","filters":{"filter":[{"xpath":"/x/y","subscriptionIds":["newSubId"]}]}}]}', _,_)
- where:
- scenario | datastoreType || datastoreName
- 'passthrough_running' | DatastoreType.PASSTHROUGH_RUNNING || "ncmp-datastore:passthrough-running"
- 'passthrough_operational' | DatastoreType.PASSTHROUGH_OPERATIONAL || "ncmp-datastore:passthrough-operational"
- }
-
- def 'Remove subscriber from a list of an ongoing cm notification subscription'() {
- given: 'a subscription exists when queried'
- def cpsPathQuery = objectUnderTest.CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y')
- mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
- cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y','subscriptionIds': ['sub-1', 'sub-2']])]
- when: 'the subscriber is removed'
- objectUnderTest.removeCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1')
- then: 'the list of subscribers is updated'
- 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'cm-data-subscriptions',
- '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters',
- '{"filter":[{"xpath":"/x/y","subscriptionIds":["sub-2"]}]}', _)
- }
-
- def 'Removing ongoing subscription with no subscribers'(){
- given: 'a subscription exists when queried but has no subscribers'
- def cpsPathQuery = objectUnderTest.CM_SUBSCRIPTION_CPS_PATH_QUERY.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y')
- mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
- cpsPathQuery, FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y','subscriptionIds': []])]
- when: 'a an ongoing subscription is refreshed'
- objectUnderTest.removeCmNotificationSubscription(DatastoreType.PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1')
- then: 'the subscription with empty subscriber list is removed'
- 1 * mockCpsDataService.deleteDataNode('NCMP-Admin', 'cm-data-subscriptions',
- '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters/filter[@xpath=\'/x/y\']',
- _)
- }
-} \ No newline at end of file
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
deleted file mode 100644
index 8fcdc3fb34..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2022 Bell Canada
- * ================================================================================
- * 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.operations
-
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
-
-import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
-import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException
-import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
-import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext
-import org.onap.cps.ncmp.api.models.DataOperationRequest
-import org.onap.cps.ncmp.api.models.CmResourceAddress
-import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent
-import org.onap.cps.ncmp.utils.TestUtils
-import org.onap.cps.utils.JsonObjectMapper
-import org.spockframework.spring.SpringBean
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.http.HttpStatus
-import org.springframework.http.ResponseEntity
-import org.springframework.test.context.ContextConfiguration
-import spock.lang.Shared
-
-@SpringBootTest
-@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, DmiWebClientConfiguration.DmiProperties, DmiDataOperations])
-class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
-
- @SpringBean
- DmiServiceUrlBuilder dmiServiceUrlBuilder = Mock()
- def dmiServiceBaseUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds/ncmp-datastore:"
- def NO_TOPIC = null
- def NO_REQUEST_ID = null
- def NO_AUTH_HEADER = null
- @Shared
- def OPTIONS_PARAM = '(a=1,b=2)'
-
- @SpringBean
- JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
-
- @Autowired
- DmiDataOperations objectUnderTest
-
- @SpringBean
- EventsPublisher eventsPublisher = Stub()
-
- def 'call get resource data for #expectedDatastoreInUrl from DMI without topic #scenario.'() {
- given: 'a cm handle for #cmHandleId'
- mockYangModelCmHandleRetrieval(dmiProperties)
- and: 'a positive response from DMI service when it is called with the expected parameters'
- def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
- def expectedUrl = dmiServiceBaseUrl + "${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}"
- mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi
- dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl
- when: 'get resource data is invoked'
- def cmResourceAddress = new CmResourceAddress(dataStore.datastoreName, cmHandleId, resourceIdentifier)
- def result = objectUnderTest.getResourceDataFromDmi(cmResourceAddress, options, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER)
- then: 'the result is the response from the DMI service'
- assert result == responseFromDmi
- where: 'the following parameters are used'
- scenario | dmiProperties | dataStore | options || expectedJson | expectedDatastoreInUrl | expectedOptionsInUrl
- 'without properties' | [] | PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
- 'with properties' | [yangModelCmHandleProperty] | PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
- 'null options' | [yangModelCmHandleProperty] | PASSTHROUGH_OPERATIONAL | null || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
- 'empty options' | [yangModelCmHandleProperty] | PASSTHROUGH_OPERATIONAL | '' || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
- 'datastore running without properties' | [] | PASSTHROUGH_RUNNING | OPTIONS_PARAM || '{"operation":"read","cmHandleProperties":{}}' | 'passthrough-running' | '&options=(a=1,b=2)'
- 'datastore running with properties' | [yangModelCmHandleProperty] | PASSTHROUGH_RUNNING | OPTIONS_PARAM || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-running' | '&options=(a=1,b=2)'
- }
-
- def 'Execute (async) data operation from DMI service.'() {
- given: 'collection of yang model cm Handles and data operation request'
- mockYangModelCmHandleCollectionRetrieval([yangModelCmHandleProperty])
- def dataOperationBatchRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json')
- def dataOperationRequest = spiedJsonObjectMapper.convertJsonString(dataOperationBatchRequestJsonData, DataOperationRequest.class)
- dataOperationRequest.dataOperationDefinitions[0].cmHandleIds = [cmHandleId]
- and: 'a positive response from DMI service when it is called with valid request parameters'
- def responseFromDmi = new ResponseEntity<Object>(HttpStatus.ACCEPTED)
- def expectedDmiBatchResourceDataUrl = "ncmp/v1/data/topic=my-topic-name"
- def expectedBatchRequestAsJson = '{"operations":[{"operation":"read","operationId":"operational-14","datastore":"ncmp-datastore:passthrough-operational","options":"some option","resourceIdentifier":"some resource identifier","cmHandles":[{"id":"some-cm-handle","moduleSetTag":"","cmHandleProperties":{"prop1":"val1"}}]}]}'
- mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, _, READ.operationName, NO_AUTH_HEADER) >> responseFromDmi
- dmiServiceUrlBuilder.getDataOperationRequestUrl(_, _) >> expectedDmiBatchResourceDataUrl
- when: 'get resource data for group of cm handles are invoked'
- objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER)
- then: 'the post operation was called and ncmp generated dmi request body json args'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER)
- }
-
- def 'Execute (async) data operation from DMI service with dmi client exception.'() {
- given: 'data operation request body and dmi resource url'
- def dmiDataOperation = DmiDataOperation.builder().operationId('some-operation-id').build()
- dmiDataOperation.getCmHandles().add(DmiOperationCmHandle.builder().id('some-cm-handle-id').build())
- def dmiDataOperationResourceDataUrl = "http://dmi-service-name:dmi-port/dmi/v1/data?topic=my-topic-name&requestId=some-request-id"
- def actualDataOperationCloudEvent = null
- when: 'exception occurs after sending request to dmi service'
- objectUnderTest.handleTaskCompletionException(new DmiClientRequestException(123, 'message', 'details', UNABLE_TO_READ_RESOURCE_DATA), dmiDataOperationResourceDataUrl, List.of(dmiDataOperation))
- then: 'a cloud event is published'
- eventsPublisher.publishCloudEvent('my-topic-name', 'some-request-id', _) >> { args -> actualDataOperationCloudEvent = args[2] }
- and: 'the event contains the expected error details'
- def eventDataValue = extractDataValue(actualDataOperationCloudEvent)
- assert eventDataValue.operationId == dmiDataOperation.operationId
- assert eventDataValue.ids == dmiDataOperation.cmHandles.id
- assert eventDataValue.statusCode == '103'
- assert eventDataValue.statusMessage == UNABLE_TO_READ_RESOURCE_DATA.message
- }
-
- def 'call get all resource data.'() {
- given: 'the system returns a cm handle with a sample property'
- mockYangModelCmHandleRetrieval([yangModelCmHandleProperty])
- and: 'a positive response from DMI service when it is called with the expected parameters'
- def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
- def expectedUrl = dmiServiceBaseUrl + "passthrough-operational?resourceIdentifier=/"
- mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}', READ, null) >> responseFromDmi
- dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl
- when: 'get resource data is invoked'
- def result = objectUnderTest.getResourceDataFromDmi( PASSTHROUGH_OPERATIONAL.datastoreName, cmHandleId, NO_REQUEST_ID)
- then: 'the result is the response from the DMI service'
- assert result == responseFromDmi
- }
-
- def 'Write data for pass-through:running datastore in DMI.'() {
- given: 'a cm handle for #cmHandleId'
- mockYangModelCmHandleRetrieval([yangModelCmHandleProperty])
- and: 'a positive response from DMI service when it is called with the expected parameters'
- def expectedUrl = dmiServiceBaseUrl + "passthrough-running?resourceIdentifier=${resourceIdentifier}"
- def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"}}'
- def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
- dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl
- mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi
- when: 'write resource method is invoked'
- def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type', NO_AUTH_HEADER)
- then: 'the result is the response from the DMI service'
- assert result == responseFromDmi
- where: 'the following operation is performed'
- operation || expectedOperationInUrl
- CREATE || 'create'
- UPDATE || 'update'
- }
-
- def extractDataValue(actualDataOperationCloudEvent) {
- return toTargetEvent(actualDataOperationCloudEvent, DataOperationEvent.class).data.responses[0]
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy
deleted file mode 100644
index 9f84fb0739..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * ============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.api.impl.utils
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
-
-import org.onap.cps.spi.model.DataNodeBuilder
-import spock.lang.Specification
-
-class DataNodeBaseSpec extends Specification {
-
- def leaves1 = [status:'PENDING', cmHandleId:'CMHandle3', details:'Subscription forwarded to dmi plugin'] as Map
- def dataNode1 = createDataNodeWithLeaves(leaves1)
-
- def leaves2 = [status:'ACCEPTED', cmHandleId:'CMHandle2', details:''] as Map
- def dataNode2 = createDataNodeWithLeaves(leaves2)
-
- def leaves3 = [status:'REJECTED', cmHandleId:'CMHandle1', details:'Cm handle does not exist'] as Map
- def dataNode3 = createDataNodeWithLeaves(leaves3)
-
- def leaves4 = [datastore:'passthrough-running'] as Map
- def dataNode4 = createDataNodeWithLeavesAndChildDataNodes(leaves4, [dataNode1, dataNode2, dataNode3])
-
- static def createDataNodeWithLeaves(leaves) {
- return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
- .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
- .withLeaves(leaves).build()
- }
-
- static def createDataNodeWithLeavesAndChildDataNodes(leaves, dataNodes) {
- return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
- .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
- .withLeaves(leaves).withChildDataNodes(dataNodes)
- .build()
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy
deleted file mode 100644
index 05e5f58983..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * ============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.api.impl.utils
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
-
-import org.onap.cps.spi.model.DataNodeBuilder
-
-class DataNodeHelperSpec extends DataNodeBaseSpec {
-
- def 'Get data node leaves as expected from a nested data node.'() {
- given: 'a nested data node'
- def dataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
- .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
- .withLeaves([clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001'])
- .withChildDataNodes([dataNode4]).build()
- when: 'the nested data node is flatten and retrieves the leaves '
- def result = DataNodeHelper.getDataNodeLeaves([dataNode])
- then: 'the result list size is 5'
- result.size() == 5
- and: 'all the leaves result list are equal to given leaves of data nodes'
- result[0] == [clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001']
- result[1] == [datastore:'passthrough-running']
- result[2] == [status:'PENDING', cmHandleId:'CMHandle3', details:'Subscription forwarded to dmi plugin']
- result[3] == [status:'ACCEPTED', cmHandleId:'CMHandle2', details:'']
- result[4] == [status:'REJECTED', cmHandleId:'CMHandle1', details:'Cm handle does not exist']
- }
-
- def 'Get cm handle id to status as expected from a nested data node.'() {
- given: 'a nested data node'
- def dataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
- .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
- .withLeaves([clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001'])
- .withChildDataNodes([dataNode4]).build()
- and: 'the nested data node is flatten and retrieves the leaves '
- def leaves = DataNodeHelper.getDataNodeLeaves([dataNode])
- when:'cm handle id to status is retrieved'
- def result = DataNodeHelper.cmHandleIdToStatusAndDetailsAsMap(leaves)
- then: 'the result list size is 3'
- result.size() == 3
- and: 'the result contains expected values'
- result == [
- CMHandle3: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map,
- CMHandle2: [details:'',status:'ACCEPTED'] as Map,
- CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map
- ] as Map
-
- }
-
- def 'Get cm handle id to status map as expected from a nested data node.'() {
- given: 'a nested data node'
- def dataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
- .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
- .withLeaves([clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001'])
- .withChildDataNodes([dataNode4]).build()
- when:'cm handle id to status is being extracted'
- def result = DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode([dataNode]);
- then: 'the result list size is 3'
- result.size() == 3
- and: 'the result contains expected values'
- result == [
- CMHandle3: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map,
- CMHandle2: [details:'',status:'ACCEPTED'] as Map,
- CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map
- ] as Map
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
deleted file mode 100644
index 86baca680a..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022-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.utils
-
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
-
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
-import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService
-import org.onap.cps.spi.utils.CpsValidator
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
-import spock.lang.Specification
-
-class DmiServiceUrlBuilderSpec extends Specification {
-
- static YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName',
- 'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'),'my-module-set-tag', 'my-alternate-id', 'my-data-producer-identifier')
-
- DmiWebClientConfiguration.DmiProperties dmiProperties = new DmiWebClientConfiguration.DmiProperties()
-
- def mockCpsValidator = Mock(CpsValidator)
-
- def objectUnderTest = new DmiServiceUrlBuilder(dmiProperties, mockCpsValidator)
-
- def setup() {
- dmiProperties.dmiBasePath = 'dmi'
- }
-
- def 'Create the dmi service url with #scenario.'() {
- given: 'uri variables'
- def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.datastoreName, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), 'cmHandle')
- and: 'query params'
- def uriQueries = objectUnderTest.populateQueryParams(resourceId, 'optionsParamInQuery', topic, moduleSetTag)
- when: 'a dmi datastore service url is generated'
- def dmiServiceUrl = objectUnderTest.getDmiDatastoreUrl(uriQueries, uriVars)
- then: 'service url is generated as expected'
- assert dmiServiceUrl == expectedDmiServiceUrl
- where: 'the following parameters are used'
- scenario | topic | moduleSetTag | resourceId || expectedDmiServiceUrl
- 'With valid resourceId' | 'topicParamInQuery' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
- 'With Empty resourceId' | 'topicParamInQuery' | '' | '' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?options=optionsParamInQuery&topic=topicParamInQuery'
- 'With valid moduleSetTag' | 'topicParamInQuery' | 'module-set-tag1' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery&moduleSetTag=module-set-tag1'
- 'With Empty moduleSetTag' | 'topicParamInQuery' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
- 'With Empty dmi base path' | 'topicParamInQuery' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
- 'With Empty topicParamInQuery' | '' | '' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery'
- }
-
- def 'Populate dmi data store url #scenario.'() {
- given: 'uri variables are created'
- dmiProperties.dmiBasePath = dmiBasePath
- def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.datastoreName, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), 'cmHandle')
- and: 'null query params'
- def uriQueries = objectUnderTest.populateQueryParams(null, null, null, null)
- when: 'a dmi datastore service url is generated'
- def dmiServiceUrl = objectUnderTest.getDmiDatastoreUrl(uriQueries, uriVars)
- then: 'the created dmi service url matches the expected'
- assert dmiServiceUrl == expectedDmiServiceUrl
- where: 'the following parameters are used'
- scenario | decription | dmiBasePath || expectedDmiServiceUrl
- 'with base path / ' | 'Invalid base path as it starts with /' | '/dmi' || 'dmiServiceName//dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running'
- 'without base path / ' | 'Valid path as it does not starts with /' | 'dmi' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running'
- }
-
- def 'Bath request Url creation.'() {
- given: 'the required path parameters'
- def batchRequestUriVariables = [dmiServiceName: 'some-service', dmiBasePath: 'testBase', cmHandleId: '123']
- and: 'the relevant query parameters'
- def batchRequestQueryParams = objectUnderTest.getDataOperationRequestQueryParams('some topic', 'some id')
- when: 'a URL is created'
- def result = objectUnderTest.getDataOperationRequestUrl(batchRequestQueryParams, batchRequestUriVariables)
- then: 'it is formed correctly'
- assert result.toString() == 'some-service/testBase/v1/data?topic=some+topic&requestId=some+id'
- }
-
- def 'Populate batch uri variables.'() {
- expect: 'Populate batch uri variables returns a map with given service name and base path from setup'
- assert objectUnderTest.populateDataOperationRequestUriVariables('some service') == [dmiServiceName: 'some service', dmiBasePath: 'dmi' ]
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy
deleted file mode 100644
index b7fa449251..0000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.onap.cps.ncmp.api.impl.utils.context
-
-import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.utils.JsonObjectMapper
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.test.context.ContextConfiguration
-import spock.lang.Specification;
-
-@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper])
-@ContextConfiguration(classes = [CpsApplicationContext.class])
-class CpsApplicationContextSpec extends Specification {
-
- def 'Verify if cps application context contains a requested bean.'() {
- when: 'cps bean is requested from application context'
- def jsonObjectMapper = CpsApplicationContext.getCpsBean(JsonObjectMapper.class)
- then: 'requested bean of JsonObjectMapper is not null'
- assert jsonObjectMapper != null
- }
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponseSpec.groovy
index 7803ae319f..055a6e7448 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponseSpec.groovy
@@ -19,16 +19,17 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.models
+package org.onap.cps.ncmp.api.inventory.models
+
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse.Status
+import spock.lang.Specification
+
+import java.util.stream.Collectors
import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST
import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
-import spock.lang.Specification
-import java.util.stream.Collectors
-
class CmHandleRegistrationResponseSpec extends Specification {
def 'Successful cm-handle Registration Response'() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CompositeStateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilderSpec.groovy
index 777b505b46..dfed3c787d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CompositeStateBuilderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilderSpec.groovy
@@ -19,13 +19,12 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory
+package org.onap.cps.ncmp.api.inventory.models
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
+
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.DataNodeBuilder
import spock.lang.Specification
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CompositeStateSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateSpec.groovy
index d8beba8de0..f6e4c8870e 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CompositeStateSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateSpec.groovy
@@ -18,20 +18,20 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory
+package org.onap.cps.ncmp.api.inventory.models
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
import spock.lang.Specification
+
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
+import static org.onap.cps.ncmp.api.inventory.models.CompositeState.DataStores
+import static org.onap.cps.ncmp.api.inventory.models.CompositeState.Operational
import static org.onap.cps.ncmp.utils.TestUtils.getResourceFileContent
import static org.springframework.util.StringUtils.trimAllWhitespace
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/TrustLevelSpec.groovy
index f2521b560c..1e1dfaaa91 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/TrustLevelSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel
+package org.onap.cps.ncmp.api.inventory.models
import spock.lang.Specification
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangResourceTest.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/YangResourceTest.groovy
index 0a0c84e256..068997591c 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/YangResourceTest.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/YangResourceTest.groovy
@@ -1,4 +1,5 @@
-package org.onap.cps.ncmp.api.models
+package org.onap.cps.ncmp.api.inventory.models
+
import spock.lang.Specification
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy
new file mode 100644
index 0000000000..215ea6c219
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy
@@ -0,0 +1,39 @@
+/*
+ * ============LICENSE_START========================================================
+ * 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.
+ * 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.config
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.utils.JsonObjectMapper
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ContextConfiguration
+import spock.lang.Specification;
+
+@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper])
+@ContextConfiguration(classes = [CpsApplicationContext.class])
+class CpsApplicationContextSpec extends Specification {
+
+ def 'Verify if cps application context contains a requested bean.'() {
+ when: 'cps bean is requested from application context'
+ def jsonObjectMapper = CpsApplicationContext.getCpsBean(JsonObjectMapper.class)
+ then: 'requested bean of JsonObjectMapper is not null'
+ assert jsonObjectMapper != null
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/DmiHttpClientConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/DmiHttpClientConfigSpec.groovy
new file mode 100644
index 0000000000..23f5edd890
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/DmiHttpClientConfigSpec.groovy
@@ -0,0 +1,73 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * 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.
+ * 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.config
+
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ContextConfiguration
+import spock.lang.Specification
+
+@SpringBootTest
+@ContextConfiguration(classes = [DmiHttpClientConfig])
+@EnableConfigurationProperties
+class DmiHttpClientConfigSpec extends Specification {
+
+ @Autowired
+ DmiHttpClientConfig dmiHttpClientConfig
+
+ def 'Test http client configuration properties of data with custom and default values'() {
+ expect: 'properties are populated correctly for data services'
+ with(dmiHttpClientConfig.dataServices) {
+ assert maximumInMemorySizeInMegabytes == 1
+ assert maximumConnectionsTotal == 2
+ assert pendingAcquireMaxCount == 3
+ assert connectionTimeoutInSeconds == 4
+ assert readTimeoutInSeconds == 5
+ assert writeTimeoutInSeconds == 6
+ }
+ }
+
+ def 'Test http client configuration properties of model with custom and default values'() {
+ expect: 'properties are populated correctly for model services'
+ with(dmiHttpClientConfig.modelServices) {
+ assert maximumInMemorySizeInMegabytes == 11
+ assert maximumConnectionsTotal == 12
+ assert pendingAcquireMaxCount == 13
+ assert connectionTimeoutInSeconds == 14
+ assert readTimeoutInSeconds == 15
+ assert writeTimeoutInSeconds == 16
+ }
+ }
+
+ def 'Test http client configuration properties of health with default values'() {
+ expect: 'properties are populated correctly for health check services'
+ with(dmiHttpClientConfig.healthCheckServices) {
+ assert maximumInMemorySizeInMegabytes == 21
+ assert maximumConnectionsTotal == 22
+ assert pendingAcquireMaxCount == 23
+ assert connectionTimeoutInSeconds == 24
+ assert readTimeoutInSeconds == 25
+ assert writeTimeoutInSeconds == 26
+ }
+ }
+}
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/config/KafkaConfigSpec.groovy
index 16f27d081b..9e1649ef93 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/config/KafkaConfigSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.kafka;
+package org.onap.cps.ncmp.config
import io.cloudevents.CloudEvent
import io.cloudevents.kafka.CloudEventDeserializer
@@ -31,12 +31,14 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.kafka.core.KafkaTemplate
import org.springframework.kafka.support.serializer.JsonDeserializer
import org.springframework.kafka.support.serializer.JsonSerializer
+import org.springframework.test.context.TestPropertySource
import spock.lang.Shared
import spock.lang.Specification
@SpringBootTest(classes = [KafkaProperties, KafkaConfig])
@EnableSharedInjection
@EnableConfigurationProperties
+@TestPropertySource(properties = ["cps.tracing.enabled=true"])
class KafkaConfigSpec extends Specification {
@Shared
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryConfigSpec.groovy
new file mode 100644
index 0000000000..cbff73113e
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryConfigSpec.groovy
@@ -0,0 +1,113 @@
+/*
+ * ============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.config
+
+import io.micrometer.observation.ObservationPredicate
+import io.micrometer.observation.ObservationRegistry
+import io.micrometer.observation.ObservationRegistry.ObservationConfig
+import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter
+import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter
+import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.server.observation.ServerRequestObservationContext
+import org.springframework.mock.web.MockHttpServletRequest
+import org.springframework.util.AntPathMatcher
+import spock.lang.Specification
+
+@SpringBootTest(classes = [OpenTelemetryConfig])
+class OpenTelemetryConfigSpec extends Specification {
+
+ def objectUnderTest
+
+ @Value('${cps.tracing.exporter.endpoint}')
+ def tracingExporterEndpointUrl
+
+ @Value('${cps.tracing.sampler.jaeger_remote.endpoint}')
+ def jaegerRemoteSamplerUrl
+
+ def setup() {
+ objectUnderTest = new OpenTelemetryConfig(
+ serviceId: 'sample-app',
+ tracingExporterEndpointUrl: tracingExporterEndpointUrl,
+ jaegerRemoteSamplerUrl: jaegerRemoteSamplerUrl,
+ excludedObservationNames: ['excluded-task-name'])
+ }
+
+ def 'OTLP exporter creation with Grpc protocol'() {
+ when: 'an OTLP exporter is created'
+ def result = objectUnderTest.createOtlpExporterGrpc()
+ then: 'expected an instance of OtlpGrpcSpanExporter'
+ assert result instanceof OtlpGrpcSpanExporter
+ }
+
+ def 'OTLP exporter creation with HTTP protocol'() {
+ when: 'an OTLP exporter is created'
+ def result = objectUnderTest.createOtlpExporterHttp()
+ then: 'an OTLP Exporter is created'
+ assert result instanceof OtlpHttpSpanExporter
+ and: 'the endpoint is correctly set'
+ assert result.builder.endpoint == 'http://exporter-test-url'
+ }
+
+ def 'Jaeger Remote Sampler Creation'() {
+ when: 'a Jaeger remote sampler is created'
+ def result = objectUnderTest.createJaegerRemoteSampler()
+ then: 'a Jaeger remote sampler is created'
+ assert result instanceof JaegerRemoteSampler
+ and: 'the sampler type is correct'
+ assert result.delegate.type == 'remoteSampling'
+ and: 'the sampler endpoint is correctly set'
+ assert result.delegate.url.toString().startsWith('http://jaeger-remote-test-url')
+ }
+
+ def 'Skipping actuator endpoints'() {
+ given: 'a mocked observation registry and config'
+ def observationRegistry = Mock(ObservationRegistry.class)
+ def observationConfig = Mock(ObservationConfig.class)
+ observationRegistry.observationConfig() >> observationConfig
+ when: 'an observation registry customizer is created and applied'
+ def result = objectUnderTest.skipActuatorEndpointsFromObservation()
+ result.customize(observationRegistry)
+ then: 'the observation predicate is set correctly'
+ 1 * observationConfig.observationPredicate(_) >> { ObservationPredicate observationPredicate ->
+ def mockedHttpServletRequest = new MockHttpServletRequest(_ as String, requestUrl)
+ def serverRequestObservationContext = new ServerRequestObservationContext(mockedHttpServletRequest, null)
+ and: 'expected predicate for endpoint'
+ assert observationPredicate.test('some-name', serverRequestObservationContext) == expectedPredicate
+ }
+ where: 'the following parameters are used'
+ scenario | requestUrl || expectedPredicate
+ 'an actuator' | '/actuator' || false
+ 'a non actuator' | '/some-api' || true
+ }
+
+ def 'Observation predicate is configured to filter out excluded tasks by name'() {
+ when: 'a path matcher and observation predicate'
+ def observationPredicate = objectUnderTest.observationPredicate(new AntPathMatcher('/'))
+ then: 'a task name is provided'
+ assert observationPredicate.test(taskName, null) == expectedPredicate
+ where: 'the following parameters are used'
+ taskName || expectedPredicate
+ 'excluded-task-name' || false
+ 'non-excluded-task-name' || true
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy
index 2c76b5bb44..ca71c345c1 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy
@@ -1,6 +1,6 @@
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * 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.
@@ -17,32 +17,32 @@
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config
-import java.time.Duration
+package org.onap.cps.ncmp.config
+
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ContextConfiguration
-import org.springframework.test.context.TestPropertySource
-import org.springframework.test.context.support.AnnotationConfigContextLoader
import spock.lang.Specification
@SpringBootTest
-@ContextConfiguration(classes = [HttpClientConfiguration])
-@EnableConfigurationProperties(HttpClientConfiguration.class)
-@TestPropertySource(properties = ["ncmp.dmi.httpclient.connectionTimeoutInSeconds=1", "ncmp.dmi.httpclient.maximumConnectionsTotal=200"])
-class HttpClientConfigurationSpec extends Specification {
+@ContextConfiguration(classes = [PolicyExecutorHttpClientConfig])
+@EnableConfigurationProperties
+class PolicyExecutorHttpClientConfigSpec extends Specification {
@Autowired
- private HttpClientConfiguration httpClientConfiguration
+ PolicyExecutorHttpClientConfig policyExecutorHttpClientConfig
- def 'Test HttpClientConfiguration properties with custom and default values'() {
- expect: 'custom property values'
- assert httpClientConfiguration.getConnectionTimeoutInSeconds() == Duration.ofSeconds(1)
- assert httpClientConfiguration.getMaximumConnectionsTotal() == 200
- and: 'default property values'
- assert httpClientConfiguration.getMaximumConnectionsPerRoute() == 50
- assert httpClientConfiguration.getIdleConnectionEvictionThresholdInSeconds() == Duration.ofSeconds(5)
+ def 'Http client configuration properties for policy executor http client.'() {
+ expect: 'properties are populated correctly for all services'
+ with(policyExecutorHttpClientConfig.allServices) {
+ assert maximumInMemorySizeInMegabytes == 31
+ assert maximumConnectionsTotal == 32
+ assert pendingAcquireMaxCount == 33
+ assert connectionTimeoutInSeconds == 34
+ assert readTimeoutInSeconds == 35
+ assert writeTimeoutInSeconds == 36
+ }
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfigSpec.groovy
index e65011f715..915bccb53d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/CmNotificationSubscriptionCacheConfigSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/CmSubscriptionConfigSpec.groovy
@@ -18,23 +18,23 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.embeddedcache
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.cache
import com.hazelcast.core.Hazelcast
import com.hazelcast.map.IMap
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate
-import org.onap.cps.ncmp.api.impl.operations.DatastoreType
+import org.onap.cps.ncmp.api.data.models.DatastoreType
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification
-@SpringBootTest(classes = [CmNotificationSubscriptionCacheConfig])
-class CmNotificationSubscriptionCacheConfigSpec extends Specification {
+@SpringBootTest(classes = [CmSubscriptionConfig])
+class CmSubscriptionConfigSpec extends Specification {
@Autowired
- IMap<String, Map<String, DmiCmNotificationSubscriptionDetails>> cmNotificationSubscriptionCache;
+ IMap<String, Map<String, DmiCmSubscriptionDetails>> cmNotificationSubscriptionCache;
def 'Embedded (hazelcast) cache for Cm Notification Subscription Cache.'() {
expect: 'system is able to create an instance of the Cm Notification Subscription Cache'
@@ -49,15 +49,15 @@ class CmNotificationSubscriptionCacheConfigSpec extends Specification {
given: 'a cm subscription properties'
def subscriptionId = 'sub123'
def dmiPluginName = 'dummydmi'
- def cmSubscriptionPredicate = new DmiCmNotificationSubscriptionPredicate(['cmhandle1', 'cmhandle2'].toSet(), DatastoreType.PASSTHROUGH_RUNNING, ['/a/b/c'].toSet())
- def cmSubscriptionCacheObject = new DmiCmNotificationSubscriptionDetails([cmSubscriptionPredicate], CmNotificationSubscriptionStatus.PENDING)
+ def cmSubscriptionPredicates = new DmiCmSubscriptionPredicate(['cmhandle1', 'cmhandle2'].toSet(), DatastoreType.PASSTHROUGH_RUNNING, ['/a/b/c'].toSet())
+ def cmSubscriptionCacheObject = new DmiCmSubscriptionDetails([cmSubscriptionPredicates], CmSubscriptionStatus.PENDING)
when: 'the cache is populated'
cmNotificationSubscriptionCache.put(subscriptionId, [(dmiPluginName): cmSubscriptionCacheObject])
then: 'the values are present in memory'
assert cmNotificationSubscriptionCache.get(subscriptionId) != null
and: 'properties match'
assert dmiPluginName == cmNotificationSubscriptionCache.get(subscriptionId).keySet()[0]
- assert cmSubscriptionCacheObject.cmNotificationSubscriptionStatus == cmNotificationSubscriptionCache.get(subscriptionId).values().cmNotificationSubscriptionStatus[0]
- assert cmSubscriptionCacheObject.dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds == cmNotificationSubscriptionCache.get(subscriptionId).values().dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds[0]
+ assert cmSubscriptionCacheObject.cmSubscriptionStatus == cmNotificationSubscriptionCache.get(subscriptionId).values().cmSubscriptionStatus[0]
+ assert cmSubscriptionCacheObject.dmiCmSubscriptionPredicates[0].targetCmHandleIds == cmNotificationSubscriptionCache.get(subscriptionId).values().dmiCmSubscriptionPredicates[0].targetCmHandleIds[0]
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy
index 43568be501..791a154608 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/DmiCmNotificationSubscriptionCacheHandlerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy
@@ -18,29 +18,29 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.cache
import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
import io.cloudevents.core.builder.CloudEventBuilder
import org.apache.kafka.clients.consumer.ConsumerRecord
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionDetails
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
+import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent
@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper])
-class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec {
+class DmiCacheHandlerSpec extends MessagingBaseSpec {
@Autowired
JsonObjectMapper jsonObjectMapper
@@ -49,12 +49,12 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec {
@SpringBean
InventoryPersistence mockInventoryPersistence = Mock(InventoryPersistence)
@SpringBean
- CmNotificationSubscriptionPersistenceService mockCmNotificationSubscriptionPersistenceService = Mock(CmNotificationSubscriptionPersistenceService)
+ CmSubscriptionPersistenceService mockCmSubscriptionPersistenceService = Mock(CmSubscriptionPersistenceService)
def testCache = [:]
- def objectUnderTest = new DmiCmNotificationSubscriptionCacheHandler(mockCmNotificationSubscriptionPersistenceService, testCache, mockInventoryPersistence)
+ def objectUnderTest = new DmiCacheHandler(mockCmSubscriptionPersistenceService, testCache, mockInventoryPersistence)
- CmNotificationSubscriptionNcmpInEvent cmNotificationSubscriptionNcmpInEvent
+ NcmpInEvent ncmpInEvent
def yangModelCmHandle1 = new YangModelCmHandle(id:'ch1',dmiServiceName:'dmi-1')
def yangModelCmHandle2 = new YangModelCmHandle(id:'ch2',dmiServiceName:'dmi-2')
def yangModelCmHandle3 = new YangModelCmHandle(id:'ch3',dmiServiceName:'dmi-1')
@@ -65,17 +65,34 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec {
initialiseMockInventoryPersistenceResponses()
}
- def 'Load CM subscription event to cache'() {
- given: 'a valid subscription event with Id'
- def subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId()
+ def 'Load CM subscription event to cache with predicates'() {
+ given: 'a subscription event with id'
+ def subscriptionId = ncmpInEvent.getData().getSubscriptionId()
and: 'list of predicates'
- def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates()
- when: 'a valid event object loaded in cache'
+ def predicates = ncmpInEvent.getData().getPredicates()
+ when: 'subscription is loaded to cache with predicates'
objectUnderTest.add(subscriptionId, predicates)
- then: 'the cache contains the correct entry with #subscriptionId subscription ID'
+ then: 'the number of entries in cache is correct'
+ assert testCache.size() == 1
+ and: 'the cache contains the correct entries'
assert testCache.containsKey(subscriptionId)
}
+ def 'Load CM subscription event to cache with dmi subscription details per dmi'() {
+ given: 'a subscription event with id'
+ def subscriptionId = ncmpInEvent.getData().getSubscriptionId()
+ and: 'dmi subscription details per dmi'
+ def dmiSubscriptionsPerDmi = [:]
+ when: 'subscription is loaded to cache with dmi subscription details per dmi'
+ objectUnderTest.add(subscriptionId, dmiSubscriptionsPerDmi)
+ then: 'the number of entries in cache is correct'
+ assert testCache.size() == 1
+ and: 'the cache contains the correct entries'
+ assert testCache.containsKey(subscriptionId)
+ and: 'the entry for the subscription ID matches the provided DMI subscription details'
+ assert testCache.get(subscriptionId) == dmiSubscriptionsPerDmi
+ }
+
def 'Get cache entry via subscription id'() {
given: 'the cache contains value for some-id'
testCache.put('some-id',[:])
@@ -89,19 +106,19 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec {
given: 'a map as the value for cache entry for some-id'
def testMap = [:]
testMap.put("dmi-1",
- new DmiCmNotificationSubscriptionDetails([],CmNotificationSubscriptionStatus.ACCEPTED))
+ new DmiCmSubscriptionDetails([],CmSubscriptionStatus.ACCEPTED))
testMap.put("dmi-2",
- new DmiCmNotificationSubscriptionDetails([],CmNotificationSubscriptionStatus.REJECTED))
+ new DmiCmSubscriptionDetails([],CmSubscriptionStatus.REJECTED))
testMap.put("dmi-3",
- new DmiCmNotificationSubscriptionDetails([],CmNotificationSubscriptionStatus.PENDING))
+ new DmiCmSubscriptionDetails([],CmSubscriptionStatus.PENDING))
testCache.put("test-id", testMap)
assert testCache.get("test-id").size() == 3
when: 'the method to remove accepted and rejected entries for test-id is called'
- objectUnderTest.removeAcceptedAndRejectedDmiCmNotificationSubscriptionEntries("test-id")
+ objectUnderTest.removeAcceptedAndRejectedDmiSubscriptionEntries("test-id")
then: 'all entries with status accepted/rejected are no longer present for test-id'
testCache.get("test-id").each { key, testResultMap ->
- assert testResultMap.cmNotificationSubscriptionStatus != CmNotificationSubscriptionStatus.ACCEPTED
- || testResultMap.cmNotificationSubscriptionStatus != CmNotificationSubscriptionStatus.REJECTED
+ assert testResultMap.cmSubscriptionStatus != CmSubscriptionStatus.ACCEPTED
+ || testResultMap.cmSubscriptionStatus != CmSubscriptionStatus.REJECTED
}
and: 'the size of the map for cache entry test-id is as expected'
assert testCache.get("test-id").size() == 1
@@ -109,9 +126,9 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec {
def 'Create map for DMI cm notification subscription per DMI service name'() {
given: 'list of predicates from the create subscription event'
- def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates()
+ def predicates = ncmpInEvent.getData().getPredicates()
when: 'method to create map of DMI cm notification subscription per DMI service name is called'
- def result = objectUnderTest.createDmiCmNotificationSubscriptionsPerDmi(predicates)
+ def result = objectUnderTest.createDmiSubscriptionsPerDmi(predicates)
then: 'the result size of resulting map is correct to the number of DMIs'
assert result.size() == 2
and: 'the cache objects per DMI exists'
@@ -120,28 +137,28 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec {
assert resultMapForDmi1 != null
assert resultMapForDmi2 != null
and: 'the size of predicates in each object is correct'
- assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates.size() == 2
- assert resultMapForDmi2.dmiCmNotificationSubscriptionPredicates.size() == 2
+ assert resultMapForDmi1.dmiCmSubscriptionPredicates.size() == 2
+ assert resultMapForDmi2.dmiCmSubscriptionPredicates.size() == 2
and: 'the subscription status in each object is correct'
- assert resultMapForDmi1.cmNotificationSubscriptionStatus.toString() == 'PENDING'
- assert resultMapForDmi2.cmNotificationSubscriptionStatus.toString() == 'PENDING'
+ assert resultMapForDmi1.cmSubscriptionStatus.toString() == 'PENDING'
+ assert resultMapForDmi2.cmSubscriptionStatus.toString() == 'PENDING'
and: 'the target cmHandles for each predicate is correct'
- assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds == ['ch1'].toSet()
- assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[1].targetCmHandleIds == ['ch3'].toSet()
+ assert resultMapForDmi1.dmiCmSubscriptionPredicates[0].targetCmHandleIds == ['ch1'].toSet()
+ assert resultMapForDmi1.dmiCmSubscriptionPredicates[1].targetCmHandleIds == ['ch3'].toSet()
- assert resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[0].targetCmHandleIds == ['ch2'].toSet()
- assert resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[1].targetCmHandleIds == ['ch4'].toSet()
+ assert resultMapForDmi2.dmiCmSubscriptionPredicates[0].targetCmHandleIds == ['ch2'].toSet()
+ assert resultMapForDmi2.dmiCmSubscriptionPredicates[1].targetCmHandleIds == ['ch4'].toSet()
and: 'the list of xpath for each is correct'
- assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[0].xpaths
- && resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[0].xpaths == ['/x1/y1','x2/y2'].toSet()
+ assert resultMapForDmi1.dmiCmSubscriptionPredicates[0].xpaths
+ && resultMapForDmi2.dmiCmSubscriptionPredicates[0].xpaths == ['/x1/y1', 'x2/y2'].toSet()
- assert resultMapForDmi1.dmiCmNotificationSubscriptionPredicates[1].xpaths
- && resultMapForDmi2.dmiCmNotificationSubscriptionPredicates[1].xpaths == ['/x3/y3','x4/y4'].toSet()
+ assert resultMapForDmi1.dmiCmSubscriptionPredicates[1].xpaths
+ && resultMapForDmi2.dmiCmSubscriptionPredicates[1].xpaths == ['/x3/y3', 'x4/y4'].toSet()
}
def 'Get map for cm handle IDs by DMI service name'() {
given: 'the predicate from the test request CM subscription event'
- def targetFilter = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates().get(0).getTargetFilter()
+ def targetFilter = ncmpInEvent.getData().getPredicates().get(0).getTargetFilter()
when: 'the method to group all target CM handles by DMI service name is called'
def mapOfCMHandleIDsByDmi = objectUnderTest.groupTargetCmHandleIdsByDmi(targetFilter)
then: 'the size of the resulting map is correct'
@@ -153,48 +170,59 @@ class DmiCmNotificationSubscriptionCacheHandlerSpec extends MessagingBaseSpec {
def 'Update subscription status in cache per DMI service name'() {
given: 'populated cache'
- def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates()
- def subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId()
+ def predicates = ncmpInEvent.getData().getPredicates()
+ def subscriptionId = ncmpInEvent.getData().getSubscriptionId()
objectUnderTest.add(subscriptionId, predicates)
when: 'subscription status per dmi is updated in cache'
- objectUnderTest.updateDmiCmNotificationSubscriptionStatusPerDmi(subscriptionId,'dmi-1', CmNotificationSubscriptionStatus.ACCEPTED)
+ objectUnderTest.updateDmiSubscriptionStatus(subscriptionId,'dmi-1', CmSubscriptionStatus.ACCEPTED)
then: 'verify status has been updated in cache'
def predicate = testCache.get(subscriptionId)
- assert predicate.get('dmi-1').cmNotificationSubscriptionStatus == CmNotificationSubscriptionStatus.ACCEPTED
+ assert predicate.get('dmi-1').cmSubscriptionStatus == CmSubscriptionStatus.ACCEPTED
}
def 'Persist Cache into database per dmi'() {
- given: 'populate cache'
- def predicates = cmNotificationSubscriptionNcmpInEvent.getData().getPredicates()
- def subscriptionId = cmNotificationSubscriptionNcmpInEvent.getData().getSubscriptionId()
+ given: 'populated cache'
+ def predicates = ncmpInEvent.getData().getPredicates()
+ def subscriptionId = ncmpInEvent.getData().getSubscriptionId()
objectUnderTest.add(subscriptionId, predicates)
when: 'subscription is persisted in database'
objectUnderTest.persistIntoDatabasePerDmi(subscriptionId,'dmi-1')
then: 'persistence service is called the correct number of times per dmi'
- 4 * mockCmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(_,_,_,subscriptionId)
+ 4 * mockCmSubscriptionPersistenceService.addCmSubscription(_,_,_,subscriptionId)
+ }
+
+ def 'Remove subscription from database per dmi'() {
+ given: 'populated cache'
+ def predicates = ncmpInEvent.getData().getPredicates()
+ def subscriptionId = ncmpInEvent.getData().getSubscriptionId()
+ objectUnderTest.add(subscriptionId, predicates)
+ when: 'subscription is persisted in database'
+ objectUnderTest.removeFromDatabase(subscriptionId,'dmi-1')
+ then: 'persistence service is called the correct number of times per dmi'
+ 4 * mockCmSubscriptionPersistenceService.removeCmSubscription(_,_,_,subscriptionId)
}
def setUpTestEvent(){
def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
- def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class)
+ def testEventSent = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class)
def testCloudEventSent = CloudEventBuilder.v1()
- .withData(objectMapper.writeValueAsBytes(testEventSent))
- .withId('subscriptionCreated')
- .withType('subscriptionCreated')
- .withSource(URI.create('some-resource'))
- .withExtension('correlationid', 'test-cmhandle1').build()
+ .withData(objectMapper.writeValueAsBytes(testEventSent))
+ .withId('subscriptionCreated')
+ .withType('subscriptionCreated')
+ .withSource(URI.create('some-resource'))
+ .withExtension('correlationid', 'test-cmhandle1').build()
def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent)
def cloudEvent = consumerRecord.value()
- cmNotificationSubscriptionNcmpInEvent = toTargetEvent(cloudEvent, CmNotificationSubscriptionNcmpInEvent.class);
+ ncmpInEvent = toTargetEvent(cloudEvent, NcmpInEvent.class);
}
def initialiseMockInventoryPersistenceResponses(){
mockInventoryPersistence.getYangModelCmHandles(['ch1','ch2'])
- >> [yangModelCmHandle1, yangModelCmHandle2]
+ >> [yangModelCmHandle1, yangModelCmHandle2]
mockInventoryPersistence.getYangModelCmHandles(['ch3','ch4'])
- >> [yangModelCmHandle3, yangModelCmHandle4]
+ >> [yangModelCmHandle3, yangModelCmHandle4]
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy
index a90fd9405f..06651be913 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/AvcEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.avc
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.cmavc
import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
@@ -28,9 +28,9 @@ import io.cloudevents.kafka.impl.KafkaHeaders
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.clients.consumer.KafkaConsumer
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
import org.onap.cps.ncmp.events.avc1_0_0.AvcEvent
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
@@ -39,18 +39,18 @@ import org.springframework.test.annotation.DirtiesContext
import org.testcontainers.spock.Testcontainers
import java.time.Duration
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
+import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent
-@SpringBootTest(classes = [EventsPublisher, AvcEventConsumer, ObjectMapper, JsonObjectMapper])
+@SpringBootTest(classes = [EventsPublisher, CmAvcEventConsumer, ObjectMapper, JsonObjectMapper])
@Testcontainers
@DirtiesContext
-class AvcEventConsumerSpec extends MessagingBaseSpec {
+class CmAvcEventConsumerSpec extends MessagingBaseSpec {
@SpringBean
EventsPublisher eventsPublisher = new EventsPublisher<CloudEvent>(legacyEventKafkaTemplate, cloudEventKafkaTemplate)
@SpringBean
- AvcEventConsumer acvEventConsumer = new AvcEventConsumer(eventsPublisher)
+ CmAvcEventConsumer acvEventConsumer = new CmAvcEventConsumer(eventsPublisher)
@Autowired
JsonObjectMapper jsonObjectMapper
@@ -85,10 +85,10 @@ class AvcEventConsumerSpec extends MessagingBaseSpec {
def convertedAvcEvent = toTargetEvent(cloudEvent, AvcEvent.class)
and: 'we have correct headers forwarded where correlation id matches'
assert KafkaHeaders.getParsedKafkaHeader(record.headers(), 'ce_correlationid') == 'test-cmhandle1'
- and: 'event id differs(as per requirement) between consumed and forwarded'
- assert KafkaHeaders.getParsedKafkaHeader(record.headers(), 'ce_id') != 'sample-eventid'
+ and: 'event id is same between consumed and forwarded'
+ assert KafkaHeaders.getParsedKafkaHeader(record.headers(), 'ce_id') == 'sample-eventid'
and: 'the event payload still matches'
assert testEventSent == convertedAvcEvent
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapperSpec.groovy
new file mode 100644
index 0000000000..5d74f45bb9
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiCmSubscriptionDetailsPerDmiMapperSpec.groovy
@@ -0,0 +1,52 @@
+/*
+ * ============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.impl.cmnotificationsubscription.dmi
+
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionKey
+import spock.lang.Specification
+
+class DmiCmSubscriptionDetailsPerDmiMapperSpec extends Specification {
+
+ def objectUnderTest = new DmiCmSubscriptionDetailsPerDmiMapper()
+
+ def 'Check for grouping of Dmi Subscription Details'() {
+ given: 'details in the form of datastore , cmhandle and xpath'
+ def subscribersPerDmi = [
+ 'dmi-1': [
+ new DmiCmSubscriptionKey('ncmp-datastore:passthrough-operational', 'ch-1', '/a/b'),
+ new DmiCmSubscriptionKey('ncmp-datastore:passthrough-operational', 'ch-2', '/a/b')
+ ],
+ 'dmi-2': [
+ new DmiCmSubscriptionKey('ncmp-datastore:passthrough-running', 'ch-3', '/c/d'),
+ new DmiCmSubscriptionKey('ncmp-datastore:passthrough-running', 'ch-3', '/e/f')
+ ]
+ ]
+ when: 'we try to map the values based on datastore and xpath'
+ def result = objectUnderTest.toDmiCmSubscriptionsPerDmi(subscribersPerDmi)
+ then: 'the mapped values are grouped as expected for dmi-1'
+ assert result['dmi-1'].dmiCmSubscriptionPredicates.size() == 1
+ assert result['dmi-1'].dmiCmSubscriptionPredicates[0].targetCmHandleIds.containsAll(['ch-1', 'ch-2'])
+ and: 'similarly for dmi-2'
+ assert result['dmi-2'].dmiCmSubscriptionPredicates.size() == 2
+ assert result['dmi-2'].dmiCmSubscriptionPredicates[0].targetCmHandleIds.contains('ch-3')
+ assert result['dmi-2'].dmiCmSubscriptionPredicates[1].targetCmHandleIds.contains('ch-3')
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapperSpec.groovy
index 763aedaa05..62d1572502 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/mapper/CmNotificationSubscriptionDmiInEventMapperSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventMapperSpec.groovy
@@ -18,22 +18,22 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription.mapper
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.DmiCmNotificationSubscriptionPredicate
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import spock.lang.Specification
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING
-class CmNotificationSubscriptionDmiInEventMapperSpec extends Specification {
+class DmiInEventMapperSpec extends Specification {
def mockInventoryPersistence = Mock(InventoryPersistence)
- def objectUnderTest = new CmNotificationSubscriptionDmiInEventMapper(mockInventoryPersistence)
+ def objectUnderTest = new DmiInEventMapper(mockInventoryPersistence)
def setup() {
def yangModelCmHandles = [new YangModelCmHandle(id: 'ch-1', dmiProperties: [new YangModelCmHandle.Property('k1', 'v1')], publicProperties: []),
@@ -43,15 +43,15 @@ class CmNotificationSubscriptionDmiInEventMapperSpec extends Specification {
def 'Check for Cm Notification Subscription DMI In Event mapping'() {
given: 'a collection of cm subscription predicates'
- def dmiCmNotificationSubscriptionPredicates = [new DmiCmNotificationSubscriptionPredicate(['ch-1'].toSet(), PASSTHROUGH_RUNNING, ['/ch-1'].toSet()),
- new DmiCmNotificationSubscriptionPredicate(['ch-2'].toSet(), PASSTHROUGH_OPERATIONAL, ['/ch-2'].toSet())]
+ def dmiSubscriptionPredicates = [new DmiCmSubscriptionPredicate(['ch-1'].toSet(), PASSTHROUGH_RUNNING, ['/ch-1'].toSet()),
+ new DmiCmSubscriptionPredicate(['ch-2'].toSet(), PASSTHROUGH_OPERATIONAL, ['/ch-2'].toSet())]
when: 'we try to map the values'
- def result = objectUnderTest.toCmNotificationSubscriptionDmiInEvent(dmiCmNotificationSubscriptionPredicates)
+ def result = objectUnderTest.toDmiInEvent(dmiSubscriptionPredicates)
then: 'it contains correct cm notification subscription cmhandle object'
- assert result.data.cmhandles.cmhandleId.containsAll(['ch-1', 'ch-2'])
- assert result.data.cmhandles.privateProperties.containsAll([['k1': 'v1'], ['k2': 'v2']])
+ assert result.data.cmHandles.cmhandleId.containsAll(['ch-1', 'ch-2'])
+ assert result.data.cmHandles.privateProperties.containsAll([['k1': 'v1'], ['k2': 'v2']])
and: 'also has the correct dmi cm notification subscription predicates'
assert result.data.predicates.targetFilter.containsAll([['ch-1'], ['ch-2']])
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducerSpec.groovy
index cfb28a0adc..34fa4549f5 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiInEventProducerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiInEventProducerSpec.groovy
@@ -18,47 +18,46 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi
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.producer.CmNotificationSubscriptionDmiInEventProducer
-import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Cmhandle
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.Data
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.CmHandle
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.Data
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent
+import org.onap.cps.ncmp.utils.events.CloudEventMapper
import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Specification
-class CmNotificationSubscriptionDmiInEventProducerSpec extends Specification {
+class DmiInEventProducerSpec extends Specification {
def mockEventsPublisher = Mock(EventsPublisher)
def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
- def objectUnderTest = new CmNotificationSubscriptionDmiInEventProducer(mockEventsPublisher, jsonObjectMapper)
+ def objectUnderTest = new DmiInEventProducer(mockEventsPublisher, jsonObjectMapper)
def 'Create and Publish Cm Notification Subscription DMI In Event'() {
given: 'a cm subscription for a dmi plugin'
def subscriptionId = 'test-subscription-id'
def dmiPluginName = 'test-dmiplugin'
def eventType = 'subscriptionCreateRequest'
- def cmNotificationSubscriptionDmiInEvent = new CmNotificationSubscriptionDmiInEvent(data: new Data(cmhandles: [new Cmhandle(cmhandleId: 'test-1', privateProperties: [:])]))
+ def dmiInEvent = new DmiInEvent(data: new Data(cmHandles: [new CmHandle(cmhandleId: 'test-1', privateProperties: [:])]))
and: 'also we have target topic for dmiPlugin'
- objectUnderTest.cmNotificationSubscriptionDmiInEventTopic = 'dmiplugin-test-topic'
+ objectUnderTest.dmiInEventTopic = 'dmiplugin-test-topic'
when: 'the event is published'
- objectUnderTest.publishCmNotificationSubscriptionDmiInEvent(subscriptionId, dmiPluginName, eventType, cmNotificationSubscriptionDmiInEvent)
+ objectUnderTest.publishDmiInEvent(subscriptionId, dmiPluginName, eventType, dmiInEvent)
then: 'the event contains the required attributes'
1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> {
args ->
{
assert args[0] == 'dmiplugin-test-topic'
assert args[1] == subscriptionId
- def cmNotificationSubscriptionDmiInEventAsCloudEvent = (args[2] as CloudEvent)
- assert cmNotificationSubscriptionDmiInEventAsCloudEvent.getExtension('correlationid') == subscriptionId + '#' + dmiPluginName
- assert cmNotificationSubscriptionDmiInEventAsCloudEvent.type == 'subscriptionCreateRequest'
- assert cmNotificationSubscriptionDmiInEventAsCloudEvent.source.toString() == 'NCMP'
- assert CloudEventMapper.toTargetEvent(cmNotificationSubscriptionDmiInEventAsCloudEvent, CmNotificationSubscriptionDmiInEvent) == cmNotificationSubscriptionDmiInEvent
+ def dmiInEventAsCloudEvent = (args[2] as CloudEvent)
+ assert dmiInEventAsCloudEvent.getExtension('correlationid') == subscriptionId + '#' + dmiPluginName
+ assert dmiInEventAsCloudEvent.type == 'subscriptionCreateRequest'
+ assert dmiInEventAsCloudEvent.source.toString() == 'NCMP'
+ assert CloudEventMapper.toTargetEvent(dmiInEventAsCloudEvent, DmiInEvent) == dmiInEvent
}
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy
index 488879db7a..bcf8780873 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionDmiOutEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
@@ -28,20 +28,23 @@ import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
import io.cloudevents.core.builder.CloudEventBuilder
import org.apache.kafka.clients.consumer.ConsumerRecord
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer.CmNotificationSubscriptionDmiOutEventConsumer
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.model.CmNotificationSubscriptionStatus
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.CmNotificationSubscriptionDmiOutEvent
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.dmi_to_ncmp.Data
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventMapper
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventProducer
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.Data
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.DmiOutEvent
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.slf4j.LoggerFactory
-import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.ACCEPTED
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.REJECTED
+
@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper])
-class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec {
+class DmiOutEventConsumerSpec extends MessagingBaseSpec {
@Autowired
JsonObjectMapper jsonObjectMapper
@@ -49,27 +52,27 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe
@Autowired
ObjectMapper objectMapper
- def mockDmiCmNotificationSubscriptionCacheHandler = Mock(DmiCmNotificationSubscriptionCacheHandler)
- def mockCmNotificationSubscriptionEventsHandler = Mock(CmNotificationSubscriptionEventsHandler)
- def mockCmNotificationSubscriptionMappersHandler = Mock(CmNotificationSubscriptionMappersHandler)
+ def mockDmiCacheHandler = Mock(DmiCacheHandler)
+ def mockNcmpOutEventProducer = Mock(NcmpOutEventProducer)
+ def mockNcmpOutEventMapper = Mock(NcmpOutEventMapper)
- def objectUnderTest = new CmNotificationSubscriptionDmiOutEventConsumer(mockDmiCmNotificationSubscriptionCacheHandler, mockCmNotificationSubscriptionEventsHandler, mockCmNotificationSubscriptionMappersHandler)
+ def objectUnderTest = new DmiOutEventConsumer(mockDmiCacheHandler, mockNcmpOutEventProducer, mockNcmpOutEventMapper)
def logger = Spy(ListAppender<ILoggingEvent>)
void setup() {
- ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionDmiOutEventConsumer.class)).addAppender(logger)
+ ((Logger) LoggerFactory.getLogger(DmiOutEventConsumer.class)).addAppender(logger)
logger.start()
}
void cleanup() {
- ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionDmiOutEventConsumer.class)).detachAndStopAllAppenders()
+ ((Logger) LoggerFactory.getLogger(DmiOutEventConsumer.class)).detachAndStopAllAppenders()
}
def 'Consume valid CM Subscription response from DMI Plugin'() {
given: 'a cmsubscription event'
def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionDmiOutEvent.json')
- def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionDmiOutEvent.class)
+ def testEventSent = jsonObjectMapper.convertJsonString(jsonData, DmiOutEvent.class)
def testCloudEventSent = CloudEventBuilder.v1()
.withData(objectMapper.writeValueAsBytes(testEventSent))
.withId('random-uuid')
@@ -78,7 +81,7 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe
.withExtension('correlationid', 'sub-1#test-dmi-plugin-name').build()
def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent)
when: 'the valid event is consumed'
- objectUnderTest.consumeCmNotificationSubscriptionDmiOutEvent(consumerRecord)
+ objectUnderTest.consumeDmiOutEvent(consumerRecord)
then: 'an event is logged with level INFO'
def loggingEvent = getLoggingEvent()
assert loggingEvent.level == Level.INFO
@@ -89,28 +92,28 @@ class CmNotificationSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpe
def 'Consume a valid CM Notification Subscription Event and perform correct actions base on status'() {
given: 'a cmNotificationSubscription event'
def dmiOutEventData = new Data(statusCode: statusCode, statusMessage: subscriptionStatus.toString())
- def cmNotificationSubscriptionDmiOutEvent = new CmNotificationSubscriptionDmiOutEvent().withData(dmiOutEventData)
+ def dmiOutEvent = new DmiOutEvent().withData(dmiOutEventData)
def testCloudEventSent = CloudEventBuilder.v1()
- .withData(objectMapper.writeValueAsBytes(cmNotificationSubscriptionDmiOutEvent))
+ .withData(objectMapper.writeValueAsBytes(dmiOutEvent))
.withId('random-uuid')
.withType('subscriptionCreateResponse')
.withSource(URI.create('test-dmi-plugin-name'))
.withExtension('correlationid', 'sub-1#test-dmi-plugin-name').build()
def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent)
when: 'the event is consumed'
- objectUnderTest.consumeCmNotificationSubscriptionDmiOutEvent(consumerRecord)
+ objectUnderTest.consumeDmiOutEvent(consumerRecord)
then: 'correct number of calls to cache'
- expectedCacheCalls * mockDmiCmNotificationSubscriptionCacheHandler.updateDmiCmNotificationSubscriptionStatusPerDmi('sub-1','test-dmi-plugin-name', subscriptionStatus)
+ expectedCacheCalls * mockDmiCacheHandler.updateDmiSubscriptionStatus('sub-1','test-dmi-plugin-name', subscriptionStatus)
and: 'correct number of calls to persist cache'
- expectedPersistenceCalls * mockDmiCmNotificationSubscriptionCacheHandler.persistIntoDatabasePerDmi('sub-1','test-dmi-plugin-name')
+ expectedPersistenceCalls * mockDmiCacheHandler.persistIntoDatabasePerDmi('sub-1','test-dmi-plugin-name')
and: 'correct number of calls to map the ncmp out event'
- 1 * mockCmNotificationSubscriptionMappersHandler.toCmNotificationSubscriptionNcmpOutEvent('sub-1', _)
+ 1 * mockNcmpOutEventMapper.toNcmpOutEvent('sub-1', _)
and: 'correct number of calls to publish the ncmp out event to client'
- 1 * mockCmNotificationSubscriptionEventsHandler.publishCmNotificationSubscriptionNcmpOutEvent('sub-1', 'subscriptionCreateResponse', _, false)
+ 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('sub-1', 'subscriptionCreateResponse', _, false)
where: 'the following parameters are used'
- scenario | subscriptionStatus | statusCode || expectedCacheCalls | expectedPersistenceCalls
- 'Accepted Status' | CmNotificationSubscriptionStatus.ACCEPTED | '1' || 1 | 1
- 'Rejected Status' | CmNotificationSubscriptionStatus.REJECTED | '2' || 1 | 0
+ scenario | subscriptionStatus | statusCode || expectedCacheCalls | expectedPersistenceCalls
+ 'Accepted Status' | ACCEPTED | '1' || 1 | 1
+ 'Rejected Status' | REJECTED | '104' || 1 | 0
}
def getLoggingEvent() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparatorSpec.groovy
new file mode 100644
index 0000000000..0ebf9a6aed
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparatorSpec.groovy
@@ -0,0 +1,62 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp
+
+
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService
+import spock.lang.Specification
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+
+class CmSubscriptionComparatorSpec extends Specification {
+
+ def mockCmSubscriptionPersistenceService = Mock(CmSubscriptionPersistenceService)
+ def objectUnderTest = new CmSubscriptionComparator(mockCmSubscriptionPersistenceService)
+
+ def 'Find Delta of given list of predicates'() {
+ given: 'A list of predicates'
+ def predicates = [new DmiCmSubscriptionPredicate(['ch-1', 'ch-2'].toSet(), PASSTHROUGH_OPERATIONAL, ['a/1/', 'b/2'].toSet())]
+ and: '3 positive responses and 1 negative.'
+ mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-1', 'a/1/') >>> true
+ mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-1', 'b/2') >>> true
+ mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-2', 'a/1/') >>> true
+ mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-2', 'b/2') >>> false
+ when: 'getDelta is called'
+ def result = objectUnderTest.getNewDmiSubscriptionPredicates(predicates)
+ then: 'verify correct delta is returned'
+ assert result.size() == 1
+ assert result[0].targetCmHandleIds[0] == 'ch-2'
+ assert result[0].xpaths[0] == 'b/2'
+
+ }
+
+ def 'Find Delta of given list of predicates when it is an ongoing Cm Subscription'() {
+ given: 'A list of predicates'
+ def predicates = [new DmiCmSubscriptionPredicate(['ch-1'].toSet(), PASSTHROUGH_OPERATIONAL, ['a/1/'].toSet())]
+ and: 'its already present'
+ mockCmSubscriptionPersistenceService.isOngoingCmSubscription(PASSTHROUGH_OPERATIONAL, 'ch-1', 'a/1/') >>> true
+ when: 'getDelta is called'
+ def result = objectUnderTest.getNewDmiSubscriptionPredicates(predicates)
+ then: 'verify correct delta is returned'
+ assert result.size() == 0
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImplSpec.groovy
new file mode 100644
index 0000000000..f902c60482
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionHandlerImplSpec.groovy
@@ -0,0 +1,172 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiCmSubscriptionDetailsPerDmiMapper
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventMapper
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.dmi.DmiInEventProducer
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_dmi.DmiInEvent
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.spi.model.DataNode
+import org.onap.cps.utils.JsonObjectMapper
+import spock.lang.Specification
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.ACCEPTED
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.PENDING
+
+class CmSubscriptionHandlerImplSpec extends Specification {
+
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def mockCmSubscriptionPersistenceService = Mock(CmSubscriptionPersistenceService)
+ def mockCmSubscriptionComparator = Mock(CmSubscriptionComparator)
+ def mockNcmpOutEventMapper = Mock(NcmpOutEventMapper)
+ def mockDmiInEventMapper = Mock(DmiInEventMapper)
+ def dmiCmSubscriptionDetailsPerDmiMapper = new DmiCmSubscriptionDetailsPerDmiMapper()
+ def mockNcmpOutEventProducer = Mock(NcmpOutEventProducer)
+ def mockDmiInEventProducer = Mock(DmiInEventProducer)
+ def mockDmiCacheHandler = Mock(DmiCacheHandler)
+ def mockInventoryPersistence = Mock(InventoryPersistence)
+
+ def objectUnderTest = new CmSubscriptionHandlerImpl(mockCmSubscriptionPersistenceService,
+ mockCmSubscriptionComparator, mockNcmpOutEventMapper, mockDmiInEventMapper, dmiCmSubscriptionDetailsPerDmiMapper,
+ mockNcmpOutEventProducer, mockDmiInEventProducer, mockDmiCacheHandler, mockInventoryPersistence)
+
+ def testDmiSubscriptionsPerDmi = ["dmi-1": new DmiCmSubscriptionDetails([], PENDING)]
+
+ def 'Consume valid and unique CmNotificationSubscriptionNcmpInEvent create message'() {
+ given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id'
+ def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
+ def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class)
+ def testListOfDeltaPredicates = [new DmiCmSubscriptionPredicate(['ch1'].toSet(), PASSTHROUGH_OPERATIONAL, ['/a/b'].toSet())]
+ mockCmSubscriptionPersistenceService.isUniqueSubscriptionId("test-id") >> true
+ and: 'relevant details is extracted from the event'
+ def subscriptionId = testEventConsumed.getData().getSubscriptionId()
+ def predicates = testEventConsumed.getData().getPredicates()
+ and: 'the cache handler returns for relevant subscription id'
+ 1 * mockDmiCacheHandler.get("test-id") >> testDmiSubscriptionsPerDmi
+ and: 'the delta predicates is returned'
+ 1 * mockCmSubscriptionComparator.getNewDmiSubscriptionPredicates(_) >> testListOfDeltaPredicates
+ and: 'the DMI in event mapper returns cm notification subscription event'
+ def testDmiInEvent = new DmiInEvent()
+ 1 * mockDmiInEventMapper.toDmiInEvent(testListOfDeltaPredicates) >> testDmiInEvent
+ when: 'the valid and unique event is consumed'
+ objectUnderTest.processSubscriptionCreateRequest(subscriptionId, predicates)
+ then: 'the subscription cache handler is called once'
+ 1 * mockDmiCacheHandler.add('test-id', _)
+ and: 'the events handler method to publish DMI event is called correct number of times with the correct parameters'
+ testDmiSubscriptionsPerDmi.size() * mockDmiInEventProducer.publishDmiInEvent(
+ "test-id", "dmi-1", "subscriptionCreateRequest", testDmiInEvent)
+ and: 'we schedule to send the response after configured time from the cache'
+ 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('test-id', 'subscriptionCreateResponse', null, true)
+ }
+
+ def 'Consume valid and Overlapping Cm Notification Subscription NcmpIn Event'() {
+ given: 'a cmNotificationSubscriptionNcmp in event with unique subscription id'
+ def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
+ def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class)
+ def noDeltaPredicates = []
+ mockCmSubscriptionPersistenceService.isUniqueSubscriptionId("test-id") >> true
+ and: 'the cache handler returns for relevant subscription id'
+ 1 * mockDmiCacheHandler.get('test-id') >> testDmiSubscriptionsPerDmi
+ and: 'the delta predicates is returned'
+ 1 * mockCmSubscriptionComparator.getNewDmiSubscriptionPredicates(_) >> noDeltaPredicates
+ when: 'the valid and unique event is consumed'
+ objectUnderTest.processSubscriptionCreateRequest('test-id', noDeltaPredicates)
+ then: 'the subscription cache handler is called once'
+ 1 * mockDmiCacheHandler.add('test-id', _)
+ and: 'the subscription details are updated in the cache'
+ 1 * mockDmiCacheHandler.updateDmiSubscriptionStatus('test-id', _, ACCEPTED)
+ and: 'we schedule to send the response after configured time from the cache'
+ 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('test-id', 'subscriptionCreateResponse', null, true)
+ }
+
+ def 'Consume valid and but non-unique CmNotificationSubscription create message'() {
+ given: 'a cmNotificationSubscriptionNcmp in event'
+ def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
+ def testEventConsumed = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class)
+ mockCmSubscriptionPersistenceService.isUniqueSubscriptionId('test-id') >> false
+ and: 'relevant details is extracted from the event'
+ def subscriptionId = testEventConsumed.getData().getSubscriptionId()
+ def predicates = testEventConsumed.getData().getPredicates()
+ and: 'the NCMP out in event mapper returns an event for rejected request'
+ def testNcmpOutEvent = new NcmpOutEvent()
+ 1 * mockNcmpOutEventMapper.toNcmpOutEventForRejectedRequest(
+ "test-id", _) >> testNcmpOutEvent
+ when: 'the valid but non-unique event is consumed'
+ objectUnderTest.processSubscriptionCreateRequest(subscriptionId, predicates)
+ then: 'the events handler method to publish DMI event is never called'
+ 0 * mockDmiInEventProducer.publishDmiInEvent(_, _, _, _)
+ and: 'the events handler method to publish NCMP out event is called once'
+ 1 * mockNcmpOutEventProducer.publishNcmpOutEvent('test-id', 'subscriptionCreateResponse', testNcmpOutEvent, false)
+ }
+
+ def 'Consume valid CmNotificationSubscriptionNcmpInEvent delete message'() {
+ given: 'a test subscription id'
+ def subscriptionId = 'test-id'
+ and: 'the persistence service returns datanodes'
+ 1 * mockCmSubscriptionPersistenceService.getAllNodesForSubscriptionId(subscriptionId) >>
+ [new DataNode(xpath: "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-1']/filters/filter[@xpath='x/y']", leaves: ['xpath': 'x/y', 'subscriptionIds': ['test-id']]),
+ new DataNode(xpath: "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-2']/filters/filter[@xpath='y/z']", leaves: ['xpath': 'y/z', 'subscriptionIds': ['test-id']])]
+ and: 'the inventory persistence returns yang model cm handles'
+ 1 * mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(dmiServiceName: 'dmi-1')
+ 1 * mockInventoryPersistence.getYangModelCmHandle('ch-2') >> new YangModelCmHandle(dmiServiceName: 'dmi-2')
+ when: 'the subscription delete request is processed'
+ objectUnderTest.processSubscriptionDeleteRequest(subscriptionId)
+ then: 'the method to publish a dmi event is called with correct parameters'
+ 1 * mockDmiInEventProducer.publishDmiInEvent(subscriptionId,'dmi-1','subscriptionDeleteRequest',_)
+ 1 * mockDmiInEventProducer.publishDmiInEvent(subscriptionId,'dmi-2','subscriptionDeleteRequest',_)
+ and: 'the method to publish nmcp out event is called with correct parameters'
+ 1 * mockNcmpOutEventProducer.publishNcmpOutEvent(subscriptionId, 'subscriptionDeleteResponse', null, true)
+ }
+
+ def 'Delete a subscriber for fully overlapping subscriptions'() {
+ given: 'a test subscription id'
+ def subscriptionId = 'test-id'
+ and: 'the persistence service returns datanodes with multiple subscribers'
+ 1 * mockCmSubscriptionPersistenceService.getAllNodesForSubscriptionId(subscriptionId) >>
+ [new DataNode(xpath: "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-1']/filters/filter[@xpath='x/y']", leaves: ['xpath': 'x/y', 'subscriptionIds': ['test-id','other-id']]),
+ new DataNode(xpath: "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-2']/filters/filter[@xpath='y/z']", leaves: ['xpath': 'y/z', 'subscriptionIds': ['test-id','other-id']])]
+ and: 'the inventory persistence returns yang model cm handles'
+ 1 * mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(dmiServiceName: 'dmi-1')
+ 1 * mockInventoryPersistence.getYangModelCmHandle('ch-2') >> new YangModelCmHandle(dmiServiceName: 'dmi-2')
+ and: 'the cache handler returns the relevant maps whenever called'
+ 2 * mockDmiCacheHandler.get(subscriptionId) >> ['dmi-1':[:],'dmi-2':[:]]
+ when: 'the subscription delete request is processed'
+ objectUnderTest.processSubscriptionDeleteRequest(subscriptionId)
+ then: 'the method to publish a dmi event is never called'
+ 0 * mockDmiInEventProducer.publishDmiInEvent(_,_,_,_)
+ and: 'the cache handler is called to remove subscriber from database per dmi'
+ 1 * mockDmiCacheHandler.removeFromDatabase('test-id', 'dmi-1')
+ 1 * mockDmiCacheHandler.removeFromDatabase('test-id', 'dmi-2')
+ and: 'the method to publish nmcp out event is called with correct parameters'
+ 1 * mockNcmpOutEventProducer.publishNcmpOutEvent(subscriptionId, 'subscriptionDeleteResponse', null, false)
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy
index f07f3c1e6f..9c24e2b005 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmNotificationSubscriptionNcmpInEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.cmsubscription
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
@@ -28,21 +28,19 @@ import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
import io.cloudevents.core.builder.CloudEventBuilder
import org.apache.kafka.clients.consumer.ConsumerRecord
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.consumer.CmNotificationSubscriptionNcmpInEventConsumer
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionHandlerService
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
-import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper])
-class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpec {
+class NcmpInEventConsumerSpec extends MessagingBaseSpec {
- def mockCmNotificationSubscriptionHandlerService = Mock(CmNotificationSubscriptionHandlerService)
- def objectUnderTest = new CmNotificationSubscriptionNcmpInEventConsumer(mockCmNotificationSubscriptionHandlerService)
+ def mockCmSubscriptionHandler = Mock(CmSubscriptionHandler)
+ def objectUnderTest = new NcmpInEventConsumer(mockCmSubscriptionHandler)
def logger = Spy(ListAppender<ILoggingEvent>)
@Autowired
@@ -52,19 +50,19 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe
ObjectMapper objectMapper
void setup() {
- ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionNcmpInEventConsumer.class)).addAppender(logger)
+ ((Logger) LoggerFactory.getLogger(NcmpInEventConsumer.class)).addAppender(logger)
logger.start()
}
void cleanup() {
- ((Logger) LoggerFactory.getLogger(CmNotificationSubscriptionNcmpInEventConsumer.class)).detachAndStopAllAppenders()
+ ((Logger) LoggerFactory.getLogger(NcmpInEventConsumer.class)).detachAndStopAllAppenders()
}
def 'Consume valid CmNotificationSubscriptionNcmpInEvent create message'() {
given: 'a cmNotificationSubscription event'
def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
- def testEventSent = jsonObjectMapper.convertJsonString(jsonData, CmNotificationSubscriptionNcmpInEvent.class)
+ def testEventSent = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class)
def testCloudEventSent = CloudEventBuilder.v1()
.withData(objectMapper.writeValueAsBytes(testEventSent))
.withId('subscriptionCreated')
@@ -78,11 +76,34 @@ class CmNotificationSubscriptionNcmpInEventConsumerSpec extends MessagingBaseSpe
def loggingEvent = getLoggingEvent()
assert loggingEvent.level == Level.INFO
and: 'the log indicates the task completed successfully'
- assert loggingEvent.formattedMessage == 'Subscription for source some-resource with subscription id test-id ...'
+ assert loggingEvent.formattedMessage == 'Subscription create request for source some-resource with subscription id test-id ...'
and: 'the subscription handler service is called once'
- 1 * mockCmNotificationSubscriptionHandlerService.processSubscriptionCreateRequest(_)
+ 1 * mockCmSubscriptionHandler.processSubscriptionCreateRequest('test-id',_)
}
+ def 'Consume valid CmNotificationSubscriptionNcmpInEvent delete message'() {
+ given: 'a cmNotificationSubscription event'
+ def jsonData = TestUtils.getResourceFileContent('cmSubscription/cmNotificationSubscriptionNcmpInEvent.json')
+ def testEventSent = jsonObjectMapper.convertJsonString(jsonData, NcmpInEvent.class)
+ def testCloudEventSent = CloudEventBuilder.v1()
+ .withData(objectMapper.writeValueAsBytes(testEventSent))
+ .withId('sub-id')
+ .withType('subscriptionDeleteRequest')
+ .withSource(URI.create('some-resource'))
+ .withExtension('correlationid', 'test-cmhandle1').build()
+ def consumerRecord = new ConsumerRecord<String, CloudEvent>('topic-name', 0, 0, 'event-key', testCloudEventSent)
+ when: 'the valid event is consumed'
+ objectUnderTest.consumeSubscriptionEvent(consumerRecord)
+ then: 'an event is logged with level INFO'
+ def loggingEvent = getLoggingEvent()
+ assert loggingEvent.level == Level.INFO
+ and: 'the log indicates the task completed successfully'
+ assert loggingEvent.formattedMessage == 'Subscription delete request for source some-resource with subscription id test-id ...'
+ and: 'the subscription handler service is called once'
+ 1 * mockCmSubscriptionHandler.processSubscriptionDeleteRequest('test-id')
+ }
+
+
def getLoggingEvent() {
return logger.list[1]
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapperSpec.groovy
new file mode 100644
index 0000000000..d3c4026962
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventMapperSpec.groovy
@@ -0,0 +1,69 @@
+/*
+ * ============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.impl.cmnotificationsubscription.ncmp
+
+
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionPredicate
+import spock.lang.Specification
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.ACCEPTED
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.PENDING
+import static org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus.REJECTED
+
+class NcmpOutEventMapperSpec extends Specification {
+
+ static Map<String, DmiCmSubscriptionDetails> dmiSubscriptionsPerDmi
+
+ def objectUnderTest = new NcmpOutEventMapper()
+
+ def setup() {
+ def dmiSubscriptionPredicateA = new DmiCmSubscriptionPredicate(['ch-A'] as Set, PASSTHROUGH_RUNNING, ['/a'] as Set)
+ def dmiSubscriptionPredicateB = new DmiCmSubscriptionPredicate(['ch-B'] as Set, PASSTHROUGH_OPERATIONAL, ['/b'] as Set)
+ def dmiSubscriptionPredicateC = new DmiCmSubscriptionPredicate(['ch-C'] as Set, PASSTHROUGH_OPERATIONAL, ['/c'] as Set)
+ dmiSubscriptionsPerDmi = ['dmi-1': new DmiCmSubscriptionDetails([dmiSubscriptionPredicateA], PENDING),
+ 'dmi-2': new DmiCmSubscriptionDetails([dmiSubscriptionPredicateB], ACCEPTED),
+ 'dmi-3': new DmiCmSubscriptionDetails([dmiSubscriptionPredicateC], REJECTED)
+ ]
+ }
+
+ def 'Check for Cm Notification Subscription Outgoing event mapping'() {
+ when: 'we try to map the event to send it to client'
+ def result = objectUnderTest.toNcmpOutEvent('test-subscription', dmiSubscriptionsPerDmi)
+ then: 'event is mapped correctly for the subscription'
+ result.data.subscriptionId == 'test-subscription'
+ and: 'the cm handle ids are part of correct list'
+ result.data.pendingTargets == ['ch-A'] as Set
+ result.data.acceptedTargets == ['ch-B'] as Set
+ result.data.rejectedTargets == ['ch-C'] as Set
+ }
+
+ def 'Check for Cm Notification Rejected Subscription Outgoing event mapping'() {
+ when: 'we try to map the event to send it to client'
+ def result = objectUnderTest.toNcmpOutEventForRejectedRequest('test-subscription', ['ch-1', 'ch-2'])
+ then: 'event is mapped correctly for the subscription id'
+ result.data.subscriptionId == 'test-subscription'
+ and: 'the cm handle ids are part of correct list'
+ result.data.withRejectedTargets(['ch-1', 'ch-2'])
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducerSpec.groovy
new file mode 100644
index 0000000000..afa2e9874e
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpOutEventProducerSpec.groovy
@@ -0,0 +1,106 @@
+package org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import io.cloudevents.CloudEvent
+import org.onap.cps.events.EventsPublisher
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.Data
+import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent
+import org.onap.cps.ncmp.utils.events.CloudEventMapper
+import org.onap.cps.utils.JsonObjectMapper
+import spock.lang.Specification
+
+class NcmpOutEventProducerSpec extends Specification {
+
+ def mockEventsPublisher = Mock(EventsPublisher)
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def mockNcmpOutEventMapper = Mock(NcmpOutEventMapper)
+ def mockDmiCacheHandler = Mock(DmiCacheHandler)
+
+ def objectUnderTest = new NcmpOutEventProducer(mockEventsPublisher, jsonObjectMapper, mockNcmpOutEventMapper, mockDmiCacheHandler)
+
+ def 'Create and #scenario Cm Notification Subscription NCMP out event'() {
+ given: 'a cm subscription response for the client'
+ def subscriptionId = 'test-subscription-id-2'
+ def eventType = 'subscriptionCreateResponse'
+ def ncmpOutEvent = new NcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-2', acceptedTargets: ['ch-1', 'ch-2']))
+ and: 'also we have target topic for publishing to client'
+ objectUnderTest.ncmpOutEventTopic = 'client-test-topic'
+ and: 'a deadline to an event'
+ objectUnderTest.dmiOutEventTimeoutInMs = 1000
+ when: 'the event is published'
+ objectUnderTest.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, 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 ncmpOutEventAsCloudEvent = (args[2] as CloudEvent)
+ assert ncmpOutEventAsCloudEvent.getExtension('correlationid') == subscriptionId
+ assert ncmpOutEventAsCloudEvent.type == 'subscriptionCreateResponse'
+ assert ncmpOutEventAsCloudEvent.source.toString() == 'NCMP'
+ assert CloudEventMapper.toTargetEvent(ncmpOutEventAsCloudEvent, NcmpOutEvent) == ncmpOutEvent
+ }
+ }
+ 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 ncmpOutEvent = new NcmpOutEvent(data: new Data(subscriptionId: 'test-subscription-id-3', acceptedTargets: ['ch-2', 'ch-3']))
+ and: 'also we have target topic for publishing to client'
+ objectUnderTest.ncmpOutEventTopic = 'client-test-topic'
+ and: 'a deadline to an event'
+ objectUnderTest.dmiOutEventTimeoutInMs = 1000
+ when: 'the event is scheduled to be published'
+ objectUnderTest.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, 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.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, false)
+ then: 'the event contains the required attributes'
+ 1 * mockEventsPublisher.publishCloudEvent(_, _, _) >> {
+ args ->
+ {
+ assert args[0] == 'client-test-topic'
+ assert args[1] == subscriptionId
+ def ncmpOutEventAsCloudEvent = (args[2] as CloudEvent)
+ assert ncmpOutEventAsCloudEvent.getExtension('correlationid') == subscriptionId
+ assert ncmpOutEventAsCloudEvent.type == 'subscriptionCreateResponse'
+ assert ncmpOutEventAsCloudEvent.source.toString() == 'NCMP'
+ assert CloudEventMapper.toTargetEvent(ncmpOutEventAsCloudEvent, NcmpOutEvent) == ncmpOutEvent
+ }
+ }
+ then: 'the cache handler is called once to remove accepted and rejected entries in cache'
+ 1 * mockDmiCacheHandler.removeAcceptedAndRejectedDmiSubscriptionEntries(subscriptionId)
+ }
+
+ def 'No event published when NCMP out event is null'() {
+ given: 'a cm subscription response for the client'
+ def subscriptionId = 'test-subscription-id-3'
+ def eventType = 'subscriptionCreateResponse'
+ def ncmpOutEvent = null
+ and: 'also we have target topic for publishing to client'
+ objectUnderTest.ncmpOutEventTopic = 'client-test-topic'
+ and: 'a deadline to an event'
+ objectUnderTest.dmiOutEventTimeoutInMs = 1000
+ when: 'the event is scheduled to be published'
+ objectUnderTest.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, true)
+ then: 'we wait for 10ms and then we receive response from DMI'
+ Thread.sleep(10)
+ and: 'we receive NO response from DMI so we publish the message on demand'
+ objectUnderTest.publishNcmpOutEvent(subscriptionId, eventType, ncmpOutEvent, false)
+ and: 'no event published'
+ 0 * mockEventsPublisher.publishCloudEvent(*_)
+ }
+
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceServiceSpec.groovy
new file mode 100644
index 0000000000..2b91065592
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/utils/CmSubscriptionPersistenceServiceSpec.groovy
@@ -0,0 +1,204 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2024 Nordix Foundation.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
+ * ================================================================================
+ * 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.impl.cmnotificationsubscription.utils
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.api.CpsQueryService
+import org.onap.cps.spi.model.DataNode
+import org.onap.cps.utils.ContentType
+import org.onap.cps.utils.JsonObjectMapper
+import spock.lang.Specification
+
+import static CmSubscriptionPersistenceService.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE
+import static CmSubscriptionPersistenceService.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH
+import static CmSubscriptionPersistenceService.CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
+class CmSubscriptionPersistenceServiceSpec extends Specification {
+
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def mockCpsQueryService = Mock(CpsQueryService)
+ def mockCpsDataService = Mock(CpsDataService)
+
+ def objectUnderTest = new CmSubscriptionPersistenceService(jsonObjectMapper, mockCpsQueryService, mockCpsDataService)
+
+ def 'Check ongoing cm subscription #scenario'() {
+ given: 'a valid cm subscription query'
+ def cpsPathQuery = "/datastores/datastore[@name='ncmp-datastore:passthrough-running']/cm-handles/cm-handle[@id='ch-1']/filters/filter[@xpath='/cps/path']"
+ and: 'datanodes optionally returned'
+ 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ cpsPathQuery, OMIT_DESCENDANTS) >> dataNode
+ when: 'we check for an ongoing cm subscription'
+ def response = objectUnderTest.isOngoingCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/cps/path')
+ then: 'we get expected response'
+ assert response == isOngoingCmSubscription
+ where: 'following scenarios are used'
+ scenario | dataNode || isOngoingCmSubscription
+ 'valid datanodes present' | [new DataNode(xpath: '/cps/path', leaves: ['subscriptionIds': ['sub-1', 'sub-2']])] || true
+ 'no datanodes present' | [] || false
+ }
+
+ def 'Checking uniqueness of incoming subscription ID'() {
+ given: 'a cps path with a subscription ID for querying'
+ def cpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_ID.formatted('some-sub')
+ and: 'relevant datanodes are returned'
+ 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', cpsPathQuery, OMIT_DESCENDANTS) >>
+ dataNodes
+ when: 'a subscription ID is tested for uniqueness'
+ def result = objectUnderTest.isUniqueSubscriptionId('some-sub')
+ then: 'result is as expected'
+ assert result == isValidSubscriptionId
+ where: 'following scenarios are used'
+ scenario | dataNodes || isValidSubscriptionId
+ 'datanodes present' | [new DataNode()] || false
+ 'no datanodes present' | [] || true
+ }
+
+ def 'Add new subscriber to an ongoing cm notification subscription'() {
+ given: 'a valid cm subscription path query'
+ def cpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y')
+ and: 'a dataNode exists for the given cps path query'
+ mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ cpsPathQuery, OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y', 'subscriptionIds': ['sub-1']])]
+ when: 'the method to add/update cm notification subscription is called'
+ objectUnderTest.addCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'newSubId')
+ then: 'data service method to update list of subscribers is called once'
+ 1 * mockCpsDataService.updateNodeLeaves(
+ 'NCMP-Admin',
+ 'cm-data-subscriptions',
+ '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters',
+ objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['sub-1', 'newSubId']), _, ContentType.JSON)
+ }
+
+ def 'Add new cm notification subscription for #datastoreType'() {
+ given: 'a valid cm subscription path query'
+ def cmSubscriptionCpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted(datastoreName, 'ch-1', '/x/y')
+ def cmHandleForSubscriptionPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted(datastoreName, 'ch-1')
+ and: 'a parent node xpath for the cm subscription path above'
+ def parentNodeXpath = '/datastores/datastore[@name=\'%s\']/cm-handles'
+ and: 'a datanode does not exist for cm subscription path query'
+ mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ cmSubscriptionCpsPathQuery,
+ OMIT_DESCENDANTS) >> []
+ and: 'a datanode does not exist for the given cm handle subscription path query'
+ mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ cmHandleForSubscriptionPathQuery, OMIT_DESCENDANTS) >> []
+ and: 'subscription is mapped as JSON'
+ def subscriptionAsJson = '{"cm-handle":[{"id":"ch-1","filters":' +
+ objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['newSubId']) + '}]}'
+ when: 'the method to add/update cm notification subscription is called'
+ objectUnderTest.addCmSubscription(datastoreType, 'ch-1', '/x/y', 'newSubId')
+ then: 'data service method to create new subscription for given subscriber is called once with the correct parameters'
+ 1 * mockCpsDataService.saveData(
+ 'NCMP-Admin',
+ 'cm-data-subscriptions',
+ parentNodeXpath.formatted(datastoreName),
+ subscriptionAsJson, _, ContentType.JSON)
+ where:
+ scenario | datastoreType || datastoreName
+ 'passthrough_running' | PASSTHROUGH_RUNNING || 'ncmp-datastore:passthrough-running'
+ 'passthrough_operational' | PASSTHROUGH_OPERATIONAL || 'ncmp-datastore:passthrough-operational'
+ }
+
+ def 'Add new cm notification subscription when xpath does not exist for existing subscription cm handle'() {
+ given: 'a valid cm subscription path query'
+ def cmSubscriptionCpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted(datastoreName, 'ch-1', '/x/y')
+ def cmHandleForSubscriptionPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted(datastoreName, 'ch-1')
+ and: 'a parent node xpath for given cm handle for subscription path above'
+ def parentNodeXpath = '/datastores/datastore[@name=\'%s\']/cm-handles/cm-handle[@id=\'%s\']/filters'
+ and: 'a datanode does not exist for cm subscription path query'
+ mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ cmSubscriptionCpsPathQuery, OMIT_DESCENDANTS) >> []
+ and: 'a datanode exists for the given cm handle subscription path query'
+ mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ cmHandleForSubscriptionPathQuery, OMIT_DESCENDANTS) >> [new DataNode()]
+ when: 'the method to add/update cm notification subscription is called'
+ objectUnderTest.addCmSubscription(datastoreType, 'ch-1', '/x/y', 'newSubId')
+ then: 'data service method to create new subscription for given subscriber is called once with the correct parameters'
+ 1 * mockCpsDataService.saveListElements(
+ 'NCMP-Admin',
+ 'cm-data-subscriptions',
+ parentNodeXpath.formatted(datastoreName, 'ch-1'),
+ objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['newSubId']), _, ContentType.JSON)
+ where:
+ scenario | datastoreType || datastoreName
+ 'passthrough_running' | PASSTHROUGH_RUNNING || 'ncmp-datastore:passthrough-running'
+ 'passthrough_operational' | PASSTHROUGH_OPERATIONAL || 'ncmp-datastore:passthrough-operational'
+ }
+
+ def 'Remove subscriber from a list of an ongoing cm notification subscription'() {
+ given: 'a subscription exists when queried'
+ def cpsPathQuery = CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y')
+ mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ cpsPathQuery, OMIT_DESCENDANTS) >> [new DataNode(xpath: cpsPathQuery, leaves: ['xpath': '/x/y', 'subscriptionIds': ['sub-1', 'sub-2']])]
+ when: 'the subscriber is removed'
+ objectUnderTest.removeCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1')
+ then: 'the list of subscribers is updated'
+ 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'cm-data-subscriptions',
+ '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters',
+ objectUnderTest.getSubscriptionDetailsAsJson('/x/y', ['sub-2']), _, ContentType.JSON)
+ }
+
+ def 'Removing last ongoing subscription for datastore and cmhandle and xpath'() {
+ given: 'a subscription exists when queried but has only 1 subscriber'
+ mockCpsQueryService.queryDataNodes(
+ 'NCMP-Admin', 'cm-data-subscriptions',
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_WITH_DATASTORE_CMHANDLE_AND_XPATH.formatted('ncmp-datastore:passthrough-running', 'ch-1', '/x/y'),
+ OMIT_DESCENDANTS) >> [new DataNode(leaves: ['xpath': '/x/y', 'subscriptionIds': ['sub-1']])]
+ and: 'the #scenario'
+ mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions',
+ CPS_PATH_QUERY_FOR_CM_SUBSCRIPTION_FILTERS_WITH_DATASTORE_AND_CMHANDLE.formatted('ncmp-datastore:passthrough-running', 'ch-1'),
+ DIRECT_CHILDREN_ONLY) >> [new DataNode(childDataNodes: listOfChildNodes)]
+ when: 'that last ongoing subscription is removed'
+ objectUnderTest.removeCmSubscription(PASSTHROUGH_RUNNING, 'ch-1', '/x/y', 'sub-1')
+ then: 'the subscription with empty subscriber list is removed'
+ 1 * mockCpsDataService.deleteDataNode('NCMP-Admin', 'cm-data-subscriptions',
+ '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']/filters/filter[@xpath=\'/x/y\']',
+ _)
+ and: 'method call to delete the cm handle is called the correct number of times'
+ numberOfCallsToDeleteCmHandle * mockCpsDataService.deleteDataNode('NCMP-Admin', 'cm-data-subscriptions',
+ '/datastores/datastore[@name=\'ncmp-datastore:passthrough-running\']/cm-handles/cm-handle[@id=\'ch-1\']',
+ _)
+ where:
+ scenario | listOfChildNodes || numberOfCallsToDeleteCmHandle
+ 'cm handle in same datastore is used for other subscriptions' | [new DataNode()] || 0
+ 'cm handle in same datastore is NOT used for other subscriptions' | [] || 1
+ }
+
+ def 'Get all nodes for subscription id'() {
+ given: 'the query service returns nodes for subscription id'
+ def expectedDataNode = new DataNode(xpath: '/some/xpath')
+ def queryServiceResponse = [expectedDataNode].asCollection()
+ 1 * mockCpsQueryService.queryDataNodes('NCMP-Admin', 'cm-data-subscriptions', '//filter/subscriptionIds[text()=\'some-id\']', OMIT_DESCENDANTS) >> queryServiceResponse
+ when: 'retrieving all nodes for subscription id'
+ def result = objectUnderTest.getAllNodesForSubscriptionId('some-id')
+ then: 'the result returns correct number of datanodes'
+ assert result.size() == 1
+ and: 'the attribute of the datanode is as expected'
+ assert result.iterator().next().xpath == expectedDataNode.xpath
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy
new file mode 100644
index 0000000000..fd76abb581
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy
@@ -0,0 +1,218 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2022 Bell Canada
+ * ================================================================================
+ * 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.impl.data
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.events.EventsPublisher
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest
+import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException
+import org.onap.cps.ncmp.config.CpsApplicationContext
+import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent
+import org.onap.cps.ncmp.impl.data.policyexecutor.PolicyExecutor
+import org.onap.cps.ncmp.impl.dmi.DmiOperationsBaseSpec
+import org.onap.cps.ncmp.impl.dmi.DmiProperties
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters
+import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.utils.JsonObjectMapper
+import org.spockframework.spring.SpringBean
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.test.context.ContextConfiguration
+import reactor.core.publisher.Mono
+import spock.lang.Shared
+
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE
+import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE
+import static org.onap.cps.ncmp.api.data.models.OperationType.PATCH
+import static org.onap.cps.ncmp.api.data.models.OperationType.READ
+import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA
+import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent
+
+@SpringBootTest
+@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, DmiProperties, DmiDataOperations, PolicyExecutor])
+class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
+
+ def NO_TOPIC = null
+ def NO_REQUEST_ID = null
+ def NO_AUTH_HEADER = null
+
+ @Shared
+ def OPTIONS_PARAM = '(a=1,b=2)'
+
+ @SpringBean
+ JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
+
+ @Autowired
+ DmiDataOperations objectUnderTest
+
+ @SpringBean
+ EventsPublisher eventsPublisher = Stub()
+
+ @SpringBean
+ PolicyExecutor policyExecutor = Mock()
+
+ @SpringBean
+ AlternateIdMatcher alternateIdMatcher = Mock()
+
+ def 'call get resource data for #expectedDataStore from DMI without topic #scenario.'() {
+ given: 'a cm handle for #cmHandleId'
+ mockYangModelCmHandleRetrieval(dmiProperties)
+ and: 'a positive response from DMI service when it is called with the expected parameters'
+ def responseFromDmi = Mono.just(new ResponseEntity<Object>('{some-key:some-value}', HttpStatus.OK))
+ def expectedUrlTemplateWithVariables = getExpectedUrlTemplateWithVariables(expectedOptions, expectedDataStore)
+ def expectedJson = '{"operation":"read","cmHandleProperties":' + expectedProperties + ',"moduleSetTag":""}'
+ mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi
+ when: 'get resource data is invoked'
+ def cmResourceAddress = new CmResourceAddress(expectedDataStore.datastoreName, cmHandleId, resourceIdentifier)
+ alternateIdMatcher.getCmHandleId(cmHandleId) >> cmHandleId
+ def result = objectUnderTest.getResourceDataFromDmi(cmResourceAddress, expectedOptions, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER).block()
+ then: 'the result is the response from the DMI service'
+ assert result.body == '{some-key:some-value}'
+ assert result.statusCode.'2xxSuccessful'
+ where: 'the following parameters are used'
+ scenario | dmiProperties || expectedDataStore | expectedOptions | expectedProperties
+ 'without properties' | [] || PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM | '{}'
+ 'with properties' | [yangModelCmHandleProperty] || PASSTHROUGH_OPERATIONAL | OPTIONS_PARAM | '{"prop1":"val1"}'
+ 'null options' | [yangModelCmHandleProperty] || PASSTHROUGH_OPERATIONAL | null | '{"prop1":"val1"}'
+ 'empty options' | [yangModelCmHandleProperty] || PASSTHROUGH_OPERATIONAL | '' | '{"prop1":"val1"}'
+ 'datastore running without properties' | [] || PASSTHROUGH_RUNNING | OPTIONS_PARAM | '{}'
+ 'datastore running with properties' | [yangModelCmHandleProperty] || PASSTHROUGH_RUNNING | OPTIONS_PARAM | '{"prop1":"val1"}'
+ }
+
+ def 'Execute (async) data operation from DMI service.'() {
+ given: 'collection of yang model cm Handles and data operation request'
+ mockYangModelCmHandleCollectionRetrieval([yangModelCmHandleProperty])
+ def dataOperationBatchRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json')
+ def dataOperationRequest = spiedJsonObjectMapper.convertJsonString(dataOperationBatchRequestJsonData, DataOperationRequest.class)
+ dataOperationRequest.dataOperationDefinitions[0].cmHandleIds = [cmHandleId]
+ and: 'a positive response from DMI service when it is called with valid request parameters'
+ def responseFromDmi = Mono.just(new ResponseEntity<Object>(HttpStatus.ACCEPTED))
+ def expectedUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/data?requestId={requestId}&topic={topic}', ['requestId': 'requestId', 'topic': 'my-topic-name'])
+ def expectedBatchRequestAsJson = '{"operations":[{"operation":"read","operationId":"operational-14","datastore":"ncmp-datastore:passthrough-operational","options":"some option","resourceIdentifier":"some resource identifier","cmHandles":[{"id":"some-cm-handle","moduleSetTag":"","cmHandleProperties":{"prop1":"val1"}}]}]}'
+ mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, _, READ, NO_AUTH_HEADER) >> responseFromDmi
+ when: 'get resource data for group of cm handles is invoked'
+ objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER)
+ then: 'the post operation was called with the expected URL and JSON request body'
+ 1 * mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, expectedBatchRequestAsJson, READ, NO_AUTH_HEADER)
+ }
+
+ def 'Execute (async) data operation from DMI service with Exception.'() {
+ given: 'collection of yang model cm Handles and data operation request'
+ mockYangModelCmHandleCollectionRetrieval([yangModelCmHandleProperty])
+ def dataOperationBatchRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json')
+ def dataOperationRequest = spiedJsonObjectMapper.convertJsonString(dataOperationBatchRequestJsonData, DataOperationRequest.class)
+ dataOperationRequest.dataOperationDefinitions[0].cmHandleIds = [cmHandleId]
+ and: 'the published cloud event will be captured'
+ def actualDataOperationCloudEvent = null
+ eventsPublisher.publishCloudEvent('my-topic-name', 'my-request-id', _) >> { args -> actualDataOperationCloudEvent = args[2] }
+ and: 'a DMI client request exception is thrown when DMI service is called'
+ mockDmiRestClient.asynchronousPostOperationWithJsonData(*_) >> { Mono.error(new DmiClientRequestException(123, '', '', UNKNOWN_ERROR)) }
+ when: 'attempt to get resource data for group of cm handles is invoked'
+ objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'my-request-id', NO_AUTH_HEADER)
+ then: 'the event contains the expected error details'
+ def eventDataValue = extractDataValue(actualDataOperationCloudEvent)
+ assert eventDataValue.statusCode == '108'
+ assert eventDataValue.statusMessage == UNKNOWN_ERROR.message
+ and: 'the event contains the correct operation details'
+ assert eventDataValue.operationId == dataOperationRequest.dataOperationDefinitions[0].operationId
+ assert eventDataValue.ids == dataOperationRequest.dataOperationDefinitions[0].cmHandleIds
+ }
+
+ def 'call get all resource data.'() {
+ given: 'the system returns a cm handle with a sample property and sample module set tag'
+ mockYangModelCmHandleRetrieval([yangModelCmHandleProperty], 'my-module-set-tag')
+ and: 'a positive response from DMI service when it is called with the expected parameters'
+ def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
+ def expectedTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}', ['resourceIdentifier': '/', 'datastore': 'ncmp-datastore:passthrough-operational', 'cmHandleId': cmHandleId])
+ def expectedJson = '{"operation":"read","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":"my-module-set-tag"}'
+ mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedTemplateWithVariables, expectedJson, READ, null) >> responseFromDmi
+ when: 'get resource data is invoked'
+ def result = objectUnderTest.getAllResourceDataFromDmi(cmHandleId, NO_REQUEST_ID)
+ then: 'the result is the response from the DMI service'
+ assert result == responseFromDmi
+ }
+
+ def 'Write data for pass-through:running datastore in DMI.'() {
+ given: 'a cm handle for #cmHandleId'
+ mockYangModelCmHandleRetrieval([yangModelCmHandleProperty])
+ alternateIdMatcher.getCmHandleId(cmHandleId) >> cmHandleId
+ and: 'a positive response from DMI service when it is called with the expected parameters'
+ def expectedUrlTemplateParameters = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}', ['resourceIdentifier': resourceIdentifier, 'datastore': 'ncmp-datastore:passthrough-running', 'cmHandleId': cmHandleId])
+ def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"},"moduleSetTag":""}'
+ def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
+ mockDmiRestClient.synchronousPostOperationWithJsonData(DATA, expectedUrlTemplateParameters, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi
+ when: 'write resource method is invoked'
+ def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type', NO_AUTH_HEADER)
+ then: 'the result is the response from the DMI service'
+ assert result == responseFromDmi
+ and: 'the permission was checked with the policy executor'
+ 1 * policyExecutor.checkPermission(_, operation, NO_AUTH_HEADER, resourceIdentifier, 'requestData' )
+ where: 'the following operation is performed'
+ operation || expectedOperationInUrl
+ CREATE || 'create'
+ UPDATE || 'update'
+ DELETE || 'delete'
+ PATCH || 'patch'
+ }
+
+ def 'State Ready validation'() {
+ given: 'a yang model cm handle'
+ populateYangModelCmHandle([] ,'')
+ when: 'Validating State of #cmHandleState'
+ def caughtException = null
+ try {
+ objectUnderTest.validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState)
+ } catch (Exception e) {
+ caughtException = e
+ }
+ then: 'only when not ready a exception is thrown'
+ if (expecteException) {
+ assert caughtException.details.contains('not in READY state')
+ } else {
+ assert caughtException == null
+ }
+ where: 'the following states are used'
+ cmHandleState || expecteException
+ CmHandleState.READY || false
+ CmHandleState.ADVISED || true
+ }
+
+ def extractDataValue(actualDataOperationCloudEvent) {
+ return toTargetEvent(actualDataOperationCloudEvent, DataOperationEvent).data.responses[0]
+ }
+
+ def getExpectedUrlTemplateWithVariables(expectedOptions, expectedDataStore) {
+ def includeOptions = !(expectedOptions == null || expectedOptions.trim().isEmpty())
+ def expectedUrlTemplate = 'myServiceName/dmi/v1/ch/{cmHandleId}/data/ds/{datastore}?resourceIdentifier={resourceIdentifier}' + (includeOptions ? '&options={options}' : '')
+ def urlVariables = ['resourceIdentifier': resourceIdentifier, 'datastore': expectedDataStore.datastoreName, 'cmHandleId': cmHandleId] + (includeOptions ? ['options': expectedOptions] : [:])
+ return new UrlTemplateParameters(expectedUrlTemplate, urlVariables)
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy
new file mode 100644
index 0000000000..314b76183e
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy
@@ -0,0 +1,80 @@
+/*
+ * ============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.impl.data
+
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.events.EventsPublisher
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress
+import org.onap.cps.ncmp.config.CpsApplicationContext
+import org.onap.cps.ncmp.impl.dmi.DmiProperties
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
+import org.onap.cps.spi.model.DataNode
+import org.spockframework.spring.SpringBean
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.context.ApplicationContext
+import org.springframework.test.context.ContextConfiguration
+import reactor.core.publisher.Mono
+import spock.lang.Specification
+
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
+@SpringBootTest
+@ContextConfiguration(classes = [CpsApplicationContext])
+class NcmpCachedResourceRequestHandlerSpec extends Specification {
+
+ def cpsDataService = Mock(CpsDataService)
+ def networkCmProxyQueryService= Mock(NetworkCmProxyQueryService)
+
+ @SpringBean
+ AlternateIdMatcher alternateIdMatcher = Mock()
+
+ @SpringBean
+ ApplicationContext applicationContext = Mock()
+
+ def objectUnderTest = new NcmpCachedResourceRequestHandler(cpsDataService, networkCmProxyQueryService)
+
+ def 'Execute a request with include descendants = #includeDescendants.'() {
+ when: 'executing a request'
+ objectUnderTest.executeRequest('ch-1', 'resource', includeDescendants)
+ then: 'it is delegated to the ncmp query service with the correct option'
+ 1 * networkCmProxyQueryService.queryResourceDataOperational('ch-1','resource', expectedFetchDescendantsOption)
+ where: 'the following options are used'
+ includeDescendants || expectedFetchDescendantsOption
+ true || INCLUDE_ALL_DESCENDANTS
+ false || OMIT_DESCENDANTS
+ }
+
+ def 'Get resource data.'() {
+ given: 'the data service returns 2 nodes for the given resource address'
+ def cmResourceAddress = new CmResourceAddress('datastore','ch-1','resource')
+ def dataNode1 = new DataNode(xpath:'p1')
+ def dataNode2 = new DataNode(xpath:'p2')
+ cpsDataService.getDataNodes('datastore','ch-1','resource',OMIT_DESCENDANTS) >> [dataNode1, dataNode2]
+ when: 'getting the resource data'
+ alternateIdMatcher.getCmHandleId('ch-1') >> 'ch-1'
+ def result = objectUnderTest.getResourceDataForCmHandle(cmResourceAddress, 'options', 'topic', 'request id', false, 'authorization')
+ then: 'the result is a "Mono" holding just the first data node'
+ assert result instanceof Mono
+ assert result.block() == dataNode1
+ }
+
+}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy
index 641715d0d2..d5db24cc33 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy
@@ -18,96 +18,71 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.controller.handlers
+package org.onap.cps.ncmp.impl.data
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException
-import org.onap.cps.ncmp.api.impl.exception.InvalidOperationException
-import org.onap.cps.ncmp.api.models.DataOperationDefinition
-import org.onap.cps.ncmp.api.models.DataOperationRequest
-import org.onap.cps.ncmp.api.models.CmResourceAddress
-import org.onap.cps.ncmp.rest.exceptions.OperationNotSupportedException
-import org.onap.cps.ncmp.rest.exceptions.PayloadTooLargeException
-import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
+import org.onap.cps.ncmp.api.data.exceptions.InvalidDatastoreException
+import org.onap.cps.ncmp.api.data.exceptions.InvalidOperationException
+import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress
+import org.onap.cps.ncmp.api.data.models.DataOperationDefinition
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest
+import org.onap.cps.ncmp.api.exceptions.PayloadTooLargeException
+import org.springframework.http.ResponseEntity
+import reactor.core.publisher.Mono
import spock.lang.Specification
-import spock.util.concurrent.PollingConditions
+
+import static org.springframework.http.HttpStatus.I_AM_A_TEAPOT
class NcmpDatastoreRequestHandlerSpec extends Specification {
- def spiedCpsNcmpTaskExecutor = Spy(CpsNcmpTaskExecutor)
- def mockNetworkCmProxyDataService = Mock(NetworkCmProxyDataService)
+ def dmiDataOperations = Mock(DmiDataOperations)
- def objectUnderTest = new NcmpPassthroughResourceRequestHandler(spiedCpsNcmpTaskExecutor, mockNetworkCmProxyDataService)
+ def objectUnderTest = new NcmpPassthroughResourceRequestHandler(dmiDataOperations)
+ def NO_TOPIC = null
def NO_AUTH_HEADER = null
- def setup() {
- objectUnderTest.timeOutInMilliSeconds = 100
- }
-
def 'Attempt to execute async get request with #scenario.'() {
given: 'notification feature is turned on/off'
objectUnderTest.notificationFeatureEnabled = notificationFeatureEnabled
- and: 'a flag to track the network service call'
- def networkServiceMethodCalled = false
and: 'a CM resource address'
def cmResourceAddress = new CmResourceAddress('ds', 'ch1', 'resource1')
- and: 'the (mocked) service will use the flag to indicate if it is called'
- mockNetworkCmProxyDataService.getResourceDataForCmHandle(cmResourceAddress, 'options', _, _, NO_AUTH_HEADER) >>
- { networkServiceMethodCalled = true }
+ and: 'the (mocked) service when called with the correct parameters (with or without topic) returns a response from dmi'
+ def dmiResponse = Mono.justOrEmpty(new ResponseEntity('dmi response',I_AM_A_TEAPOT))
+ dmiDataOperations.getResourceDataFromDmi(cmResourceAddress, 'options', NO_TOPIC, _, NO_AUTH_HEADER) >> dmiResponse
+ dmiDataOperations.getResourceDataFromDmi(cmResourceAddress, 'options', topic, _, NO_AUTH_HEADER) >> dmiResponse
when: 'get request is executed with topic = #topic'
- objectUnderTest.executeRequest(cmResourceAddress, 'options', topic, false, NO_AUTH_HEADER)
- then: 'the task is executed in an async fashion or not'
- expectedCalls * spiedCpsNcmpTaskExecutor.executeTask(*_)
- and: 'the service request is invoked'
- new PollingConditions().within(1) {
- assert networkServiceMethodCalled == true
+ def response = objectUnderTest.executeRequest(cmResourceAddress, 'options', topic, false, NO_AUTH_HEADER)
+ then: 'a successful result with/without request id is returned'
+ if (expectSynchronousResponse) {
+ assert response == 'dmi response'
+ } else { // expect request id in a map
+ assert response.keySet()[0] == 'requestId'
}
where: 'the following parameters are used'
- scenario | notificationFeatureEnabled | topic || expectedCalls
- 'feature on, valid topic' | true | 'valid' || 1
- 'feature on, no topic' | true | null || 0
- 'feature off, valid topic' | false | 'valid' || 0
- 'feature off, no topic' | false | null || 0
+ scenario | notificationFeatureEnabled | topic || expectSynchronousResponse
+ 'feature on, valid topic' | true | 'valid' || false
+ 'feature on, no topic' | true | null || true
+ 'feature off, valid topic' | false | 'valid' || true
+ 'feature off, no topic' | false | null || true
}
def 'Attempt to execute async data operation request with feature #scenario.'() {
given: 'a extended request handler that supports bulk requests'
- def objectUnderTest = new NcmpPassthroughResourceRequestHandler(spiedCpsNcmpTaskExecutor, mockNetworkCmProxyDataService)
+ def objectUnderTest = new NcmpPassthroughResourceRequestHandler(dmiDataOperations)
and: 'notification feature is turned on/off'
objectUnderTest.notificationFeatureEnabled = notificationFeatureEnabled
when: 'data operation request is executed'
- objectUnderTest.executeRequest('someTopic', new DataOperationRequest(), NO_AUTH_HEADER)
+ def dataOperationDefinition = new DataOperationDefinition(operation: 'read', datastore: 'ncmp-datastore:passthrough-running', cmHandleIds: ['ch'])
+ def result = objectUnderTest.executeAsynchronousRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER)
then: 'the task is executed in an async fashion or not'
- expectedCalls * spiedCpsNcmpTaskExecutor.executeTaskWithErrorHandling(*_)
+ expectedCalls * dmiDataOperations.requestResourceDataFromDmi('someTopic', _, _, NO_AUTH_HEADER)
+ and:
+ result.keySet()[0] == expectedKeyInMap
where: 'the following parameters are used'
- scenario | notificationFeatureEnabled || expectedCalls
- 'on' | true || 1
- 'off' | false || 0
- }
-
- def 'Execute async data operation request with datastore #datastore.'() {
- given: 'notification feature is turned on'
- objectUnderTest.notificationFeatureEnabled = true
- and: 'a data operation request with datastore: #datastore'
- def dataOperationDefinition = new DataOperationDefinition(operation: 'read', datastore: datastore)
- def dataOperationRequest = new DataOperationRequest(dataOperationDefinitions: [dataOperationDefinition])
- and: ' a flag to track the network service call'
- def networkServiceMethodCalled = false
- and: 'the (mocked) service will use the flag to indicate it is called'
- mockNetworkCmProxyDataService.executeDataOperationForCmHandles('myTopic', dataOperationRequest, _, NO_AUTH_HEADER) >> {
- networkServiceMethodCalled = true
- }
- when: 'data operation request is executed'
- objectUnderTest.executeRequest('myTopic', dataOperationRequest, NO_AUTH_HEADER)
- then: 'the task is executed in an async fashion'
- 1 * spiedCpsNcmpTaskExecutor.executeTaskWithErrorHandling(*_)
- and: 'the network service is invoked'
- new PollingConditions().within(1) {
- assert networkServiceMethodCalled == true
- }
- where: 'the following datastores are used'
- datastore << ['ncmp-datastore:passthrough-running', 'ncmp-datastore:passthrough-operational']
+ scenario | notificationFeatureEnabled || expectedCalls || expectedKeyInMap
+ 'on' | true || 1 || 'requestId'
+ 'off' | false || 0 || 'status'
}
def 'Attempt to execute async data operation request with error #scenario'() {
@@ -115,7 +90,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification {
def dataOperationDefinition = new DataOperationDefinition(operation: 'read', datastore: datastore)
when: 'data operation request is executed'
def dataOperationRequest = new DataOperationRequest(dataOperationDefinitions: [dataOperationDefinition])
- objectUnderTest.executeRequest('myTopic', dataOperationRequest, NO_AUTH_HEADER)
+ objectUnderTest.executeAsynchronousRequest('myTopic', dataOperationRequest, NO_AUTH_HEADER)
then: 'the correct error is thrown'
def thrown = thrown(InvalidDatastoreException)
assert thrown.message.contains(expectedErrorMessage)
@@ -129,7 +104,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification {
given: 'a data operation definition with operation: #operation'
def dataOperationDefinition = new DataOperationDefinition(operation: operation, datastore: 'ncmp-datastore:passthrough-running')
when: 'data operation request is executed'
- objectUnderTest.executeRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER)
+ objectUnderTest.executeAsynchronousRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER)
then: 'the expected type of exception is thrown'
thrown(expectedException)
where: 'the following operations are used'
@@ -143,11 +118,11 @@ class NcmpDatastoreRequestHandlerSpec extends Specification {
def 'Attempt to execute async data operation request with too many cm handles.'() {
given: 'a data operation definition with too many cm handles'
- def tooMany = objectUnderTest.MAXIMUM_CM_HANDLES_PER_OPERATION+1
+ def tooMany = objectUnderTest.MAXIMUM_CM_HANDLES_PER_OPERATION + 1
def cmHandleIds = new String[tooMany]
def dataOperationDefinition = new DataOperationDefinition(operationId: 'abc', operation: 'read', datastore: 'ncmp-datastore:passthrough-running', cmHandleIds: cmHandleIds)
when: 'data operation request is executed'
- objectUnderTest.executeRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER)
+ objectUnderTest.executeAsynchronousRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER)
then: 'a payload too large exception is thrown'
def exceptionThrown = thrown(PayloadTooLargeException)
and: 'the error message contains the offending number of cm handles'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy
new file mode 100644
index 0000000000..5f83ad5f83
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy
@@ -0,0 +1,109 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2021 Pantheon.tech
+ * Modifications Copyright (C) 2021-2022 Bell Canada
+ * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * ================================================================================
+ * 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.impl.data
+
+
+import org.onap.cps.ncmp.api.data.models.CmResourceAddress
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
+import org.onap.cps.spi.model.DataNode
+import reactor.core.publisher.Mono
+import spock.lang.Specification
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.OPERATIONAL
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE
+import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE
+
+class NetworkCmProxyFacadeSpec extends Specification {
+
+ def mockDmiDataOperations = Mock(DmiDataOperations)
+ def mockNcmpCachedResourceRequestHandler = Mock(NcmpCachedResourceRequestHandler)
+ def mockNcmpPassthroughResourceRequestHandler = Mock(NcmpPassthroughResourceRequestHandler)
+ def mockAlternateIdMatcher = Mock(AlternateIdMatcher)
+
+ def objectUnderTest = new NetworkCmProxyFacade(mockNcmpCachedResourceRequestHandler, mockNcmpPassthroughResourceRequestHandler, mockDmiDataOperations, mockAlternateIdMatcher)
+
+ def NO_TOPIC = null
+
+ def 'Execute Data Operation for CM Handles (delegation).'() {
+ given: 'a data operation request'
+ def dataOperationRequest = Mock(DataOperationRequest)
+ and: ' a response from the (mocked) pass-through request handler for the given parameters'
+ def responseFromHandler = [attr:'value']
+ mockNcmpPassthroughResourceRequestHandler.executeAsynchronousRequest('topic', dataOperationRequest, 'authorization') >> responseFromHandler
+ expect: 'the response form the handler'
+ assert objectUnderTest.executeDataOperationForCmHandles('topic', dataOperationRequest, 'authorization') == responseFromHandler
+ }
+
+ def 'Query Resource Data for cm handle (delegation).'() {
+ given: 'a response from the (mocked) cached data handler for the given parameters'
+ def responseFromHandler = [Mock(DataNode)]
+ mockNcmpCachedResourceRequestHandler.executeRequest('ch-1', 'some cps path', true) >> responseFromHandler
+ expect: 'the response form the handler'
+ assert objectUnderTest.queryResourceDataForCmHandle('ch-1','some cps path',true) == responseFromHandler
+ }
+
+ def 'Choosing Data Request Handler.'() {
+ expect: '(a mock of) #expectedHandler'
+ assert objectUnderTest.getNcmpDatastoreRequestHandler(datastore.datastoreName).class.name.startsWith(expectedHandler.name)
+ where:
+ datastore || expectedHandler
+ OPERATIONAL || NcmpCachedResourceRequestHandler.class
+ PASSTHROUGH_RUNNING || NcmpPassthroughResourceRequestHandler.class
+ PASSTHROUGH_OPERATIONAL || NcmpPassthroughResourceRequestHandler.class
+ }
+
+ def 'Write resource data for pass-through running from DMI using POST (delegation).'() {
+ when: 'write resource data is called'
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', CREATE,
+ '{some-json}', 'application/json', null)
+ then: 'DMI called with correct data'
+ 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', CREATE, '{some-json}', 'application/json', null)
+ }
+
+ def 'Get resource data from DMI (delegation).'() {
+ given: 'a cm resource address for datastore operational'
+ def cmResourceAddress = new CmResourceAddress('ncmp-datastore:operational', 'some CM Handle', 'some resource Id')
+ and: 'get resource data from DMI is called'
+ mockAlternateIdMatcher.getCmHandleId('some CM Handle') >> 'some CM Handle'
+ mockNcmpCachedResourceRequestHandler.executeRequest(cmResourceAddress, 'options', NO_TOPIC, false, 'authorization') >>
+ Mono.just('dmi response')
+ when: 'get resource data operational for the given cm resource address is called'
+ def response = objectUnderTest.getResourceDataForCmHandle(cmResourceAddress, 'options', NO_TOPIC, false, 'authorization').block()
+ then: 'DMI returns a json response'
+ assert response == 'dmi response'
+ }
+
+ def 'Update resource data for pass-through running from dmi (delegation).'() {
+ when: 'get resource data is called'
+ objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
+ 'testResourceId', UPDATE,
+ '{some-json}', 'application/json', 'authorization')
+ then: 'DMI called with correct data'
+ 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', UPDATE, '{some-json}', 'application/json', 'authorization')
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImplSpec.groovy
index 5f4f248c65..6d0cf84e20 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyQueryServiceImplSpec.groovy
@@ -18,16 +18,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl
-
-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_DMI_REGISTRY_ANCHOR
+package org.onap.cps.ncmp.impl.data
import org.onap.cps.api.CpsQueryService
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.model.DataNode
import spock.lang.Specification
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+
class NetworkCmProxyQueryServiceImplSpec extends Specification {
def mockCpsQueryService = Mock(CpsQueryService)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy
index f646ee5bfe..4bcafe8c61 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy
@@ -18,23 +18,24 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async
+package org.onap.cps.ncmp.impl.data.async
import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.kafka.clients.consumer.KafkaConsumer
import org.apache.kafka.common.serialization.StringDeserializer
import org.mapstruct.factory.Mappers
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent
import org.onap.cps.ncmp.event.model.NcmpAsyncRequestResponseEvent
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.annotation.DirtiesContext
import org.testcontainers.spock.Testcontainers
+
import java.time.Duration
@SpringBootTest(classes = [EventsPublisher, AsyncRestRequestResponseEventConsumer, ObjectMapper, JsonObjectMapper])
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy
index 369b496ca7..afb594ab04 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/DataOperationEventConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy
@@ -18,21 +18,21 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async
+package org.onap.cps.ncmp.impl.data.async
import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
+import io.cloudevents.core.builder.CloudEventBuilder
import io.cloudevents.kafka.CloudEventDeserializer
import io.cloudevents.kafka.CloudEventSerializer
import io.cloudevents.kafka.impl.KafkaHeaders
-import io.cloudevents.core.builder.CloudEventBuilder
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.clients.consumer.KafkaConsumer
import org.apache.kafka.common.header.internals.RecordHeaders
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
@@ -40,9 +40,10 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.kafka.listener.adapter.RecordFilterStrategy
import org.springframework.test.annotation.DirtiesContext
import org.testcontainers.spock.Testcontainers
+
import java.time.Duration
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
+import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent
@SpringBootTest(classes = [EventsPublisher, DataOperationEventConsumer, RecordFilterStrategies, JsonObjectMapper, ObjectMapper])
@Testcontainers
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/FilterStrategiesIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy
index fba1f953f4..01d2a3666b 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/FilterStrategiesIntegrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy
@@ -18,13 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async
+package org.onap.cps.ncmp.impl.data.async
import io.cloudevents.core.builder.CloudEventBuilder
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.impl.config.kafka.KafkaConfig
-import org.onap.cps.ncmp.api.kafka.ConsumerBaseSpec
+import org.onap.cps.ncmp.config.KafkaConfig
import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent
+import org.onap.cps.ncmp.utils.events.ConsumerBaseSpec
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -32,6 +32,7 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.annotation.DirtiesContext
import org.testcontainers.spock.Testcontainers
import spock.util.concurrent.PollingConditions
+
import java.util.concurrent.TimeUnit
@SpringBootTest(classes =[DataOperationEventConsumer, AsyncRestRequestResponseEventConsumer, RecordFilterStrategies, KafkaConfig])
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapperSpec.groovy
index 07e9b49ff6..c7f094b1eb 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventMapperSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/NcmpAsyncRequestResponseEventMapperSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async
+package org.onap.cps.ncmp.impl.data.async
import org.mapstruct.factory.Mappers
import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategiesSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategiesSpec.groovy
index 4189a8b381..5ff2a3b55d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/RecordFilterStrategiesSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/RecordFilterStrategiesSpec.groovy
@@ -1,8 +1,8 @@
-package org.onap.cps.ncmp.api.impl.async
+package org.onap.cps.ncmp.impl.data.async
-import spock.lang.Specification
import org.apache.kafka.common.header.Header
import org.apache.kafka.common.header.Headers
+import spock.lang.Specification
import java.nio.charset.Charset
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/SerializationIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy
index ee89333006..3fe7ec222e 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/async/SerializationIntegrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy
@@ -18,18 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.async
+package org.onap.cps.ncmp.impl.data.async
import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.core.builder.CloudEventBuilder
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.impl.config.kafka.KafkaConfig
-import org.onap.cps.ncmp.api.kafka.ConsumerBaseSpec
+import org.onap.cps.ncmp.config.KafkaConfig
import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent
import org.onap.cps.ncmp.event.model.NcmpAsyncRequestResponseEvent
import org.onap.cps.ncmp.events.async1_0_0.Data
import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent
import org.onap.cps.ncmp.events.async1_0_0.Response
+import org.onap.cps.ncmp.utils.events.ConsumerBaseSpec
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy
new file mode 100644
index 0000000000..c859bb0a09
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy
@@ -0,0 +1,45 @@
+/*
+ * ============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.impl.data.policyexecutor
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.config.PolicyExecutorHttpClientConfig
+import org.onap.cps.ncmp.impl.policyexecutor.PolicyExecutorWebClientConfiguration
+import org.onap.cps.ncmp.utils.WebClientBuilderTestConfig
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ContextConfiguration
+import spock.lang.Specification
+
+@SpringBootTest
+@ContextConfiguration(classes = [ObjectMapper, PolicyExecutor, PolicyExecutorWebClientConfiguration, PolicyExecutorHttpClientConfig, WebClientBuilderTestConfig ])
+class PolicyExecutorConfigurationSpec extends Specification {
+
+ @Autowired
+ PolicyExecutor objectUnderTest
+
+ def 'Policy executor configuration properties.'() {
+ expect: 'properties used from application.yml'
+ assert objectUnderTest.enabled
+ assert objectUnderTest.serverAddress == 'http://localhost'
+ assert objectUnderTest.serverPort == '8785'
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
new file mode 100644
index 0000000000..63a915ab64
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
@@ -0,0 +1,154 @@
+/*
+ * ============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.impl.data.policyexecutor
+
+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 com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.exceptions.NcmpException
+import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException
+import org.onap.cps.ncmp.api.exceptions.ServerNcmpException
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.slf4j.LoggerFactory
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.web.reactive.function.client.WebClient
+import reactor.core.publisher.Mono
+import spock.lang.Specification
+
+import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE
+import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE
+import static org.onap.cps.ncmp.api.data.models.OperationType.PATCH
+import static org.onap.cps.ncmp.api.data.models.OperationType.UPDATE
+
+class PolicyExecutorSpec extends Specification {
+
+ def mockWebClient = Mock(WebClient)
+ def mockRequestBodyUriSpec = Mock(WebClient.RequestBodyUriSpec)
+ def mockResponseSpec = Mock(WebClient.ResponseSpec)
+ def spiedObjectMapper = Spy(ObjectMapper)
+
+ PolicyExecutor objectUnderTest = new PolicyExecutor(mockWebClient, spiedObjectMapper)
+
+ def logAppender = Spy(ListAppender<ILoggingEvent>)
+
+ def someValidJson = '{"Hello":"World"}'
+
+ def setup() {
+ setupLogger()
+ objectUnderTest.enabled = true
+ mockWebClient.post() >> mockRequestBodyUriSpec
+ mockRequestBodyUriSpec.uri(*_) >> mockRequestBodyUriSpec
+ mockRequestBodyUriSpec.header(*_) >> mockRequestBodyUriSpec
+ mockRequestBodyUriSpec.body(*_) >> mockRequestBodyUriSpec
+ mockRequestBodyUriSpec.retrieve() >> mockResponseSpec
+ }
+
+ def cleanup() {
+ ((Logger) LoggerFactory.getLogger(PolicyExecutor)).detachAndStopAllAppenders()
+ }
+
+ def 'Permission check with allow response.'() {
+ given: 'allow response'
+ mockResponse([decision:'allow'], HttpStatus.OK)
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), operationType, 'my credentials','my resource',someValidJson)
+ then: 'system logs the operation is allowed'
+ assert getLogEntry(2) == 'Policy Executor allows the operation'
+ and: 'no exception occurs'
+ noExceptionThrown()
+ where: 'all write operations are tested'
+ operationType << [ CREATE, DELETE, PATCH, UPDATE ]
+ }
+
+ def 'Permission check with other response (not allowed).'() {
+ given: 'other response'
+ mockResponse([decision:'other', decisionId:123, message:'I dont like Mondays' ], HttpStatus.OK)
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson)
+ then: 'Policy Executor exception is thrown'
+ def thrownException = thrown(PolicyExecutorException)
+ assert thrownException.message == 'Policy Executor did not allow request. Decision #123 : other'
+ assert thrownException.details == 'I dont like Mondays'
+ }
+
+ def 'Permission check with non 2xx response.'() {
+ given: 'other response'
+ mockResponse([], HttpStatus.I_AM_A_TEAPOT)
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson)
+ then: 'Server Ncmp exception is thrown'
+ def thrownException = thrown(ServerNcmpException)
+ assert thrownException.message == 'Policy Executor invocation failed'
+ assert thrownException.details == 'HTTP status code: 418'
+ }
+
+ def 'Permission check with invalid response from Policy Executor.'() {
+ given: 'invalid response from Policy executor'
+ mockResponseSpec.toEntity(*_) >> invalidResponse
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials','my resource',someValidJson)
+ then: 'system logs the expected message'
+ assert getLogEntry(1) == expectedMessage
+ where: 'following invalid responses are received'
+ invalidResponse || expectedMessage
+ Mono.empty() || 'No valid response from policy, ignored'
+ Mono.just(new ResponseEntity<>(null, HttpStatus.OK)) || 'No valid response body from policy, ignored'
+ }
+
+ def 'Permission check with an invalid change request json.'() {
+ when: 'permission is checked for an invalid change request'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', 'invalid json string')
+ then: 'an ncmp exception thrown'
+ def ncmpException = thrown(NcmpException)
+ ncmpException.message == 'Cannot convert Change Request data to Object'
+ ncmpException.details.contains('invalid json string')
+ }
+
+ def 'Permission check feature disabled.'() {
+ given: 'feature is disabled'
+ objectUnderTest.enabled = false
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson)
+ then: 'system logs that the feature not enabled'
+ assert getLogEntry(0) == 'Policy Executor Enabled: false'
+ }
+
+ def mockResponse(mockResponseAsMap, httpStatus) {
+ JsonNode jsonNode = spiedObjectMapper.readTree(spiedObjectMapper.writeValueAsString(mockResponseAsMap))
+ def mono = Mono.just(new ResponseEntity<>(jsonNode, httpStatus))
+ mockResponseSpec.toEntity(*_) >> mono
+ }
+
+ def setupLogger() {
+ def logger = LoggerFactory.getLogger(PolicyExecutor)
+ logger.setLevel(Level.TRACE)
+ logger.addAppender(logAppender)
+ logAppender.start()
+ }
+
+ def getLogEntry(index) {
+ logAppender.list[index].formattedMessage
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy
index 9028b9e5ed..84eafb0da3 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils.data.operation
+package org.onap.cps.ncmp.impl.data.utils
import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
@@ -26,27 +26,28 @@ import io.cloudevents.kafka.CloudEventDeserializer
import io.cloudevents.kafka.impl.KafkaHeaders
import org.apache.kafka.clients.consumer.KafkaConsumer
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.NcmpResponseStatus
-import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
-import org.onap.cps.ncmp.api.models.DataOperationRequest
+import org.onap.cps.ncmp.api.data.models.DataOperationRequest
+import org.onap.cps.ncmp.api.data.models.OperationType
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder
+import org.onap.cps.ncmp.config.CpsApplicationContext
import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent
+import org.onap.cps.ncmp.impl.data.models.DmiDataOperation
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
-import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
+import org.springframework.util.LinkedMultiValueMap
import java.time.Duration
-import java.util.concurrent.TimeoutException
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY
+import static org.onap.cps.ncmp.utils.events.CloudEventMapper.toTargetEvent
-@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, ObjectMapper])
-class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
+@ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext])
+class DmiDataOperationsHelperSpec extends MessagingBaseSpec {
def static clientTopic = 'my-topic-name'
def static dataOperationType = 'org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent'
@@ -57,9 +58,6 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
@SpringBean
EventsPublisher eventPublisher = new EventsPublisher<CloudEvent>(legacyEventKafkaTemplate, cloudEventKafkaTemplate)
- @Autowired
- ObjectMapper objectMapper
-
def 'Process per data operation request with #serviceName.'() {
given: 'data operation request with 3 operations'
def dataOperationRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json')
@@ -67,7 +65,7 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
and: '4 known cm handles: ch1-dmi1, ch2-dmi1, ch3-dmi2, ch4-dmi2'
def yangModelCmHandles = getYangModelCmHandles()
when: 'data operation request is processed'
- def operationsOutPerDmiServiceName = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles)
+ def operationsOutPerDmiServiceName = DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles)
and: 'converted to a json node'
def dmiDataOperationRequestBody = jsonObjectMapper.asJsonString(operationsOutPerDmiServiceName.get(serviceName))
def dmiDataOperationRequestBodyAsJsonNode = jsonObjectMapper.convertToJsonNode(dmiDataOperationRequestBody).get(operationIndex)
@@ -97,7 +95,7 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
and: '1 known cm handles: ch1-dmi1'
def yangModelCmHandles = getYangModelCmHandlesForOneCmHandle()
when: 'data operation request is processed'
- def operationsOutPerDmiServiceName = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles)
+ def operationsOutPerDmiServiceName = DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(clientTopic,'request-id', dataOperationRequest, yangModelCmHandles)
and: 'converted to a json node'
def dmiDataOperationRequestBody = operationsOutPerDmiServiceName['dmi1']
def cmHandlesInRequestBody = dmiDataOperationRequestBody[0].cmHandles
@@ -115,7 +113,7 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
def dataOperationRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json')
def dataOperationRequest = jsonObjectMapper.convertJsonString(dataOperationRequestJsonData, DataOperationRequest.class)
when: 'data operation request is processed'
- ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(clientTopic, 'request-id', dataOperationRequest, yangModelCmHandles)
+ DmiDataOperationsHelper.processPerDefinitionInDataOperationsRequest(clientTopic, 'request-id', dataOperationRequest, yangModelCmHandles)
and: 'subscribed client specified topic is polled and first record is selected'
def consumerRecordOut = cloudEventKafkaConsumer.poll(Duration.ofMillis(1500)).last()
then: 'verify cloud compliant headers'
@@ -135,34 +133,10 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
jsonObjectMapper.asJsonString(dataOperationResponseEvent.data.responses) == dataOperationResponseEventJson
}
- def 'Publish error response for entire data operations request when async task fails'() {
- given: 'consumer subscribing to client topic'
- def cloudEventKafkaConsumer = new KafkaConsumer<>(eventConsumerConfigProperties(consumerGroupId, CloudEventDeserializer))
- cloudEventKafkaConsumer.subscribe([clientTopic])
- and: 'data operation request having non-ready and non-existing cm handle ids'
- def dataOperationRequestJsonData = TestUtils.getResourceFileContent('dataOperationRequest.json')
- def dataOperationRequest = jsonObjectMapper.convertJsonString(dataOperationRequestJsonData, DataOperationRequest.class)
- when: 'an error occurs for the entire data operations request'
- ResourceDataOperationRequestUtils.handleAsyncTaskCompletionForDataOperationsRequest(clientTopic, 'request-id', dataOperationRequest, exceptionThrown)
- and: 'subscribed client specified topic is polled and first record is selected'
- def consumerRecordOut = cloudEventKafkaConsumer.poll(Duration.ofMillis(1500)).last()
- def dataOperationResponseEvent = toTargetEvent(consumerRecordOut.value(), DataOperationEvent.class)
- then: 'data operation response event response size is 3'
- dataOperationResponseEvent.data.responses.size() == 3
- and: 'all 3 have the expected error code'
- dataOperationResponseEvent.data.responses.each {
- assert it.statusCode == errorReportedToClientTopic.code
- }
- where:
- scenario | exceptionThrown | consumerGroupId || errorReportedToClientTopic
- 'task timed out' | new TimeoutException() | 'test-2' || NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING
- 'unspecified error' | new RuntimeException() | 'test-3' || NcmpResponseStatus.UNKNOWN_ERROR
- }
-
static def getYangModelCmHandles() {
def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
- def readyState = new CompositeStateBuilder().withCmHandleState(CmHandleState.READY).withLastUpdatedTimeNow().build()
- def advisedState = new CompositeStateBuilder().withCmHandleState(CmHandleState.ADVISED).withLastUpdatedTimeNow().build()
+ def readyState = new CompositeStateBuilder().withCmHandleState(READY).withLastUpdatedTimeNow().build()
+ def advisedState = new CompositeStateBuilder().withCmHandleState(ADVISED).withLastUpdatedTimeNow().build()
return [new YangModelCmHandle(id: 'ch1-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState),
new YangModelCmHandle(id: 'ch2-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState),
new YangModelCmHandle(id: 'ch6-dmi1', dmiServiceName: 'dmi1', dmiProperties: dmiProperties, compositeState: readyState),
@@ -176,7 +150,16 @@ class ResourceDataOperationRequestUtilsSpec extends MessagingBaseSpec {
static def getYangModelCmHandlesForOneCmHandle() {
def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
- def readyState = new CompositeStateBuilder().withCmHandleState(CmHandleState.READY).withLastUpdatedTimeNow().build()
+ def readyState = new CompositeStateBuilder().withCmHandleState(READY).withLastUpdatedTimeNow().build()
return [new YangModelCmHandle(id: 'ch1-dmi1', dmiServiceName: 'dmi1', moduleSetTag: 'module-set-tag1', dmiProperties: dmiProperties, compositeState: readyState)]
}
+
+ def mockAndPopulateErrorMap(errorReportedToClientTopic) {
+ def dmiDataOperation = DmiDataOperation.builder().operation(OperationType.fromOperationName('read'))
+ .operationId('some-op-id').datastore('ncmp-datastore:passthrough-operational')
+ .options('some-option').resourceIdentifier('some-resource-identifier').build()
+ def cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>()
+ cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperation, Map.of(errorReportedToClientTopic, ['some-cm-handle-id']))
+ return cmHandleIdsPerResponseCodesPerOperation
+ }
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImplSpec.groovy
new file mode 100644
index 0000000000..74bd0484df
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobResultServiceImplSpec.groovy
@@ -0,0 +1,55 @@
+/*
+ * ============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.impl.datajobs
+
+import org.onap.cps.ncmp.impl.dmi.DmiProperties
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters
+import reactor.core.publisher.Mono
+import spock.lang.Specification
+
+class DataJobResultServiceImplSpec extends Specification {
+
+ def mockDmiRestClient = Mock(DmiRestClient)
+ def mockDmiProperties = Mock(DmiProperties)
+ def objectUnderTest = new DataJobResultServiceImpl(mockDmiRestClient, mockDmiProperties)
+
+ def setup() {
+ mockDmiProperties.dmiBasePath >> 'dmi'
+ }
+
+ def 'Retrieve data job result.'() {
+ given: 'the required parameters for querying'
+ def dmiServiceName = 'some-dmi-service'
+ def dataProducerJobId = 'some-data-producer-job-id'
+ def dataProducerId = 'some-data-producer-id'
+ def authorization = 'my authorization header'
+ def destination = 'some-destination'
+ def urlParams = new UrlTemplateParameters('some-dmi-service/dmi/v1/cmwriteJob/dataProducer/{dataProducerId}/dataProducerJob/{dataProducerJobId}/result?destination={destination}', ['dataProducerJobId':'some-data-producer-job-id', 'dataProducerId':'some-data-producer-id', 'destination': 'some-destination'])
+ and: 'the rest client returns the result for the given parameters'
+ mockDmiRestClient.getDataJobResult(urlParams, authorization) >> Mono.just('some result')
+ when: 'the job status is queried'
+ def result = objectUnderTest.getDataJobResult(authorization, dmiServiceName,dataProducerId, dataProducerJobId, destination)
+ then: 'the result from the rest client is returned'
+ assert result != null
+ assert result == 'some result'
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy
new file mode 100644
index 0000000000..4b536b9710
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy
@@ -0,0 +1,84 @@
+/*
+ * ============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.impl.datajobs
+
+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.onap.cps.ncmp.api.datajobs.models.DataJobMetadata
+import org.onap.cps.ncmp.api.datajobs.models.DataJobReadRequest
+import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest
+import org.onap.cps.ncmp.api.datajobs.models.ReadOperation
+import org.onap.cps.ncmp.api.datajobs.models.WriteOperation
+import org.slf4j.LoggerFactory
+import spock.lang.Specification
+
+class DataJobServiceImplSpec extends Specification {
+
+ def mockWriteRequestExaminer = Mock(WriteRequestExaminer)
+ def mockDmiSubJobRequestHandler = Mock(DmiSubJobRequestHandler)
+
+ def objectUnderTest = new DataJobServiceImpl(mockDmiSubJobRequestHandler, mockWriteRequestExaminer)
+
+ def myDataJobMetadata = new DataJobMetadata('', '', '')
+ def authorization = 'my authorization header'
+
+ def logger = Spy(ListAppender<ILoggingEvent>)
+
+ def setup() {
+ setupLogger()
+ }
+
+ def cleanup() {
+ ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)).detachAndStopAllAppenders()
+ }
+
+ def 'Read data job request.'() {
+ when: 'read data job request is processed'
+ def readOperation = new ReadOperation('', '', '', [], [], '', '', 1)
+ objectUnderTest.readDataJob(authorization, 'my-job-id', myDataJobMetadata, new DataJobReadRequest([readOperation]))
+ 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 read operation is: my-job-id')
+ }
+
+ def 'Write data-job request.'() {
+ given: 'data job metadata and write request'
+ def dataJobWriteRequest = new DataJobWriteRequest([new WriteOperation('', '', '', null)])
+ and: 'a map of producer key and dmi 3gpp write operation'
+ def dmiWriteOperationsPerProducerKey = [:]
+ when: 'write data job request is processed'
+ objectUnderTest.writeDataJob(authorization, 'my-job-id', myDataJobMetadata, dataJobWriteRequest)
+ then: 'the examiner service is called and a map is returned'
+ 1 * mockWriteRequestExaminer.splitDmiWriteOperationsFromRequest('my-job-id', dataJobWriteRequest) >> dmiWriteOperationsPerProducerKey
+ and: 'the dmi request handler is called with the result from the examiner'
+ 1 * mockDmiSubJobRequestHandler.sendRequestsToDmi(authorization, 'my-job-id', myDataJobMetadata, dmiWriteOperationsPerProducerKey)
+ }
+
+ 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/impl/datajobs/DataJobStatusServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobStatusServiceImplSpec.groovy
new file mode 100644
index 0000000000..be46d885e0
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobStatusServiceImplSpec.groovy
@@ -0,0 +1,53 @@
+/*
+ * ============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.impl.datajobs
+
+import org.onap.cps.ncmp.impl.dmi.DmiProperties
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters
+import reactor.core.publisher.Mono
+import spock.lang.Specification
+
+class DataJobStatusServiceImplSpec extends Specification {
+
+ def mockDmiRestClient = Mock(DmiRestClient)
+ def mockDmiProperties = Mock(DmiProperties)
+ def objectUnderTest = new DataJobStatusServiceImpl(mockDmiRestClient, mockDmiProperties)
+
+ def setup() {
+ mockDmiProperties.dmiBasePath >> 'dmi'
+ }
+
+ def 'Forward a data job status query to DMI.' () {
+ given: 'the required parameters for querying'
+ def dmiServiceName = 'some-dmi-service'
+ def dataProducerId = 'some-data-producer-id'
+ def dataProducerJobId = 'some-data-producer-job-id'
+ def authorization = 'my authorization header'
+ def urlParams = new UrlTemplateParameters('some-dmi-service/dmi/v1/cmwriteJob/dataProducer/{dataProducerId}/dataProducerJob/{dataProducerJobId}/status', ['dataProducerId':'some-data-producer-id', 'dataProducerJobId':'some-data-producer-job-id'])
+ and: 'the rest client returns a status for the given parameters'
+ mockDmiRestClient.getDataJobStatus(urlParams, authorization) >> Mono.just('some status')
+ when: 'the job status is queried'
+ def status = objectUnderTest.getDataJobStatus(authorization, dmiServiceName, dataProducerId, dataProducerJobId)
+ then: 'the status from the rest client is returned'
+ assert status == 'some status'
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy
new file mode 100644
index 0000000000..041fbd95ee
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy
@@ -0,0 +1,40 @@
+package org.onap.cps.ncmp.impl.datajobs
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.data.models.OperationType
+import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata
+import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation
+import org.onap.cps.ncmp.api.datajobs.models.ProducerKey
+import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse
+import org.onap.cps.ncmp.impl.dmi.DmiProperties
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient
+import org.onap.cps.ncmp.impl.models.RequiredDmiService
+import org.onap.cps.utils.JsonObjectMapper
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import spock.lang.Specification
+
+class DmiSubJobRequestHandlerSpec extends Specification {
+
+ def mockDmiRestClient = Mock(DmiRestClient)
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def mockDmiProperties = Mock(DmiProperties)
+ def objectUnderTest = new DmiSubJobRequestHandler(mockDmiRestClient, mockDmiProperties, jsonObjectMapper)
+
+ def 'Send a sub-job request to the DMI Plugin.'() {
+ given: 'a data job id, metadata and a map of producer keys and write operations to create a request'
+ def dataJobId = 'some-job-id'
+ def dataJobMetadata = new DataJobMetadata('d1', 't1', 't2')
+ def dmiWriteOperation = new DmiWriteOperation('p', 'operation', 'tag', null, 'o1', [:])
+ def dmiWriteOperationsPerProducerKey = [new ProducerKey('dmi1', 'prod1'): [dmiWriteOperation]]
+ def authorization = 'my authorization header'
+ and: 'the dmi rest client will return a response (for the correct parameters)'
+ def responseEntity = new ResponseEntity<>(new SubJobWriteResponse('my-sub-job-id', 'dmi1', 'prod1'), HttpStatus.OK)
+ def expectedJson = '{"destination":"d1","dataAcceptType":"t1","dataContentType":"t2","dataProducerId":"prod1","dataJobId":"some-job-id","data":[{"path":"p","op":"operation","moduleSetTag":"tag","value":null,"operationId":"o1","privateProperties":{}}]}'
+ mockDmiRestClient.synchronousPostOperationWithJsonData(RequiredDmiService.DATA, _, expectedJson, OperationType.CREATE, authorization) >> responseEntity
+ when: 'sending request to DMI invoked'
+ objectUnderTest.sendRequestsToDmi(authorization, dataJobId, dataJobMetadata, dmiWriteOperationsPerProducerKey)
+ then: 'the result contains the expected sub-job id'
+ assert responseEntity.body.subJobId == 'my-sub-job-id'
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy
new file mode 100644
index 0000000000..84eb78b751
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy
@@ -0,0 +1,63 @@
+
+package org.onap.cps.ncmp.impl.datajobs
+
+import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest
+import org.onap.cps.ncmp.api.datajobs.models.WriteOperation
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
+import org.onap.cps.spi.model.DataNode
+import spock.lang.Specification
+
+class WriteRequestExaminerSpec extends Specification {
+
+ def mockAlternateIdMatcher = Mock(AlternateIdMatcher)
+ def objectUnderTest = new WriteRequestExaminer(mockAlternateIdMatcher)
+
+ def setup() {
+ def ch1 = new DataNode(leaves: [id: 'ch1', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p1'])
+ def ch2 = new DataNode(leaves: [id: 'ch2', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p1'])
+ def ch3 = new DataNode(leaves: [id: 'ch3', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p2'])
+ def ch4 = new DataNode(leaves: [id: 'ch4', 'dmi-service-name': 'dmiB', 'data-producer-identifier': 'p1'])
+ mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn1', '/') >> ch1
+ mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn2', '/') >> ch2
+ mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn3', '/') >> ch3
+ mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn4', '/') >> ch4
+ }
+
+ def 'Create a map of dmi write requests per producer key with #scenario.'() {
+ given: 'a write request with some write operations'
+ def writeOperations = writeOperationFdns.collect {
+ new WriteOperation(it, '', '', null)
+ }
+ and: 'operations are wrapped in a write request'
+ def dataJobWriteRequest = new DataJobWriteRequest(writeOperations)
+ when: 'the DMI write operations are split from the request'
+ def dmiWriteOperationsPerProducerKey = objectUnderTest.splitDmiWriteOperationsFromRequest('some id', dataJobWriteRequest)
+ then: 'we get the expected number of keys and values.'
+ def producerKeysAsStrings = dmiWriteOperationsPerProducerKey.keySet().collect {
+ it.toString()
+ }
+ assert producerKeysAsStrings.size() == expectedKeys.size()
+ assert expectedKeys.containsAll(producerKeysAsStrings)
+ where:
+ scenario | writeOperationFdns || expectedKeys
+ 'one fdn' | ['fdn1'] || ['dmiA#p1']
+ 'a duplicated target' | ['fdn1','fdn1'] || ['dmiA#p1']
+ 'two different targets' | ['fdn1','fdn2'] || ['dmiA#p1']
+ 'two different targets and different producer keys' | ['fdn1','fdn3'] || ['dmiA#p1', 'dmiA#p2']
+ 'two different targets and different DMI services' | ['fdn1','fdn4'] || ['dmiA#p1', 'dmiB#p1']
+ 'many targets with different dmi service names and producer keys' | ['fdn1', 'fdn2', 'fdn3', 'fdn4'] || ['dmiA#p1', 'dmiA#p2', 'dmiB#p1']
+ }
+
+ def 'Validate the ordering of the created sub jobs.'() {
+ given: 'a few write operations for the same producer'
+ def writeOperations = (1..3).collect {
+ new WriteOperation('fdn1', '', it.toString(), null)
+ }
+ and: 'operation is wrapped in a write request'
+ def dataJobWriteRequest = new DataJobWriteRequest(writeOperations)
+ when: 'the DMI write operations are split from the request'
+ def dmiWriteOperations = objectUnderTest.splitDmiWriteOperationsFromRequest('some id', dataJobWriteRequest).values().iterator().next()
+ then: 'we get the operation ids in the expected order.'
+ assert dmiWriteOperations.operationId == ['1', '2', '3']
+ }
+}
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/impl/dmi/DmiOperationsBaseSpec.groovy
index 042cb4a0d6..65fda8718c 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/impl/dmi/DmiOperationsBaseSpec.groovy
@@ -18,17 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations
+package org.onap.cps.ncmp.impl.dmi
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.spi.utils.CpsValidator
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.spockframework.spring.SpringBean
import spock.lang.Shared
import spock.lang.Specification
@@ -44,17 +40,13 @@ abstract class DmiOperationsBaseSpec extends Specification {
@SpringBean
InventoryPersistence mockInventoryPersistence = Mock()
- def mockCpsValidator = Mock(CpsValidator)
-
@SpringBean
ObjectMapper spyObjectMapper = Spy()
- @SpringBean
- DmiServiceUrlBuilder dmiServiceUrlBuilder = new DmiServiceUrlBuilder(new DmiWebClientConfiguration.DmiProperties(), mockCpsValidator)
-
def yangModelCmHandle = new YangModelCmHandle()
- def static dmiServiceName = 'some service name'
+ def static dmiServiceName = 'myServiceName'
def static cmHandleId = 'some-cm-handle'
+ def static alternateId = 'alt-id-' + cmHandleId
def static resourceIdentifier = 'parent/child'
def mockYangModelCmHandleRetrieval(dmiProperties) {
@@ -68,7 +60,7 @@ abstract class DmiOperationsBaseSpec extends Specification {
}
def mockYangModelCmHandleCollectionRetrieval(dmiProperties) {
- populateYangModelCmHandle(dmiProperties, "")
+ populateYangModelCmHandle(dmiProperties, '')
mockInventoryPersistence.getYangModelCmHandles(_) >> [yangModelCmHandle]
}
@@ -77,6 +69,7 @@ abstract class DmiOperationsBaseSpec extends Specification {
yangModelCmHandle.dmiServiceName = dmiServiceName
yangModelCmHandle.dmiProperties = dmiProperties
yangModelCmHandle.id = cmHandleId
+ yangModelCmHandle.alternateId = alternateId
yangModelCmHandle.compositeState = new CompositeState()
yangModelCmHandle.compositeState.cmHandleState = CmHandleState.READY
yangModelCmHandle.moduleSetTag = moduleSetTag
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy
new file mode 100644
index 0000000000..418b3bb3c8
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy
@@ -0,0 +1,38 @@
+/*-
+ * ============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.impl.dmi
+
+
+import spock.lang.Specification
+
+class DmiPropertiesSpec extends Specification {
+
+ def objectUnderTest = new DmiProperties()
+
+ def 'Geting dmi base path.'() {
+ given: 'base path of #dmiBasePath'
+ objectUnderTest.dmiBasePath = dmiBasePath
+ expect: 'Preceding and trailing slash wil be removed'
+ assert objectUnderTest.getDmiBasePath() == 'test'
+ where: 'the following dmi base paths are used'
+ dmiBasePath << [ 'test' , '/test', 'test/', '/test/' ]
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy
new file mode 100644
index 0000000000..4d47ef14a0
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy
@@ -0,0 +1,191 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2022 Bell Canada
+ * ================================================================================
+ * 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.impl.dmi
+
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.databind.node.ObjectNode
+import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters
+import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.utils.JsonObjectMapper
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
+import org.springframework.http.HttpStatusCode
+import org.springframework.http.ResponseEntity
+import org.springframework.web.client.HttpServerErrorException
+import org.springframework.web.reactive.function.client.WebClient
+import org.springframework.web.reactive.function.client.WebClientRequestException
+import org.springframework.web.reactive.function.client.WebClientResponseException
+import reactor.core.publisher.Mono
+import spock.lang.Specification
+
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
+import static org.onap.cps.ncmp.api.data.models.OperationType.READ
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL
+
+class DmiRestClientSpec extends Specification {
+
+ static final NO_AUTH_HEADER = null
+ static final BASIC_AUTH_HEADER = 'Basic c29tZSB1c2VyOnNvbWUgcGFzc3dvcmQ='
+ static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token'
+ static final urlTemplateParameters = new UrlTemplateParameters('/{pathParam1}/{pathParam2}', ['pathParam1': 'my', 'pathParam2': 'url'])
+
+ def mockDataServicesWebClient = Mock(WebClient)
+ def mockModelServicesWebClient = Mock(WebClient)
+ def mockHealthChecksWebClient = Mock(WebClient)
+
+ def mockRequestBody = Mock(WebClient.RequestBodyUriSpec)
+ def mockResponse = Mock(WebClient.ResponseSpec)
+
+ def mockDmiProperties = Mock(DmiProperties)
+
+ JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+
+ DmiRestClient objectUnderTest = new DmiRestClient(mockDmiProperties, jsonObjectMapper, mockDataServicesWebClient, mockModelServicesWebClient, mockHealthChecksWebClient)
+
+ def setup() {
+ mockRequestBody.uri(_,_) >> mockRequestBody
+ mockRequestBody.headers(_) >> mockRequestBody
+ mockRequestBody.body(_) >> mockRequestBody
+ mockRequestBody.retrieve() >> mockResponse
+ }
+
+ def 'DMI POST Operation with JSON for DMI Data Service '() {
+ given: 'the Data web client returns a valid response entity for the expected parameters'
+ mockDataServicesWebClient.post() >> mockRequestBody
+ mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Data service', HttpStatus.I_AM_A_TEAPOT))
+ when: 'POST operation is invoked fro Data Service'
+ def response = objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
+ then: 'the output of the method is equal to the output from the test template'
+ assert response.statusCode == HttpStatus.I_AM_A_TEAPOT
+ assert response.body == 'from Data service'
+ }
+
+ def 'DMI POST Operation with JSON for DMI Model Service '() {
+ given: 'the Model web client returns a valid response entity for the expected parameters'
+ mockModelServicesWebClient.post() >> mockRequestBody
+ mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Model service', HttpStatus.I_AM_A_TEAPOT))
+ when: 'POST operation is invoked for Model Service'
+ def response = objectUnderTest.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
+ then: 'the output of the method is equal to the output from the test template'
+ assert response.statusCode == HttpStatus.I_AM_A_TEAPOT
+ assert response.body == 'from Model service'
+ }
+
+ def 'Dmi service sends client error response when #scenario'() {
+ given: 'the web client unable to return response entity but error'
+ mockDataServicesWebClient.post() >> mockRequestBody
+ mockResponse.toEntity(Object.class) >> Mono.error(exceptionType)
+ when: 'POST operation is invoked'
+ objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER)
+ then: 'a http client exception is thrown'
+ def thrown = thrown(DmiClientRequestException)
+ and: 'the exception has the relevant details from the error response'
+ assert thrown.ncmpResponseStatus == expectedNcmpResponseStatusCode
+ assert thrown.httpStatusCode == httpStatusCode
+ where: 'the following errors occur'
+ scenario | httpStatusCode | exceptionType || expectedNcmpResponseStatusCode
+ 'dmi service unavailable' | 503 | new WebClientRequestException(new RuntimeException('some-error'), null, null, new HttpHeaders()) || DMI_SERVICE_NOT_RESPONDING
+ 'dmi request timeout' | 408 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || DMI_SERVICE_NOT_RESPONDING
+ 'dmi server error' | 500 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || UNABLE_TO_READ_RESOURCE_DATA
+ 'dmi service unavailable' | 503 | new HttpServerErrorException(HttpStatusCode.valueOf(503)) || DMI_SERVICE_NOT_RESPONDING
+ 'unknown error' | 500 | new Throwable('message') || UNKNOWN_ERROR
+ }
+
+ def 'Dmi trust level is determined by spring boot health status'() {
+ given: 'a health check response'
+ def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json')
+ def jsonNode = jsonObjectMapper.convertJsonString(dmiPluginHealthCheckResponseJsonData, JsonNode.class)
+ ((ObjectNode) jsonNode).put('status', 'my status')
+ mockHealthChecksWebClient.get() >> mockRequestBody
+ mockResponse.onStatus(_,_)>> mockResponse
+ mockResponse.bodyToMono(JsonNode.class) >> Mono.just(jsonNode)
+ when: 'get trust level of the dmi plugin'
+ def urlTemplateParameters = new UrlTemplateParameters('some url', [:])
+ def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block()
+ then: 'the status value from the json is returned'
+ assert result == 'my status'
+ }
+
+ def 'Failing to get dmi plugin health status #scenario'() {
+ given: 'web client instance with #scenario'
+ mockHealthChecksWebClient.get() >> mockRequestBody
+ mockResponse.onStatus(_, _) >> mockResponse
+ mockResponse.bodyToMono(_) >> Mono.error(exceptionType)
+ when: 'attempt to get health status of the dmi plugin'
+ def urlTemplateParameters = new UrlTemplateParameters('some url', [:])
+ def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block()
+ then: 'result will be empty'
+ assert result == ''
+ where: 'the following responses are used'
+ scenario | exceptionType
+ 'dmi request timeout' | new WebClientResponseException('some-message', 408, 'some-text', null, null, null)
+ 'dmi service unavailable' | new HttpServerErrorException(HttpStatus.SERVICE_UNAVAILABLE)
+ }
+
+ def 'DMI auth header #scenario'() {
+ when: 'Specific dmi properties are provided'
+ mockDmiProperties.dmiBasicAuthEnabled >> authEnabled
+ mockDmiProperties.authUsername >> 'some user'
+ mockDmiProperties.authPassword >> 'some password'
+ then: 'http headers to conditionally have Authorization header'
+ def httpHeaders = new HttpHeaders()
+ objectUnderTest.configureHttpHeaders(httpHeaders, ncmpAuthHeader)
+ def outputAuthHeader = (httpHeaders.Authorization == null ? null : httpHeaders.Authorization[0])
+ assert outputAuthHeader == expectedAuthHeader
+ where: 'the following configurations are used'
+ scenario | authEnabled | ncmpAuthHeader || expectedAuthHeader
+ 'DMI basic auth enabled, no NCMP bearer token' | true | NO_AUTH_HEADER || BASIC_AUTH_HEADER
+ 'DMI basic auth enabled, with NCMP bearer token' | true | BEARER_AUTH_HEADER || BASIC_AUTH_HEADER
+ 'DMI basic auth disabled, no NCMP bearer token' | false | NO_AUTH_HEADER || NO_AUTH_HEADER
+ 'DMI basic auth disabled, with NCMP bearer token' | false | BEARER_AUTH_HEADER || BEARER_AUTH_HEADER
+ 'DMI basic auth disabled, with NCMP basic auth' | false | BASIC_AUTH_HEADER || NO_AUTH_HEADER
+ }
+
+ def 'DMI GET Operation for DMI Data Service '() {
+ given: 'the Data web client returns a valid response entity for the expected parameters'
+ mockDataServicesWebClient.get() >> mockRequestBody
+ def jsonNode = jsonObjectMapper.convertJsonString('{"status":"some status"}', JsonNode.class)
+ ((ObjectNode) jsonNode).put('status', 'some status')
+ mockResponse.bodyToMono(JsonNode.class) >> Mono.just(jsonNode)
+ when: 'GET operation is invoked for Data Service'
+ def response = objectUnderTest.getDataJobStatus(urlTemplateParameters, NO_AUTH_HEADER).block()
+ then: 'the response equals to the expected value'
+ assert response == 'some status'
+ }
+
+ def 'Get data job result from DMI.'() {
+ given: 'the Data web client returns a valid response entity for the expected parameters'
+ mockDataServicesWebClient.get() >> mockRequestBody
+ def result = 'some result'
+ mockResponse.bodyToMono(String.class) >> Mono.just(result)
+ when: 'GET operation is invoked for Data Service'
+ def response = objectUnderTest.getDataJobResult(urlTemplateParameters, NO_AUTH_HEADER).block()
+ then: 'the response has some value'
+ assert response != null
+ assert result == 'some result'
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfigurationSpec.groovy
new file mode 100644
index 0000000000..cb209beef0
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientsConfigurationSpec.groovy
@@ -0,0 +1,70 @@
+/*-
+ * ============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.impl.dmi
+
+
+import org.onap.cps.ncmp.config.DmiHttpClientConfig
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ContextConfiguration
+import org.springframework.web.reactive.function.client.WebClient
+import spock.lang.Specification
+
+@SpringBootTest
+@ContextConfiguration(classes = [DmiHttpClientConfig])
+@EnableConfigurationProperties
+class DmiWebClientsConfigurationSpec extends Specification {
+
+ def webClientBuilder = Mock(WebClient.Builder) {
+ defaultHeaders(_) >> it
+ clientConnector(_) >> it
+ codecs(_) >> it
+ build() >> Mock(WebClient)
+ }
+
+ def dmiHttpClientConfiguration = Spy(DmiHttpClientConfig.class)
+
+ def objectUnderTest = new DmiWebClientsConfiguration(dmiHttpClientConfiguration)
+
+ def 'Web client for data services.'() {
+ when: 'creating a web client for dmi data services'
+ def result = objectUnderTest.dataServicesWebClient(webClientBuilder)
+ then: 'a web client is created successfully'
+ assert result != null
+ assert result instanceof WebClient
+ }
+
+ def 'Web client model services.'() {
+ when: 'creating a web client for dmi model services'
+ def result = objectUnderTest.modelServicesWebClient(webClientBuilder)
+ then: 'a web client is created successfully'
+ assert result != null
+ assert result instanceof WebClient
+ }
+
+ def 'Web client health check services.'() {
+ when: 'creating a web client for dmi health check services'
+ def result = objectUnderTest.healthChecksWebClient(webClientBuilder)
+ then: 'a web client is created successfully'
+ assert result != null
+ assert result instanceof WebClient
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/AlternateIdCheckerSpec.groovy
index 1e843676be..b976ff4284 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/AlternateIdCheckerSpec.groovy
@@ -18,81 +18,47 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils
+package org.onap.cps.ncmp.impl.inventory
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.model.DataNode
-import org.onap.cps.spi.model.DataNodeBuilder
import spock.lang.Specification
class AlternateIdCheckerSpec extends Specification {
def mockInventoryPersistenceService = Mock(InventoryPersistence)
- def someDataNode = new DataNodeBuilder().build()
- def dataNodeFoundException = new DataNodeNotFoundException('', '')
def objectUnderTest = new AlternateIdChecker(mockInventoryPersistenceService)
- def 'Check new cm handle with new alternate id.'() {
- given: 'inventory persistence can not find cm handle id'
- mockInventoryPersistenceService.getYangModelCmHandle('ch 1') >> {throw dataNodeFoundException}
- and: 'inventory persistence can not find alternate id'
- mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId('alternate id') >> {throw dataNodeFoundException}
- expect: 'mapping can be added'
- assert objectUnderTest.canApplyAlternateId('ch 1', 'alternate id')
- }
-
- def 'Check new cm handle with used alternate id.'() {
- given: 'inventory persistence can not find cm handle id'
- mockInventoryPersistenceService.getYangModelCmHandle('ch 1') >> {throw dataNodeFoundException}
- and: 'inventory persistence can find alternate id'
- mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId('alternate id') >> { someDataNode }
- expect: 'mapping can not be added'
- assert objectUnderTest.canApplyAlternateId('ch 1', 'alternate id') == false
- }
-
- def 'Check for existing cm handle with #currentAlternateId.'() {
- given: 'a cm handle with the #currentAlternateId'
- def yangModelCmHandle = new YangModelCmHandle(alternateId: currentAlternateId)
- and: 'inventory service finds the cm handle'
- mockInventoryPersistenceService.getYangModelCmHandle('my cm handle') >> yangModelCmHandle
- expect: 'add mapping returns expected result'
- assert canAdd == objectUnderTest.canApplyAlternateId('my cm handle', 'same alternate id')
- where: 'following alternate ids is used'
- currentAlternateId || canAdd
- 'same alternate id' || true
- 'other alternate id' || false
- }
-
def 'Check a batch of created cm handles with #scenario.'() {
- given: 'a batch of 2 new cm handles alternate id ids #alt1 and #alt2'
+ given: 'a batch of 2 new cm handles with alternate ids #alt1 and #alt2'
def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: alt1),
new NcmpServiceCmHandle(cmHandleId: 'ch-2', alternateId: alt2)]
and: 'the database already contains cm handle(s) with these alternate ids: #altAlreadyInDb'
- mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >>
- { args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() }
+ mockInventoryPersistenceService.getCmHandleDataNodesByAlternateIds(_ as Collection<String>) >>
+ { args -> args[0].stream().filter(altId -> altAlreadyInDb.contains(altId)).map(altId -> new DataNode(leaves: ["alternate-id": altId])).toList() }
when: 'the batch of new cm handles is checked'
def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.CREATE)
then: 'the result contains ids of the rejected cm handles'
assert result == expectedRejectedCmHandleIds
where: 'the following alternate ids are used'
- scenario | alt1 | alt2 | altAlreadyInDb || expectedRejectedCmHandleIds
- 'blank alternate ids' | '' | '' | ['dont matter'] || []
- 'null alternate ids' | null | null | ['dont matter'] || []
- 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || []
- 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || ['ch-1']
- 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || ['ch-2']
+ scenario | alt1 | alt2 | altAlreadyInDb || expectedRejectedCmHandleIds
+ 'blank alternate ids' | '' | '' | ['dont matter'] || []
+ 'null alternate ids' | null | null | ['dont matter'] || []
+ 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || []
+ 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || ['ch-1']
+ 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1', 'fdn2'] || ['ch-1', 'ch-2']
+ 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || ['ch-2']
}
def 'Check a batch of updates to existing cm handles with #scenario.'() {
- given: 'a batch of 1 existing cm handle update alternate id to #proposedAlt'
+ given: 'a batch of 1 existing cm handle to update alternate id to #proposedAlt'
def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: proposedAlt)]
and: 'the database already contains a cm handle with alternate id: #altAlreadyInDb'
- mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >>
- { args -> altAlreadyInDb.equals(args[0]) ? new DataNode() : throwDataNodeNotFoundException() }
+ mockInventoryPersistenceService.getCmHandleDataNodesByAlternateIds(_ as Collection<String>) >>
+ { args -> args[0].stream().filter(altId -> altAlreadyInDb == altId).map(altId -> new DataNode(leaves: ["alternate-id": altId])).toList() }
mockInventoryPersistenceService.getYangModelCmHandle(_) >> new YangModelCmHandle(alternateId: altAlreadyInDb)
when: 'the batch of cm handle updates is checked'
def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.UPDATE)
@@ -105,9 +71,20 @@ class AlternateIdCheckerSpec extends Specification {
'used different alternate id' | 'otherFdn' | 'fdn1' || ['ch-1']
}
- def throwDataNodeNotFoundException() {
- // cannot 'return' an exception in conditional stub behavior, so hence a method call that will always throw this exception
- throw dataNodeFoundException
+ def 'Check update of non-existing cm handle.'() {
+ given: 'a batch of 1 non-existing cm handle to update alternate id'
+ def batch = [new NcmpServiceCmHandle(cmHandleId: 'non-existing', alternateId: 'altId')]
+ and: 'the database does not contain any cm handles'
+ mockInventoryPersistenceService.getCmHandleDataNodesByAlternateIds(_) >> []
+ mockInventoryPersistenceService.getYangModelCmHandle(_) >> { throwDataNodeNotFoundException() }
+ when: 'the batch of cm handle updates is checked'
+ def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.UPDATE)
+ then: 'the result has no rejected cm handles'
+ assert result.empty
+ }
+
+ static throwDataNodeNotFoundException() {
+ throw new DataNodeNotFoundException('', '')
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/RestQueryParametersValidatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryParametersValidatorSpec.groovy
index dc471e64fa..15526a0c86 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/RestQueryParametersValidatorSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryParametersValidatorSpec.groovy
@@ -18,21 +18,20 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils
+package org.onap.cps.ncmp.impl.inventory
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.ConditionProperties
import spock.lang.Specification
-class RestQueryParametersValidatorSpec extends Specification {
-
+class CmHandleQueryParametersValidatorSpec extends Specification {
def 'CM Handle Query validation: empty query.'() {
given: 'a cm handle query'
def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
when: 'validator is invoked'
- RestQueryParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters, [])
+ CmHandleQueryParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters, [])
then: 'data validation exception is not thrown'
noExceptionThrown()
}
@@ -45,7 +44,7 @@ class RestQueryParametersValidatorSpec extends Specification {
condition.conditionParameters = [['key':'value']]
cmHandleQueryParameters.cmHandleQueryParameters = [condition]
when: 'validator is invoked'
- RestQueryParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters, ['validConditionName'])
+ CmHandleQueryParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters, ['validConditionName'])
then: 'data validation exception is not thrown'
noExceptionThrown()
}
@@ -58,17 +57,17 @@ class RestQueryParametersValidatorSpec extends Specification {
condition.conditionParameters = conditionParameters
cmHandleQueryParameters.cmHandleQueryParameters = [condition]
when: 'validator is invoked'
- RestQueryParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters, ['validConditionName'])
+ CmHandleQueryParametersValidator.validateCmHandleQueryParameters(cmHandleQueryParameters, ['validConditionName'])
then: 'a data validation exception is thrown'
def thrown = thrown(DataValidationException)
and: 'the exception details contain the correct significant term '
- thrown.details.contains(expectedWordInDetails)
+ assert thrown.details.contains(expectedWordInDetails)
where:
scenario | conditionName | conditionParameters || expectedWordInDetails
'unknown condition name' | 'unknownCondition' | [['key': 'value']] || 'conditionName'
'no condition name' | '' | [['key': 'value']] || 'conditionName'
+ 'empty conditions' | 'validConditionName' | [] || 'conditionsParameters'
'empty properties' | 'validConditionName' | [[:]] || 'conditionsParameter'
- 'empty conditions' | 'validConditionName' | [[:]] || 'conditionsParameter'
'too many properties' | 'validConditionName' | [[key1: 'value1', key2: 'value2']] || 'conditionsParameter'
'empty key' | 'validConditionName' | [['': 'wrong']] || 'conditionsParameter'
}
@@ -77,14 +76,14 @@ class RestQueryParametersValidatorSpec extends Specification {
given: 'a condition property'
def conditionProperty = [moduleName: 'value']
when: 'validator is invoked'
- RestQueryParametersValidator.validateModuleNameConditionProperties(conditionProperty)
+ CmHandleQueryParametersValidator.validateModuleNameConditionProperties(conditionProperty)
then: 'data validation exception is not thrown'
noExceptionThrown()
}
def 'CM Handle Query validation: validate module name condition properties - #scenario.'() {
when: 'validator is invoked'
- RestQueryParametersValidator.validateModuleNameConditionProperties(conditionProperty)
+ CmHandleQueryParametersValidator.validateModuleNameConditionProperties(conditionProperty)
then: 'a data validation exception is thrown'
thrown(DataValidationException)
where:
@@ -95,7 +94,7 @@ class RestQueryParametersValidatorSpec extends Specification {
def 'Validate CmHandle where an exception is thrown due to #scenario.'() {
when: 'the validator is called on a cps path condition property'
- RestQueryParametersValidator.validateCpsPathConditionProperties(conditionProperty)
+ CmHandleQueryParametersValidator.validateCpsPathConditionProperties(conditionProperty)
then: 'a data validation exception is thrown'
def e = thrown(DataValidationException)
and: 'exception message matches the expected message'
@@ -109,12 +108,12 @@ class RestQueryParametersValidatorSpec extends Specification {
def 'No conditions.'() {
expect: 'no conditions always returns true'
- RestQueryParametersValidator.validateCpsPathConditionProperties([:]) == true
+ CmHandleQueryParametersValidator.validateCpsPathConditionProperties([:]) == true
}
def 'Validate CmHandle where #scenario.'() {
when: 'the validator is called on a cps path condition property'
- def result = RestQueryParametersValidator.validateCpsPathConditionProperties(['cpsPath':cpsPath])
+ def result = CmHandleQueryParametersValidator.validateCpsPathConditionProperties(['cpsPath':cpsPath])
then: 'the expected boolean value is returned'
result == expectedBoolean
where:
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy
index 2f9d264947..7e34fe2822 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy
@@ -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");
@@ -19,23 +19,27 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory
+package org.onap.cps.ncmp.impl.inventory
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.spi.utils.CpsValidator
-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.NCMP_DMI_REGISTRY_PARENT
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.api.CpsDataService
+import org.onap.cps.api.CpsQueryService
+import org.onap.cps.impl.utils.CpsValidator
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
import org.onap.cps.spi.model.DataNode
import spock.lang.Shared
import spock.lang.Specification
-class CmHandleQueriesImplSpec extends Specification {
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
- def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
+class CmHandleQueryServiceImplSpec extends Specification {
+
+ def mockCpsQueryService = Mock(CpsQueryService)
+ def mockCpsDataService = Mock(CpsDataService)
def trustLevelPerDmiPlugin = [:]
@@ -43,7 +47,7 @@ class CmHandleQueriesImplSpec extends Specification {
def mockCpsValidator = Mock(CpsValidator)
- def objectUnderTest = new CmHandleQueriesImpl(mockCpsDataPersistenceService, trustLevelPerDmiPlugin, trustLevelPerCmHandle, mockCpsValidator)
+ def objectUnderTest = new CmHandleQueryServiceImpl(mockCpsDataService, mockCpsQueryService, trustLevelPerDmiPlugin, trustLevelPerCmHandle, mockCpsValidator)
@Shared
def static sampleDataNodes = [new DataNode()]
@@ -102,7 +106,7 @@ class CmHandleQueriesImplSpec extends Specification {
def 'Query CmHandles by a private field\'s value.'() {
given: 'a data node exists with a certain additional-property'
- mockCpsDataPersistenceService.queryDataNodes(_, _, dataNodeWithPrivateField, _) >> [pnfDemo5]
+ mockCpsQueryService.queryDataNodes(_, _, dataNodeWithPrivateField, _) >> [pnfDemo5]
when: 'a query on CmHandle private properties is executed using a map'
def result = objectUnderTest.queryCmHandleAdditionalProperties(['Contact3': 'newemailforstore3@bookstore.com'])
then: 'one cm handle is returned'
@@ -113,7 +117,7 @@ class CmHandleQueriesImplSpec extends Specification {
given: 'a cm handle state to query'
def cmHandleState = CmHandleState.ADVISED
and: 'the persistence service returns a list of data nodes'
- mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
'//state[@cm-handle-state="ADVISED"]/ancestor::cm-handles', INCLUDE_ALL_DESCENDANTS) >> sampleDataNodes
when: 'cm handles are fetched by state'
def result = objectUnderTest.queryCmHandlesByState(cmHandleState)
@@ -125,7 +129,7 @@ class CmHandleQueriesImplSpec extends Specification {
given: 'a cm handle state to compare'
def cmHandleState = state
and: 'the persistence service returns a list of data nodes'
- mockCpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
NCMP_DMI_REGISTRY_PARENT + '/cm-handles[@id=\'some-cm-handle\']/state',
OMIT_DESCENDANTS) >> [new DataNode(leaves: ['cm-handle-state': 'READY'])]
when: 'cm handles are compared by state'
@@ -142,7 +146,7 @@ class CmHandleQueriesImplSpec extends Specification {
given: 'a cm handle state to query'
def cmHandleState = CmHandleState.READY
and: 'cps data service returns a list of data nodes'
- mockCpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
NCMP_DMI_REGISTRY_PARENT + '/cm-handles[@id=\'some-cm-handle\']/state',
OMIT_DESCENDANTS) >> [new DataNode(leaves: ['cm-handle-state': 'READY'])]
when: 'cm handles are fetched by state and id'
@@ -155,7 +159,7 @@ class CmHandleQueriesImplSpec extends Specification {
given: 'a cm handle state to query'
def cmHandleState = CmHandleState.READY
and: 'cps data service returns a list of data nodes'
- mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
'//state/datastores/operational[@sync-state="'+'UNSYNCHRONIZED'+'"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> sampleDataNodes
when: 'cm handles are fetched by the UNSYNCHRONIZED operational sync state'
def result = objectUnderTest.queryCmHandlesByOperationalSyncState(DataStoreSyncState.UNSYNCHRONIZED)
@@ -165,10 +169,10 @@ class CmHandleQueriesImplSpec extends Specification {
def 'Retrieve cm handle by cps path '() {
given: 'a cm handle state to query based on the cps path'
- def cmHandleDataNode = new DataNode(xpath: 'xpath', leaves: ['cm-handle-state': 'LOCKED'])
- def cpsPath = '//cps-path'
- and: 'cps data service returns a valid data node'
- mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ def cmHandleDataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='ch-1']", leaves: ['id': 'ch-1'])
+ def cpsPath = "//state[@cm-handle-state='LOCKED']"
+ and: 'cps data service returns a valid data node for cm handle ancestor'
+ mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
cpsPath + '/ancestor::cm-handles', INCLUDE_ALL_DESCENDANTS)
>> Arrays.asList(cmHandleDataNode)
when: 'get cm handles by cps path is invoked'
@@ -177,6 +181,20 @@ class CmHandleQueriesImplSpec extends Specification {
assert result.contains(cmHandleDataNode)
}
+ def 'Retrieve cm handle by cps path querying cm handle directly'() {
+ given: 'a cm handle to query based on the cps path'
+ def cmHandleDataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='ch-2']", leaves: ['id': 'ch-2'])
+ def cpsPath = "//cm-handles[@alternate-id='1']"
+ and: 'cps data service returns a valid data node'
+ mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ cpsPath, INCLUDE_ALL_DESCENDANTS)
+ >> Arrays.asList(cmHandleDataNode)
+ when: 'get cm handles by cps path is invoked'
+ def result = objectUnderTest.queryCmHandleAncestorsByCpsPath(cpsPath, INCLUDE_ALL_DESCENDANTS)
+ then: 'the returned result is a list of data nodes returned by cps data service'
+ assert result.contains(cmHandleDataNode)
+ }
+
def 'Get all cm handles by dmi plugin identifier'() {
given: 'the DataNodes queried for a given cpsPath are returned from the persistence service.'
mockResponses()
@@ -189,15 +207,15 @@ class CmHandleQueriesImplSpec extends Specification {
}
void mockResponses() {
- mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact\" and @value=\"newemailforstore@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo2, pnfDemo4]
- mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"wont_match\" and @value=\"wont_match\"]/ancestor::cm-handles', _) >> []
- mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"newemailforstore2@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo4]
- mockCpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"\"]/ancestor::cm-handles', _) >> []
- mockCpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"READY\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo3]
- mockCpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"LOCKED\"]/ancestor::cm-handles', _) >> [pnfDemo2, pnfDemo4]
- mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo2]
- mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo4]
- mockCpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-model-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo2, pnfDemo4]
+ mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"Contact\" and @value=\"newemailforstore@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo2, pnfDemo4]
+ mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"wont_match\" and @value=\"wont_match\"]/ancestor::cm-handles', _) >> []
+ mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"newemailforstore2@bookstore.com\"]/ancestor::cm-handles', _) >> [pnfDemo4]
+ mockCpsQueryService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"\"]/ancestor::cm-handles', _) >> []
+ mockCpsQueryService.queryDataNodes(_, _, '//state[@cm-handle-state=\"READY\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo3]
+ mockCpsQueryService.queryDataNodes(_, _, '//state[@cm-handle-state=\"LOCKED\"]/ancestor::cm-handles', _) >> [pnfDemo2, pnfDemo4]
+ mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo2]
+ mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo4]
+ mockCpsQueryService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-model-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo2, pnfDemo4]
}
def static createDataNode(dataNodeId) {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy
index 260772714a..1beab20def 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl
+package org.onap.cps.ncmp.impl.inventory
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
@@ -28,13 +28,12 @@ import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.read.ListAppender
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.api.CpsDataService
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.DataNodeBuilder
+import org.onap.cps.utils.ContentType
import org.onap.cps.utils.JsonObjectMapper
import org.slf4j.LoggerFactory
import spock.lang.Specification
@@ -42,22 +41,22 @@ import spock.lang.Specification
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND
import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
-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.models.CmHandleRegistrationResponse.Status
+import static org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse.Status
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
-class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
+class CmHandleRegistrationServicePropertyHandlerSpec extends Specification {
def mockInventoryPersistence = Mock(InventoryPersistence)
def mockCpsDataService = Mock(CpsDataService)
def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
def mockAlternateIdChecker = Mock(AlternateIdChecker)
- def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker)
+ def objectUnderTest = new CmHandleRegistrationServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker)
def logger = Spy(ListAppender<ILoggingEvent>)
void setup() {
- def setupLogger = ((Logger) LoggerFactory.getLogger(NetworkCmProxyDataServicePropertyHandler.class))
+ def setupLogger = ((Logger) LoggerFactory.getLogger(CmHandleRegistrationServicePropertyHandler.class))
setupLogger.addAppender(logger)
setupLogger.setLevel(Level.DEBUG)
logger.start()
@@ -66,7 +65,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
}
void cleanup() {
- ((Logger) LoggerFactory.getLogger(NetworkCmProxyDataServicePropertyHandler.class)).detachAndStopAllAppenders()
+ ((Logger) LoggerFactory.getLogger(CmHandleRegistrationServicePropertyHandler.class)).detachAndStopAllAppenders()
}
def static cmHandleId = 'myHandle1'
@@ -209,7 +208,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
when: 'cm handle properties is updated'
def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest)
then: 'the update is delegated to cps data service with correct parameters'
- 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >>
+ 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _, ContentType.JSON) >>
{ args ->
assert args[3].contains('alt-1')
}
@@ -241,12 +240,12 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
given: 'an existing cm handle with no data producer identifier'
DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': 'cmHandleId','data-producer-identifier': oldDataProducerIdentifier])
and: 'an update request with a new data producer identifier'
- def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dataProducerIdentifier: 'someDataProducerIdentifier')
+ def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dataProducerIdentifier: 'New Data Producer Identifier')
when: 'data producer identifier updated'
objectUnderTest.updateDataProducerIdentifier(existingCmHandleDataNode, ncmpServiceCmHandle)
then: 'the update node leaves method is invoked once'
- 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> { args ->
- assert args[3].contains('someDataProducerIdentifier')
+ 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _, ContentType.JSON) >> { args ->
+ assert args[3].contains('New Data Producer Identifier')
}
and: 'correct information is logged'
def lastLoggingEvent = logger.list[0]
@@ -258,6 +257,17 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
'blank to something' | ''
}
+ def 'Update CM Handle data producer identifier with same value'() {
+ given: 'an existing cm handle with no data producer identifier'
+ DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': 'cmHandleId','data-producer-identifier': 'same id'])
+ and: 'an update request with a new data producer identifier'
+ def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dataProducerIdentifier: 'same id')
+ when: 'data producer identifier updated'
+ objectUnderTest.updateDataProducerIdentifier(existingCmHandleDataNode, ncmpServiceCmHandle)
+ then: 'the update node leaves method is not invoked'
+ 0 * mockCpsDataService.updateNodeLeaves(*_)
+ }
+
def 'Update CM Handle data producer identifier from some data producer identifier to another data producer identifier'() {
given: 'an existing cm handle with a data producer identifier'
DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': 'cmHandleId', 'data-producer-identifier': 'someDataProducerIdentifier'])
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy
index fbfbac59e0..dcff2e9b89 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy
@@ -19,62 +19,52 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl
+package org.onap.cps.ncmp.impl.inventory
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
-
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
-import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker
-import org.onap.cps.ncmp.api.models.UpgradedCmHandles
-import com.fasterxml.jackson.databind.ObjectMapper
import com.hazelcast.map.IMap
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
-import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
-import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
-import org.onap.cps.ncmp.api.impl.exception.DmiRequestException
-import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.exceptions.DmiRequestException
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
+import org.onap.cps.ncmp.api.inventory.models.UpgradedCmHandles
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler
+import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager
import org.onap.cps.spi.exceptions.AlreadyDefinedException
+import org.onap.cps.spi.exceptions.CpsException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
-import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Specification
-class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR
+import static org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse.Status
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+
+class CmHandleRegistrationServiceSpec extends Specification {
def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')
def mockCpsModuleService = Mock(CpsModuleService)
- def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
- def mockDmiDataOperations = Mock(DmiDataOperations)
- def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler)
+ def mockNetworkCmProxyDataServicePropertyHandler = Mock(CmHandleRegistrationServicePropertyHandler)
def mockInventoryPersistence = Mock(InventoryPersistence)
- def mockCmHandleQueries = Mock(CmHandleQueries)
- def stubbedNetworkCmProxyCmHandlerQueryService = Stub(NetworkCmProxyCmHandleQueryService)
+ def mockCmHandleQueries = Mock(CmHandleQueryService)
def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
def mockCpsDataService = Mock(CpsDataService)
def mockModuleSyncStartedOnCmHandles = Mock(IMap<String, Object>)
- def trustLevelPerDmiPlugin = [:]
def mockTrustLevelManager = Mock(TrustLevelManager)
def mockAlternateIdChecker = Mock(AlternateIdChecker)
- def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations,
- mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmHandleQueries,
- stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService,
- mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockAlternateIdChecker))
+ def objectUnderTest = Spy(new CmHandleRegistrationService(
+ mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCpsDataService, mockLcmEventsCmHandleStateHandler,
+ mockModuleSyncStartedOnCmHandles, mockTrustLevelManager, mockAlternateIdChecker))
def setup() {
// always accept all cm handles
@@ -152,9 +142,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'create cm handles registration and sync modules is called with the correct plugin information'
1 * objectUnderTest.processCreatedCmHandles(dmiPluginRegistration, _)
- and: 'dmi is added to the dmi trustLevel map'
- assert trustLevelPerDmiPlugin.size() == 1
- assert trustLevelPerDmiPlugin.containsKey(expectedDmiPluginRegisteredName)
where:
scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedDmiPluginRegisteredName
'combined DMI plugin' | 'service1' | '' | '' || 'service1'
@@ -221,7 +208,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
when: 'registration is updated'
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'trustLevel is set for the created cm-handle'
- 1 * mockTrustLevelManager.handleInitialRegistrationOfTrustLevels(expectedMapping)
+ 1 * mockTrustLevelManager.registerCmHandles(expectedMapping)
where:
scenario | registrationTrustLevel || expectedMapping
'with trusted cm handle' | TrustLevel.COMPLETE || [ 'ch-1' : TrustLevel.COMPLETE ]
@@ -418,4 +405,46 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
'an unexpected exception' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed'
}
+ def 'Set Cm Handle Data Sync Enabled Flag where data sync flag is #scenario'() {
+ given: 'an existing cm handle composite state'
+ def compositeState = new CompositeState(cmHandleState: CmHandleState.READY, dataSyncEnabled: initialDataSyncEnabledFlag,
+ dataStores: CompositeState.DataStores.builder()
+ .operationalDataStore(CompositeState.Operational.builder()
+ .dataStoreSyncState(initialDataSyncState)
+ .build()).build())
+ and: 'get cm handle state returns the composite state for the given cm handle id'
+ mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
+ when: 'set data sync enabled is called with the data sync enabled flag set to #dataSyncEnabledFlag'
+ objectUnderTest.setDataSyncEnabled('some-cm-handle-id', dataSyncEnabledFlag)
+ then: 'the data sync enabled flag is set to #dataSyncEnabled'
+ compositeState.dataSyncEnabled == dataSyncEnabledFlag
+ and: 'the data store sync state is set to #expectedDataStoreSyncState'
+ compositeState.dataStores.operationalDataStore.dataStoreSyncState == expectedDataStoreSyncState
+ and: 'the cps data service to delete data nodes is invoked the expected number of times'
+ deleteDataNodeExpectedNumberOfInvocation * mockCpsDataService.deleteDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'some-cm-handle-id', '/netconf-state', _)
+ and: 'the inventory persistence service to update node leaves is called with the correct values'
+ saveCmHandleStateExpectedNumberOfInvocations * mockInventoryPersistence.saveCmHandleState('some-cm-handle-id', compositeState)
+ where: 'the following data sync enabled flag is used'
+ scenario | dataSyncEnabledFlag | initialDataSyncEnabledFlag | initialDataSyncState || expectedDataStoreSyncState | deleteDataNodeExpectedNumberOfInvocation | saveCmHandleStateExpectedNumberOfInvocations
+ 'enabled' | true | false | DataStoreSyncState.NONE_REQUESTED || DataStoreSyncState.UNSYNCHRONIZED | 0 | 1
+ 'disabled' | false | true | DataStoreSyncState.UNSYNCHRONIZED || DataStoreSyncState.NONE_REQUESTED | 0 | 1
+ 'disabled where sync-state is currently SYNCHRONIZED' | false | true | DataStoreSyncState.SYNCHRONIZED || DataStoreSyncState.NONE_REQUESTED | 1 | 1
+ 'is set to existing flag state' | true | true | DataStoreSyncState.UNSYNCHRONIZED || DataStoreSyncState.UNSYNCHRONIZED | 0 | 0
+ }
+
+ def 'Set cm Handle Data Sync Enabled flag with following cm handle not in ready state exception' () {
+ given: 'a cm handle composite state'
+ def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, dataSyncEnabled: false)
+ and: 'get cm handle state returns the composite state for the given cm handle id'
+ mockInventoryPersistence.getCmHandleState('some-cm-handle-id') >> compositeState
+ when: 'set data sync enabled is called with the data sync enabled flag set to true'
+ objectUnderTest.setDataSyncEnabled('some-cm-handle-id', true)
+ then: 'the expected exception is thrown'
+ thrown(CpsException)
+ and: 'the inventory persistence service to update node leaves is not invoked'
+ 0 * mockInventoryPersistence.saveCmHandleState(_, _)
+ }
+
+
+
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
index 9907e9ab21..1830f1331d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,36 +20,39 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory
-
-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.NCMP_DMI_REGISTRY_PARENT
-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.NO_TIMESTAMP
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+package org.onap.cps.ncmp.impl.inventory
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.impl.utils.CpsValidator
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.FetchDescendantsOption
-import org.onap.cps.ncmp.api.impl.exception.NoAlternateIdParentFoundException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
-import org.onap.cps.spi.utils.CpsValidator
+import org.onap.cps.utils.ContentType
import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Shared
import spock.lang.Specification
+
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NO_TIMESTAMP
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
class InventoryPersistenceImplSpec extends Specification {
def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
@@ -62,7 +65,7 @@ class InventoryPersistenceImplSpec extends Specification {
def mockCpsValidator = Mock(CpsValidator)
- def mockCmHandleQueries = Mock(CmHandleQueries)
+ def mockCmHandleQueries = Mock(CmHandleQueryService)
def objectUnderTest = new InventoryPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService, mockCpsModuleService,
mockCpsValidator, mockCpsAnchorService, mockCmHandleQueries)
@@ -164,7 +167,7 @@ class InventoryPersistenceImplSpec extends Specification {
when: 'update cm handle state is invoked with the #scenario state'
objectUnderTest.saveCmHandleState(cmHandleId, compositeState)
then: 'update node leaves is invoked with the correct params'
- 1 * mockCpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime)
+ 1 * mockCpsDataService.updateDataNodeAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime, ContentType.JSON)
where: 'the following states are used'
scenario | cmHandleState || expectedJsonData
'READY' | CmHandleState.READY || '{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
@@ -180,7 +183,7 @@ class InventoryPersistenceImplSpec extends Specification {
def cmHandleStateMap = ['Some-Cm-Handle1' : compositeState1, 'Some-Cm-Handle2' : compositeState2]
objectUnderTest.saveCmHandleStateBatch(cmHandleStateMap)
then: 'update node leaves is invoked with the correct params'
- 1 * mockCpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandlesJsonDataMap, _ as OffsetDateTime)
+ 1 * mockCpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandlesJsonDataMap, _ as OffsetDateTime, ContentType.JSON)
where: 'the following states are used'
scenario | cmHandleState || cmHandlesJsonDataMap
'READY' | CmHandleState.READY || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
@@ -229,7 +232,7 @@ class InventoryPersistenceImplSpec extends Specification {
objectUnderTest.saveCmHandle(yangModelCmHandle)
then: 'the data service method to save list elements is called once'
1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
- _,null) >> {
+ _,null, ContentType.JSON) >> {
args -> {
assert args[3].startsWith('{"cm-handles":[{"id":"cmhandle","additional-properties":[],"public-properties":[]}]}')
}
@@ -244,7 +247,7 @@ class InventoryPersistenceImplSpec extends Specification {
objectUnderTest.saveCmHandleBatch([yangModelCmHandle1, yangModelCmHandle2])
then: 'CPS Data Service persists both cm handles as a batch'
1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- NCMP_DMI_REGISTRY_PARENT, _,null) >> {
+ NCMP_DMI_REGISTRY_PARENT, _,null, ContentType.JSON) >> {
args -> {
def jsonData = (args[3] as String)
jsonData.contains('cmhandle1')
@@ -294,7 +297,7 @@ class InventoryPersistenceImplSpec extends Specification {
1 * mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, expectedXPath, INCLUDE_ALL_DESCENDANTS)
}
- def 'Get cm handle data node'() {
+ def 'Get cm handle data node by alternate id'() {
given: 'expected xPath to get cmHandle data node'
def expectedXPath = '/dmi-registry/cm-handles[@alternate-id=\'alternate id\']'
and: 'query service is invoked with expected xpath'
@@ -303,41 +306,6 @@ class InventoryPersistenceImplSpec extends Specification {
assert objectUnderTest.getCmHandleDataNodeByAlternateId('alternate id') == new DataNode()
}
- def 'Find cm handle parent data node using alternate ids'() {
- given: 'cm handle in the registry with alternateId /a/b'
- def matchingCpsPath = "/dmi-registry/cm-handles[@alternate-id='/a/b']"
- mockCmHandleQueries.queryNcmpRegistryByCpsPath(matchingCpsPath, OMIT_DESCENDANTS) >> [new DataNode()]
- and: 'no other cm handle'
- mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
- expect: 'querying for alternate id a matching result found'
- assert objectUnderTest.getCmHandleDataNodeByLongestMatchAlternateId(alternateId, '/') != null
- where: 'the following parameters are used'
- scenario | alternateId
- 'exact match' | '/a/b'
- 'exact match with trailing separator' | '/a/b/'
- 'child match' | '/a/b/c'
- }
-
- def 'Find cm handle parent data node using alternate ids mismatches'() {
- given: 'cm handle in the registry with alternateId'
- def matchingCpsPath = "/dmi-registry/cm-handles[@alternate-id='${cpsPath}]"
- mockCmHandleQueries.queryNcmpRegistryByCpsPath(matchingCpsPath, OMIT_DESCENDANTS) >> [new DataNode()]
- and: 'no other cm handle'
- mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
- when: 'attempt to find alternateId'
- objectUnderTest.getCmHandleDataNodeByLongestMatchAlternateId(alternateId, '/')
- then: 'no alternate id found exception thrown'
- def thrown = thrown(NoAlternateIdParentFoundException)
- and: 'the exception has the relevant details from the error response'
- assert thrown.message == 'No matching (parent) cm handle found using alternate ids'
- assert thrown.details == 'cannot find a datanode with alternate id ' + alternateId
- where: 'the following parameters are used'
- scenario | alternateId | cpsPath
- 'no match for parent only' | '/a' | '/a/b'
- 'no match at all' | '/x/y/z' | '/a/b'
- 'no match with trailing separator' | '/c/d/' | '/c/d'
- }
-
def 'Attempt to get non existing cm handle data node by alternate id'() {
given: 'query service is invoked and returns empty collection of data nodes'
mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> []
@@ -348,6 +316,22 @@ class InventoryPersistenceImplSpec extends Specification {
assert thrownException.getMessage().contains('DataNode not found')
}
+ def 'Get multiple cm handle data nodes by alternate ids'() {
+ given: 'expected xPath to get cmHandle data node'
+ def expectedXPath = "/dmi-registry/cm-handles[@alternate-id='A' or @alternate-id='B']"
+ when: 'getting the cm handle data node'
+ objectUnderTest.getCmHandleDataNodesByAlternateIds(['A', 'B'])
+ then: 'query service is invoked with expected xpath'
+ 1 * mockCmHandleQueries.queryNcmpRegistryByCpsPath(expectedXPath, OMIT_DESCENDANTS)
+ }
+
+ def 'Get multiple cm handle data nodes by alternate ids, passing empty collection'() {
+ when: 'getting the cm handle data node for no alternate ids'
+ objectUnderTest.getCmHandleDataNodesByAlternateIds([])
+ then: 'query service is not invoked'
+ 0 * mockCmHandleQueries.queryNcmpRegistryByCpsPath(_, _)
+ }
+
def 'Get CM handles that has given module names'() {
when: 'the method to get cm handles is called'
objectUnderTest.getCmHandleIdsWithGivenModules(['sample-module-name'])
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
new file mode 100644
index 0000000000..9e07de48bf
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
@@ -0,0 +1,274 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2021 Pantheon.tech
+ * Modifications Copyright (C) 2021-2022 Bell Canada
+ * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * ================================================================================
+ * 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.impl.inventory
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.api.inventory.models.ConditionApiProperties
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
+import org.onap.cps.spi.model.ConditionProperties
+import org.onap.cps.utils.JsonObjectMapper
+import spock.lang.Specification
+
+class NetworkCmProxyInventoryFacadeSpec extends Specification {
+
+ def mockCmHandleRegistrationService = Mock(CmHandleRegistrationService)
+ def mockCmHandleQueryService = Mock(CmHandleQueryService)
+ def mockParameterizedCmHandleQueryService = Mock(ParameterizedCmHandleQueryService)
+ def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
+ def mockInventoryPersistence = Mock(InventoryPersistence)
+ def mockTrustLevelManager = Mock(TrustLevelManager)
+ def mockAlternateIdMatcher = Mock(AlternateIdMatcher)
+ def objectUnderTest = new NetworkCmProxyInventoryFacade(mockCmHandleRegistrationService, mockCmHandleQueryService, mockParameterizedCmHandleQueryService, mockInventoryPersistence, spiedJsonObjectMapper, mockTrustLevelManager, mockAlternateIdMatcher)
+
+ def 'Update DMI Registration'() {
+ given: 'an (updated) dmi plugin registration'
+ def dmiPluginRegistration = Mock(DmiPluginRegistration)
+ when: 'the registration is submitted '
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ then: 'the call is delegated to the cm handle registration service'
+ 1 * mockCmHandleRegistrationService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ }
+
+ def 'Execute cm handle id search for inventory'() {
+ given: 'a ConditionApiProperties object'
+ def conditionProperties = new ConditionProperties()
+ conditionProperties.conditionName = 'hasAllProperties'
+ conditionProperties.conditionParameters = [ [ 'some-key' : 'some-value' ] ]
+ def cmHandleQueryServiceParameters = new CmHandleQueryServiceParameters()
+ cmHandleQueryServiceParameters.cmHandleQueryParameters = [conditionProperties] as List<ConditionProperties>
+ and: 'the system returns an set of cmHandle ids'
+ mockParameterizedCmHandleQueryService.queryCmHandleIdsForInventory(*_) >> [ 'cmHandle1', 'cmHandle2' ]
+ when: 'executing the search'
+ def result = objectUnderTest.executeParameterizedCmHandleIdSearch(cmHandleQueryServiceParameters)
+ then: 'the result returns the correct 2 elements'
+ assert result.size() == 2
+ assert result.contains('cmHandle1')
+ assert result.contains('cmHandle2')
+ }
+
+ def 'Get all cm handle IDs by DMI plugin identifier.' () {
+ given: 'cm handle queries service returns cm handles'
+ 1 * mockCmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier') >> ['cm-handle-1','cm-handle-2']
+ when: 'cm handle Ids are requested with dmi plugin identifier'
+ def result = objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier('some-dmi-plugin-identifier')
+ then: 'the result size is correct'
+ assert result.size() == 2
+ and: 'the result returns the correct details'
+ assert result.containsAll('cm-handle-1','cm-handle-2')
+ }
+
+ def 'Getting Yang Resources for a given #scenario'() {
+ when: 'yang resources is called'
+ objectUnderTest.getYangResourcesModuleReferences(cmHandleRef)
+ then: 'alternate id matcher is called'
+ mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
+ and: 'CPS module services is invoked for the correct cm handle'
+ 1 * mockInventoryPersistence.getYangResourcesModuleReferences('some-cm-handle')
+ where: 'following cm handle reference is used'
+ scenario | cmHandleRef
+ 'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
+ 'Cm Handle Reference as alternate-id' | 'some-alternate-id'
+ }
+
+ def 'Get a cm handle details using #scenario'() {
+ given: 'the system returns a yang modelled cm handle'
+ def dmiServiceName = 'some service name'
+ def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
+ lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details('lock details').build(),
+ lastUpdateTime: 'some-timestamp',
+ dataSyncEnabled: false,
+ dataStores: dataStores())
+ def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
+ def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
+ def moduleSetTag = 'some-module-set-tag'
+ def alternateId = 'some-alternate-id'
+ def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName, dmiProperties: dmiProperties,
+ publicProperties: publicProperties, compositeState: compositeState, moduleSetTag: moduleSetTag, alternateId: alternateId)
+ mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
+ 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
+ and: 'a trust level for the cm handle in the cache'
+ mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
+ when: 'getting cm handle details for a given cm handle id from ncmp service'
+ def result = objectUnderTest.getNcmpServiceCmHandle(cmHandleRef)
+ then: 'the result is a ncmpServiceCmHandle'
+ assert result.class == NcmpServiceCmHandle.class
+ and: 'the cm handle contains the cm handle id'
+ assert result.cmHandleId == 'some-cm-handle'
+ and: 'the cm handle contains the alternate id'
+ assert result.alternateId == 'some-alternate-id'
+ and: 'the cm handle contains the module-set-tag'
+ assert result.moduleSetTag == 'some-module-set-tag'
+ and: 'the cm handle contains the DMI Properties'
+ assert result.dmiProperties ==[ Book:'Romance Novel' ]
+ and: 'the cm handle contains the public Properties'
+ assert result.publicProperties == [ "Public Book":'Public Romance Novel' ]
+ and: 'the cm handle contains the cm handle composite state'
+ assert result.compositeState == compositeState
+ and: 'the cm handle contains the trust level from the cache'
+ assert result.currentTrustLevel == TrustLevel.COMPLETE
+ where: 'following cm handle reference is used'
+ scenario | cmHandleRef
+ 'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
+ 'Cm Handle Reference as alternate-id' | 'some-alternate-id'
+ }
+
+ def 'Get cm handle public properties using #scenario'() {
+ given: 'a yang modelled cm handle'
+ def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
+ def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
+ def cmHandleId = 'some-cm-handle'
+ def alternateId = 'some-alternate-id'
+ def yangModelCmHandle = new YangModelCmHandle(id:cmHandleId, alternateId: alternateId, dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties)
+ and: 'we have corresponding cm handle for the cm handle reference'
+ 1 * mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> cmHandleId
+ and: 'the system returns this yang modelled cm handle'
+ 1 * mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
+ when: 'getting cm handle public properties for a given cm handle reference from ncmp service'
+ def result = objectUnderTest.getCmHandlePublicProperties(cmHandleRef)
+ then: 'the result returns the correct data'
+ assert result == [ 'public prop' : 'some public prop' ]
+ where: 'following cm handle reference is used'
+ scenario | cmHandleRef
+ 'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
+ 'Cm Handle Reference as alternate-id' | 'some-alternate-id'
+ }
+
+ def 'Get cm handle composite state using #scenario'() {
+ given: 'a yang modelled cm handle'
+ def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
+ lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
+ lastUpdateTime: 'some-timestamp',
+ dataSyncEnabled: false,
+ dataStores: dataStores())
+ def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')]
+ def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
+ def cmHandleId = 'some-cm-handle'
+ def alternateId = 'some-alternate-id'
+ def yangModelCmHandle = new YangModelCmHandle(id:cmHandleId, alternateId: alternateId, dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
+ and: 'we have corresponding cm handle for the cm handle reference'
+ 1 * mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> cmHandleId
+ and: 'the system returns this yang modelled cm handle'
+ 1 * mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
+ when: 'getting cm handle composite state for a given cm handle id from ncmp service'
+ def result = objectUnderTest.getCmHandleCompositeState(cmHandleRef)
+ then: 'the result returns the correct data'
+ assert result == compositeState
+ where: 'following cm handle reference is used'
+ scenario | cmHandleRef
+ 'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
+ 'Cm Handle Reference as alternate-id' | 'some-alternate-id'
+ }
+
+ def 'Execute cm handle id search'() {
+ given: 'valid CmHandleQueryApiParameters input'
+ def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
+ def conditionApiProperties = new ConditionApiProperties()
+ conditionApiProperties.conditionName = 'hasAllModules'
+ conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
+ cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
+ and: 'query cm handle method return with a data node list'
+ mockParameterizedCmHandleQueryService.queryCmHandleIds(
+ spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
+ >> ['cm-handle-id-1']
+ when: 'execute cm handle search is called'
+ def result = objectUnderTest.executeCmHandleIdSearch(cmHandleQueryApiParameters)
+ then: 'result is the same collection as returned by the CPS Data Service'
+ assert result == ['cm-handle-id-1']
+ }
+
+ def 'Getting module definitions by module for a given #scenario'() {
+ when: 'get module definitions is performed with module name and cm handle reference'
+ objectUnderTest.getModuleDefinitionsByCmHandleAndModule(cmHandleRef, 'some-module', '2021-08-04')
+ then: 'alternate id matcher returns some cm handle id for a given cm handle reference'
+ mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
+ and: 'ncmp inventory persistence service is invoked once with correct parameters'
+ 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
+ where: 'following cm handle reference is used'
+ scenario | cmHandleRef
+ 'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
+ 'Cm Handle Reference as alternate-id' | 'some-alternate-id'
+ }
+
+ def 'Getting module definitions for a given #scenario'() {
+ when: 'get module definitions is performed with cm handle reference'
+ objectUnderTest.getModuleDefinitionsByCmHandleReference(cmHandleRef)
+ then: 'alternate id matcher returns some cm handle id for a given cm handle reference'
+ mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> 'some-cm-handle'
+ then: 'ncmp inventory persistence service is invoked once with correct parameter'
+ 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
+ where: 'following cm handle reference is used'
+ scenario | cmHandleRef
+ 'Cm Handle Reference as cm handle-id' | 'some-cm-handle'
+ 'Cm Handle Reference as alternate-id' | 'some-alternate-id'
+ }
+
+ def 'Execute cm handle search'() {
+ given: 'valid CmHandleQueryApiParameters input'
+ def cmHandleQueryApiParameters = new CmHandleQueryApiParameters()
+ def conditionApiProperties = new ConditionApiProperties()
+ conditionApiProperties.conditionName = 'hasAllModules'
+ conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']]
+ cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties]
+ and: 'query cm handle method returns two cm handles'
+ mockParameterizedCmHandleQueryService.queryCmHandles(
+ spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
+ >> [new YangModelCmHandle(id: 'ch-0', dmiProperties: [], publicProperties: []),
+ new YangModelCmHandle(id: 'ch-1', dmiProperties: [], publicProperties: [])]
+ and: 'a trust level for cm handles'
+ mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
+ when: 'execute cm handle search is called'
+ def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters)
+ then: 'result consists of the two cm handles returned by the CPS Data Service'
+ assert result.size() == 2
+ assert result[0].cmHandleId == 'ch-0'
+ assert result[1].cmHandleId == 'ch-1'
+ and: 'cm handles have trust level'
+ assert result[0].currentTrustLevel == TrustLevel.COMPLETE
+ assert result[1].currentTrustLevel == TrustLevel.COMPLETE
+ }
+
+ def 'Set Cm Handle Data Sync flag.'() {
+ when: 'setting data sync enabled flag'
+ objectUnderTest.setDataSyncEnabled('ch-1',true)
+ then: 'call is delegated to the cm handle registration service'
+ mockCmHandleRegistrationService.setDataSyncEnabled('ch-1', true)
+ }
+
+ def dataStores() {
+ CompositeState.DataStores.builder().operationalDataStore(CompositeState.Operational.builder()
+ .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED)
+ .lastSyncTime('some-timestamp').build()).build()
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy
index 7c410cc58a..08644202c6 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-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.
@@ -18,17 +18,11 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+package org.onap.cps.ncmp.impl.inventory
import org.onap.cps.cpspath.parser.PathParsingException
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueriesImpl
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.exceptions.DataInUseException
import org.onap.cps.spi.exceptions.DataValidationException
@@ -36,16 +30,18 @@ import org.onap.cps.spi.model.ConditionProperties
import org.onap.cps.spi.model.DataNode
import spock.lang.Specification
-class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+
+class ParameterizedCmHandleQueryServiceSpec extends Specification {
- def cmHandleQueries = Mock(CmHandleQueries)
- def partiallyMockedCmHandleQueries = Spy(CmHandleQueries)
+ def cmHandleQueries = Mock(CmHandleQueryService)
+ def partiallyMockedCmHandleQueries = Spy(CmHandleQueryService)
def mockInventoryPersistence = Mock(InventoryPersistence)
def dmiRegistry = new DataNode(xpath: NCMP_DMI_REGISTRY_PARENT, childDataNodes: createDataNodeList(['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4']))
- def objectUnderTest = new NetworkCmProxyCmHandleQueryServiceImpl(cmHandleQueries, mockInventoryPersistence)
- def objectUnderTestWithPartiallyMockedQueries = new NetworkCmProxyCmHandleQueryServiceImpl(partiallyMockedCmHandleQueries, mockInventoryPersistence)
+ def objectUnderTest = new ParameterizedCmHandleQueryServiceImpl(cmHandleQueries, mockInventoryPersistence)
+ def objectUnderTestWithPartiallyMockedQueries = new ParameterizedCmHandleQueryServiceImpl(partiallyMockedCmHandleQueries, mockInventoryPersistence)
def 'Query cm handle ids with cpsPath.'() {
given: 'a cmHandleWithCpsPath condition property'
@@ -60,6 +56,19 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
assert result == ['some-cmhandle-id'] as Set
}
+ def 'Query cm handle where cps path itself is ancestor axis.'() {
+ given: 'a cmHandleWithCpsPath condition property'
+ def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
+ def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
+ cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
+ and: 'the query get the cm handle data nodes excluding all descendants returns a datanode'
+ cmHandleQueries.queryCmHandleAncestorsByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(leaves: ['id':'some-cmhandle-id'])]
+ when: 'the query is executed for cm handle ids'
+ def result = objectUnderTest.queryCmHandleIdsForInventory(cmHandleQueryParameters)
+ then: 'the correct expected cm handles ids are returned'
+ assert result == ['some-cmhandle-id'] as Set
+ }
+
def 'Cm handle ids query with error: #scenario.'() {
given: 'a cmHandleWithCpsPath condition property'
def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
@@ -129,10 +138,10 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
and: 'the inventory service is called with teh correct if and returns a yang model cm handle'
1 * mockInventoryPersistence.getYangModelCmHandles(['ch1']) >>
[new YangModelCmHandle(id: 'abc', dmiProperties: [new YangModelCmHandle.Property('name','value')], publicProperties: [])]
- and: 'the expected cm handle(s) are returned as NCMP Service cm handles'
- assert result[0] instanceof NcmpServiceCmHandle
+ and: 'the expected cm handle(s) are returned as Yang Model cm handles'
+ assert result[0] instanceof YangModelCmHandle
assert result.size() == 1
- assert result[0].dmiProperties == [name:'value']
+ assert result[0].dmiProperties.size() == 1
}
def 'Query cm handle ids when the query is empty.'() {
@@ -155,7 +164,7 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
def result = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
then: 'the correct cm handles are returned'
assert result.size() == 4
- assert result.cmHandleId.containsAll('PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4')
+ assert result.id.containsAll('PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4')
}
def 'Query CMHandleId with #scenario.' () {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditionsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditionsSpec.groovy
index 100705ff57..26541de64b 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/CmHandleQueryConditionsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/CmHandleQueryConditionsSpec.groovy
@@ -18,7 +18,8 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils
+package org.onap.cps.ncmp.impl.inventory.models
+
import spock.lang.Specification
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/InventoryQueryConditionsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/InventoryQueryConditionsSpec.groovy
index 00edb8d0da..2e7122268f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/InventoryQueryConditionsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/InventoryQueryConditionsSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START========================================================
- * Copyright (c) 2022 Nordix Foundation.
+ * Copyright (c) 2022-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.
@@ -18,19 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils
+package org.onap.cps.ncmp.impl.inventory.models
import spock.lang.Specification
class InventoryQueryConditionsSpec extends Specification {
def 'Inventory query condition names.'() {
- expect: '3 conditions with the correct names'
- assert InventoryQueryConditions.ALL_CONDITION_NAMES.size() == 3
+ expect: '4 conditions with the correct names'
+ assert InventoryQueryConditions.ALL_CONDITION_NAMES.size() == 4
assert InventoryQueryConditions.ALL_CONDITION_NAMES.containsAll('hasAllProperties',
'hasAllAdditionalProperties',
- 'cmHandleWithDmiPlugin')
+ 'cmHandleWithDmiPlugin',
+ 'cmHandleWithCpsPath')
}
-
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandleSpec.groovy
index cfc6ffda19..4908379a4e 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/models/YangModelCmHandleSpec.groovy
@@ -18,18 +18,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.yangmodels
+package org.onap.cps.ncmp.impl.inventory.models
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
import spock.lang.Specification
-import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA
-import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.MODEL
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL
class YangModelCmHandleSpec extends Specification {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/executor/AsyncTaskExecutorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/AsyncTaskExecutorSpec.groovy
index 64ecafefc7..751c97a4d0 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/executor/AsyncTaskExecutorSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/AsyncTaskExecutorSpec.groovy
@@ -18,12 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync.executor
+package org.onap.cps.ncmp.impl.inventory.sync
+
-import org.onap.cps.ncmp.api.impl.inventory.sync.executor.AsyncTaskExecutor
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification
+
import java.util.concurrent.TimeoutException
import java.util.function.Supplier
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/DataSyncWatchdogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DataSyncWatchdogSpec.groovy
index 0ffb567916..2ee5226dc2 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/DataSyncWatchdogSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DataSyncWatchdogSpec.groovy
@@ -18,19 +18,19 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+package org.onap.cps.ncmp.impl.inventory.sync
import com.hazelcast.map.IMap
import org.onap.cps.api.CpsDataService
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import spock.lang.Specification
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+
class DataSyncWatchdogSpec extends Specification {
def mockInventoryPersistence = Mock(InventoryPersistence)
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/impl/inventory/sync/DmiModelOperationsSpec.groovy
index ae9c1749e5..c80aa7b242 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/impl/inventory/sync/DmiModelOperationsSpec.groovy
@@ -19,11 +19,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations
+package org.onap.cps.ncmp.impl.inventory.sync
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
+import org.onap.cps.ncmp.impl.dmi.DmiOperationsBaseSpec
+import org.onap.cps.ncmp.impl.dmi.DmiProperties
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
@@ -34,12 +36,16 @@ import org.springframework.http.ResponseEntity
import org.springframework.test.context.ContextConfiguration
import spock.lang.Shared
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ
+import static org.onap.cps.ncmp.api.data.models.OperationType.READ
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL
@SpringBootTest
-@ContextConfiguration(classes = [DmiWebClientConfiguration.DmiProperties, DmiModelOperations])
+@ContextConfiguration(classes = [DmiProperties, DmiModelOperations])
class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
+ def expectedModulesUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/modules', ['cmHandleId': cmHandleId])
+ def expectedModuleResourcesUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/moduleResources', ['cmHandleId': cmHandleId])
+
@Shared
def newModuleReferences = [new ModuleReference('mod1','A'), new ModuleReference('mod2','X')]
@@ -56,10 +62,8 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
mockYangModelCmHandleRetrieval([])
and: 'a positive response from DMI service when it is called with the expected parameters'
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":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER)
- >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
then: 'the result consists of expected module references'
@@ -72,7 +76,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
and: 'any response from DMI service when it is called with the expected parameters'
// TODO (toine): production code ignores any error code from DMI, this should be improved in future
def responseFromDmi = new ResponseEntity(bodyAsMap, HttpStatus.NO_CONTENT)
- mockDmiRestClient.postOperationWithJsonData(*_) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi
when: 'get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
then: 'the result is empty'
@@ -90,7 +94,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
mockYangModelCmHandleRetrieval(dmiProperties)
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",
+ mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables,
'{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'a get module references is called'
def result = objectUnderTest.getModuleReferences(yangModelCmHandle)
@@ -109,7 +113,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
def responseFromDmi = new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'],
[moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK)
def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
- mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+ mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
'{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
@@ -125,7 +129,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
and: 'a positive response from DMI service when it is called with tha expected parameters'
// TODO (toine): production code ignores any error code from DMI, this should be improved in future
def responseFromDmi = new ResponseEntity(responseFromDmiBody, HttpStatus.NO_CONTENT)
- mockDmiRestClient.postOperationWithJsonData(*_) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
then: 'the result is empty'
@@ -141,7 +145,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
mockYangModelCmHandleRetrieval(dmiProperties)
and: 'a positive response from DMI service when it is called with the expected moduleSetTag, modules and properties'
def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
- mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
+ mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
'{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}',
READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
@@ -159,17 +163,17 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
mockYangModelCmHandleRetrieval([], moduleSetTag)
and: 'a positive response from DMI service when it is called with the expected moduleSetTag'
def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
- mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
- '{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}',
- READ, NO_AUTH_HEADER) >> responseFromDmi
+ mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables,
+ '{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi
when: 'get new yang resources from DMI service'
def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences)
then: 'the result is the response from DMI service'
assert result == [mod1:'some yang source']
where: 'the following Module Set Tags are used'
- scenario | moduleSetTag || expectedModuleSetTagInRequest
- 'Without module set tag' | '' || ''
- 'With module set tag' | 'moduleSetTag1' || '"moduleSetTag":"moduleSetTag1",'
+ scenario | moduleSetTag || expectedModuleSetTagInRequest
+ 'Without module set tag' | '' || ''
+ 'With module set tag' | 'moduleSetTag1' || '"moduleSetTag":"moduleSetTag1",'
+ 'Special characters in module set tag' | 'module:set#tag$2' || '"moduleSetTag":"module:set#tag$2",'
}
def 'Retrieving yang resources from DMI with no module references.'() {
@@ -180,7 +184,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
then: 'no resources are returned'
assert result == [:]
and: 'no request is sent to DMI'
- 0 * mockDmiRestClient.postOperationWithJsonData(*_)
+ 0 * mockDmiRestClient.synchronousPostOperationWithJsonData(*_)
}
def 'Retrieving yang resources from DMI with null DMI properties.'() {
@@ -204,5 +208,4 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec {
and: 'the message indicates a parsing error'
exceptionThrown.message.toLowerCase().contains('parsing error')
}
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
index 44bc182000..65b7ff6d6f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
@@ -19,40 +19,36 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync
-
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.LOCKED_MISBEHAVING
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_SYNC_FAILED
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE_FAILED
+package org.onap.cps.ncmp.impl.inventory.sync
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.core.read.ListAppender
-import org.slf4j.LoggerFactory
-import org.springframework.context.annotation.AnnotationConfigApplicationContext
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder
+import org.onap.cps.ncmp.impl.data.DmiDataOperations
+import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.model.DataNode
import org.onap.cps.utils.JsonObjectMapper
+import org.slf4j.LoggerFactory
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import spock.lang.Specification
-import java.time.OffsetDateTime
-import java.time.format.DateTimeFormatter
import java.util.stream.Collectors
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE_FAILED
+
class ModuleOperationsUtilsSpec extends Specification{
- def mockCmHandleQueries = Mock(CmHandleQueries)
+ def mockCmHandleQueries = Mock(CmHandleQueryService)
def mockDmiDataOperations = Mock(DmiDataOperations)
@@ -60,17 +56,12 @@ class ModuleOperationsUtilsSpec extends Specification{
def objectUnderTest = new ModuleOperationsUtils(mockCmHandleQueries, mockDmiDataOperations, jsonObjectMapper)
- def static neverUpdatedBefore = '1900-01-01T00:00:00.000+0100'
-
- def static now = OffsetDateTime.now()
-
- def static nowAsString = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(now)
-
def static dataNode = new DataNode(leaves: ['id': 'cm-handle-123'])
def applicationContext = new AnnotationConfigApplicationContext()
def logger = (Logger) LoggerFactory.getLogger(ModuleOperationsUtils)
+
def loggingListAppender
void setup() {
@@ -103,7 +94,7 @@ class ModuleOperationsUtilsSpec extends Specification{
given: 'A locked state'
def compositeState = new CompositeState(lockReason: lockReason)
when: 'update cm handle details and attempts is called'
- objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, MODULE_SYNC_FAILED, 'new error message')
+ objectUnderTest.updateLockReasonWithAttempts(compositeState, MODULE_SYNC_FAILED, 'new error message')
then: 'the composite state lock reason and details are updated'
assert compositeState.lockReason.lockReasonCategory == MODULE_SYNC_FAILED
assert compositeState.lockReason.details.contains(expectedDetails)
@@ -118,14 +109,14 @@ class ModuleOperationsUtilsSpec extends Specification{
def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED)
.withLockReason(MODULE_UPGRADE, "Upgrade to ModuleSetTag: " + moduleSetTag).build()
when: 'update cm handle details'
- objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, MODULE_UPGRADE_FAILED, 'new error message')
+ objectUnderTest.updateLockReasonWithAttempts(compositeState, MODULE_UPGRADE_FAILED, 'new error message')
then: 'the composite state lock reason and details are updated'
assert compositeState.lockReason.lockReasonCategory == MODULE_UPGRADE_FAILED
- assert compositeState.lockReason.details.contains("Upgrade to ModuleSetTag: " + expectedDetails)
+ assert compositeState.lockReason.details.contains(expectedDetails)
where:
scenario | moduleSetTag || expectedDetails
- 'a module set tag' | 'someModuleSetTag' || 'someModuleSetTag'
- 'empty module set tag' | '' || ''
+ 'a module set tag' | 'someModuleSetTag' || 'Upgrade to ModuleSetTag: someModuleSetTag'
+ 'empty module set tag' | '' || 'Attempt'
}
def 'Get all locked cm-Handles where lock reasons are model sync failed or upgrade'() {
@@ -135,49 +126,9 @@ class ModuleOperationsUtilsSpec extends Specification{
when: 'get locked Misbehaving cm handle is called'
def result = objectUnderTest.getCmHandlesThatFailedModelSyncOrUpgrade()
then: 'the returned cm handle collection is the correct size'
- result.size() == 1
+ assert result.size() == 1
and: 'the correct cm handle is returned'
- result[0].id == 'cm-handle-123'
- }
-
- def 'Retry Locked Cm-Handle where the last update time is #scenario'() {
- given: 'Last update was #lastUpdateMinutesAgo minutes ago (-1 means never)'
- def lastUpdatedTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(now.minusMinutes(lastUpdateMinutesAgo))
- if (lastUpdateMinutesAgo < 0 ) {
- lastUpdatedTime = neverUpdatedBefore
- }
- when: 'checking to see if cm handle is ready for retry'
- def result = objectUnderTest.needsModuleSyncRetryOrUpgrade(new CompositeStateBuilder()
- .withLockReason(MODULE_SYNC_FAILED, lockDetails)
- .withLastUpdatedTime(lastUpdatedTime).build())
- then: 'retry is only attempted when expected'
- assert result == retryExpected
- and: 'logs contain related information'
- def logs = loggingListAppender.list.toString()
- assert logs.contains(logReason)
- where: 'the following parameters are used'
- scenario | lastUpdateMinutesAgo | lockDetails | logReason || retryExpected
- 'never attempted before' | -1 | 'Fist attempt:' | 'First Attempt:' || true
- '1st attempt, last attempt > 2 minute ago' | 3 | 'Attempt #1 failed: some error' | 'Retry due now' || true
- '2nd attempt, last attempt < 4 minutes ago' | 1 | 'Attempt #2 failed: some error' | 'Time until next attempt is 3 minutes:' || false
- '2nd attempt, last attempt > 4 minutes ago' | 5 | 'Attempt #2 failed: some error' | 'Retry due now' || true
- }
-
- def 'Retry Locked Cm-Handle with lock reasons (category) #lockReasonCategory'() {
- when: 'checking to see if cm handle is ready for retry'
- def result = objectUnderTest.needsModuleSyncRetryOrUpgrade(new CompositeStateBuilder()
- .withLockReason(lockReasonCategory, 'some details')
- .withLastUpdatedTime(nowAsString).build())
- then: 'verify retry attempts'
- assert !result
- and: 'logs contain related information'
- def logs = loggingListAppender.list.toString()
- assert logs.contains(logReason)
- where: 'the following lock reasons occurred'
- scenario | lockReasonCategory || logReason
- 'module upgrade' | MODULE_UPGRADE_FAILED || 'First Attempt:'
- 'module sync failed' | MODULE_SYNC_FAILED || 'First Attempt:'
- 'lock misbehaving' | LOCKED_MISBEHAVING || 'Locked for other reason'
+ assert result[0].id == 'cm-handle-123'
}
def 'Get a Cm-Handle where #scenario'() {
@@ -197,19 +148,25 @@ class ModuleOperationsUtilsSpec extends Specification{
'all Cm-Handle synchronized' | [] | false || 0 | [] as Set
}
- def 'Get resource data through DMI Operations #scenario'() {
- given: 'the inventory persistence service returns a collection of data nodes'
+ def 'Retrieve resource data from DMI operations for #scenario'() {
+ given: 'a JSON string representing the resource data'
def jsonString = '{"stores:bookstore":{"categories":[{"code":"01"}]}}'
- JsonNode jsonNode = jsonObjectMapper.convertToJsonNode(jsonString);
- def responseEntity = new ResponseEntity<>(jsonNode, HttpStatus.OK)
- mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.datastoreName, 'cm-handle-123', _) >> responseEntity
+ JsonNode jsonNode = jsonObjectMapper.convertToJsonNode(jsonString)
+ and: 'DMI operations are mocked to return a response based on the scenario'
+ def responseEntity = new ResponseEntity<>(statusCode == HttpStatus.OK ? jsonNode : null, statusCode)
+ mockDmiDataOperations.getAllResourceDataFromDmi('cm-handle-123', _) >> responseEntity
when: 'get resource data is called'
def result = objectUnderTest.getResourceData('cm-handle-123')
- then: 'the returned data is correct'
- result == jsonString
+ then: 'the returned data matches the expected result'
+ assert result == expectedResult
+ where:
+ scenario | statusCode | expectedResult
+ 'successful response' | HttpStatus.OK | '{"stores:bookstore":{"categories":[{"code":"01"}]}}'
+ 'response with not found status' | HttpStatus.NOT_FOUND | null
+ 'response with internal server error' | HttpStatus.INTERNAL_SERVER_ERROR | null
}
- def 'Extract module set tag and number of attempt when lock reason contains #scenario'() {
+ def 'Extract module set tag and number of attempt when lock reason contains #scenario'() {
expect: 'lock reason details are extracted correctly'
def result = objectUnderTest.getLockedCompositeStateDetails(new CompositeStateBuilder().withLockReason(MODULE_UPGRADE, lockReasonDetails).build().lockReason)
and: 'the result contains the correct moduleSetTag'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy
index cb933fafbe..6030e5debf 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy
@@ -18,46 +18,38 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync
+package org.onap.cps.ncmp.impl.inventory.sync
import org.onap.cps.api.CpsAnchorService
-
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE
-
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.spi.model.DataNode
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
-import org.onap.cps.spi.model.DataNodeBuilder
-import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Specification
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE
+
class ModuleSyncServiceSpec extends Specification {
def mockCpsModuleService = Mock(CpsModuleService)
def mockDmiModelOperations = Mock(DmiModelOperations)
def mockCpsAnchorService = Mock(CpsAnchorService)
- def mockCmHandleQueries = Mock(CmHandleQueries)
+ def mockCmHandleQueries = Mock(CmHandleQueryService)
def mockCpsDataService = Mock(CpsDataService)
def mockJsonObjectMapper = Mock(JsonObjectMapper)
def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService,
- mockCmHandleQueries, mockCpsDataService, mockCpsAnchorService, mockJsonObjectMapper)
+ mockCpsDataService, mockCpsAnchorService, mockJsonObjectMapper)
def expectedDataspaceName = NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
- def static cmHandleWithModuleSetTag = new DataNodeBuilder()
- .withXpath("/dmi-registry/cm-handles[@id='otherId']")
- .withLeaves(['id': 'otherId', 'module-set-tag': 'tag-1'])
- .withAnchor('otherId').build()
def 'Sync model for a NEW cm handle using module set tags: #scenario.'() {
given: 'a cm handle state to be synced'
@@ -72,8 +64,8 @@ class ModuleSyncServiceSpec extends Specification {
mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, identifiedNewModuleReferences) >> newModuleNameContentToMap
and: 'the module service identifies #identifiedNewModuleReferences.size() new modules'
mockCpsModuleService.identifyNewModuleReferences(moduleReferences) >> identifiedNewModuleReferences
- and: 'system contains other cm handle with "same tag" (that is READY)'
- mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> existingCmHandlesWithSameTag
+ and: 'the service returns a list of module references when queried with the specified attributes'
+ mockCpsModuleService.getModuleReferencesByAttribute(*_) >> existingModuleReferences
when: 'module sync is triggered'
objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle)
then: 'create schema set from module is invoked with correct parameters'
@@ -81,10 +73,10 @@ class ModuleSyncServiceSpec extends Specification {
and: 'anchor is created with the correct parameters'
1 * mockCpsAnchorService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'ch-1', 'ch-1')
where: 'the following parameters are used'
- scenario | existingModuleResourcesInCps | identifiedNewModuleReferences | newModuleNameContentToMap | moduleSetTag | existingCmHandlesWithSameTag
- 'one new module, new tag' | [['module2': '2'], ['module3': '3']] | [new ModuleReference('module1', '1')] | [module1: 'some yang source'] | '' | []
- 'no new module, new tag' | [['module1': '1'], ['module2': '2']] | [] | [:] | 'new-tag-1' | []
- 'same tag' | [['module1': '1'], ['module2': '2']] | [] | [:] | 'same-tag' | [cmHandleWithModuleSetTag]
+ scenario | identifiedNewModuleReferences | newModuleNameContentToMap | moduleSetTag | existingModuleReferences
+ 'one new module, new tag' | [new ModuleReference('module1', '1')] | [module1: 'some yang source'] | '' | []
+ 'no new module, new tag' | [] | [:] | 'new-tag-1' | []
+ 'same tag' | [] | [:] | 'same-tag' | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')]
}
def 'Upgrade model for an existing cm handle with Module Set Tag where the modules are #scenario'() {
@@ -103,8 +95,8 @@ class ModuleSyncServiceSpec extends Specification {
mockCpsModuleService.identifyNewModuleReferences(_) >> []
and: 'CPS-Core returns list of existing module resources for TBD'
mockCpsModuleService.getYangResourcesModuleReferences(*_) >> [ new ModuleReference('module1','1') ]
- and: 'system contains #existingCmHandlesWithSameTag.size() cm handles with same tag'
- mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> existingCmHandlesWithSameTag
+ and: 'the service returns a list of module references when queried with the specified attributes'
+ mockCpsModuleService.getModuleReferencesByAttribute(*_) >> existingModuleReferences
and: 'the other cm handle is a state ready'
mockCmHandleQueries.cmHandleHasState('otherId', CmHandleState.READY) >> true
when: 'module sync is triggered'
@@ -116,9 +108,9 @@ class ModuleSyncServiceSpec extends Specification {
and: 'No anchor is created for the upgraded cm handle'
0 * mockCpsAnchorService.createAnchor(*_)
where: 'the following parameters are used'
- scenario | existingCmHandlesWithSameTag
+ scenario | existingModuleReferences
'new' | []
- 'in database' | [cmHandleWithModuleSetTag]
+ 'in database' | [new ModuleReference('module1', '1')]
}
def 'upgrade model for a existing cm handle'() {
@@ -132,9 +124,8 @@ class ModuleSyncServiceSpec extends Specification {
and: 'the module service returns some module references'
def moduleReferences = [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')]
mockCpsModuleService.getYangResourcesModuleReferences(*_)>> moduleReferences
- and: 'a cm handle with the same moduleSetTag can be found in the registry'
- mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> [new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'cmHandleId-1\']', leaves: ['id': 'cmHandleId-1'],
- childDataNodes: [new DataNode(xpath: '/dmi-registry/cm-handles[@id=\'cmHandleId-1\']/state', leaves: ['cm-handle-state': 'READY'])])]
+ and: 'the service returns a list of module references when queried with the specified attributes'
+ mockCpsModuleService.getModuleReferencesByAttribute(*_) >> moduleReferences
when: 'module upgrade is triggered'
objectUnderTest.syncAndUpgradeSchemaSet(yangModelCmHandle)
then: 'the upgrade is delegated to the module service (with the correct parameters)'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasksSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
index 6c0d6dfb87..160744a7d7 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasksSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
@@ -19,10 +19,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync
-
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_SYNC_FAILED
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE_FAILED
+package org.onap.cps.ncmp.impl.inventory.sync
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
@@ -31,18 +28,21 @@ import ch.qos.logback.core.read.ListAppender
import com.hazelcast.config.Config
import com.hazelcast.instance.impl.HazelcastInstanceFactory
import com.hazelcast.map.IMap
-import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler
import org.onap.cps.spi.model.DataNode
import org.slf4j.LoggerFactory
import spock.lang.Specification
import java.util.concurrent.atomic.AtomicInteger
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE_FAILED
+
class ModuleSyncTasksSpec extends Specification {
def logger = Spy(ListAppender<ILoggingEvent>)
@@ -95,70 +95,52 @@ class ModuleSyncTasksSpec extends Specification {
assert batchCount.get() == 4
}
- def 'Module Sync ADVISED cm handle with failure during sync.'() {
- given: 'a cm handle in an ADVISED state'
- def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.ADVISED)
- and: 'the inventory persistence cm handle returns a ADVISED state for the cm handle'
- def cmHandleState = new CompositeState(cmHandleState: CmHandleState.ADVISED)
- 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> cmHandleState
- and: 'module sync service attempts to sync the cm handle and throws an exception'
- 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
+ def 'Handle CM handle failure during #scenario and log MODULE_UPGRADE lock reason'() {
+ given: 'a CM handle in LOCKED state with a specific lock reason'
+ def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.LOCKED)
+ def expectedCmHandleState = new CompositeState(cmHandleState: CmHandleState.LOCKED, lockReason: CompositeState
+ .LockReason.builder().lockReasonCategory(lockReasonCategory).details(lockReasonDetails).build())
+ 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> expectedCmHandleState
+ and: 'module sync service attempts to sync/upgrade the CM handle and throws an exception'
+ mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { throw new Exception('some exception') }
+ mockModuleSyncService.syncAndUpgradeSchemaSet(_) >> { throw new Exception('some exception') }
when: 'module sync is executed'
objectUnderTest.performModuleSync([cmHandle], batchCount)
- then: 'update lock reason, details and attempts is invoked'
- 1 * mockSyncUtils.updateLockReasonDetailsAndAttempts(cmHandleState, MODULE_SYNC_FAILED, 'some exception')
+ then: 'lock reason is updated with number of attempts'
+ 1 * mockSyncUtils.updateLockReasonWithAttempts(expectedCmHandleState, expectedLockReasonCategory, 'some exception')
and: 'the state handler is called to update the state to LOCKED'
1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> { args ->
assertBatch(args, ['cm-handle'], CmHandleState.LOCKED)
}
and: 'batch count is decremented by one'
assert batchCount.get() == 4
- }
-
- def 'Failed cm handle during #scenario.'() {
- given: 'a cm handle in LOCKED state'
- def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.LOCKED)
- and: 'the inventory persistence cm handle returns a LOCKED state with reason for the cm handle'
- def expectedCmHandleState = new CompositeState(cmHandleState: cmHandleState, lockReason: CompositeState
- .LockReason.builder().lockReasonCategory(lockReasonCategory).details(lockReasonDetails).build())
- 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> expectedCmHandleState
- and: 'module sync service attempts to sync/upgrade the cm handle and throws an exception'
- mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
- mockModuleSyncService.syncAndUpgradeSchemaSet(*_) >> { throw new Exception('some exception') }
- when: 'module sync is executed'
- objectUnderTest.performModuleSync([cmHandle], batchCount)
- then: 'update lock reason, details and attempts is invoked'
- 1 * mockSyncUtils.updateLockReasonDetailsAndAttempts(expectedCmHandleState, expectedLockReasonCategory, 'some exception')
where:
- scenario | cmHandleState | lockReasonCategory | lockReasonDetails || expectedLockReasonCategory
- 'module upgrade' | CmHandleState.LOCKED | MODULE_UPGRADE_FAILED | 'Upgrade to ModuleSetTag: some-module-set-tag' || MODULE_UPGRADE_FAILED
- 'module sync' | CmHandleState.LOCKED | MODULE_SYNC_FAILED | 'some lock details' || MODULE_SYNC_FAILED
+ scenario | lockReasonCategory | lockReasonDetails || expectedLockReasonCategory
+ 'module sync' | MODULE_SYNC_FAILED | 'some lock details' || MODULE_SYNC_FAILED
+ 'module upgrade' | MODULE_UPGRADE_FAILED | 'Upgrade to ModuleSetTag: some-module-set-tag' || MODULE_UPGRADE_FAILED
+ 'module upgrade' | MODULE_UPGRADE | 'Upgrade in progress' || MODULE_UPGRADE_FAILED
}
+
def 'Reset failed CM Handles #scenario.'() {
given: 'cm handles in an locked state'
def lockedState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED)
- .withLockReason(LockReasonCategory.MODULE_SYNC_FAILED, '').withLastUpdatedTimeNow().build()
+ .withLockReason(MODULE_SYNC_FAILED, '').withLastUpdatedTimeNow().build()
def yangModelCmHandle1 = new YangModelCmHandle(id: 'cm-handle-1', compositeState: lockedState)
def yangModelCmHandle2 = new YangModelCmHandle(id: 'cm-handle-2', compositeState: lockedState)
- def expectedCmHandleStatePerCmHandle = [(yangModelCmHandle1): CmHandleState.ADVISED]
+ def expectedCmHandleStatePerCmHandle
+ = [(yangModelCmHandle1): CmHandleState.ADVISED, (yangModelCmHandle2): CmHandleState.ADVISED]
and: 'clear in progress map'
resetModuleSyncStartedOnCmHandles(moduleSyncStartedOnCmHandles)
and: 'add cm handle entry into progress map'
moduleSyncStartedOnCmHandles.put('cm-handle-1', 'started')
moduleSyncStartedOnCmHandles.put('cm-handle-2', 'started')
- and: 'sync utils retry locked cm handle returns #isReadyForRetry'
- mockSyncUtils.needsModuleSyncRetryOrUpgrade(lockedState) >>> isReadyForRetry
when: 'resetting failed cm handles'
objectUnderTest.resetFailedCmHandles([yangModelCmHandle1, yangModelCmHandle2])
then: 'updated to state "ADVISED" from "READY" is called as often as there are cm handles ready for retry'
- expectedNumberOfInvocationsToUpdateCmHandleState * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(expectedCmHandleStatePerCmHandle)
- and: 'after reset performed size of in progress map'
- assert moduleSyncStartedOnCmHandles.size() == inProgressMapSize
- where:
- scenario | isReadyForRetry | inProgressMapSize || expectedNumberOfInvocationsToUpdateCmHandleState
- 'retry locked cm handle' | [true, false] | 1 || 1
- 'do not retry locked cm handle' | [false, false] | 2 || 0
+ 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(expectedCmHandleStatePerCmHandle)
+ and: 'after reset performed progress map is empty'
+ assert moduleSyncStartedOnCmHandles.size() == 0
}
def 'Module Sync ADVISED cm handle without entry in progress map.'() {
@@ -188,6 +170,24 @@ class ModuleSyncTasksSpec extends Specification {
assert loggingEvent.formattedMessage == 'ch-1 removed from in progress map'
}
+ def 'Sync and upgrade CM handle if in upgrade state for #scenario'() {
+ given: 'a CM handle in an upgrade state'
+ def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.LOCKED)
+ def compositeState = new CompositeState(lockReason: CompositeState.LockReason.builder().lockReasonCategory(lockReasonCategory).build())
+ 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> compositeState
+ when: 'module sync is executed'
+ objectUnderTest.performModuleSync([cmHandle], batchCount)
+ then: 'the module sync service should attempt to sync and upgrade the CM handle'
+ 1 * mockModuleSyncService.syncAndUpgradeSchemaSet(_) >> { args ->
+ assert args[0].id == 'cm-handle'
+ }
+ where: 'the following lock reasons are used'
+ scenario | lockReasonCategory
+ 'module upgrade' | MODULE_UPGRADE
+ 'module upgrade failed' | MODULE_UPGRADE_FAILED
+ }
+
+
def 'Remove non-existing cm handle id from hazelcast map'() {
given: 'hazelcast map does not contains cm handle id'
def result = moduleSyncStartedOnCmHandles.get('non-existing-cm-handle')
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy
index 1752a17a19..155edc8bc6 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy
@@ -19,15 +19,15 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync
+package org.onap.cps.ncmp.impl.inventory.sync
import com.hazelcast.map.IMap
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.sync.executor.AsyncTaskExecutor
-import java.util.concurrent.ArrayBlockingQueue
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.spi.model.DataNode
import spock.lang.Specification
+import java.util.concurrent.ArrayBlockingQueue
+
class ModuleSyncWatchdogSpec extends Specification {
def mockSyncUtils = Mock(ModuleOperationsUtils)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfigSpec.groovy
index 6d09df0d44..8e59922c41 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfigSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.embeddedcache
+package org.onap.cps.ncmp.impl.inventory.sync
import com.hazelcast.config.Config
import com.hazelcast.core.Hazelcast
@@ -29,6 +29,7 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
import spock.util.concurrent.PollingConditions
+
import java.util.concurrent.BlockingQueue
import java.util.concurrent.TimeUnit
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/config/WatchdogSchedulingConfigurerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/WatchdogSchedulingConfigurerSpec.groovy
index f37d5a41eb..a943962e96 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/config/WatchdogSchedulingConfigurerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/WatchdogSchedulingConfigurerSpec.groovy
@@ -18,7 +18,8 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.inventory.sync.config
+package org.onap.cps.ncmp.impl.inventory.sync
+
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy
index 3ae95209f2..bd7c321bc7 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy
@@ -18,21 +18,21 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm
-
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.ADVISED
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETED
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETING
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.LOCKED
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.READY
-import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_SYNC_FAILED
-
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
+package org.onap.cps.ncmp.impl.inventory.sync.lcm
+
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import spock.lang.Specification
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETED
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETING
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.LOCKED
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED
+
class LcmEventsCmHandleStateHandlerImplSpec extends Specification {
def mockInventoryPersistence = Mock(InventoryPersistence)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy
index bef2963cff..e0a552ea99 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreatorSpec.groovy
@@ -18,19 +18,19 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm
-
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.ADVISED
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETING
-import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.READY
+package org.onap.cps.ncmp.impl.inventory.sync.lcm
import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.CompositeState
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.models.CompositeState
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.events.lcm.v1.Values
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
import spock.lang.Specification
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.DELETING
+import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.READY
+
class LcmEventsCreatorSpec extends Specification {
LcmEventHeaderMapper lcmEventsHeaderMapper = Mappers.getMapper(LcmEventHeaderMapper)
@@ -190,4 +190,4 @@ class LcmEventsCreatorSpec extends Specification {
'blank target and existing values' | '' | '' | '' | '' | '' | ''
'new target value and blank existing values' | '' | 'someAlternateId' | '' | 'someAlternateId' | '' | 'someDataProducerIdentifier'
}
-} \ No newline at end of file
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy
index e2bdc5d1f6..3e7ed9aff6 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsPublisherSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy
@@ -18,16 +18,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm
+package org.onap.cps.ncmp.impl.inventory.sync.lcm
import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.kafka.clients.consumer.KafkaConsumer
import org.apache.kafka.common.serialization.StringDeserializer
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
import org.onap.cps.ncmp.events.lcm.v1.Event
import org.onap.cps.ncmp.events.lcm.v1.LcmEvent
import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.ncmp.utils.events.MessagingBaseSpec
import org.onap.cps.utils.JsonObjectMapper
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy
index 0b6b5a7b9f..73c66089a3 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsServiceSpec.groovy
@@ -18,11 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.lcm
+package org.onap.cps.ncmp.impl.inventory.sync.lcm
+import static org.onap.cps.ncmp.events.lcm.v1.Values.CmHandleState.ADVISED
+import static org.onap.cps.ncmp.events.lcm.v1.Values.CmHandleState.READY
+
+import io.micrometer.core.instrument.Tag
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry
import org.onap.cps.events.EventsPublisher
+import org.onap.cps.ncmp.events.lcm.v1.Event
import org.onap.cps.ncmp.events.lcm.v1.LcmEvent
import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader
+import org.onap.cps.ncmp.events.lcm.v1.Values
import org.onap.cps.utils.JsonObjectMapper
import org.springframework.kafka.KafkaException
import spock.lang.Specification
@@ -31,14 +38,16 @@ class LcmEventsServiceSpec extends Specification {
def mockLcmEventsPublisher = Mock(EventsPublisher)
def mockJsonObjectMapper = Mock(JsonObjectMapper)
+ def meterRegistry = new SimpleMeterRegistry()
- def objectUnderTest = new LcmEventsService(mockLcmEventsPublisher, mockJsonObjectMapper)
+ def objectUnderTest = new LcmEventsService(mockLcmEventsPublisher, mockJsonObjectMapper, meterRegistry)
def 'Create and Publish lcm event where events are #scenario'() {
given: 'a cm handle id, Lcm Event, and headers'
def cmHandleId = 'test-cm-handle-id'
def eventId = UUID.randomUUID().toString()
- def lcmEvent = new LcmEvent(eventId: eventId, eventCorrelationId: cmHandleId)
+ def event = getEventWithCmHandleState(ADVISED, READY)
+ def lcmEvent = new LcmEvent(event: event, eventId: eventId, eventCorrelationId: cmHandleId)
and: 'we also have a lcm event header'
def lcmEventHeader = new LcmEventHeader(eventId: eventId, eventCorrelationId: cmHandleId)
and: 'notificationsEnabled is #notificationsEnabled and it will be true as default'
@@ -57,6 +66,16 @@ class LcmEventsServiceSpec extends Specification {
assert eventHeaders.get('eventCorrelationId') == cmHandleId
}
}
+ and: 'metrics are recorded with correct tags'
+ def timer = meterRegistry.find('cps.ncmp.lcm.events.publish').timer()
+ if (notificationsEnabled) {
+ assert timer != null
+ assert timer.count() == expectedTimesMethodCalled
+ def tags = timer.getId().getTags()
+ assert tags.containsAll(Tag.of('oldCmHandleState', ADVISED.value()), Tag.of('newCmHandleState', READY.value()))
+ } else {
+ assert timer == null
+ }
where: 'the following values are used'
scenario | notificationsEnabled || expectedTimesMethodCalled
'enabled' | true || 1
@@ -67,7 +86,8 @@ class LcmEventsServiceSpec extends Specification {
given: 'a cm handle id and Lcm Event and notification enabled'
def cmHandleId = 'test-cm-handle-id'
def eventId = UUID.randomUUID().toString()
- def lcmEvent = new LcmEvent(eventId: eventId, eventCorrelationId: cmHandleId)
+ and: 'event #event'
+ def lcmEvent = new LcmEvent(event: event, eventId: eventId, eventCorrelationId: cmHandleId)
def lcmEventHeader = new LcmEventHeader(eventId: eventId, eventCorrelationId: cmHandleId)
objectUnderTest.notificationsEnabled = true
when: 'publisher set to throw an exception'
@@ -76,6 +96,35 @@ class LcmEventsServiceSpec extends Specification {
objectUnderTest.publishLcmEvent(cmHandleId, lcmEvent, lcmEventHeader)
then: 'the exception is just logged and not bubbled up'
noExceptionThrown()
+ and: 'metrics are recorded with error tags'
+ def timer = meterRegistry.find('cps.ncmp.lcm.events.publish').timer()
+ assert timer != null
+ assert timer.count() == 1
+ def expectedTags = [Tag.of('oldCmHandleState', 'N/A'), Tag.of('newCmHandleState', 'N/A')]
+ def tags = timer.getId().getTags()
+ assert tags.containsAll(expectedTags)
+ where: 'the following values are used'
+ scenario | event
+ 'without values' | new Event()
+ 'without cm handle state' | getEvent()
}
+ def getEvent() {
+ def event = new Event()
+ def values = new Values()
+ event.setOldValues(values)
+ event.setNewValues(values)
+ event
+ }
+
+ def getEventWithCmHandleState(oldCmHandleState, newCmHandleState) {
+ def event = new Event()
+ def advisedCmHandleStateValues = new Values()
+ advisedCmHandleStateValues.setCmHandleState(oldCmHandleState)
+ event.setOldValues(advisedCmHandleStateValues)
+ def readyCmHandleStateValues = new Values()
+ readyCmHandleStateValues.setCmHandleState(newCmHandleState)
+ event.setNewValues(readyCmHandleStateValues)
+ return event
+ }
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumerSpec.groovy
index 42a1c5d5ae..c7d0616bb2 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumerSpec.groovy
@@ -18,23 +18,24 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel
+package org.onap.cps.ncmp.impl.inventory.trustlevel
import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
import io.cloudevents.core.builder.CloudEventBuilder
import org.apache.kafka.clients.consumer.ConsumerRecord
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel
import org.onap.cps.utils.JsonObjectMapper
import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification
@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper])
-class DeviceHeartbeatConsumerSpec extends Specification {
+class DeviceTrustLevelMessageConsumerSpec extends Specification {
def mockTrustLevelManager = Mock(TrustLevelManager)
- def objectUnderTest = new DeviceHeartbeatConsumer(mockTrustLevelManager)
+ def objectUnderTest = new DeviceTrustLevelMessageConsumer(mockTrustLevelManager)
def objectMapper = new ObjectMapper()
def jsonObjectMapper = new JsonObjectMapper(objectMapper)
@@ -46,9 +47,9 @@ class DeviceHeartbeatConsumerSpec extends Specification {
def consumerRecord = new ConsumerRecord<String, CloudEvent>('test-device-heartbeat', 0, 0, 'sample-message-key', eventFromDmi)
consumerRecord.headers().add('ce_id', objectMapper.writeValueAsBytes('ch-1'))
when: 'the event is consumed'
- objectUnderTest.heartbeatListener(consumerRecord)
+ objectUnderTest.deviceTrustLevelListener(consumerRecord)
then: 'cm handles are stored with correct trust level'
- 1 * mockTrustLevelManager.handleUpdateOfDeviceTrustLevel('"ch-1"', TrustLevel.COMPLETE)
+ 1 * mockTrustLevelManager.updateCmHandleTrustLevel('"ch-1"', TrustLevel.COMPLETE)
}
def createTrustLevelEvent(eventPayload) {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy
index 446126be94..32f4503005 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.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.
@@ -18,36 +18,35 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel.dmiavailability
+package org.onap.cps.ncmp.impl.inventory.trustlevel
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.client.DmiRestClient
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
+import org.onap.cps.ncmp.impl.dmi.DmiRestClient
+import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters
+import reactor.core.publisher.Mono
import spock.lang.Specification
-class DmiPluginWatchDogSpec extends Specification {
+class DmiPluginTrustLevelWatchDogSpec extends Specification {
def mockDmiRestClient = Mock(DmiRestClient)
- def mockNetworkCmProxyDataService = Mock(NetworkCmProxyDataService)
+ def mockCmHandleQueryService = Mock(CmHandleQueryService)
def mockTrustLevelManager = Mock(TrustLevelManager)
def trustLevelPerDmiPlugin = [:]
- def objectUnderTest = new DmiPluginWatchDog(mockDmiRestClient,
- mockNetworkCmProxyDataService,
- mockTrustLevelManager,
- trustLevelPerDmiPlugin)
+ def objectUnderTest = new DmiPluginTrustLevelWatchDog(mockDmiRestClient, mockCmHandleQueryService, mockTrustLevelManager, trustLevelPerDmiPlugin)
def 'watch dmi plugin health status for #dmiHealhStatus'() {
given: 'the cache has been initialised and "knows" about dmi-1'
trustLevelPerDmiPlugin.put('dmi-1', dmiOldTrustLevel)
and: 'dmi client returns health status #dmiHealhStatus'
- mockDmiRestClient.getDmiHealthStatus('dmi-1') >> dmiHealhStatus
+ def urlTemplateParameters = new UrlTemplateParameters('dmi-1/actuator/health', [:])
+ mockDmiRestClient.getDmiHealthStatus(urlTemplateParameters) >> Mono.just(dmiHealhStatus)
when: 'dmi watch dog method runs'
objectUnderTest.checkDmiAvailability()
then: 'the update delegated to manager'
- numberOfCalls * mockTrustLevelManager.handleUpdateOfDmiTrustLevel('dmi-1', _, newDmiTrustLevel)
+ numberOfCalls * mockTrustLevelManager.updateDmi('dmi-1', _, newDmiTrustLevel)
where: 'the following parameters are used'
dmiHealhStatus | dmiOldTrustLevel | newDmiTrustLevel || numberOfCalls
'UP' | TrustLevel.COMPLETE | TrustLevel.COMPLETE || 0
@@ -56,5 +55,4 @@ class DmiPluginWatchDogSpec extends Specification {
'UP' | TrustLevel.NONE | TrustLevel.COMPLETE || 1
'' | TrustLevel.COMPLETE | TrustLevel.NONE || 1
}
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy
index c213ab626e..e79a471015 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy
@@ -18,11 +18,11 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.config.embeddedcache
+package org.onap.cps.ncmp.impl.inventory.trustlevel
import com.hazelcast.config.Config
import com.hazelcast.core.Hazelcast
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManagerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy
index 886648a7e9..7dc9602e46 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManagerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.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.
@@ -18,11 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.trustlevel
+package org.onap.cps.ncmp.impl.inventory.trustlevel
-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.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.TrustLevel
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher
import spock.lang.Specification
class TrustLevelManagerSpec extends Specification {
@@ -31,14 +33,23 @@ class TrustLevelManagerSpec extends Specification {
def trustLevelPerDmiPlugin = [:]
def mockInventoryPersistence = Mock(InventoryPersistence)
- def mockAttributeValueChangeEventPublisher = Mock(AvcEventPublisher)
+ def mockAttributeValueChangeEventPublisher = Mock(CmAvcEventPublisher)
def objectUnderTest = new TrustLevelManager(trustLevelPerCmHandle, trustLevelPerDmiPlugin, mockInventoryPersistence, mockAttributeValueChangeEventPublisher)
+ def 'Initial dmi registration'() {
+ given: 'a dmi plugin'
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'dmi-1')
+ when: 'method to register to the cache is called'
+ objectUnderTest.registerDmiPlugin(dmiPluginRegistration)
+ then: 'dmi plugin in the cache and trusted'
+ assert trustLevelPerDmiPlugin.get('dmi-1') == TrustLevel.COMPLETE
+ }
+
def 'Initial cm handle registration'() {
given: 'two cm handles: one with no trust level and one trusted'
def cmHandleModelsToBeCreated = ['ch-1': null, 'ch-2': TrustLevel.COMPLETE]
- when: 'the initial registration handled'
- objectUnderTest.handleInitialRegistrationOfTrustLevels(cmHandleModelsToBeCreated)
+ when: 'method to register to the cache is called'
+ objectUnderTest.registerCmHandles(cmHandleModelsToBeCreated)
then: 'no notification sent'
0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
and: 'both cm handles are in the cache and are trusted'
@@ -49,8 +60,8 @@ class TrustLevelManagerSpec extends Specification {
def 'Initial cm handle registration with a cm handle that is not trusted'() {
given: 'a not trusted cm handle'
def cmHandleModelsToBeCreated = ['ch-2': TrustLevel.NONE]
- when: 'the initial registration handled'
- objectUnderTest.handleInitialRegistrationOfTrustLevels(cmHandleModelsToBeCreated)
+ when: 'method to register to the cache is called'
+ objectUnderTest.registerCmHandles(cmHandleModelsToBeCreated)
then: 'notification is sent'
1 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
}
@@ -61,7 +72,7 @@ class TrustLevelManagerSpec extends Specification {
and: 'a trusted cm handle'
trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
when: 'the update is handled'
- objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.NONE)
+ objectUnderTest.updateDmi('my-dmi', ['ch-1'], TrustLevel.NONE)
then: 'notification is sent'
1 * mockAttributeValueChangeEventPublisher.publishAvcEvent('ch-1', 'trustLevel', 'COMPLETE', 'NONE')
and: 'the dmi in the cache is not trusted'
@@ -74,54 +85,74 @@ class TrustLevelManagerSpec extends Specification {
and: 'a trusted cm handle'
trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
when: 'the update is handled'
- objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.COMPLETE)
+ objectUnderTest.updateDmi('my-dmi', ['ch-1'], TrustLevel.COMPLETE)
then: 'no notification is sent'
0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
and: 'the dmi in the cache is trusted'
assert trustLevelPerDmiPlugin.get('my-dmi') == TrustLevel.COMPLETE
}
- def 'Device trust level updated'() {
+ def 'CmHandle trust level updated'() {
given: 'a non trusted cm handle'
trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE)
and: 'a trusted dmi plugin'
trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE)
and: 'inventory persistence service returns yang model cm handle'
mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(id: 'ch-1', dmiDataServiceName: 'my-dmi')
- when: 'update of device to COMPLETE trust level handled'
- objectUnderTest.handleUpdateOfDeviceTrustLevel('ch-1', TrustLevel.COMPLETE)
+ when: 'update of CmHandle to COMPLETE trust level handled'
+ objectUnderTest.updateCmHandleTrustLevel('ch-1', TrustLevel.COMPLETE)
then: 'the cm handle in the cache is trusted'
assert trustLevelPerCmHandle.get('ch-1', TrustLevel.COMPLETE)
and: 'notification is sent'
1 * mockAttributeValueChangeEventPublisher.publishAvcEvent('ch-1', 'trustLevel', 'NONE', 'COMPLETE')
}
- def 'Device trust level updated with same value'() {
+ def 'CmHandle trust level updated with same value'() {
given: 'a non trusted cm handle'
trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE)
and: 'a trusted dmi plugin'
trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE)
and: 'inventory persistence service returns yang model cm handle'
mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(id: 'ch-1', dmiDataServiceName: 'my-dmi')
- when: 'update of device trust to the same level (NONE)'
- objectUnderTest.handleUpdateOfDeviceTrustLevel('ch-1', TrustLevel.NONE)
+ when: 'update of CmHandle trust to the same level (NONE)'
+ objectUnderTest.updateCmHandleTrustLevel('ch-1', TrustLevel.NONE)
then: 'the cm handle in the cache is not trusted'
assert trustLevelPerCmHandle.get('ch-1', TrustLevel.NONE)
and: 'no notification is sent'
0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
}
- def 'Dmi trust level restored to complete with non trusted device'() {
+ def 'Dmi trust level restored to complete with non trusted CmHandle'() {
given: 'a non trusted dmi'
trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE)
- and: 'a non trusted device'
+ and: 'a non trusted CmHandle'
trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE)
when: 'restore the dmi trust level to COMPLETE'
- objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.COMPLETE)
+ objectUnderTest.updateDmi('my-dmi', ['ch-1'], TrustLevel.COMPLETE)
then: 'the cm handle in the cache is still NONE'
assert trustLevelPerCmHandle.get('ch-1') == TrustLevel.NONE
and: 'no notification is sent'
0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
}
+ def 'Select effective trust level among CmHandle and dmi plugin'() {
+ given: 'a non trusted dmi'
+ trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE)
+ and: 'a trusted CmHandle'
+ trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
+ when: 'effective trust level selected'
+ def effectiveTrustLevel = objectUnderTest.getEffectiveTrustLevel('my-dmi', 'ch-1')
+ then: 'effective trust level is trusted'
+ assert effectiveTrustLevel == TrustLevel.NONE
+ }
+
+ def 'CmHandle trust level removed'() {
+ given: 'a cm handle'
+ trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
+ when: 'the remove is handled'
+ objectUnderTest.removeCmHandles(['ch-1'])
+ then: 'cm handle removed from the cache'
+ assert trustLevelPerCmHandle.get('ch-1') == null
+ }
+
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/policyexecutor/PolicyExecutorWebClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/policyexecutor/PolicyExecutorWebClientConfigurationSpec.groovy
new file mode 100644
index 0000000000..cf5e1a383c
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/policyexecutor/PolicyExecutorWebClientConfigurationSpec.groovy
@@ -0,0 +1,53 @@
+/*-
+ * ============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.impl.policyexecutor
+
+import org.onap.cps.ncmp.config.PolicyExecutorHttpClientConfig
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ContextConfiguration
+import org.springframework.web.reactive.function.client.WebClient
+import spock.lang.Specification
+
+@SpringBootTest
+@ContextConfiguration(classes = [PolicyExecutorHttpClientConfig])
+@EnableConfigurationProperties
+class PolicyExecutorWebClientConfigurationSpec extends Specification {
+
+ def webClientBuilder = Mock(WebClient.Builder) {
+ defaultHeaders(_) >> it
+ clientConnector(_) >> it
+ codecs(_) >> it
+ build() >> Mock(WebClient)
+ }
+
+ def httpClientConfiguration = Spy(PolicyExecutorHttpClientConfig.class)
+
+ def objectUnderTest = new PolicyExecutorWebClientConfiguration(httpClientConfiguration)
+
+ def 'Web client policy executor.'() {
+ when: 'create a web client for policy executor'
+ def result = objectUnderTest.policyExecutorWebClient(webClientBuilder)
+ then: 'a web client is created successfully'
+ assert result != null
+ assert result instanceof WebClient
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy
new file mode 100644
index 0000000000..a497b4554a
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy
@@ -0,0 +1,80 @@
+/*
+ * ============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.impl.utils
+
+import org.onap.cps.ncmp.exceptions.NoAlternateIdMatchFoundException
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException
+import org.onap.cps.spi.model.DataNode
+import spock.lang.Specification
+
+class AlternateIdMatcherSpec extends Specification {
+
+ def mockInventoryPersistence = Mock(InventoryPersistence)
+ def objectUnderTest = new AlternateIdMatcher(mockInventoryPersistence)
+
+ def setup() {
+ given: 'cm handle in the registry with alternate id /a/b'
+ mockInventoryPersistence.getCmHandleDataNodeByAlternateId('/a/b') >> new DataNode()
+ and: 'no other cm handle'
+ mockInventoryPersistence.getCmHandleDataNodeByAlternateId(_) >> { throw new DataNodeNotFoundException('', '') }
+ }
+
+ def 'Finding longest alternate id matches.'() {
+ expect: 'querying for alternate id a matching result found'
+ assert objectUnderTest.getCmHandleDataNodeByLongestMatchingAlternateId(targetAlternateId, '/') != null
+ where: 'the following parameters are used'
+ scenario | targetAlternateId
+ 'exact match' | '/a/b'
+ 'parent match' | '/a/b/c'
+ 'grand parent match' | '/a/b/c/d'
+ 'trailing separator match' | '/a/b/'
+ }
+
+ def 'Attempt to find longest alternate id match without any matches.'() {
+ when: 'attempt to find alternateId'
+ objectUnderTest.getCmHandleDataNodeByLongestMatchingAlternateId(targetAlternateId, '/')
+ then: 'no alternate id match found exception thrown'
+ def thrown = thrown(NoAlternateIdMatchFoundException)
+ and: 'the exception has the relevant details from the error response'
+ assert thrown.message == 'No matching cm handle found using alternate ids'
+ assert thrown.details == 'cannot find a datanode with alternate id ' + targetAlternateId
+ where: 'the following parameters are used'
+ scenario | targetAlternateId
+ 'no match for parent only' | '/a'
+ 'no match for other child' | '/a/c'
+ 'no match at all' | '/x/y'
+ }
+
+ def 'Get cmHandle id from passed cmHandleReference (cmHandleId scenario)' () {
+ when: 'a cmHandleCmReference is passed in'
+ def result = objectUnderTest.getCmHandleId(cmHandleReference)
+ then: 'the inventory persistence service returns a cm handle (or not)'
+ mockInventoryPersistence.isExistingCmHandleId(cmHandleReference) >> existingCmHandleIdResponse
+ mockInventoryPersistence.getCmHandleDataNodeByAlternateId(cmHandleReference) >> alternateIdGetResponse
+ and: 'correct result is returned'
+ assert result == cmHandleReference
+ where:
+ cmHandleReference | existingCmHandleIdResponse | alternateIdGetResponse
+ 'ch-1' | true | ''
+ 'alt-1' | false | new DataNode(leaves: [id:'alt-1'])
+ }
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy
new file mode 100644
index 0000000000..7f07165df3
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy
@@ -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.impl.utils
+
+import spock.lang.Specification
+
+import java.time.Year
+
+class EventDateTimeFormatterSpec extends Specification {
+
+ def 'Get ISO formatted date and time.' () {
+ expect: 'iso formatted date and time starts with current year'
+ assert EventDateTimeFormatter.getCurrentIsoFormattedDateTime().startsWith(String.valueOf(Year.now()))
+ }
+
+ def 'Convert date time from string to OffsetDateTime type.'() {
+ when: 'date time as a string is converted to OffsetDateTime type'
+ def result = EventDateTimeFormatter.toIsoOffsetDateTime('2024-05-28T18:28:02.869+0100')
+ then: 'the result convert back back to a string is the same as the original timestamp (except the format of timezone offset)'
+ assert result.toString() == '2024-05-28T18:28:02.869+01:00'
+ }
+
+ def 'Convert blank string.' () {
+ expect: 'converting a blank string result in null'
+ assert EventDateTimeFormatter.toIsoOffsetDateTime(' ') == null
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/YangDataConverterSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/YangDataConverterSpec.groovy
index 0ae348c074..bb45e8ad96 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/YangDataConverterSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/YangDataConverterSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.utils
+package org.onap.cps.ncmp.impl.utils
import org.onap.cps.spi.model.DataNode
import spock.lang.Specification
@@ -33,8 +33,7 @@ class YangDataConverterSpec extends Specification{
leaves: ['name': 'pubProp1', 'value': 'pubValue1'])
def dataNodeCmHandle = new DataNode(leaves:['id':'sample-id'], childDataNodes:[dataNodeAdditionalProperties, dataNodePublicProperties])
when: 'the dataNode is converted'
- def yangModelCmHandle =
- YangDataConverter.convertCmHandleToYangModel(dataNodeCmHandle)
+ def yangModelCmHandle = YangDataConverter.toYangModelCmHandle(dataNodeCmHandle)
then: 'the converted object has the correct id'
assert yangModelCmHandle.id == 'sample-id'
and: 'the additional (dmi, private) properties are included'
@@ -50,7 +49,7 @@ class YangDataConverterSpec extends Specification{
def dataNodes = [new DataNode(xpath:'/dmi-registry/cm-handles[@id=\'some-cm-handle\']', leaves: ['id':'some-cm-handle']),
new DataNode(xpath:'/dmi-registry/cm-handles[@id=\'another-cm-handle\']', leaves: ['id':'another-cm-handle'])]
when: 'the data nodes are converted'
- def yangModelCmHandles = YangDataConverter.convertDataNodesToYangModelCmHandles(dataNodes)
+ def yangModelCmHandles = YangDataConverter.toYangModelCmHandles(dataNodes)
then: 'verify both have returned and CmHandleIds are correct'
assert yangModelCmHandles.size() == 2
assert yangModelCmHandles.id.containsAll(['some-cm-handle', 'another-cm-handle'])
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilderSpec.groovy
new file mode 100644
index 0000000000..9e051156f7
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilderSpec.groovy
@@ -0,0 +1,63 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022-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.impl.utils.http
+
+import spock.lang.Specification
+
+class RestServiceUrlTemplateBuilderSpec extends Specification {
+
+ def objectUnderTest = new RestServiceUrlTemplateBuilder()
+
+ def 'Build URL template parameters with (variable) path segments and query parameters.'() {
+ given: 'the URL details are given to the builder'
+ objectUnderTest.fixedPathSegment('segment')
+ objectUnderTest.variablePathSegment('myVariableSegment','someValue')
+ objectUnderTest.fixedPathSegment('segment?with:special&characters')
+ objectUnderTest.queryParameter('param1', 'abc')
+ objectUnderTest.queryParameter('param2', 'value?with#special:characters')
+ when: 'the URL template parameters are created'
+ def result = objectUnderTest.createUrlTemplateParameters('myServer', 'myBasePath')
+ then: 'the URL template contains variable names instead of value and un-encoded fixed segment'
+ assert result.urlTemplate == 'myServer/myBasePath/v1/segment/{myVariableSegment}/segment?with:special&characters?param1={param1}&param2={param2}'
+ and: 'URL variables contains name and un-encoded value pairs'
+ assert result.urlVariables == ['myVariableSegment': 'someValue', 'param1': 'abc', 'param2': 'value?with#special:characters']
+ }
+
+ def 'Build URL template parameters with special characters in query parameters.'() {
+ given: 'the query parameter is given to the builder'
+ objectUnderTest.queryParameter('my&param', 'special&characters=are?not\\encoded')
+ when: 'the URL template parameters are created'
+ def result = objectUnderTest.createUrlTemplateParameters('myServer', 'myBasePath')
+ then: 'Special characters are not encoded'
+ assert result.urlVariables == ['my&param': 'special&characters=are?not\\encoded']
+ }
+
+ def 'Build URL template parameters with empty query parameters.'() {
+ when: 'the query parameter is given to the builder'
+ objectUnderTest.queryParameter('param', value)
+ and: 'the URL template parameters are create'
+ def result = objectUnderTest.createUrlTemplateParameters('myServer', 'myBasePath')
+ then: 'no parameter gets added'
+ assert result.urlVariables.isEmpty()
+ where: 'the following parameter values are used'
+ value << [ null, '', ' ' ]
+ }
+}
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 b0be29d933..38eeaa589f 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
@@ -23,16 +23,16 @@ package org.onap.cps.ncmp.init
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.core.read.ListAppender
-import org.onap.cps.api.CpsDataspaceService
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
+import org.onap.cps.api.CpsDataspaceService
import org.onap.cps.api.CpsModuleService
-import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException
+import org.onap.cps.ncmp.exceptions.NcmpStartUpException
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.exceptions.AlreadyDefinedException
-import org.springframework.boot.SpringApplication
import org.slf4j.LoggerFactory
-import org.springframework.boot.context.event.ApplicationReadyEvent
+import org.springframework.boot.SpringApplication
+import org.springframework.boot.context.event.ApplicationStartedEvent
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import spock.lang.Specification
@@ -64,18 +64,18 @@ class AbstractModelLoaderSpec extends Specification {
applicationContext.close()
}
- def 'Application ready event'() {
- when: 'Application (ready) event is triggered'
- objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent))
+ def 'Application started event'() {
+ when: 'Application (started) event is triggered'
+ objectUnderTest.onApplicationEvent(Mock(ApplicationStartedEvent))
then: 'the onboard/upgrade method is executed'
1 * objectUnderTest.onboardOrUpgradeModel()
}
- def 'Application ready event with start up exception'() {
+ def 'Application started event with start up exception'() {
given: 'a start up exception is thrown doing model onboarding'
objectUnderTest.onboardOrUpgradeModel() >> { throw new NcmpStartUpException('test message','details are not logged') }
- when: 'Application (ready) event is triggered'
- objectUnderTest.onApplicationEvent(new ApplicationReadyEvent(new SpringApplication(), null, applicationContext, null))
+ when: 'Application (started) event is triggered'
+ objectUnderTest.onApplicationEvent(new ApplicationStartedEvent(new SpringApplication(), null, applicationContext, null))
then: 'the exception message is logged'
def logs = loggingListAppender.list.toString()
assert logs.contains('test message')
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy
index f3b405b117..caaad8d34d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy
@@ -27,15 +27,15 @@ import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsDataspaceService
import org.onap.cps.api.CpsModuleService
-import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException
+import org.onap.cps.ncmp.exceptions.NcmpStartUpException
import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.model.Dataspace
import org.slf4j.LoggerFactory
-import org.springframework.boot.context.event.ApplicationReadyEvent
+import org.springframework.boot.context.event.ApplicationStartedEvent
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import spock.lang.Specification
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
class CmDataSubscriptionModelLoaderSpec extends Specification {
@@ -65,11 +65,11 @@ class CmDataSubscriptionModelLoaderSpec extends Specification {
applicationContext.close()
}
- def 'Onboard subscription model via application ready event.'() {
+ def 'Onboard subscription model via application started event.'() {
given: 'dataspace is ready for use'
mockCpsDataspaceService.getDataspace(NCMP_DATASPACE_NAME) >> new Dataspace('')
when: 'the application is ready'
- objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent))
+ objectUnderTest.onApplicationEvent(Mock(ApplicationStartedEvent))
then: 'the module service to create schema set is called once'
1 * mockCpsModuleService.createSchemaSet(NCMP_DATASPACE_NAME, 'cm-data-subscriptions', expectedYangResourcesToContentMap)
and: 'the admin service to create an anchor set is called once'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy
index cd659bb528..76c1589be3 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy
@@ -20,23 +20,22 @@
package org.onap.cps.ncmp.init
-import org.onap.cps.api.CpsAnchorService
-
-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 ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.core.read.ListAppender
-import org.onap.cps.api.CpsDataspaceService
+import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
+import org.onap.cps.api.CpsDataspaceService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.spi.model.Dataspace
import org.slf4j.LoggerFactory
-import org.springframework.boot.context.event.ApplicationReadyEvent
+import org.springframework.boot.context.event.ApplicationStartedEvent
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import spock.lang.Specification
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+
class InventoryModelLoaderSpec extends Specification {
def mockCpsAdminService = Mock(CpsDataspaceService)
@@ -68,8 +67,8 @@ class InventoryModelLoaderSpec extends Specification {
def 'Onboard subscription model via application ready event.'() {
given: 'dataspace is ready for use'
mockCpsAdminService.getDataspace(NCMP_DATASPACE_NAME) >> new Dataspace('')
- when: 'the application is ready'
- objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent))
+ when: 'the application is started'
+ objectUnderTest.onApplicationEvent(Mock(ApplicationStartedEvent))
then: 'the module service is used to create the new schema set from the correct resource'
1 * mockCpsModuleService.createSchemaSet(NCMP_DATASPACE_NAME, 'dmi-registry-2024-02-23', expectedYangResourceToContentMap)
and: 'the admin service is used to update the anchor'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy
index 101a29b29e..051f5df4cf 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/avc/ncmptoclient/AvcEventPublisherSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy
@@ -18,25 +18,22 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient
+package org.onap.cps.ncmp.utils.events
import com.fasterxml.jackson.databind.ObjectMapper
import io.cloudevents.CloudEvent
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext
-import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
+import org.onap.cps.ncmp.config.CpsApplicationContext
import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc
import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent
import org.onap.cps.utils.JsonObjectMapper
import org.springframework.test.context.ContextConfiguration
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
-
@ContextConfiguration(classes = [CpsApplicationContext, ObjectMapper, JsonObjectMapper])
-class AvcEventPublisherSpec extends MessagingBaseSpec {
+class CmAvcEventPublisherSpec extends MessagingBaseSpec {
def mockEventsPublisher = Mock(EventsPublisher<CloudEvent>)
- def objectUnderTest = new AvcEventPublisher(mockEventsPublisher)
+ def objectUnderTest = new CmAvcEventPublisher(mockEventsPublisher)
def 'Publish an attribute value change event'() {
given: 'the event key'
@@ -52,7 +49,7 @@ class AvcEventPublisherSpec extends MessagingBaseSpec {
then: 'the cloud event publisher is invoked with the correct data'
1 * mockEventsPublisher.publishCloudEvent(_, someEventKey,
cloudEvent -> {
- def actualAvcs = toTargetEvent(cloudEvent, AvcEvent.class).data.attributeValueChange
+ def actualAvcs = CloudEventMapper.toTargetEvent(cloudEvent, AvcEvent.class).data.attributeValueChange
def expectedAvc = new Avc(attributeName: someAttributeName,
oldAttributeValue: someOldAttributeValue,
newAttributeValue: someNewAttributeValue)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/ConsumerBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/ConsumerBaseSpec.groovy
index 28f8b02880..73dc2a37c5 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/ConsumerBaseSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/ConsumerBaseSpec.groovy
@@ -18,7 +18,8 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.kafka
+package org.onap.cps.ncmp.utils.events
+
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/MessagingBaseSpec.groovy
index 0356c3fcdc..377a1a6637 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/MessagingBaseSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.kafka
+package org.onap.cps.ncmp.utils.events
import io.cloudevents.CloudEvent
import io.cloudevents.kafka.CloudEventSerializer
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/TopicValidatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy
index 15e2c1c6a0..8fc3e18c7f 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/util/TopicValidatorSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy
@@ -18,9 +18,9 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.rest.util
+package org.onap.cps.ncmp.utils.events
-import org.onap.cps.ncmp.rest.exceptions.InvalidTopicException
+import org.onap.cps.ncmp.api.exceptions.InvalidTopicException
import spock.lang.Specification
class TopicValidatorSpec extends Specification {
diff --git a/cps-ncmp-service/src/test/java/org/onap/cps/ncmp/utils/WebClientBuilderTestConfig.java b/cps-ncmp-service/src/test/java/org/onap/cps/ncmp/utils/WebClientBuilderTestConfig.java
new file mode 100644
index 0000000000..2f6b270076
--- /dev/null
+++ b/cps-ncmp-service/src/test/java/org/onap/cps/ncmp/utils/WebClientBuilderTestConfig.java
@@ -0,0 +1,40 @@
+/*
+ * ============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.utils;
+
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@TestConfiguration
+public class WebClientBuilderTestConfig {
+
+ /**
+ * Configures and creates a web client builder bean to make it accessible for the Spring Boot Test Context.
+ *
+ * @return a WebClient Builder instance.
+ */
+ @Bean
+ public WebClient.Builder webClientBuilder() {
+ return WebClient.builder();
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml
index cc620b83a3..c76831da74 100644
--- a/cps-ncmp-service/src/test/resources/application.yml
+++ b/cps-ncmp-service/src/test/resources/application.yml
@@ -16,6 +16,15 @@
# SPDX-License-Identifier: Apache-2.0
# ============LICENSE_END=========================================================
+cps:
+ tracing:
+ sampler:
+ jaeger_remote:
+ endpoint: http://jaeger-Remote-test-url
+ exporter:
+ endpoint: http://exporter-test-url
+ enabled: true
+
spring:
kafka:
producer:
@@ -37,8 +46,27 @@ app:
ncmp:
dmi:
httpclient:
- connectionTimeoutInSeconds: 180
- maximumInMemorySizeInMegabytes: 16
+ data-services:
+ maximumInMemorySizeInMegabytes: 1
+ maximumConnectionsTotal: 2
+ pendingAcquireMaxCount: 3
+ connectionTimeoutInSeconds: 4
+ readTimeoutInSeconds: 5
+ writeTimeoutInSeconds: 6
+ model-services:
+ maximumInMemorySizeInMegabytes: 11
+ maximumConnectionsTotal: 12
+ pendingAcquireMaxCount: 13
+ connectionTimeoutInSeconds: 14
+ readTimeoutInSeconds: 15
+ writeTimeoutInSeconds: 16
+ healthCheckServices:
+ maximumInMemorySizeInMegabytes: 21
+ maximumConnectionsTotal: 22
+ pendingAcquireMaxCount: 23
+ connectionTimeoutInSeconds: 24
+ readTimeoutInSeconds: 25
+ writeTimeoutInSeconds: 26
auth:
username: some-user
password: some-password
@@ -53,6 +81,19 @@ ncmp:
async-executor:
parallelism-level: 3
+ policy-executor:
+ enabled: true
+ server:
+ address: http://localhost
+ port: 8785
+ httpclient:
+ all-services:
+ maximumInMemorySizeInMegabytes: 31
+ maximumConnectionsTotal: 32
+ pendingAcquireMaxCount: 33
+ connectionTimeoutInSeconds: 34
+ readTimeoutInSeconds: 35
+ writeTimeoutInSeconds: 36
# Custom Hazelcast Config.
hazelcast:
diff --git a/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json b/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json
index 6b665495c0..04d37b8bb9 100644
--- a/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json
+++ b/cps-ncmp-service/src/test/resources/cmSubscription/cmNotificationSubscriptionNcmpInEvent.json
@@ -6,14 +6,14 @@
"targetFilter": ["ch1","ch2"],
"scopeFilter": {
"datastore": "ncmp-datastore:passthrough-operational",
- "xpath-filter": ["/x1/y1","x2/y2"]
+ "xpathFilter": ["/x1/y1","x2/y2"]
}
},
{
"targetFilter": ["ch3","ch4"],
"scopeFilter": {
"datastore": "ncmp-datastore:passthrough-operational",
- "xpath-filter": ["/x3/y3","x4/y4"]
+ "xpathFilter": ["/x3/y3","x4/y4"]
}
}
]
diff --git a/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json b/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json
index 5b297c86c2..1dc14bd65e 100644
--- a/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json
+++ b/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json
@@ -10,11 +10,8 @@
"operation":"replace",
"target":"ran-network:ran-network/NearRTRIC[@id='22']/GNBCUCPFunction[@id='cucpserver2']/NRCellCU[@id='15549']/NRCellRelation[@id='14427']",
"value":{
- "attributes":[
- {
- "isHoAllowed":true
- }
- ]
+ "color": "yellow",
+ "name": "Apple"
}
},
{
diff --git a/cps-parent/pom.xml b/cps-parent/pom.xml
index 594aa1f0f5..430f4b5cd8 100644
--- a/cps-parent/pom.xml
+++ b/cps-parent/pom.xml
@@ -32,7 +32,7 @@
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
@@ -368,6 +368,7 @@
<exclude>org/onap/cps/ncmp/rest/model/*</exclude>
<exclude>org/onap/cps/**/*MapperImpl.class</exclude>
<exclude>org/onap/cps/ncmp/rest/stub/*</exclude>
+ <exclude>org/onap/cps/policyexecutor/stub/model/*</exclude>
</excludes>
</configuration>
<executions>
@@ -409,30 +410,6 @@
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>exec-maven-plugin</artifactId>
- <version>1.6.0</version>
- <executions>
- <execution>
- <id>generate-csv</id>
- <phase>prepare-package</phase>
- <goals>
- <goal>exec</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <executable>${script.executor}</executable>
- <workingDirectory>${parent.directory}/cps-ri/src/main/resources/</workingDirectory>
- <arguments>
- <argument>yangResourceCsvGenerator.py</argument>
- <argument>dmi-registry@2021-12-13</argument>
- <argument>dmi-registry@2022-02-10</argument>
- <argument>dmi-registry@2022-05-10</argument>
- </arguments>
- </configuration>
- </plugin>
</plugins>
</build>
</project>
diff --git a/cps-path-parser/pom.xml b/cps-path-parser/pom.xml
index 3176d9a471..f71d9aabcd 100644
--- a/cps-path-parser/pom.xml
+++ b/cps-path-parser/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4 b/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4
index 3aef120fed..444702db48 100644
--- a/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4
+++ b/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation
+ * Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,23 +27,23 @@
grammar CpsPath ;
-cpsPath : ( prefix | descendant | incorrectPrefix ) multipleLeafConditions? textFunctionCondition? containsFunctionCondition? ancestorAxis? invalidPostFix?;
+cpsPath : ( prefix | descendant ) multipleLeafConditions? textFunctionCondition? containsFunctionCondition? ancestorAxis? EOF ;
-ancestorAxis : SLASH KW_ANCESTOR COLONCOLON ancestorPath ;
+slash : SLASH ;
-ancestorPath : yangElement ( SLASH yangElement)* ;
+ancestorAxis : KW_ANCESTOR_AXIS_PREFIX ancestorPath ;
-textFunctionCondition : SLASH leafName OB KW_TEXT_FUNCTION EQ StringLiteral CB ;
+ancestorPath : yangElement ( slash yangElement)* ;
-containsFunctionCondition : OB KW_CONTAINS_FUNCTION OP AT leafName COMMA StringLiteral CP CB ;
+textFunctionCondition : slash leafName OB KW_TEXT_FUNCTION EQ StringLiteral CB ;
-parent : ( SLASH yangElement)* ;
+containsFunctionCondition : OB KW_CONTAINS_FUNCTION OP AT leafName COMMA StringLiteral CP CB ;
-prefix : parent SLASH containerName ;
+parent : ( slash yangElement)* ;
-descendant : SLASH prefix ;
+prefix : parent slash containerName ;
-incorrectPrefix : SLASH SLASH SLASH+ ;
+descendant : slash prefix ;
yangElement : containerName listElementRef? ;
@@ -61,8 +61,6 @@ booleanOperators : ( KW_AND | KW_OR ) ;
comparativeOperators : ( EQ | GT | LT | GE | LE ) ;
-invalidPostFix : (AT | CB | COLONCOLON | comparativeOperators ).+ ;
-
/*
* Lexer Rules
* Most of the lexer rules below are inspired by
@@ -89,7 +87,8 @@ KW_ANCESTOR : 'ancestor' ;
KW_AND : 'and' ;
KW_TEXT_FUNCTION: 'text()' ;
KW_OR : 'or' ;
-KW_CONTAINS_FUNCTION: 'contains' ;
+KW_CONTAINS_FUNCTION : 'contains' ;
+KW_ANCESTOR_AXIS_PREFIX : SLASH KW_ANCESTOR COLONCOLON ;
IntegerLiteral : FragDigits ;
// Add below type definitions for leafvalue comparision in https://jira.onap.org/browse/CPS-440
diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java
index de261e64b3..ed7dbecc18 100644
--- a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java
+++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation
+ * Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,6 @@ import org.onap.cps.cpspath.parser.antlr4.CpsPathBaseListener;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.AncestorAxisContext;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.DescendantContext;
-import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.IncorrectPrefixContext;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.LeafConditionContext;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.MultipleLeafConditionsContext;
import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.PrefixContext;
@@ -37,17 +36,19 @@ import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.TextFunctionConditionCon
public class CpsPathBuilder extends CpsPathBaseListener {
+ private static final String NO_PARENT_PATH = "";
+
private static final String OPEN_BRACKET = "[";
private static final String CLOSE_BRACKET = "]";
private final CpsPathQuery cpsPathQuery = new CpsPathQuery();
- private final List<CpsPathQuery.DataLeaf> leavesData = new ArrayList<>();
+ private final List<CpsPathQuery.LeafCondition> leafConditions = new ArrayList<>();
private final StringBuilder normalizedXpathBuilder = new StringBuilder();
- private final StringBuilder normalizedAncestorPathBuilder = new StringBuilder();
+ private int startIndexOfAncestorSchemaNodeIdentifier = 0;
private boolean processingAncestorAxis = false;
@@ -55,11 +56,9 @@ public class CpsPathBuilder extends CpsPathBaseListener {
private final List<String> booleanOperators = new ArrayList<>();
- private final List<String> comparativeOperators = new ArrayList<>();
-
@Override
- public void exitInvalidPostFix(final CpsPathParser.InvalidPostFixContext ctx) {
- throw new PathParsingException(ctx.getText());
+ public void exitSlash(final CpsPathParser.SlashContext ctx) {
+ normalizedXpathBuilder.append("/");
}
@Override
@@ -69,16 +68,19 @@ public class CpsPathBuilder extends CpsPathBaseListener {
@Override
public void exitParent(final CpsPathParser.ParentContext ctx) {
- cpsPathQuery.setNormalizedParentPath(normalizedXpathBuilder.toString());
- }
-
- @Override
- public void exitIncorrectPrefix(final IncorrectPrefixContext ctx) {
- throw new PathParsingException("CPS path can only start with one or two slashes (/)");
+ final String normalizedParentPath;
+ if (normalizedXpathBuilder.toString().equals("/")) {
+ normalizedParentPath = NO_PARENT_PATH;
+ } else {
+ normalizedParentPath = normalizedXpathBuilder.toString();
+ }
+ cpsPathQuery.setNormalizedParentPath(normalizedParentPath);
}
@Override
public void exitLeafCondition(final LeafConditionContext ctx) {
+ final String leafName = ctx.leafName().getText();
+ final String operator = ctx.comparativeOperators().getText();
final Object comparisonValue;
if (ctx.IntegerLiteral() != null) {
comparisonValue = Integer.valueOf(ctx.IntegerLiteral().getText());
@@ -87,7 +89,7 @@ public class CpsPathBuilder extends CpsPathBaseListener {
} else {
throw new PathParsingException("Unsupported comparison value encountered in expression" + ctx.getText());
}
- leafContext(ctx.leafName(), comparisonValue);
+ leafContext(leafName, operator, comparisonValue);
}
@Override
@@ -96,40 +98,36 @@ public class CpsPathBuilder extends CpsPathBaseListener {
}
@Override
- public void exitComparativeOperators(final CpsPathParser.ComparativeOperatorsContext ctx) {
- comparativeOperators.add(ctx.getText());
- }
-
- @Override
public void exitDescendant(final DescendantContext ctx) {
cpsPathQuery.setCpsPathPrefixType(DESCENDANT);
- cpsPathQuery.setDescendantName(normalizedXpathBuilder.substring(1));
- normalizedXpathBuilder.insert(0, "/");
+ cpsPathQuery.setDescendantName(normalizedXpathBuilder.substring(2));
}
@Override
public void enterMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
normalizedXpathBuilder.append(OPEN_BRACKET);
- leavesData.clear();
+ leafConditions.clear();
booleanOperators.clear();
- comparativeOperators.clear();
}
@Override
public void exitMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
normalizedXpathBuilder.append(CLOSE_BRACKET);
- cpsPathQuery.setLeavesData(leavesData);
+ cpsPathQuery.setLeafConditions(leafConditions);
}
@Override
public void enterAncestorAxis(final AncestorAxisContext ctx) {
processingAncestorAxis = true;
+ normalizedXpathBuilder.append("/ancestor::");
+ startIndexOfAncestorSchemaNodeIdentifier = normalizedXpathBuilder.length();
}
@Override
public void exitAncestorAxis(final AncestorAxisContext ctx) {
- cpsPathQuery.setAncestorSchemaNodeIdentifier(normalizedAncestorPathBuilder.substring(1));
processingAncestorAxis = false;
+ cpsPathQuery.setAncestorSchemaNodeIdentifier(
+ normalizedXpathBuilder.substring(startIndexOfAncestorSchemaNodeIdentifier));
}
@Override
@@ -147,48 +145,36 @@ public class CpsPathBuilder extends CpsPathBaseListener {
@Override
public void enterListElementRef(final CpsPathParser.ListElementRefContext ctx) {
normalizedXpathBuilder.append(OPEN_BRACKET);
- if (processingAncestorAxis) {
- normalizedAncestorPathBuilder.append(OPEN_BRACKET);
- }
}
@Override
public void exitListElementRef(final CpsPathParser.ListElementRefContext ctx) {
normalizedXpathBuilder.append(CLOSE_BRACKET);
- if (processingAncestorAxis) {
- normalizedAncestorPathBuilder.append(CLOSE_BRACKET);
- }
}
CpsPathQuery build() {
cpsPathQuery.setNormalizedXpath(normalizedXpathBuilder.toString());
cpsPathQuery.setContainerNames(containerNames);
cpsPathQuery.setBooleanOperators(booleanOperators);
- cpsPathQuery.setComparativeOperators(comparativeOperators);
return cpsPathQuery;
}
@Override
public void exitContainerName(final CpsPathParser.ContainerNameContext ctx) {
final String containerName = ctx.getText();
- normalizedXpathBuilder.append("/")
- .append(containerName);
- containerNames.add(containerName);
- if (processingAncestorAxis) {
- normalizedAncestorPathBuilder.append("/").append(containerName);
+ normalizedXpathBuilder.append(containerName);
+ if (!processingAncestorAxis) {
+ containerNames.add(containerName);
}
}
- private void leafContext(final CpsPathParser.LeafNameContext ctx, final Object comparisonValue) {
- leavesData.add(new CpsPathQuery.DataLeaf(ctx.getText(), comparisonValue));
- appendCondition(normalizedXpathBuilder, ctx.getText(), comparisonValue);
- if (processingAncestorAxis) {
- appendCondition(normalizedAncestorPathBuilder, ctx.getText(), comparisonValue);
- }
+ private void leafContext(final String leafName, final String operator, final Object comparisonValue) {
+ leafConditions.add(new CpsPathQuery.LeafCondition(leafName, operator, comparisonValue));
+ appendCondition(normalizedXpathBuilder, leafName, operator, comparisonValue);
}
private void appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name,
- final Object value) {
+ final String operator, final Object value) {
final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1);
final boolean isStartOfExpression = lastCharacter == '[';
if (!isStartOfExpression) {
@@ -196,7 +182,7 @@ public class CpsPathBuilder extends CpsPathBaseListener {
}
currentNormalizedPathBuilder.append("@")
.append(name)
- .append(getLastElement(comparativeOperators))
+ .append(operator)
.append("'")
.append(value.toString().replace("'", "''"))
.append("'");
diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java
index f98df05a28..03602b64f6 100644
--- a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java
+++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation
+ * Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,8 +25,6 @@ import static org.onap.cps.cpspath.parser.CpsPathPrefixType.ABSOLUTE;
import java.util.List;
import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -40,12 +38,11 @@ public class CpsPathQuery {
private List<String> containerNames;
private CpsPathPrefixType cpsPathPrefixType = ABSOLUTE;
private String descendantName;
- private List<DataLeaf> leavesData;
+ private List<LeafCondition> leafConditions;
private String ancestorSchemaNodeIdentifier = "";
private String textFunctionConditionLeafName;
private String textFunctionConditionValue;
private List<String> booleanOperators;
- private List<String> comparativeOperators;
private String containsFunctionConditionLeafName;
private String containsFunctionConditionValue;
@@ -74,7 +71,7 @@ public class CpsPathQuery {
* @return boolean value.
*/
public boolean hasLeafConditions() {
- return leavesData != null;
+ return leafConditions != null;
}
/**
@@ -104,11 +101,6 @@ public class CpsPathQuery {
return cpsPathPrefixType == ABSOLUTE && hasLeafConditions();
}
- @Getter
- @EqualsAndHashCode
- @AllArgsConstructor
- public static class DataLeaf {
- private final String name;
- private final Object value;
- }
+ public record LeafCondition(String name, String operator, Object value) { }
+
}
diff --git a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy
index ae7ee598ab..16430d2fa5 100644
--- a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy
+++ b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation
+ * Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,8 +48,8 @@ class CpsPathQuerySpec extends Specification {
and: 'the right query parameters are set'
assert result.xpathPrefix == expectedXpathPrefix
assert result.hasLeafConditions()
- assert result.leavesData[0].name == expectedLeafName
- assert result.leavesData[0].value == expectedLeafValue
+ assert result.leafConditions[0].name() == expectedLeafName
+ assert result.leafConditions[0].value() == expectedLeafValue
where: 'the following data is used'
scenario | cpsPath || expectedXpathPrefix | expectedLeafName | expectedLeafValue
'leaf of type String' | '/parent/child[@common-leaf-name="common-leaf-value"]' || '/parent/child' | 'common-leaf-name' | 'common-leaf-value'
@@ -91,13 +91,14 @@ class CpsPathQuerySpec extends Specification {
'descendant with leaf condition has "<" operator' | '//cps-path[@key<10]' || "//cps-path[@key<'10']"
'descendant with leaf condition has ">=" operator' | '//cps-path[@key>=8]' || "//cps-path[@key>='8']"
'descendant with leaf condition has "<=" operator' | '//cps-path[@key<=12]' || "//cps-path[@key<='12']"
- 'descendant with leaf value and ancestor' | '//cps-path[@key=1]/ancestor:parent[@key=1]' || "//cps-path[@key='1']/ancestor:parent[@key='1']"
+ 'descendant with leaf value and ancestor' | '//cps-path[@key=1]/ancestor::parent[@key=1]' || "//cps-path[@key='1']/ancestor::parent[@key='1']"
'parent & child' | '/parent/child' || '/parent/child'
'parent leaf of type Integer & child' | '/parent/child[@code=1]/child2' || "/parent/child[@code='1']/child2"
'parent leaf with double quotes' | '/parent/child[@code="1"]/child2' || "/parent/child[@code='1']/child2"
'parent leaf with double quotes inside single quotes' | '/parent/child[@code=\'"1"\']/child2' || "/parent/child[@code='\"1\"']/child2"
'parent leaf with single quotes inside double quotes' | '/parent/child[@code="\'1\'"]/child2' || "/parent/child[@code='''1''']/child2"
'leaf with single quotes inside double quotes' | '/parent/child[@code="\'1\'"]' || "/parent/child[@code='''1''']"
+ 'leaf with single quotes inside single quotes' | "/parent/child[@code='I''m quoted']" || "/parent/child[@code='I''m quoted']"
'leaf with more than one attribute' | '/parent/child[@key1=1 and @key2="abc"]' || "/parent/child[@key1='1' and @key2='abc']"
'parent & child with more than one attribute' | '/parent/child[@key1=1 and @key2="abc"]/child2' || "/parent/child[@key1='1' and @key2='abc']/child2"
'leaf with more than one attribute has OR operator' | '/parent/child[@key1=1 or @key2="abc"]' || "/parent/child[@key1='1' or @key2='abc']"
@@ -123,11 +124,11 @@ class CpsPathQuerySpec extends Specification {
when: 'the given cps path is parsed'
def result = CpsPathQuery.createFrom(cpsPath)
then: 'the expected number of leaves are returned'
- result.leavesData.size() == expectedNumberOfLeaves
+ result.leafConditions.size() == expectedNumberOfLeaves
and: 'the given operator(s) returns in the correct order'
result.booleanOperators == expectedOperators
and: 'the given comparativeOperator(s) returns in the correct order'
- result.comparativeOperators == expectedComparativeOperator
+ result.leafConditions.operator == expectedComparativeOperator
where: 'the following data is used'
cpsPath || expectedNumberOfLeaves || expectedOperators || expectedComparativeOperator
'/parent[@code=1]/child[@common-leaf-name-int=5]' || 1 || [] || ['=']
@@ -234,19 +235,19 @@ class CpsPathQuerySpec extends Specification {
when: 'the given cps path is parsed using multiple conditions on same leaf'
def result = CpsPathQuery.createFrom('/test[@same-name="value1" or @same-name="value2"]')
then: 'two leaves are present with correct values'
- assert result.leavesData.size() == 2
- assert result.leavesData[0].name == "same-name"
- assert result.leavesData[0].value == "value1"
- assert result.leavesData[1].name == "same-name"
- assert result.leavesData[1].value == "value2"
+ assert result.leafConditions.size() == 2
+ assert result.leafConditions[0].name == "same-name"
+ assert result.leafConditions[0].value == "value1"
+ assert result.leafConditions[1].name == "same-name"
+ assert result.leafConditions[1].value == "value2"
}
def 'Ordering of data leaves is preserved.'() {
when: 'the given cps path is parsed'
def result = CpsPathQuery.createFrom(cpsPath)
then: 'the order of the data leaves is preserved'
- assert result.leavesData[0].name == expectedFirstLeafName
- assert result.leavesData[1].name == expectedSecondLeafName
+ assert result.leafConditions[0].name == expectedFirstLeafName
+ assert result.leafConditions[1].name == expectedSecondLeafName
where: 'the following data is used'
cpsPath || expectedFirstLeafName | expectedSecondLeafName
'/test[@name1="value1" and @name2="value2"]' || 'name1' | 'name2'
diff --git a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathUtilSpec.groovy b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathUtilSpec.groovy
index d62f337b75..29bb3c7b58 100644
--- a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathUtilSpec.groovy
+++ b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathUtilSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * Copyright (C) 2022-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.
@@ -36,21 +36,40 @@ class CpsPathUtilSpec extends Specification {
'single quotes' | "/parent/child[@common-leaf-name='123']"
}
- def 'Normalized parent xpaths'() {
- when: 'a given xpath with #scenario is parsed'
- def result = CpsPathUtil.getNormalizedParentXpath(xpath)
+ def 'Normalized parent paths of absolute paths'() {
+ when: 'a given cps path is parsed'
+ def result = CpsPathUtil.getNormalizedParentXpath(cpsPath)
then: 'the result is the expected parent path'
assert result == expectedParentPath
- where: 'the following xpaths are used'
- scenario | xpath || expectedParentPath
- 'no child' | '/parent' || ''
- 'child and parent' | '/parent/child' || '/parent'
- 'grand child' | '/parent/child/grandChild' || '/parent/child'
- 'parent & top is list element' | '/parent[@id=1]/child' || "/parent[@id='1']"
- 'parent is list element' | '/parent/child[@id=1]/grandChild' || "/parent/child[@id='1']"
- 'parent is list element with /' | "/parent/child[@id='a/b']/grandChild" || "/parent/child[@id='a/b']"
- 'parent is list element with [' | "/parent/child[@id='a[b']/grandChild" || "/parent/child[@id='a[b']"
- 'parent is list element using "' | '/parent/child[@id="x"]/grandChild' || "/parent/child[@id='x']"
+ where: 'the following absolute cps paths are used'
+ cpsPath || expectedParentPath
+ '/parent' || ''
+ '/parent/child' || '/parent'
+ '/parent/child/grandChild' || '/parent/child'
+ '/parent[@id=1]/child' || "/parent[@id='1']"
+ '/parent/child[@id=1]/grandChild' || "/parent/child[@id='1']"
+ '/parent/child/grandChild[@id="x"]' || "/parent/child"
+ '/parent/ancestor::grandparent' || ''
+ '/parent/child/ancestor::grandparent' || '/parent'
+ '/parent/child/name[text()="value"]' || '/parent'
+ }
+
+ def 'Normalized parent paths of descendant paths'() {
+ when: 'a given cps path is parsed'
+ def result = CpsPathUtil.getNormalizedParentXpath(cpsPath)
+ then: 'the result is the expected parent path'
+ assert result == expectedParentPath
+ where: 'the following descendant cps paths are used'
+ cpsPath || expectedParentPath
+ '//parent' || ''
+ '//parent/child' || '//parent'
+ '//parent/child/grandChild' || '//parent/child'
+ '//parent[@id=1]/child' || "//parent[@id='1']"
+ '//parent/child[@id=1]/grandChild' || "//parent/child[@id='1']"
+ '//parent/child/grandChild[@id="x"]' || "//parent/child"
+ '//parent/ancestor::grandparent' || ''
+ '//parent/child/ancestor::grandparent' || '//parent'
+ '//parent/child/name[text()="value"]' || '//parent'
}
def 'Get node ID sequence for given xpath'() {
@@ -67,17 +86,19 @@ class CpsPathUtilSpec extends Specification {
'parent is list element' | '/parent/child[@id=1]/grandChild' || ["parent","child","grandChild"]
'parent is list element with /' | "/parent/child[@id='a/b']/grandChild" || ["parent","child","grandChild"]
'parent is list element with [' | "/parent/child[@id='a[b']/grandChild" || ["parent","child","grandChild"]
+ 'does not include ancestor node' | '/parent/child/ancestor::grandparent' || ["parent","child"]
}
def 'Recognizing (absolute) xpaths to List elements'() {
expect: 'check for list returns the correct values'
assert CpsPathUtil.isPathToListElement(xpath) == expectList
where: 'the following xpaths are used'
- xpath || expectList
- '/parent[@id=1]' || true
- '/parent[@id=1]/child' || false
- '/parent/child[@id=1]' || true
- '//child[@id=1]' || false
+ xpath || expectList
+ '/parent[@id=1]' || true
+ '/parent[@id=1]/child' || false
+ '/parent/child[@id=1]' || true
+ '//child[@id=1]' || false
+ '/parent/ancestor::grandparent[@id=1]' || false
}
def 'Parsing Exception'() {
diff --git a/cps-rest/docs/openapi/components.yml b/cps-rest/docs/openapi/components.yml
index c1b111bfab..25ef6a452a 100644
--- a/cps-rest/docs/openapi/components.yml
+++ b/cps-rest/docs/openapi/components.yml
@@ -1,7 +1,7 @@
# ============LICENSE_START=======================================================
# Copyright (c) 2021-2022 Bell Canada.
# Modifications Copyright (C) 2021-2023 Nordix Foundation
-# Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+# Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
# Modifications Copyright (C) 2022 Deutsche Telekom AG
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -114,6 +114,8 @@ components:
<categories>
<code>1</code>
<name>SciFi</name>
+ <code>2</code>
+ <name>kids</name>
</categories>
</bookstore>
</stores>
@@ -139,17 +141,17 @@ components:
name: kids
deltaReportSample:
value:
- - action: "ADD"
+ - action: "create"
xpath: "/bookstore/categories/[@code=3]"
target-data:
code: 3,
name: "kidz"
- - action: "REMOVE"
+ - action: "remove"
xpath: "/bookstore/categories/[@code=1]"
source-data:
code: 1,
name: "Fiction"
- - action: "UPDATE"
+ - action: "replace"
xpath: "/bookstore/categories/[@code=2]"
source-data:
name: "Funny"
@@ -181,6 +183,14 @@ components:
schema:
type: string
example: my-anchor
+ sourceAnchorNameInPath:
+ name: source-anchor-name
+ in: path
+ description: source-anchor-name
+ required: true
+ schema:
+ type: string
+ example: my-anchor
schemaSetNameInQuery:
name: schema-set-name
in: query
@@ -277,10 +287,10 @@ components:
type: string
enum: [v1, v2]
default: v2
- contentTypeHeader:
+ contentTypeInHeader:
name: Content-Type
in: header
- description: Content type header
+ description: Content type in header
schema:
type: string
example: 'application/json'
@@ -374,7 +384,7 @@ components:
Created:
description: Created
content:
- text/plain:
+ application/json:
schema:
type: string
example: my-resource
diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml
index b9d2e5940e..4418a3b9b7 100644
--- a/cps-rest/docs/openapi/cpsData.yml
+++ b/cps-rest/docs/openapi/cpsData.yml
@@ -1,7 +1,7 @@
# ============LICENSE_START=======================================================
# Copyright (c) 2021-2022 Bell Canada.
# Modifications Copyright (C) 2021-2022 Nordix Foundation
-# Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+# Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
# Modifications Copyright (C) 2022 Deutsche Telekom AG
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,15 +32,24 @@ listElementByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/requiredXpathInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
required: true
content:
application/json:
schema:
- type: object
+ type: string
examples:
dataSample:
$ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
responses:
'201':
$ref: 'components.yml#/components/responses/Created'
@@ -94,7 +103,7 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
- - $ref: 'components.yml#/components/parameters/contentTypeHeader'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
required: true
content:
@@ -112,7 +121,6 @@ nodesByDataspaceAndAnchor:
examples:
dataSample:
$ref: 'components.yml#/components/examples/dataSampleXml'
-
responses:
'201':
$ref: 'components.yml#/components/responses/Created'
@@ -137,15 +145,24 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
required: true
content:
application/json:
schema:
- type: object
+ type: string
examples:
dataSample:
$ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
responses:
'200':
$ref: 'components.yml#/components/responses/Ok'
@@ -188,15 +205,24 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
required: true
content:
application/json:
schema:
- type: object
+ type: string
examples:
dataSample:
$ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
responses:
'200':
$ref: 'components.yml#/components/responses/Ok'
diff --git a/cps-rest/docs/openapi/cpsDataV2.yml b/cps-rest/docs/openapi/cpsDataV2.yml
index cbb5ce4104..d5a8ef3891 100644
--- a/cps-rest/docs/openapi/cpsDataV2.yml
+++ b/cps-rest/docs/openapi/cpsDataV2.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (c) 2022-2023 TechMahindra Ltd.
+# Copyright (c) 2022-2024 TechMahindra Ltd.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ nodeByDataspaceAndAnchor:
$ref: 'components.yml#/components/responses/InternalServerError'
x-codegen-request-body-name: xpath
-deltaByDataspaceAndAnchors:
+delta:
get:
description: Get delta between two anchors within a given dataspace
tags:
@@ -55,7 +55,7 @@ deltaByDataspaceAndAnchors:
operationId: getDeltaByDataspaceAndAnchors
parameters:
- $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
- - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/sourceAnchorNameInPath'
- $ref: 'components.yml#/components/parameters/targetAnchorNameInQuery'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
- $ref: 'components.yml#/components/parameters/descendantsInQuery'
@@ -75,4 +75,53 @@ deltaByDataspaceAndAnchors:
$ref: 'components.yml#/components/responses/Forbidden'
'500':
$ref: 'components.yml#/components/responses/InternalServerError'
- x-codegen-request-body-name: xpath \ No newline at end of file
+ x-codegen-request-body-name: xpath
+ post:
+ description: Get delta between an anchor in a dataspace and JSON payload
+ tags:
+ - cps-data
+ summary: Get delta between an anchor and JSON payload
+ operationId: getDeltaByDataspaceAnchorAndPayload
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/sourceAnchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ json:
+ type: object
+ example:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 01
+ name: SciFi
+ - code: 02
+ name: kids
+ file:
+ type: string
+ format: binary
+ required:
+ - json
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/deltaReportSample'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '401':
+ $ref: 'components.yml#/components/responses/Unauthorized'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError' \ No newline at end of file
diff --git a/cps-rest/docs/openapi/openapi.yml b/cps-rest/docs/openapi/openapi.yml
index f29335a0a9..70f06fbee2 100644
--- a/cps-rest/docs/openapi/openapi.yml
+++ b/cps-rest/docs/openapi/openapi.yml
@@ -2,7 +2,7 @@
# Copyright (C) 2021-2023 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2021 Bell Canada.
-# Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+# Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ openapi: 3.0.3
info:
title: ONAP Open API v3 Configuration Persistence Service
description: Configuration Persistence Service is a Model Driven Generic Database
- version: "1.0.0"
+ version: "3.5.2"
contact:
name: ONAP
url: "https://onap.readthedocs.io"
@@ -31,10 +31,6 @@ info:
license:
name: "Apache 2.0"
url: "http://www.apache.org/licenses/LICENSE-2.0"
- x-planned-retirement-date: "202212"
- x-component: "Modeling"
- x-logo:
- url: "cps_logo.png"
servers:
- url: /cps/api
@@ -104,8 +100,8 @@ paths:
/{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
$ref: 'cpsData.yml#/listElementByDataspaceAndAnchor'
- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta:
- $ref: 'cpsDataV2.yml#/deltaByDataspaceAndAnchors'
+ /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta:
+ $ref: 'cpsDataV2.yml#/delta'
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
$ref: 'cpsQueryV1Deprecated.yml#/nodesByDataspaceAndAnchorAndCpsPath'
diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml
index ccfb77fb69..4bcb01af4c 100644
--- a/cps-rest/pom.xml
+++ b/cps-rest/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
index 4f9328b6cd..6015e0e3ae 100755
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
@@ -3,7 +3,7 @@
* Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021-2023 Nordix Foundation
- * Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
* Modifications Copyright (C) 2022 Deutsche Telekom AG
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,12 +24,15 @@
package org.onap.cps.rest.controller;
+import static org.onap.cps.rest.utils.MultipartFileUtil.extractYangResourcesMap;
+
import io.micrometer.core.annotation.Timed;
import jakarta.validation.ValidationException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
@@ -46,9 +49,9 @@ import org.onap.cps.utils.PrefixResolver;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("${rest.api.cps-base-path}")
@@ -66,11 +69,10 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<String> createNode(final String apiVersion,
final String dataspaceName, final String anchorName,
- @RequestHeader(value = "Content-Type") final String contentTypeHeader,
+ final String contentTypeInHeader,
final String nodeData, final String parentNodeXpath,
final String observedTimestamp) {
- final ContentType contentType = contentTypeHeader.contains(MediaType.APPLICATION_XML_VALUE) ? ContentType.XML
- : ContentType.JSON;
+ final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
if (isRootXpath(parentNodeXpath)) {
cpsDataService.saveData(dataspaceName, anchorName, nodeData,
toOffsetDateTime(observedTimestamp), contentType);
@@ -93,9 +95,11 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<String> addListElements(final String apiVersion, final String dataspaceName,
final String anchorName, final String parentNodeXpath,
- final Object jsonData, final String observedTimestamp) {
+ final String contentTypeInHeader, final String nodeData,
+ final String observedTimestamp) {
+ final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
cpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath,
- jsonObjectMapper.asJsonString(jsonData), toOffsetDateTime(observedTimestamp));
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@@ -133,19 +137,23 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<Object> updateNodeLeaves(final String apiVersion, final String dataspaceName,
- final String anchorName, final Object jsonData, final String parentNodeXpath, final String observedTimestamp) {
+ final String anchorName, final String contentTypeInHeader,
+ final String nodeData, final String parentNodeXpath,
+ final String observedTimestamp) {
+ final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath,
- jsonObjectMapper.asJsonString(jsonData), toOffsetDateTime(observedTimestamp));
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
return new ResponseEntity<>(HttpStatus.OK);
}
@Override
- public ResponseEntity<Object> replaceNode(final String apiVersion,
- final String dataspaceName, final String anchorName,
- final Object jsonData, final String parentNodeXpath, final String observedTimestamp) {
- cpsDataService
- .updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath,
- jsonObjectMapper.asJsonString(jsonData), toOffsetDateTime(observedTimestamp));
+ public ResponseEntity<Object> replaceNode(final String apiVersion, final String dataspaceName,
+ final String anchorName, final String contentTypeInHeader,
+ final String nodeData, final String parentNodeXpath,
+ final String observedTimestamp) {
+ final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
+ cpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath,
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
return new ResponseEntity<>(HttpStatus.OK);
}
@@ -168,6 +176,27 @@ public class DataRestController implements CpsDataApi {
}
@Override
+ public ResponseEntity<Object> getDeltaByDataspaceAnchorAndPayload(final String dataspaceName,
+ final String sourceAnchorName,
+ final Object jsonPayload,
+ final String xpath,
+ final MultipartFile multipartFile) {
+ final FetchDescendantsOption fetchDescendantsOption = FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
+
+ final Map<String, String> yangResourceMap;
+ if (multipartFile == null) {
+ yangResourceMap = Collections.emptyMap();
+ } else {
+ yangResourceMap = extractYangResourcesMap(multipartFile);
+ }
+ final Collection<DeltaReport> deltaReports = Collections.unmodifiableList(
+ cpsDataService.getDeltaByDataspaceAnchorAndPayload(dataspaceName, sourceAnchorName,
+ xpath, yangResourceMap, jsonPayload.toString(), fetchDescendantsOption));
+
+ return new ResponseEntity<>(jsonObjectMapper.asJsonString(deltaReports), HttpStatus.OK);
+ }
+
+ @Override
@Timed(value = "cps.data.controller.get.delta",
description = "Time taken to get delta between anchors")
public ResponseEntity<Object> getDeltaByDataspaceAndAnchors(final String dataspaceName,
@@ -184,6 +213,10 @@ public class DataRestController implements CpsDataApi {
return new ResponseEntity<>(jsonObjectMapper.asJsonString(deltaBetweenAnchors), HttpStatus.OK);
}
+ private static ContentType getContentTypeFromHeader(final String contentTypeInHeader) {
+ return contentTypeInHeader.contains(MediaType.APPLICATION_XML_VALUE) ? ContentType.XML : ContentType.JSON;
+ }
+
private static boolean isRootXpath(final String xpath) {
return ROOT_XPATH.equals(xpath);
}
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
index 12c9c4c605..5241f61bd9 100755
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
@@ -4,7 +4,7 @@
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021-2022 Bell Canada.
* Modifications Copyright (C) 2022 Deutsche Telekom AG
- * Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,9 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
+import org.springframework.mock.web.MockMultipartFile
import org.springframework.test.web.servlet.MockMvc
+import org.springframework.web.multipart.MultipartFile
import spock.lang.Shared
import spock.lang.Specification
@@ -49,6 +51,7 @@ import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
@@ -101,6 +104,10 @@ class DataRestControllerSpec extends Specification {
static DataNode dataNodeWithChild = new DataNodeBuilder().withXpath('/parent')
.withChildDataNodes([new DataNodeBuilder().withXpath("/parent/child").build()]).build()
+ @Shared
+ static MultipartFile multipartYangFile = new MockMultipartFile("file", 'filename.yang', "text/plain", 'content'.getBytes())
+
+
def setup() {
dataNodeBaseEndpointV1 = "$basePath/v1/dataspaces/$dataspaceName"
dataNodeBaseEndpointV2 = "$basePath/v2/dataspaces/$dataspaceName"
@@ -185,22 +192,25 @@ class DataRestControllerSpec extends Specification {
def rootNodeXpath = '/'
when: 'list-node endpoint is invoked with post (create) operation'
def postRequestBuilder = post("$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes")
- .contentType(MediaType.APPLICATION_JSON)
+ .contentType(contentType)
.param('xpath', rootNodeXpath )
- .content(requestBodyJson)
+ .content(requestBody)
if (observedTimestamp != null)
postRequestBuilder.param('observed-timestamp', observedTimestamp)
def response = mvc.perform(postRequestBuilder).andReturn().response
then: 'a created response is returned'
response.status == expectedHttpStatus.value()
then: 'the java API was called with the correct parameters'
- expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, rootNodeXpath, expectedJsonData,
- { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+ expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, rootNodeXpath, expectedData,
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, expectedContentType)
where:
- scenario | observedTimestamp || expectedApiCount | expectedHttpStatus
- 'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.CREATED
- 'without observed-timestamp' | null || 1 | HttpStatus.CREATED
- 'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
+ scenario | observedTimestamp | contentType | requestBody || expectedApiCount | expectedHttpStatus | expectedData | expectedContentType
+ 'Content type JSON with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON
+ 'Content type JSON without observed-timestamp' | null | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON
+ 'Content type JSON with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_JSON | requestBodyJson || 0 | HttpStatus.BAD_REQUEST | expectedJsonData | ContentType.JSON
+ 'Content type XML with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML
+ 'Content type XML without observed-timestamp' | null | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML
+ 'Content type XML with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_XML | requestBodyXml || 0 | HttpStatus.BAD_REQUEST | expectedXmlData | ContentType.XML
}
def 'Save list elements #scenario.'() {
@@ -208,22 +218,25 @@ class DataRestControllerSpec extends Specification {
def parentNodeXpath = 'parent node xpath'
when: 'list-node endpoint is invoked with post (create) operation'
def postRequestBuilder = post("$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes")
- .contentType(MediaType.APPLICATION_JSON)
+ .contentType(contentType)
.param('xpath', parentNodeXpath)
- .content(requestBodyJson)
+ .content(requestBody)
if (observedTimestamp != null)
postRequestBuilder.param('observed-timestamp', observedTimestamp)
def response = mvc.perform(postRequestBuilder).andReturn().response
then: 'a created response is returned'
response.status == expectedHttpStatus.value()
then: 'the java API was called with the correct parameters'
- expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, expectedJsonData,
- { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+ expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, expectedData,
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, expectedContentType)
where:
- scenario | observedTimestamp || expectedApiCount | expectedHttpStatus
- 'with observed-timestamp' | '2021-03-03T23:59:59.999-0400' || 1 | HttpStatus.CREATED
- 'without observed-timestamp' | null || 1 | HttpStatus.CREATED
- 'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
+ scenario | observedTimestamp | contentType | requestBody || expectedApiCount | expectedHttpStatus | expectedData | expectedContentType
+ 'Content type JSON with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON
+ 'Content type JSON without observed-timestamp' | null | MediaType.APPLICATION_JSON | requestBodyJson || 1 | HttpStatus.CREATED | expectedJsonData | ContentType.JSON
+ 'Content type JSON with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_JSON | requestBodyJson || 0 | HttpStatus.BAD_REQUEST | expectedJsonData | ContentType.JSON
+ 'Content type XML with observed-timestamp' | '2021-03-03T23:59:59.999-0400' | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML
+ 'Content type XML without observed-timestamp' | null | MediaType.APPLICATION_XML | requestBodyXml || 1 | HttpStatus.CREATED | expectedXmlData | ContentType.XML
+ 'Content type XML with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_XML | requestBodyXml || 0 | HttpStatus.BAD_REQUEST | expectedXmlData | ContentType.XML
}
def 'Get data node with leaves'() {
@@ -337,7 +350,7 @@ class DataRestControllerSpec extends Specification {
def 'Get delta between two anchors'() {
given: 'the service returns a list containing delta reports'
- def deltaReports = new DeltaReportBuilder().actionAdd().withXpath('/bookstore').withSourceData('bookstore-name': 'Easons').withTargetData('bookstore-name': 'Easons').build()
+ def deltaReports = new DeltaReportBuilder().actionReplace().withXpath('some xpath').withSourceData('some key': 'some value').withTargetData('some key': 'some value').build()
def xpath = 'some xpath'
def endpoint = "$dataNodeBaseEndpointV2/anchors/sourceAnchor/delta"
mockCpsDataService.getDeltaByDataspaceAndAnchors(dataspaceName, 'sourceAnchor', 'targetAnchor', xpath, OMIT_DESCENDANTS) >> [deltaReports]
@@ -350,7 +363,48 @@ class DataRestControllerSpec extends Specification {
then: 'expected response code is returned'
assert response.status == HttpStatus.OK.value()
and: 'the response contains expected value'
- assert response.contentAsString.contains("[{\"action\":\"add\",\"xpath\":\"/bookstore\",\"sourceData\":{\"bookstore-name\":\"Easons\"},\"targetData\":{\"bookstore-name\":\"Easons\"}}]")
+ assert response.contentAsString.contains("[{\"action\":\"replace\",\"xpath\":\"some xpath\",\"sourceData\":{\"some key\":\"some value\"},\"targetData\":{\"some key\":\"some value\"}}]")
+ }
+
+ def 'Get delta between anchor and JSON payload with multipart file'() {
+ given: 'sample delta report, xpath, yang model file and json payload'
+ def deltaReports = new DeltaReportBuilder().actionCreate().withXpath('some xpath').build()
+ def xpath = 'some xpath'
+ def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/delta"
+ and: 'the service layer returns a list containing delta reports'
+ mockCpsDataService.getDeltaByDataspaceAnchorAndPayload(dataspaceName, anchorName, xpath, ['filename.yang':'content'], expectedJsonData, INCLUDE_ALL_DESCENDANTS) >> [deltaReports]
+ when: 'get delta request is performed using REST API'
+ def response =
+ mvc.perform(multipart(endpoint)
+ .file(multipartYangFile)
+ .param("json", requestBodyJson)
+ .param('xpath', xpath)
+ .contentType(MediaType.MULTIPART_FORM_DATA))
+ .andReturn().response
+ then: 'expected response code is returned'
+ assert response.status == HttpStatus.OK.value()
+ and: 'the response contains expected value'
+ assert response.contentAsString.contains("[{\"action\":\"create\",\"xpath\":\"some xpath\"}]")
+ }
+
+ def 'Get delta between anchor and JSON payload without multipart file'() {
+ given: 'sample delta report, xpath, and json payload'
+ def deltaReports = new DeltaReportBuilder().actionRemove().withXpath('some xpath').build()
+ def xpath = 'some xpath'
+ def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/delta"
+ and: 'the service layer returns a list containing delta reports'
+ mockCpsDataService.getDeltaByDataspaceAnchorAndPayload(dataspaceName, anchorName, xpath, [:], expectedJsonData, INCLUDE_ALL_DESCENDANTS) >> [deltaReports]
+ when: 'get delta request is performed using REST API'
+ def response =
+ mvc.perform(multipart(endpoint)
+ .param("json", requestBodyJson)
+ .param('xpath', xpath)
+ .contentType(MediaType.MULTIPART_FORM_DATA))
+ .andReturn().response
+ then: 'expected response code is returned'
+ assert response.status == HttpStatus.OK.value()
+ and: 'the response contains expected value'
+ assert response.contentAsString.contains("[{\"action\":\"remove\",\"xpath\":\"some xpath\"}]")
}
def 'Update data node leaves: #scenario.'() {
@@ -360,19 +414,22 @@ class DataRestControllerSpec extends Specification {
def response =
mvc.perform(
patch(endpoint)
- .contentType(MediaType.APPLICATION_JSON)
- .content(requestBodyJson)
+ .contentType(contentType)
+ .content(requestBody)
.param('xpath', inputXpath)
).andReturn().response
then: 'the service method is invoked with expected parameters'
- 1 * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, xpathServiceParameter, expectedJsonData, null)
+ 1 * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, xpathServiceParameter, expectedData, null, expectedContentType)
and: 'response status indicates success'
response.status == HttpStatus.OK.value()
where:
- scenario | inputXpath || xpathServiceParameter
- 'root node by default' | '' || '/'
- 'root node by choice' | '/' || '/'
- 'some xpath by parent' | '/some/xpath' || '/some/xpath'
+ scenario | inputXpath | contentType || xpathServiceParameter | requestBody | expectedData | expectedContentType
+ 'JSON content: root node by default' | '' | MediaType.APPLICATION_JSON || '/' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'JSON content: root node by choice' | '/' | MediaType.APPLICATION_JSON || '/' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'JSON content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_JSON || '/some/xpath' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'XML content: root node by default' | '' | MediaType.APPLICATION_XML || '/' | requestBodyXml | expectedXmlData | ContentType.XML
+ 'XML content: root node by choice' | '/' | MediaType.APPLICATION_XML || '/' | requestBodyXml | expectedXmlData | ContentType.XML
+ 'XML content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_XML || '/some/xpath' | requestBodyXml | expectedXmlData | ContentType.XML
}
def 'Update data node leaves with observedTimestamp'() {
@@ -389,7 +446,7 @@ class DataRestControllerSpec extends Specification {
).andReturn().response
then: 'the service method is invoked with expected parameters'
expectedApiCount * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, '/', expectedJsonData,
- { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
and: 'response status indicates success'
response.status == expectedHttpStatus.value()
where:
@@ -405,19 +462,22 @@ class DataRestControllerSpec extends Specification {
def response =
mvc.perform(
put(endpoint)
- .contentType(MediaType.APPLICATION_JSON)
- .content(requestBodyJson)
+ .contentType(contentType)
+ .content(requestBody)
.param('xpath', inputXpath))
.andReturn().response
then: 'the service method is invoked with expected parameters'
- 1 * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, xpathServiceParameter, expectedJsonData, noTimestamp)
+ 1 * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, xpathServiceParameter, expectedData, noTimestamp, expectedContentType)
and: 'response status indicates success'
response.status == HttpStatus.OK.value()
where:
- scenario | inputXpath || xpathServiceParameter
- 'root node by default' | '' || '/'
- 'root node by choice' | '/' || '/'
- 'some xpath by parent' | '/some/xpath' || '/some/xpath'
+ scenario | inputXpath | contentType || xpathServiceParameter | requestBody | expectedData | expectedContentType
+ 'JSON content: root node by default' | '' | MediaType.APPLICATION_JSON || '/' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'JSON content: root node by choice' | '/' | MediaType.APPLICATION_JSON || '/' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'JSON content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_JSON || '/some/xpath' | requestBodyJson | expectedJsonData | ContentType.JSON
+ 'XML content: root node by default' | '' | MediaType.APPLICATION_XML || '/' | requestBodyXml | expectedXmlData | ContentType.XML
+ 'XML content: root node by choice' | '/' | MediaType.APPLICATION_XML || '/' | requestBodyXml | expectedXmlData | ContentType.XML
+ 'XML content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_XML || '/some/xpath' | requestBodyXml | expectedXmlData | ContentType.XML
}
def 'Update data node and descendants with observedTimestamp.'() {
@@ -434,7 +494,7 @@ class DataRestControllerSpec extends Specification {
.andReturn().response
then: 'the service method is invoked with expected parameters'
expectedApiCount * mockCpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, '/', expectedJsonData,
- { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) })
+ { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }, ContentType.JSON)
and: 'response status indicates success'
response.status == expectedHttpStatus.value()
where:
@@ -504,4 +564,5 @@ class DataRestControllerSpec extends Specification {
'without observed timestamp' | null || 1 | HttpStatus.NO_CONTENT
'with invalid observed timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
}
+
}
diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml
index 221e1a9bf2..57e6528441 100644
--- a/cps-ri/pom.xml
+++ b/cps-ri/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsAdminPersistenceServiceImpl.java
index 56a046496e..b85b0f9b98 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsAdminPersistenceServiceImpl.java
@@ -21,24 +21,24 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl;
+package org.onap.cps.ri;
import jakarta.transaction.Transactional;
import java.util.Collection;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.SchemaSetEntity;
+import org.onap.cps.ri.repository.AnchorRepository;
+import org.onap.cps.ri.repository.DataspaceRepository;
+import org.onap.cps.ri.repository.SchemaSetRepository;
import org.onap.cps.spi.CpsAdminPersistenceService;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.SchemaSetEntity;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.DataspaceInUseException;
import org.onap.cps.spi.model.Anchor;
import org.onap.cps.spi.model.Dataspace;
-import org.onap.cps.spi.repository.AnchorRepository;
-import org.onap.cps.spi.repository.DataspaceRepository;
-import org.onap.cps.spi.repository.SchemaSetRepository;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;
@@ -107,6 +107,12 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
}
@Override
+ public Anchor getAnchor(final String dataspaceName, final String anchorName) {
+ final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
+ return toAnchor(anchorEntity);
+ }
+
+ @Override
public Collection<Anchor> getAnchors(final String dataspaceName) {
final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final Collection<AnchorEntity> anchorEntities = anchorRepository.findAllByDataspace(dataspaceEntity);
@@ -114,7 +120,14 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
}
@Override
- public Collection<Anchor> getAnchors(final String dataspaceName, final String schemaSetName) {
+ public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> anchorNames) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ return anchorRepository.findAllByDataspaceAndNameIn(dataspaceEntity, anchorNames)
+ .stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet());
+ }
+
+ @Override
+ public Collection<Anchor> getAnchorsBySchemaSetName(final String dataspaceName, final String schemaSetName) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final SchemaSetEntity schemaSetEntity = schemaSetRepository.getByDataspaceAndName(
dataspaceEntity, schemaSetName);
@@ -124,7 +137,8 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
}
@Override
- public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) {
+ public Collection<Anchor> getAnchorsBySchemaSetNames(final String dataspaceName,
+ final Collection<String> schemaSetNames) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
return anchorRepository.findAllByDataspaceAndSchemaSetNameIn(dataspaceEntity, schemaSetNames)
.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet());
@@ -137,11 +151,6 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
inputModuleNames.size());
}
- @Override
- public Anchor getAnchor(final String dataspaceName, final String anchorName) {
- return toAnchor(getAnchorEntity(dataspaceName, anchorName));
- }
-
@Transactional
@Override
public void deleteAnchor(final String dataspaceName, final String anchorName) {
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java
index fd47793a7a..ec46fea4cb 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java
@@ -21,7 +21,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl;
+package org.onap.cps.ri;
import static org.onap.cps.spi.PaginationOption.NO_PAGINATION;
@@ -48,12 +48,16 @@ import org.hibernate.StaleStateException;
import org.onap.cps.cpspath.parser.CpsPathQuery;
import org.onap.cps.cpspath.parser.CpsPathUtil;
import org.onap.cps.cpspath.parser.PathParsingException;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.FragmentEntity;
+import org.onap.cps.ri.repository.AnchorRepository;
+import org.onap.cps.ri.repository.DataspaceRepository;
+import org.onap.cps.ri.repository.FragmentRepository;
+import org.onap.cps.ri.utils.SessionManager;
import org.onap.cps.spi.CpsDataPersistenceService;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.PaginationOption;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.FragmentEntity;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.ConcurrencyException;
import org.onap.cps.spi.exceptions.CpsAdminException;
@@ -62,10 +66,6 @@ import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
import org.onap.cps.spi.exceptions.DataNodeNotFoundExceptionBatch;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.DataNodeBuilder;
-import org.onap.cps.spi.repository.AnchorRepository;
-import org.onap.cps.spi.repository.DataspaceRepository;
-import org.onap.cps.spi.repository.FragmentRepository;
-import org.onap.cps.spi.utils.SessionManager;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java
index 17f13b81ad..6f491ba3b7 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java
@@ -21,7 +21,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl;
+package org.onap.cps.ri;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -48,21 +48,21 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.SchemaSetEntity;
+import org.onap.cps.ri.models.YangResourceEntity;
+import org.onap.cps.ri.models.YangResourceModuleReference;
+import org.onap.cps.ri.repository.DataspaceRepository;
+import org.onap.cps.ri.repository.ModuleReferenceRepository;
+import org.onap.cps.ri.repository.SchemaSetRepository;
+import org.onap.cps.ri.repository.YangResourceRepository;
import org.onap.cps.spi.CpsModulePersistenceService;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.SchemaSetEntity;
-import org.onap.cps.spi.entities.YangResourceEntity;
-import org.onap.cps.spi.entities.YangResourceModuleReference;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.DuplicatedYangResourceException;
import org.onap.cps.spi.exceptions.ModelValidationException;
import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.spi.model.ModuleReference;
import org.onap.cps.spi.model.SchemaSet;
-import org.onap.cps.spi.repository.DataspaceRepository;
-import org.onap.cps.spi.repository.ModuleReferenceRepository;
-import org.onap.cps.spi.repository.SchemaSetRepository;
-import org.onap.cps.spi.repository.YangResourceRepository;
import org.opendaylight.yangtools.yang.common.Revision;
import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
@@ -241,6 +241,15 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ
return moduleReferenceRepository.identifyNewModuleReferences(moduleReferencesToCheck);
}
+ @Override
+ public Collection<ModuleReference> getModuleReferencesByAttribute(final String dataspaceName,
+ final String anchorName,
+ final Map<String, String> parentAttributes,
+ final Map<String, String> childAttributes) {
+ return moduleReferenceRepository.findModuleReferences(dataspaceName, anchorName, parentAttributes,
+ childAttributes);
+ }
+
private Set<YangResourceEntity> synchronizeYangResources(
final Map<String, String> moduleReferenceNameToContentMap) {
final Map<String, YangResourceEntity> checksumToEntityMap = moduleReferenceNameToContentMap.entrySet().stream()
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java b/cps-ri/src/main/java/org/onap/cps/ri/models/AnchorEntity.java
index ac06b0b5a4..bf9e25daf1 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/models/AnchorEntity.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.entities;
+package org.onap.cps.ri.models;
import jakarta.persistence.Column;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java b/cps-ri/src/main/java/org/onap/cps/ri/models/DataspaceEntity.java
index ddfb09c942..689ae2c000 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/DataspaceEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/models/DataspaceEntity.java
@@ -19,7 +19,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.entities;
+package org.onap.cps.ri.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java b/cps-ri/src/main/java/org/onap/cps/ri/models/FragmentEntity.java
index c763f61f8f..2c851b60a5 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/models/FragmentEntity.java
@@ -19,7 +19,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.entities;
+package org.onap.cps.ri.models;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/SchemaSetEntity.java b/cps-ri/src/main/java/org/onap/cps/ri/models/SchemaSetEntity.java
index e07f766ed0..e99f79e330 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/SchemaSetEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/models/SchemaSetEntity.java
@@ -17,7 +17,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.entities;
+package org.onap.cps.ri.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/YangResourceEntity.java b/cps-ri/src/main/java/org/onap/cps/ri/models/YangResourceEntity.java
index 0c54baa4df..2b2d7924db 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/YangResourceEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/models/YangResourceEntity.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.entities;
+package org.onap.cps.ri.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/YangResourceModuleReference.java b/cps-ri/src/main/java/org/onap/cps/ri/models/YangResourceModuleReference.java
index 3c39c6baac..28ef56d38a 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/YangResourceModuleReference.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/models/YangResourceModuleReference.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.entities;
+package org.onap.cps.ri.models;
import org.springframework.beans.factory.annotation.Value;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java
index d78a016c2e..7fe14b3173 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java
@@ -18,13 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.Collection;
import java.util.Optional;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.SchemaSetEntity;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.SchemaSetEntity;
import org.onap.cps.spi.exceptions.AnchorNotFoundException;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/DataspaceRepository.java
index b1ce127c4a..b79d802d95 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/DataspaceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/DataspaceRepository.java
@@ -18,10 +18,10 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.Optional;
-import org.onap.cps.spi.entities.DataspaceEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
import org.onap.cps.spi.exceptions.DataspaceNotFoundException;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentPrefetchRepository.java
index 2460db869a..6813995d99 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentPrefetchRepository.java
@@ -18,11 +18,11 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.Collection;
+import org.onap.cps.ri.models.FragmentEntity;
import org.onap.cps.spi.FetchDescendantsOption;
-import org.onap.cps.spi.entities.FragmentEntity;
public interface FragmentPrefetchRepository {
Collection<FragmentEntity> prefetchDescendantsOfFragmentEntities(
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentPrefetchRepositoryImpl.java
index c187f20ea9..bcf01b3d76 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentPrefetchRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentPrefetchRepositoryImpl.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.sql.Connection;
import java.util.Collection;
@@ -29,9 +29,9 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.FragmentEntity;
import org.onap.cps.spi.FetchDescendantsOption;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.FragmentEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java
index b2014757d7..b8bbf59c23 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentQueryBuilder.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentQueryBuilder.java
@@ -19,34 +19,30 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
-import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
import org.onap.cps.cpspath.parser.CpsPathPrefixType;
import org.onap.cps.cpspath.parser.CpsPathQuery;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.FragmentEntity;
+import org.onap.cps.ri.utils.EscapeUtils;
import org.onap.cps.spi.PaginationOption;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.FragmentEntity;
import org.onap.cps.spi.exceptions.CpsPathException;
-import org.onap.cps.spi.utils.EscapeUtils;
import org.springframework.stereotype.Component;
@RequiredArgsConstructor
-@Slf4j
@Component
public class FragmentQueryBuilder {
- private static final AnchorEntity ACROSS_ALL_ANCHORS = null;
@PersistenceContext
private EntityManager entityManager;
@@ -59,8 +55,14 @@ public class FragmentQueryBuilder {
* @return a executable query object
*/
public Query getQueryForAnchorAndCpsPath(final AnchorEntity anchorEntity, final CpsPathQuery cpsPathQuery) {
- return getQueryForDataspaceOrAnchorAndCpsPath(anchorEntity.getDataspace(),
- anchorEntity, cpsPathQuery, Collections.emptyList());
+ final StringBuilder sqlStringBuilder = new StringBuilder();
+ final Map<String, Object> queryParameters = new HashMap<>();
+
+ sqlStringBuilder.append("SELECT fragment.* FROM fragment");
+ addWhereClauseForAnchor(anchorEntity, sqlStringBuilder, queryParameters);
+ addNodeSearchConditions(cpsPathQuery, sqlStringBuilder, queryParameters, false);
+
+ return getQuery(sqlStringBuilder.toString(), queryParameters, FragmentEntity.class);
}
/**
@@ -73,8 +75,18 @@ public class FragmentQueryBuilder {
public Query getQueryForDataspaceAndCpsPath(final DataspaceEntity dataspaceEntity,
final CpsPathQuery cpsPathQuery,
final List<Long> anchorIdsForPagination) {
- return getQueryForDataspaceOrAnchorAndCpsPath(dataspaceEntity, ACROSS_ALL_ANCHORS,
- cpsPathQuery, anchorIdsForPagination);
+ final StringBuilder sqlStringBuilder = new StringBuilder();
+ final Map<String, Object> queryParameters = new HashMap<>();
+
+ sqlStringBuilder.append("SELECT fragment.* FROM fragment");
+ if (anchorIdsForPagination.isEmpty()) {
+ addWhereClauseForDataspace(dataspaceEntity, sqlStringBuilder, queryParameters);
+ } else {
+ addWhereClauseForAnchorIds(anchorIdsForPagination, sqlStringBuilder, queryParameters);
+ }
+ addNodeSearchConditions(cpsPathQuery, sqlStringBuilder, queryParameters, true);
+
+ return getQuery(sqlStringBuilder.toString(), queryParameters, FragmentEntity.class);
}
/**
@@ -89,52 +101,52 @@ public class FragmentQueryBuilder {
final PaginationOption paginationOption) {
final StringBuilder sqlStringBuilder = new StringBuilder();
final Map<String, Object> queryParameters = new HashMap<>();
- sqlStringBuilder.append("SELECT distinct(fragment.anchor_id) FROM fragment "
- + "JOIN anchor ON anchor.id = fragment.anchor_id WHERE dataspace_id = :dataspaceId");
- queryParameters.put("dataspaceId", dataspaceEntity.getId());
- addAbsoluteParentXpathSearchCondition(cpsPathQuery, sqlStringBuilder, queryParameters, ACROSS_ALL_ANCHORS);
- addXpathSearchCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
- addLeafConditions(cpsPathQuery, sqlStringBuilder);
- addTextFunctionCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
- addContainsFunctionCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
- if (PaginationOption.NO_PAGINATION != paginationOption) {
- sqlStringBuilder.append(" ORDER BY fragment.anchor_id");
- addPaginationCondition(sqlStringBuilder, queryParameters, paginationOption);
- }
- final Query query = entityManager.createNativeQuery(sqlStringBuilder.toString());
+ sqlStringBuilder.append("SELECT distinct(fragment.anchor_id) FROM fragment");
+ addWhereClauseForDataspace(dataspaceEntity, sqlStringBuilder, queryParameters);
+ addNodeSearchConditions(cpsPathQuery, sqlStringBuilder, queryParameters, true);
+ sqlStringBuilder.append(" ORDER BY fragment.anchor_id");
+ addPaginationCondition(sqlStringBuilder, queryParameters, paginationOption);
+
+ return getQuery(sqlStringBuilder.toString(), queryParameters, Long.class);
+ }
+
+ private Query getQuery(final String sql, final Map<String, Object> queryParameters, final Class<?> returnType) {
+ final Query query = entityManager.createNativeQuery(sql, returnType);
setQueryParameters(query, queryParameters);
return query;
}
- private Query getQueryForDataspaceOrAnchorAndCpsPath(final DataspaceEntity dataspaceEntity,
- final AnchorEntity anchorEntity,
- final CpsPathQuery cpsPathQuery,
- final List<Long> anchorIdsForPagination) {
- final StringBuilder sqlStringBuilder = new StringBuilder();
- final Map<String, Object> queryParameters = new HashMap<>();
+ private static void addWhereClauseForAnchor(final AnchorEntity anchorEntity,
+ final StringBuilder sqlStringBuilder,
+ final Map<String, Object> queryParameters) {
+ sqlStringBuilder.append(" WHERE anchor_id = :anchorId");
+ queryParameters.put("anchorId", anchorEntity.getId());
+ }
- if (anchorEntity == ACROSS_ALL_ANCHORS) {
- sqlStringBuilder.append("SELECT fragment.* FROM fragment JOIN anchor ON anchor.id = fragment.anchor_id"
- + " WHERE dataspace_id = :dataspaceId");
- queryParameters.put("dataspaceId", dataspaceEntity.getId());
- if (!anchorIdsForPagination.isEmpty()) {
- sqlStringBuilder.append(" AND anchor_id IN (:anchorIdsForPagination)");
- queryParameters.put("anchorIdsForPagination", anchorIdsForPagination);
- }
- } else {
- sqlStringBuilder.append("SELECT * FROM fragment WHERE anchor_id = :anchorId");
- queryParameters.put("anchorId", anchorEntity.getId());
- }
- addAbsoluteParentXpathSearchCondition(cpsPathQuery, sqlStringBuilder, queryParameters, anchorEntity);
+ private static void addWhereClauseForAnchorIds(final List<Long> anchorIdsForPagination,
+ final StringBuilder sqlStringBuilder,
+ final Map<String, Object> queryParameters) {
+ sqlStringBuilder.append(" WHERE anchor_id IN (:anchorIdsForPagination)");
+ queryParameters.put("anchorIdsForPagination", anchorIdsForPagination);
+ }
+
+ private static void addWhereClauseForDataspace(final DataspaceEntity dataspaceEntity,
+ final StringBuilder sqlStringBuilder,
+ final Map<String, Object> queryParameters) {
+ sqlStringBuilder.append(" JOIN anchor ON anchor.id = fragment.anchor_id WHERE dataspace_id = :dataspaceId");
+ queryParameters.put("dataspaceId", dataspaceEntity.getId());
+ }
+
+ private static void addNodeSearchConditions(final CpsPathQuery cpsPathQuery,
+ final StringBuilder sqlStringBuilder,
+ final Map<String, Object> queryParameters,
+ final boolean acrossAnchors) {
+ addAbsoluteParentXpathSearchCondition(cpsPathQuery, sqlStringBuilder, queryParameters, acrossAnchors);
addXpathSearchCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
addLeafConditions(cpsPathQuery, sqlStringBuilder);
addTextFunctionCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
addContainsFunctionCondition(cpsPathQuery, sqlStringBuilder, queryParameters);
-
- final Query query = entityManager.createNativeQuery(sqlStringBuilder.toString(), FragmentEntity.class);
- setQueryParameters(query, queryParameters);
- return query;
}
private static void addXpathSearchCondition(final CpsPathQuery cpsPathQuery,
@@ -152,12 +164,12 @@ public class FragmentQueryBuilder {
private static void addAbsoluteParentXpathSearchCondition(final CpsPathQuery cpsPathQuery,
final StringBuilder sqlStringBuilder,
final Map<String, Object> queryParameters,
- final AnchorEntity anchorEntity) {
+ final boolean acrossAnchors) {
if (CpsPathPrefixType.ABSOLUTE.equals(cpsPathQuery.getCpsPathPrefixType())) {
if (cpsPathQuery.getNormalizedParentPath().isEmpty()) {
sqlStringBuilder.append(" AND parent_id IS NULL");
} else {
- if (anchorEntity == ACROSS_ALL_ANCHORS) {
+ if (acrossAnchors) {
sqlStringBuilder.append(" AND parent_id IN (SELECT id FROM fragment WHERE xpath = :parentXpath)");
} else {
sqlStringBuilder.append(" AND parent_id = (SELECT id FROM fragment WHERE xpath = :parentXpath"
@@ -171,10 +183,12 @@ public class FragmentQueryBuilder {
private static void addPaginationCondition(final StringBuilder sqlStringBuilder,
final Map<String, Object> queryParameters,
final PaginationOption paginationOption) {
- final Integer offset = (paginationOption.getPageIndex() - 1) * paginationOption.getPageSize();
- sqlStringBuilder.append(" LIMIT :pageSize OFFSET :offset");
- queryParameters.put("pageSize", paginationOption.getPageSize());
- queryParameters.put("offset", offset);
+ if (PaginationOption.NO_PAGINATION != paginationOption) {
+ final Integer offset = (paginationOption.getPageIndex() - 1) * paginationOption.getPageSize();
+ sqlStringBuilder.append(" LIMIT :pageSize OFFSET :offset");
+ queryParameters.put("pageSize", paginationOption.getPageSize());
+ queryParameters.put("offset", offset);
+ }
}
private static Integer getTextValueAsInt(final CpsPathQuery cpsPathQuery) {
@@ -185,40 +199,34 @@ public class FragmentQueryBuilder {
}
}
- private void addLeafConditions(final CpsPathQuery cpsPathQuery, final StringBuilder sqlStringBuilder) {
+ private static void addLeafConditions(final CpsPathQuery cpsPathQuery, final StringBuilder sqlStringBuilder) {
if (cpsPathQuery.hasLeafConditions()) {
- queryLeafConditions(cpsPathQuery, sqlStringBuilder);
- }
- }
-
- private void queryLeafConditions(final CpsPathQuery cpsPathQuery, final StringBuilder sqlStringBuilder) {
- sqlStringBuilder.append(" AND (");
- final Queue<String> booleanOperatorsQueue = new LinkedList<>(cpsPathQuery.getBooleanOperators());
- final Queue<String> comparativeOperatorQueue = new LinkedList<>(cpsPathQuery.getComparativeOperators());
- cpsPathQuery.getLeavesData().forEach(leaf -> {
- final String nextComparativeOperator = comparativeOperatorQueue.poll();
- if (leaf.getValue() instanceof Integer) {
- sqlStringBuilder.append("(attributes ->> '").append(leaf.getName()).append("')\\:\\:int");
- sqlStringBuilder.append(nextComparativeOperator);
- sqlStringBuilder.append(leaf.getValue());
- } else {
- if ("=".equals(nextComparativeOperator)) {
- final String leafValueAsText = leaf.getValue().toString();
- sqlStringBuilder.append("attributes ->> '").append(leaf.getName()).append("'");
- sqlStringBuilder.append(" = '");
- sqlStringBuilder.append(EscapeUtils.escapeForSqlStringLiteral(leafValueAsText));
- sqlStringBuilder.append("'");
+ sqlStringBuilder.append(" AND (");
+ final Queue<String> booleanOperatorsQueue = new LinkedList<>(cpsPathQuery.getBooleanOperators());
+ cpsPathQuery.getLeafConditions().forEach(leafCondition -> {
+ if (leafCondition.value() instanceof Integer) {
+ sqlStringBuilder.append("(attributes ->> '").append(leafCondition.name()).append("')\\:\\:int");
+ sqlStringBuilder.append(leafCondition.operator());
+ sqlStringBuilder.append(leafCondition.value());
} else {
- throw new CpsPathException(" can use only " + nextComparativeOperator + " with integer ");
+ if ("=".equals(leafCondition.operator())) {
+ final String leafValueAsText = leafCondition.value().toString();
+ sqlStringBuilder.append("attributes ->> '").append(leafCondition.name()).append("'");
+ sqlStringBuilder.append(" = '");
+ sqlStringBuilder.append(EscapeUtils.escapeForSqlStringLiteral(leafValueAsText));
+ sqlStringBuilder.append("'");
+ } else {
+ throw new CpsPathException(" can use only " + leafCondition.operator() + " with integer ");
+ }
}
- }
- if (!booleanOperatorsQueue.isEmpty()) {
- sqlStringBuilder.append(" ");
- sqlStringBuilder.append(booleanOperatorsQueue.poll());
- sqlStringBuilder.append(" ");
- }
- });
- sqlStringBuilder.append(")");
+ if (!booleanOperatorsQueue.isEmpty()) {
+ sqlStringBuilder.append(" ");
+ sqlStringBuilder.append(booleanOperatorsQueue.poll());
+ sqlStringBuilder.append(" ");
+ }
+ });
+ sqlStringBuilder.append(")");
+ }
}
private static void addTextFunctionCondition(final CpsPathQuery cpsPathQuery,
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java
index 1a31d2b499..8edc3f2311 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java
@@ -1,140 +1,140 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation.
- * Modifications Copyright (C) 2020-2021 Bell Canada.
- * Modifications Copyright (C) 2020-2021 Pantheon.tech.
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
- * ================================================================================
- * 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.spi.repository;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.FragmentEntity;
-import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
-import org.onap.cps.spi.utils.EscapeUtils;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Modifying;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.query.Param;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>, FragmentRepositoryCpsPathQuery,
- FragmentPrefetchRepository {
-
- Optional<FragmentEntity> findByAnchorAndXpath(AnchorEntity anchorEntity, String xpath);
-
- default FragmentEntity getByAnchorAndXpath(final AnchorEntity anchorEntity, final String xpath) {
- return findByAnchorAndXpath(anchorEntity, xpath).orElseThrow(() ->
- new DataNodeNotFoundException(anchorEntity.getDataspace().getName(), anchorEntity.getName(), xpath));
- }
-
- @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)",
- nativeQuery = true)
- List<FragmentEntity> findByAnchorIdAndXpathIn(@Param("anchorId") long anchorId,
- @Param("xpaths") String[] xpaths);
-
- default List<FragmentEntity> findByAnchorAndXpathIn(final AnchorEntity anchorEntity,
- final Collection<String> xpaths) {
- return findByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths.toArray(new String[0]));
- }
-
- @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId \n"
- + "AND xpath LIKE :escapedXpath||'[@%]' AND xpath NOT LIKE :escapedXpath||'[@%]/%[@%]'",
- nativeQuery = true)
- List<FragmentEntity> findListByAnchorIdAndEscapedXpath(@Param("anchorId") long anchorId,
- @Param("escapedXpath") String escapedXpath);
-
- default List<FragmentEntity> findListByAnchorAndXpath(final AnchorEntity anchorEntity, final String xpath) {
- final String escapedXpath = EscapeUtils.escapeForSqlLike(xpath);
- return findListByAnchorIdAndEscapedXpath(anchorEntity.getId(), escapedXpath);
- }
-
- @Query(value = "SELECT fragment.* FROM fragment JOIN anchor ON anchor.id = fragment.anchor_id "
- + "WHERE dataspace_id = :dataspaceId AND xpath = ANY (:xpaths)", nativeQuery = true)
- List<FragmentEntity> findByDataspaceIdAndXpathIn(@Param("dataspaceId") int dataspaceId,
- @Param("xpaths") String[] xpaths);
-
- default List<FragmentEntity> findByDataspaceAndXpathIn(final DataspaceEntity dataspaceEntity,
- final Collection<String> xpaths) {
- return findByDataspaceIdAndXpathIn(dataspaceEntity.getId(), xpaths.toArray(new String[0]));
- }
-
- @Query(value = "SELECT * FROM fragment WHERE anchor_id IN (:anchorIds)"
- + " AND xpath = ANY (:xpaths)", nativeQuery = true)
- List<FragmentEntity> findByAnchorIdsAndXpathIn(@Param("anchorIds") Long[] anchorIds,
- @Param("xpaths") String[] xpaths);
-
- @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId LIMIT 1", nativeQuery = true)
- Optional<FragmentEntity> findOneByAnchorId(@Param("anchorId") long anchorId);
-
- @Modifying
- @Query(value = "DELETE FROM fragment WHERE anchor_id = ANY (:anchorIds)", nativeQuery = true)
- void deleteByAnchorIdIn(@Param("anchorIds") long[] anchorIds);
-
- default void deleteByAnchorIn(final Collection<AnchorEntity> anchorEntities) {
- deleteByAnchorIdIn(anchorEntities.stream().map(AnchorEntity::getId).mapToLong(id -> id).toArray());
- }
-
- @Modifying
- @Query(value = "DELETE FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)", nativeQuery = true)
- void deleteByAnchorIdAndXpaths(@Param("anchorId") long anchorId, @Param("xpaths") String[] xpaths);
-
- default void deleteByAnchorIdAndXpaths(final long anchorId, final Collection<String> xpaths) {
- deleteByAnchorIdAndXpaths(anchorId, xpaths.toArray(new String[0]));
- }
-
- @Modifying
- @Query(value = "DELETE FROM fragment f WHERE anchor_id = :anchorId AND xpath LIKE ANY (:xpathPatterns)",
- nativeQuery = true)
- void deleteByAnchorIdAndXpathLikeAny(@Param("anchorId") long anchorId,
- @Param("xpathPatterns") String[] xpathPatterns);
-
- default void deleteListsByAnchorIdAndXpaths(long anchorId, Collection<String> xpaths) {
- deleteByAnchorIdAndXpathLikeAny(anchorId,
- xpaths.stream().map(xpath -> EscapeUtils.escapeForSqlLike(xpath) + "[@%").toArray(String[]::new));
- }
-
- @Query(value = "SELECT xpath FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)",
- nativeQuery = true)
- List<String> findAllXpathByAnchorIdAndXpathIn(@Param("anchorId") long anchorId,
- @Param("xpaths") String[] xpaths);
-
- default List<String> findAllXpathByAnchorAndXpathIn(final AnchorEntity anchorEntity,
- final Collection<String> xpaths) {
- return findAllXpathByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths.toArray(new String[0]));
- }
-
- @Query(value = "SELECT EXISTS(SELECT 1 FROM fragment WHERE anchor_id = :anchorId"
- + " AND xpath LIKE :xpathPattern LIMIT 1)", nativeQuery = true)
- boolean existsByAnchorIdAndParentXpathAndXpathLike(@Param("anchorId") long anchorId,
- @Param("xpathPattern") String xpathPattern);
-
- default boolean existsByAnchorAndXpathStartsWith(final AnchorEntity anchorEntity, final String xpath) {
- return existsByAnchorIdAndParentXpathAndXpathLike(anchorEntity.getId(),
- EscapeUtils.escapeForSqlLike(xpath) + "%");
- }
-
- @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId AND parent_id IS NULL", nativeQuery = true)
- List<FragmentEntity> findRootsByAnchorId(@Param("anchorId") long anchorId);
-
-}
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021-2023 Nordix Foundation.
+ * Modifications Copyright (C) 2020-2021 Bell Canada.
+ * Modifications Copyright (C) 2020-2021 Pantheon.tech.
+ * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * ================================================================================
+ * 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.ri.repository;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.FragmentEntity;
+import org.onap.cps.ri.utils.EscapeUtils;
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>, FragmentRepositoryCpsPathQuery,
+ FragmentPrefetchRepository {
+
+ Optional<FragmentEntity> findByAnchorAndXpath(AnchorEntity anchorEntity, String xpath);
+
+ default FragmentEntity getByAnchorAndXpath(final AnchorEntity anchorEntity, final String xpath) {
+ return findByAnchorAndXpath(anchorEntity, xpath).orElseThrow(() ->
+ new DataNodeNotFoundException(anchorEntity.getDataspace().getName(), anchorEntity.getName(), xpath));
+ }
+
+ @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)",
+ nativeQuery = true)
+ List<FragmentEntity> findByAnchorIdAndXpathIn(@Param("anchorId") long anchorId,
+ @Param("xpaths") String[] xpaths);
+
+ default List<FragmentEntity> findByAnchorAndXpathIn(final AnchorEntity anchorEntity,
+ final Collection<String> xpaths) {
+ return findByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths.toArray(new String[0]));
+ }
+
+ @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId \n"
+ + "AND xpath LIKE :escapedXpath||'[@%]' AND xpath NOT LIKE :escapedXpath||'[@%]/%[@%]'",
+ nativeQuery = true)
+ List<FragmentEntity> findListByAnchorIdAndEscapedXpath(@Param("anchorId") long anchorId,
+ @Param("escapedXpath") String escapedXpath);
+
+ default List<FragmentEntity> findListByAnchorAndXpath(final AnchorEntity anchorEntity, final String xpath) {
+ final String escapedXpath = EscapeUtils.escapeForSqlLike(xpath);
+ return findListByAnchorIdAndEscapedXpath(anchorEntity.getId(), escapedXpath);
+ }
+
+ @Query(value = "SELECT fragment.* FROM fragment JOIN anchor ON anchor.id = fragment.anchor_id "
+ + "WHERE dataspace_id = :dataspaceId AND xpath = ANY (:xpaths)", nativeQuery = true)
+ List<FragmentEntity> findByDataspaceIdAndXpathIn(@Param("dataspaceId") int dataspaceId,
+ @Param("xpaths") String[] xpaths);
+
+ default List<FragmentEntity> findByDataspaceAndXpathIn(final DataspaceEntity dataspaceEntity,
+ final Collection<String> xpaths) {
+ return findByDataspaceIdAndXpathIn(dataspaceEntity.getId(), xpaths.toArray(new String[0]));
+ }
+
+ @Query(value = "SELECT * FROM fragment WHERE anchor_id IN (:anchorIds)"
+ + " AND xpath = ANY (:xpaths)", nativeQuery = true)
+ List<FragmentEntity> findByAnchorIdsAndXpathIn(@Param("anchorIds") Long[] anchorIds,
+ @Param("xpaths") String[] xpaths);
+
+ @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId LIMIT 1", nativeQuery = true)
+ Optional<FragmentEntity> findOneByAnchorId(@Param("anchorId") long anchorId);
+
+ @Modifying
+ @Query(value = "DELETE FROM fragment WHERE anchor_id = ANY (:anchorIds)", nativeQuery = true)
+ void deleteByAnchorIdIn(@Param("anchorIds") long[] anchorIds);
+
+ default void deleteByAnchorIn(final Collection<AnchorEntity> anchorEntities) {
+ deleteByAnchorIdIn(anchorEntities.stream().map(AnchorEntity::getId).mapToLong(id -> id).toArray());
+ }
+
+ @Modifying
+ @Query(value = "DELETE FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)", nativeQuery = true)
+ void deleteByAnchorIdAndXpaths(@Param("anchorId") long anchorId, @Param("xpaths") String[] xpaths);
+
+ default void deleteByAnchorIdAndXpaths(final long anchorId, final Collection<String> xpaths) {
+ deleteByAnchorIdAndXpaths(anchorId, xpaths.toArray(new String[0]));
+ }
+
+ @Modifying
+ @Query(value = "DELETE FROM fragment f WHERE anchor_id = :anchorId AND xpath LIKE ANY (:xpathPatterns)",
+ nativeQuery = true)
+ void deleteByAnchorIdAndXpathLikeAny(@Param("anchorId") long anchorId,
+ @Param("xpathPatterns") String[] xpathPatterns);
+
+ default void deleteListsByAnchorIdAndXpaths(long anchorId, Collection<String> xpaths) {
+ deleteByAnchorIdAndXpathLikeAny(anchorId,
+ xpaths.stream().map(xpath -> EscapeUtils.escapeForSqlLike(xpath) + "[@%").toArray(String[]::new));
+ }
+
+ @Query(value = "SELECT xpath FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)",
+ nativeQuery = true)
+ List<String> findAllXpathByAnchorIdAndXpathIn(@Param("anchorId") long anchorId,
+ @Param("xpaths") String[] xpaths);
+
+ default List<String> findAllXpathByAnchorAndXpathIn(final AnchorEntity anchorEntity,
+ final Collection<String> xpaths) {
+ return findAllXpathByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths.toArray(new String[0]));
+ }
+
+ @Query(value = "SELECT EXISTS(SELECT 1 FROM fragment WHERE anchor_id = :anchorId"
+ + " AND xpath LIKE :xpathPattern LIMIT 1)", nativeQuery = true)
+ boolean existsByAnchorIdAndParentXpathAndXpathLike(@Param("anchorId") long anchorId,
+ @Param("xpathPattern") String xpathPattern);
+
+ default boolean existsByAnchorAndXpathStartsWith(final AnchorEntity anchorEntity, final String xpath) {
+ return existsByAnchorIdAndParentXpathAndXpathLike(anchorEntity.getId(),
+ EscapeUtils.escapeForSqlLike(xpath) + "%");
+ }
+
+ @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId AND parent_id IS NULL", nativeQuery = true)
+ List<FragmentEntity> findRootsByAnchorId(@Param("anchorId") long anchorId);
+
+}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java
index 9c279618b0..49c8e76ab5 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQuery.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQuery.java
@@ -19,14 +19,14 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.List;
import org.onap.cps.cpspath.parser.CpsPathQuery;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.FragmentEntity;
import org.onap.cps.spi.PaginationOption;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.FragmentEntity;
public interface FragmentRepositoryCpsPathQuery {
List<FragmentEntity> findByAnchorAndCpsPath(AnchorEntity anchorEntity, CpsPathQuery cpsPathQuery);
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQueryImpl.java
index 78e0f08c44..01b2813cd3 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryCpsPathQueryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepositoryCpsPathQueryImpl.java
@@ -1,6 +1,6 @@
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation.
+ * Copyright (C) 2021-2024 Nordix Foundation.
* Modifications Copyright (C) 2023 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,28 +19,23 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import jakarta.transaction.Transactional;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.cpspath.parser.CpsPathQuery;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.FragmentEntity;
import org.onap.cps.spi.PaginationOption;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.FragmentEntity;
@RequiredArgsConstructor
@Slf4j
public class FragmentRepositoryCpsPathQueryImpl implements FragmentRepositoryCpsPathQuery {
- @PersistenceContext
- private EntityManager entityManager;
-
private final FragmentQueryBuilder fragmentQueryBuilder;
@Override
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceQuery.java
index 00e53aa00f..ad0f9c5c61 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceQuery.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceQuery.java
@@ -1,6 +1,6 @@
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation.
+ * Copyright (C) 2022-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.
@@ -18,9 +18,10 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.Collection;
+import java.util.Map;
import org.onap.cps.spi.model.ModuleReference;
/**
@@ -29,4 +30,8 @@ import org.onap.cps.spi.model.ModuleReference;
public interface ModuleReferenceQuery {
Collection<ModuleReference> identifyNewModuleReferences(final Collection<ModuleReference> moduleReferencesToCheck);
+
+ Collection<ModuleReference> findModuleReferences(final String dataspaceName, final String anchorName,
+ final Map<String, String> parentAttributes,
+ final Map<String, String> childAttributes);
}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepository.java
index 15ffa372f9..e9b866cc19 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepository.java
@@ -18,9 +18,9 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
-import org.onap.cps.spi.entities.YangResourceEntity;
+import org.onap.cps.ri.models.YangResourceEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java
new file mode 100644
index 0000000000..c160fb1e38
--- /dev/null
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java
@@ -0,0 +1,179 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 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.ri.repository;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.Query;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.spi.model.ModuleReference;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@Transactional
+@RequiredArgsConstructor
+public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ private final TempTableCreator tempTableCreator;
+
+ @Override
+ @SneakyThrows
+ public Collection<ModuleReference> identifyNewModuleReferences(
+ final Collection<ModuleReference> moduleReferencesToCheck) {
+
+ if (moduleReferencesToCheck == null || moduleReferencesToCheck.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final Collection<List<String>> sqlData = new HashSet<>(moduleReferencesToCheck.size());
+ for (final ModuleReference moduleReference : moduleReferencesToCheck) {
+ final List<String> row = new ArrayList<>(2);
+ row.add(moduleReference.getModuleName());
+ row.add(moduleReference.getRevision());
+ sqlData.add(row);
+ }
+
+ final String tempTableName = tempTableCreator.createTemporaryTable(
+ "moduleReferencesToCheckTemp", sqlData, "module_name", "revision");
+
+ return identifyNewModuleReferencesForCmHandle(tempTableName);
+ }
+
+ /**
+ * Finds module references based on specified dataspace, anchor, and attribute filters.
+ * This method constructs and executes a SQL query to retrieve module references. The query applies filters to
+ * parent and child fragments using the provided attribute maps. The `parentAttributes` are used to filter
+ * parent fragments, while `childAttributes` filter child fragments.
+ *
+ * @param dataspaceName the name of the dataspace to filter on.
+ * @param anchorName the name of the anchor to filter on.
+ * @param parentAttributes a map of attributes for filtering parent fragments.
+ * @param childAttributes a map of attributes for filtering child fragments.
+ * @return a collection of {@link ModuleReference} objects that match the specified filters.
+ */
+ @Transactional
+ @SuppressWarnings("unchecked")
+ @Override
+ public Collection<ModuleReference> findModuleReferences(final String dataspaceName, final String anchorName,
+ final Map<String, String> parentAttributes,
+ final Map<String, String> childAttributes) {
+
+ final String parentFragmentWhereClause = buildWhereClause(childAttributes, "parentFragment");
+ final String childFragmentWhereClause = buildWhereClause(parentAttributes, "childFragment");
+
+ final String moduleReferencesSqlQuery = buildModuleReferencesSqlQuery(parentFragmentWhereClause,
+ childFragmentWhereClause);
+
+ final Query query = entityManager.createNativeQuery(moduleReferencesSqlQuery);
+ setQueryParameters(query, parentAttributes, childAttributes, anchorName, dataspaceName);
+ return processQueryResults(query.getResultList());
+ }
+
+ private String buildWhereClause(final Map<String, String> attributes, final String alias) {
+ return attributes.keySet().stream()
+ .map(attributeName -> String.format("%s.attributes->>'%s' = ?", alias, attributeName))
+ .collect(Collectors.joining(" AND "));
+ }
+
+ private void setQueryParameters(final Query query, final Map<String, String> parentAttributes,
+ final Map<String, String> childAttributes, final String anchorName,
+ final String dataspaceName) {
+ final String childAttributeValue = childAttributes.entrySet().iterator().next().getValue();
+ query.setParameter(1, childAttributeValue);
+
+ final String parentAttributeValue = parentAttributes.entrySet().iterator().next().getValue();
+ query.setParameter(2, parentAttributeValue);
+
+ query.setParameter(3, anchorName);
+ query.setParameter(4, dataspaceName);
+ }
+
+ private String buildModuleReferencesSqlQuery(final String parentFragmentClause, final String childFragmentClause) {
+ return """
+ WITH Fragment AS (
+ SELECT childFragment.attributes->>'id' AS schema_set_name
+ FROM fragment parentFragment
+ JOIN fragment childFragment ON parentFragment.parent_id = childFragment.id
+ JOIN anchor anchorInfo ON parentFragment.anchor_id = anchorInfo.id
+ JOIN dataspace dataspaceInfo ON anchorInfo.dataspace_id = dataspaceInfo.id
+ WHERE %s
+ AND %s
+ AND anchorInfo.name = ?
+ AND dataspaceInfo.name = ?
+ LIMIT 1
+ ),
+ SchemaSet AS (
+ SELECT id
+ FROM schema_set
+ WHERE name = (SELECT schema_set_name FROM Fragment)
+ )
+ SELECT yangResource.module_name, yangResource.revision
+ FROM yang_resource yangResource
+ JOIN schema_set_yang_resources schemaSetYangResources
+ ON yangResource.id = schemaSetYangResources.yang_resource_id
+ WHERE schemaSetYangResources.schema_set_id = (SELECT id FROM SchemaSet);
+ """.formatted(parentFragmentClause, childFragmentClause);
+ }
+
+ private Collection<ModuleReference> processQueryResults(final List<Object[]> queryResults) {
+ if (queryResults.isEmpty()) {
+ log.info("No module references found for the provided attributes.");
+ return Collections.emptyList();
+ }
+ return queryResults.stream()
+ .map(queryResult -> {
+ final String name = (String) queryResult[0];
+ final String revision = (String) queryResult[1];
+ return new ModuleReference(name, revision);
+ })
+ .collect(Collectors.toList());
+ }
+
+ private Collection<ModuleReference> identifyNewModuleReferencesForCmHandle(final String tempTableName) {
+ final String sql = String.format(
+ "SELECT %1$s.module_name, %1$s.revision"
+ + " FROM %1$s LEFT JOIN yang_resource"
+ + " ON yang_resource.module_name=%1$s.module_name"
+ + " AND yang_resource.revision=%1$s.revision"
+ + " WHERE yang_resource.module_name IS NULL;", tempTableName);
+
+ @SuppressWarnings("unchecked")
+ final List<Object[]> resultsAsObjects = entityManager.createNativeQuery(sql).getResultList();
+
+ final List<ModuleReference> resultsAsModuleReferences = new ArrayList<>(resultsAsObjects.size());
+ for (final Object[] row : resultsAsObjects) {
+ resultsAsModuleReferences.add(new ModuleReference((String) row[0], (String) row[1]));
+ }
+ return resultsAsModuleReferences;
+ }
+}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java
index 3c5f973cb0..9357a5c6a7 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java
@@ -19,13 +19,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.SchemaSetEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.SchemaSetEntity;
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetYangResourceRepository.java
index aacebd63b3..8350d5728c 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetYangResourceRepository.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.List;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetYangResourceRepositoryImpl.java
index c786a62d0c..287bcda01b 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/SchemaSetYangResourceRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetYangResourceRepositoryImpl.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/TempTableCreator.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java
index 5804b2dc5d..cc83ab7d94 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/TempTableCreator.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
@@ -31,7 +31,7 @@ import java.util.UUID;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.spi.utils.EscapeUtils;
+import org.onap.cps.ri.utils.EscapeUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceNativeRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceNativeRepository.java
index 9ae32b3e78..ef7b12dc9c 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceNativeRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceNativeRepository.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.Collection;
import java.util.List;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceNativeRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceNativeRepositoryImpl.java
index c84ff427e6..c65ab7d6fa 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceNativeRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceNativeRepositoryImpl.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java
index 8be0d9a33b..9a11592310 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java
@@ -18,13 +18,13 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.repository;
+package org.onap.cps.ri.repository;
import java.util.Collection;
import java.util.List;
import java.util.Set;
-import org.onap.cps.spi.entities.YangResourceEntity;
-import org.onap.cps.spi.entities.YangResourceModuleReference;
+import org.onap.cps.ri.models.YangResourceEntity;
+import org.onap.cps.ri.models.YangResourceModuleReference;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/config/CpsSessionFactory.java b/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsSessionFactory.java
index 5241ea0096..c0291176f4 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/config/CpsSessionFactory.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsSessionFactory.java
@@ -18,15 +18,15 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.config;
+package org.onap.cps.ri.utils;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
-import org.onap.cps.spi.entities.SchemaSetEntity;
-import org.onap.cps.spi.entities.YangResourceEntity;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.models.SchemaSetEntity;
+import org.onap.cps.ri.models.YangResourceEntity;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/utils/CpsValidatorImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java
index c727388b25..4f942a37ea 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/utils/CpsValidatorImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java
@@ -18,16 +18,16 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl.utils;
+package org.onap.cps.ri.utils;
import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.Collection;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.PaginationOption;
import org.onap.cps.spi.exceptions.DataValidationException;
-import org.onap.cps.spi.utils.CpsValidator;
import org.springframework.stereotype.Component;
@Slf4j
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/utils/EscapeUtils.java b/cps-ri/src/main/java/org/onap/cps/ri/utils/EscapeUtils.java
index 2b61d39503..5323ae6bc9 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/utils/EscapeUtils.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/utils/EscapeUtils.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.utils;
+package org.onap.cps.ri.utils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/utils/SessionManager.java b/cps-ri/src/main/java/org/onap/cps/ri/utils/SessionManager.java
index 6150bf9dbe..b81a0bd39d 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/utils/SessionManager.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/utils/SessionManager.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.utils;
+package org.onap.cps.ri.utils;
import com.google.common.util.concurrent.TimeLimiter;
import com.google.common.util.concurrent.UncheckedExecutionException;
@@ -36,13 +36,12 @@ import lombok.extern.slf4j.Slf4j;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Session;
-import org.onap.cps.spi.config.CpsSessionFactory;
-import org.onap.cps.spi.entities.AnchorEntity;
-import org.onap.cps.spi.entities.DataspaceEntity;
+import org.onap.cps.ri.models.AnchorEntity;
+import org.onap.cps.ri.models.DataspaceEntity;
+import org.onap.cps.ri.repository.AnchorRepository;
+import org.onap.cps.ri.repository.DataspaceRepository;
import org.onap.cps.spi.exceptions.SessionManagerException;
import org.onap.cps.spi.exceptions.SessionTimeoutException;
-import org.onap.cps.spi.repository.AnchorRepository;
-import org.onap.cps.spi.repository.DataspaceRepository;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/utils/TimeLimiterProvider.java b/cps-ri/src/main/java/org/onap/cps/ri/utils/TimeLimiterProvider.java
index 2bd7ac3763..10031c0b28 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/utils/TimeLimiterProvider.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/utils/TimeLimiterProvider.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.utils;
+package org.onap.cps.ri.utils;
import com.google.common.util.concurrent.SimpleTimeLimiter;
import com.google.common.util.concurrent.TimeLimiter;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
deleted file mode 100644
index 454848b98f..0000000000
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/ModuleReferenceRepositoryImpl.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022 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.spi.repository;
-
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.PersistenceContext;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import lombok.AllArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.spi.model.ModuleReference;
-import org.springframework.transaction.annotation.Transactional;
-
-@Slf4j
-@Transactional
-@AllArgsConstructor
-public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
-
- @PersistenceContext
- private EntityManager entityManager;
-
- private TempTableCreator tempTableCreator;
-
- @Override
- @SneakyThrows
- public Collection<ModuleReference> identifyNewModuleReferences(
- final Collection<ModuleReference> moduleReferencesToCheck) {
-
- if (moduleReferencesToCheck == null || moduleReferencesToCheck.isEmpty()) {
- return Collections.emptyList();
- }
-
- final Collection<List<String>> sqlData = new HashSet<>(moduleReferencesToCheck.size());
- for (final ModuleReference moduleReference : moduleReferencesToCheck) {
- final List<String> row = new ArrayList<>(2);
- row.add(moduleReference.getModuleName());
- row.add(moduleReference.getRevision());
- sqlData.add(row);
- }
-
- final String tempTableName = tempTableCreator.createTemporaryTable(
- "moduleReferencesToCheckTemp", sqlData, "module_name", "revision");
-
- return identifyNewModuleReferencesForCmHandle(tempTableName);
- }
-
- private Collection<ModuleReference> identifyNewModuleReferencesForCmHandle(final String tempTableName) {
- final String sql = String.format(
- "SELECT %1$s.module_name, %1$s.revision"
- + " FROM %1$s LEFT JOIN yang_resource"
- + " ON yang_resource.module_name=%1$s.module_name"
- + " AND yang_resource.revision=%1$s.revision"
- + " WHERE yang_resource.module_name IS NULL;", tempTableName);
-
- @SuppressWarnings("unchecked")
- final List<Object[]> resultsAsObjects = entityManager.createNativeQuery(sql).getResultList();
-
- final List<ModuleReference> resultsAsModuleReferences = new ArrayList<>(resultsAsObjects.size());
- for (final Object[] row : resultsAsObjects) {
- resultsAsModuleReferences.add(new ModuleReference((String) row[0], (String) row[1]));
- }
-
- return resultsAsModuleReferences;
- }
-}
diff --git a/cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/README.md b/cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/README.md
deleted file mode 100644
index 212acb9006..0000000000
--- a/cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
- ============LICENSE_START=======================================================
- Copyright (C) 2022 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=========================================================
--->
-
-##Placeholder folder for generated CSV files as part of yang models.
-
-Do not remove this folder \ No newline at end of file
diff --git a/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2021-12-13.yang b/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2021-12-13.yang
deleted file mode 100644
index ed3559bf61..0000000000
--- a/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2021-12-13.yang
+++ /dev/null
@@ -1,63 +0,0 @@
-module dmi-registry {
-
- yang-version 1.1;
-
- namespace "org:onap:cps:ncmp";
-
- prefix dmi-reg;
-
- contact "dylan.byrne@est.tech";
-
- revision "2021-05-20" {
- description
- "Initial Version";
- }
-
- revision "2021-10-20" {
- description
- "Added dmi-data-service-name & dmi-model-service-name to allow separate DMI instances for each responsibility";
- }
-
- revision "2021-12-13" {
- description
- "Added new list of public additonal properties for a Cm-Handle which are exposed to clients of the NCMP interface";
- }
-
- container dmi-registry {
- list cm-handles {
- key "id";
- leaf id {
- type string;
- }
- leaf dmi-service-name {
- type string;
- }
- leaf dmi-data-service-name {
- type string;
- }
- leaf dmi-model-service-name {
- type string;
- }
-
- list additional-properties {
- key "name";
- leaf name {
- type string;
- }
- leaf value {
- type string;
- }
- }
-
- list public-properties {
- key "name";
- leaf name {
- type string;
- }
- leaf value {
- type string;
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-02-10.yang b/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-02-10.yang
deleted file mode 100644
index 3c6d990c5d..0000000000
--- a/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-02-10.yang
+++ /dev/null
@@ -1,81 +0,0 @@
-module dmi-registry {
-
- yang-version 1.1;
-
- namespace "org:onap:cps:ncmp";
-
- prefix dmi-reg;
-
- contact "toine.siebelink@est.tech";
-
- revision "2022-02-10" {
- description
- "Added State, LockReason, LockReasonDetails to aid with cmHandle sync and timestamp to aid with retry/timeout scenarios";
- }
-
- revision "2021-12-13" {
- description
- "Added new list of public additional properties for a Cm-Handle which are exposed to clients of the NCMP interface";
- }
-
- revision "2021-10-20" {
- description
- "Added dmi-data-service-name & dmi-model-service-name to allow separate DMI instances for each responsibility";
- }
-
- revision "2021-05-20" {
- description
- "Initial Version";
- }
-
- container dmi-registry {
- list cm-handles {
- key "id";
- leaf id {
- type string;
- }
- leaf dmi-service-name {
- type string;
- }
- leaf dmi-data-service-name {
- type string;
- }
- leaf dmi-model-service-name {
- type string;
- }
-
- list additional-properties {
- key "name";
- leaf name {
- type string;
- }
- leaf value {
- type string;
- }
- }
-
- list public-properties {
- key "name";
- leaf name {
- type string;
- }
- leaf value {
- type string;
- }
- }
-
- leaf state {
- type string;
- }
- leaf lock-reason {
- type string;
- }
- leaf lock-reason-details {
- type string;
- }
- leaf last-update-time {
- type string;
- }
- }
- }
-}
diff --git a/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-05-10.yang b/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-05-10.yang
deleted file mode 100644
index 77517968c6..0000000000
--- a/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2022-05-10.yang
+++ /dev/null
@@ -1,123 +0,0 @@
-module dmi-registry {
-
- yang-version 1.1;
-
- namespace "org:onap:cps:ncmp";
-
- prefix dmi-reg;
-
- contact "toine.siebelink@est.tech";
-
- revision "2022-05-10" {
- description
- "Added DataSyncEnabled, SyncState with State, LastSyncTime, DataStoreSyncState with Operational and Running syncstate";
- }
-
- revision "2022-02-10" {
- description
- "Added State, LockReason, LockReasonDetails to aid with cmHandle sync and timestamp to aid with retry/timeout scenarios";
- }
-
- revision "2021-12-13" {
- description
- "Added new list of public additional properties for a Cm-Handle which are exposed to clients of the NCMP interface";
- }
-
- revision "2021-10-20" {
- description
- "Added dmi-data-service-name & dmi-model-service-name to allow separate DMI instances for each responsibility";
- }
-
- revision "2021-05-20" {
- description
- "Initial Version";
- }
-
- grouping LockReason {
- leaf reason {
- type string;
- }
- leaf details {
- type string;
- }
- }
-
- grouping SyncState {
- leaf sync-state {
- type string;
- }
- leaf last-sync-time {
- type string;
- }
- }
-
- grouping Datastores {
- container operational {
- uses SyncState;
- }
- container running {
- uses SyncState;
- }
- }
-
- container dmi-registry {
- list cm-handles {
- key "id";
- leaf id {
- type string;
- }
- leaf dmi-service-name {
- type string;
- }
- leaf dmi-data-service-name {
- type string;
- }
- leaf dmi-model-service-name {
- type string;
- }
-
- list additional-properties {
- key "name";
- leaf name {
- type string;
- }
- leaf value {
- type string;
- }
- }
-
- list public-properties {
- key "name";
- leaf name {
- type string;
- }
- leaf value {
- type string;
- }
- }
-
- container state {
- leaf cm-handle-state {
- type string;
- }
-
- container lock-reason {
- uses LockReason;
- }
-
- leaf last-update-time {
- type string;
- }
-
- leaf data-sync-enabled {
- type boolean;
- default "false";
- }
-
- container datastores {
- uses Datastores;
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/cps-ri/src/main/resources/yangResourceCsvGenerator.py b/cps-ri/src/main/resources/yangResourceCsvGenerator.py
deleted file mode 100644
index 3a076d4378..0000000000
--- a/cps-ri/src/main/resources/yangResourceCsvGenerator.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# ============LICENSE_START=======================================================
-# Copyright (C) 2022 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=========================================================
-
-
-import csv
-import datetime
-import hashlib
-import sys
-import re
-
-yang_source = ''
-checksum = ''
-regexForModuleName = '(?<=module)(.*)(?={)'
-regexForRevision = '(?<=revision)(.*)(?={)'
-
-def main():
- for yang_source in sys.argv[1:]:
- checksum = hashlib.sha256(str(yang_source).encode()).hexdigest()
-
- with open('changelog/db/changes/data/yang-models/' + yang_source + '.yang', 'r') as content:
- dmiRegistry = content.read()
-
- try:
- latestRevision = re.search(regexForRevision, dmiRegistry).group(0).replace('\"','').strip()
- except:
- print("ERROR IN in yangResourceCsvGenerator.py: Unable to find revision for " + yang_source + '.yang')
-
- try:
- module_name = re.search(regexForModuleName, dmiRegistry).group(0).strip()
- except:
- print("ERROR IN in yangResourceCsvGenerator.py: Unable to find module name for " + yang_source + '.yang')
-
- #If true, file was created after module_name and revision columns were added to yang-resources table
- writeWithModuleNameAndRevision = yang_source != 'dmi-registry@2021-12-13'
-
- try:
- # open the file in the write mode
- with open('changelog/db/changes/data/dmi/generated-csv/generated_yang_resource_' + yang_source + '.csv', 'w', newline='') \
- as file:
- writer = csv.writer(file, delimiter='|')
- if(writeWithModuleNameAndRevision):
- writer.writerow(["name", "content", "checksum", "module_name", "revision"])
- writer.writerow([yang_source + '.yang', dmiRegistry, checksum, module_name, latestRevision])
- else:
- writer.writerow(["name", "content", "checksum"])
- writer.writerow([yang_source + '.yang', dmiRegistry, checksum])
- except:
- print("ERROR IN in yangResourceCsvGenerator.py: Unable to write to changelog/db/changes/data/dmi/generated-csv/generated_yang_resource_" + yang_source + ".csv")
-
-
-main() \ No newline at end of file
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsDataPersistenceServiceImplSpec.groovy
index c72c3046e8..36bf55e2db 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsDataPersistenceServiceImplSpec.groovy
@@ -18,29 +18,29 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl
+package org.onap.cps.ri
import com.fasterxml.jackson.databind.ObjectMapper
import org.hibernate.StaleStateException
+import org.onap.cps.ri.models.AnchorEntity
+import org.onap.cps.ri.models.DataspaceEntity
+import org.onap.cps.ri.models.FragmentEntity
+import org.onap.cps.ri.repository.AnchorRepository
+import org.onap.cps.ri.repository.DataspaceRepository
+import org.onap.cps.ri.repository.FragmentRepository
+import org.onap.cps.ri.utils.SessionManager
import org.onap.cps.spi.FetchDescendantsOption
-import org.onap.cps.spi.entities.AnchorEntity
-import org.onap.cps.spi.entities.DataspaceEntity
-import org.onap.cps.spi.entities.FragmentEntity
-
import org.onap.cps.spi.exceptions.ConcurrencyException
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.DataNodeBuilder
-import org.onap.cps.spi.repository.AnchorRepository
-import org.onap.cps.spi.repository.DataspaceRepository
-import org.onap.cps.spi.repository.FragmentRepository
-import org.onap.cps.spi.utils.SessionManager
import org.onap.cps.utils.JsonObjectMapper
import org.springframework.dao.DataIntegrityViolationException
import spock.lang.Specification
+
import java.util.stream.Collectors
-class CpsDataPersistenceServiceSpec extends Specification {
+class CpsDataPersistenceServiceImplSpec extends Specification {
def mockDataspaceRepository = Mock(DataspaceRepository)
def mockAnchorRepository = Mock(AnchorRepository)
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceConcurrencySpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceConcurrencySpec.groovy
index 2e4dba2e9b..b892fe4dae 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceConcurrencySpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceConcurrencySpec.groovy
@@ -18,19 +18,19 @@
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl
+package org.onap.cps.ri
import org.hibernate.exception.ConstraintViolationException
+import org.onap.cps.ri.models.DataspaceEntity
+import org.onap.cps.ri.models.SchemaSetEntity
+import org.onap.cps.ri.repository.DataspaceRepository
+import org.onap.cps.ri.repository.ModuleReferenceRepository
+import org.onap.cps.ri.repository.SchemaSetRepository
+import org.onap.cps.ri.repository.YangResourceRepository
import org.onap.cps.spi.CpsAdminPersistenceService
import org.onap.cps.spi.CpsModulePersistenceService
-import org.onap.cps.spi.entities.DataspaceEntity
-import org.onap.cps.spi.entities.SchemaSetEntity
import org.onap.cps.spi.exceptions.DuplicatedYangResourceException
import org.onap.cps.spi.model.ModuleReference
-import org.onap.cps.spi.repository.DataspaceRepository
-import org.onap.cps.spi.repository.ModuleReferenceRepository
-import org.onap.cps.spi.repository.SchemaSetRepository
-import org.onap.cps.spi.repository.YangResourceRepository
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceImplSpec.groovy
index 3447a1c599..1b61ff39c0 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceImplSpec.groovy
@@ -17,25 +17,26 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl
+package org.onap.cps.ri
import org.hibernate.exception.ConstraintViolationException
+import org.onap.cps.ri.models.SchemaSetEntity
+import org.onap.cps.ri.repository.DataspaceRepository
+import org.onap.cps.ri.repository.ModuleReferenceRepository
+import org.onap.cps.ri.repository.SchemaSetRepository
+import org.onap.cps.ri.repository.YangResourceRepository
import org.onap.cps.spi.CpsModulePersistenceService
-import org.onap.cps.spi.entities.SchemaSetEntity
import org.onap.cps.spi.exceptions.DuplicatedYangResourceException
import org.onap.cps.spi.model.ModuleReference
-import org.onap.cps.spi.repository.DataspaceRepository
-import org.onap.cps.spi.repository.ModuleReferenceRepository
-import org.onap.cps.spi.repository.SchemaSetRepository
-import org.onap.cps.spi.repository.YangResourceRepository
import org.springframework.dao.DataIntegrityViolationException
import spock.lang.Specification
+
import java.sql.SQLException
/**
* Specification unit test class for CPS module persistence service.
*/
-class CpsModulePersistenceServiceSpec extends Specification {
+class CpsModulePersistenceServiceImplSpec extends Specification {
CpsModulePersistenceService objectUnderTest
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/utils/CpsValidatorSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/utils/CpsValidatorImplSpec.groovy
index 8d348443c7..d57bf25058 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/utils/CpsValidatorSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/ri/utils/CpsValidatorImplSpec.groovy
@@ -18,13 +18,14 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.impl.utils
+package org.onap.cps.ri.utils
+
import org.onap.cps.spi.PaginationOption
import org.onap.cps.spi.exceptions.DataValidationException
import spock.lang.Specification
-class CpsValidatorSpec extends Specification {
+class CpsValidatorImplSpec extends Specification {
def objectUnderTest = new CpsValidatorImpl()
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/utils/EscapeUtilsSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/utils/EscapeUtilsSpec.groovy
index 52330e6251..8afd9695a7 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/utils/EscapeUtilsSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/ri/utils/EscapeUtilsSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.utils
+package org.onap.cps.ri.utils
import spock.lang.Specification
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/utils/SessionManagerSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/utils/SessionManagerSpec.groovy
index feda338b80..b50a20c124 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/utils/SessionManagerSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/ri/utils/SessionManagerSpec.groovy
@@ -18,20 +18,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.utils
+package org.onap.cps.ri.utils
import com.google.common.util.concurrent.TimeLimiter
import com.google.common.util.concurrent.UncheckedExecutionException
import org.hibernate.HibernateException
+import org.hibernate.Session
import org.hibernate.Transaction
-import org.onap.cps.spi.config.CpsSessionFactory
-import org.onap.cps.spi.entities.AnchorEntity
+import org.onap.cps.ri.models.AnchorEntity
+import org.onap.cps.ri.repository.AnchorRepository
+import org.onap.cps.ri.repository.DataspaceRepository
import org.onap.cps.spi.exceptions.SessionManagerException
-import org.onap.cps.spi.repository.AnchorRepository
-import org.onap.cps.spi.repository.DataspaceRepository
import spock.lang.Specification
-import org.hibernate.Session
-import java.util.concurrent.ExecutionException
class SessionManagerSpec extends Specification {
diff --git a/cps-service/pom.xml b/cps-service/pom.xml
index 4224968778..37a45957f3 100644
--- a/cps-service/pom.xml
+++ b/cps-service/pom.xml
@@ -29,7 +29,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -144,18 +144,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
- <dependency>
- <groupId>io.cloudevents</groupId>
- <artifactId>cloudevents-json-jackson</artifactId>
- </dependency>
- <dependency>
- <groupId>io.cloudevents</groupId>
- <artifactId>cloudevents-kafka</artifactId>
- </dependency>
- <dependency>
- <groupId>io.cloudevents</groupId>
- <artifactId>cloudevents-spring</artifactId>
- </dependency>
<!-- T E S T D E P E N D E N C I E S -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java
index a247150c15..fcb969ba30 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsAnchorService.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.
@@ -37,6 +37,15 @@ public interface CpsAnchorService {
void createAnchor(String dataspaceName, String schemaSetName, String anchorName);
/**
+ * Get an anchor in the given dataspace using the anchor name.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @return an anchor
+ */
+ Anchor getAnchor(String dataspaceName, String anchorName);
+
+ /**
* Read all anchors in the given dataspace.
*
* @param dataspaceName dataspace name
@@ -45,13 +54,22 @@ public interface CpsAnchorService {
Collection<Anchor> getAnchors(String dataspaceName);
/**
+ * Read all anchors in the given dataspace with the anchor names.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorNames anchor names
+ * @return a collection of anchors
+ */
+ Collection<Anchor> getAnchors(String dataspaceName, Collection<String> anchorNames);
+
+ /**
* Read all anchors associated with the given schema-set in the given dataspace.
*
* @param dataspaceName dataspace name
* @param schemaSetName schema-set name
* @return a collection of anchors
*/
- Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName);
+ Collection<Anchor> getAnchorsBySchemaSetName(String dataspaceName, String schemaSetName);
/**
* Read all anchors associated with the given schema-sets in the given dataspace.
@@ -60,16 +78,7 @@ public interface CpsAnchorService {
* @param schemaSetNames schema-set names
* @return a collection of anchors
*/
- Collection<Anchor> getAnchors(String dataspaceName, Collection<String> schemaSetNames);
-
- /**
- * Get an anchor in the given dataspace using the anchor name.
- *
- * @param dataspaceName dataspace name
- * @param anchorName anchor name
- * @return an anchor
- */
- Anchor getAnchor(String dataspaceName, String anchorName);
+ Collection<Anchor> getAnchorsBySchemaSetNames(String dataspaceName, Collection<String> schemaSetNames);
/**
* Delete anchor by name in given dataspace.
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index 0abcc05f9c..68e1880d77 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -4,7 +4,7 @@
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021-2022 Bell Canada
* Modifications Copyright (C) 2022 Deutsche Telekom AG
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2023-2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ public interface CpsDataService {
* @param anchorName anchor name
* @param nodeData node data
* @param observedTimestamp observedTimestamp
- * @param contentType node data content type
+ * @param contentType JSON/XML content type
*/
void saveData(String dataspaceName, String anchorName, String nodeData, OffsetDateTime observedTimestamp,
ContentType contentType);
@@ -80,7 +80,7 @@ public interface CpsDataService {
* @param parentNodeXpath parent node xpath
* @param nodeData node data
* @param observedTimestamp observedTimestamp
- * @param contentType node data content type
+ * @param contentType JSON/XML content type
*
*/
void saveData(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
@@ -93,11 +93,12 @@ public interface CpsDataService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param parentNodeXpath parent node xpath
- * @param jsonData json data representing list element(s)
+ * @param nodeData node data representing list element(s)
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void saveListElements(String dataspaceName, String anchorName, String parentNodeXpath, String jsonData,
- OffsetDateTime observedTimestamp);
+ void saveListElements(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Retrieves all the datanodes by XPath for given dataspace and anchor.
@@ -132,11 +133,12 @@ public interface CpsDataService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param parentNodeXpath xpath to parent node
- * @param jsonData json data
+ * @param nodeData node data
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void updateNodeLeaves(String dataspaceName, String anchorName, String parentNodeXpath, String jsonData,
- OffsetDateTime observedTimestamp);
+ void updateNodeLeaves(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Replaces an existing data node's content including descendants.
@@ -144,22 +146,24 @@ public interface CpsDataService {
* @param dataspaceName dataspace name
* @param anchorName anchor name
* @param parentNodeXpath xpath to parent node
- * @param jsonData json data
+ * @param nodeData node data
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void updateDataNodeAndDescendants(String dataspaceName, String anchorName, String parentNodeXpath, String jsonData,
- OffsetDateTime observedTimestamp);
+ void updateDataNodeAndDescendants(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Replaces multiple existing data nodes' content including descendants in a batch operation.
*
* @param dataspaceName dataspace name
* @param anchorName anchor name
- * @param nodesJsonData map of xpath and node JSON data
+ * @param nodeDataPerXPath map of xpath and node JSON/XML data
* @param observedTimestamp observedTimestamp
+ * @param contentType JSON/XML content type
*/
- void updateDataNodesAndDescendants(String dataspaceName, String anchorName, Map<String, String> nodesJsonData,
- OffsetDateTime observedTimestamp);
+ void updateDataNodesAndDescendants(String dataspaceName, String anchorName, Map<String, String> nodeDataPerXPath,
+ OffsetDateTime observedTimestamp, ContentType contentType);
/**
* Replaces list content by removing all existing elements and inserting the given new elements as json
@@ -302,4 +306,20 @@ public interface CpsDataService {
List<DeltaReport> getDeltaByDataspaceAndAnchors(String dataspaceName, String sourceAnchorName,
String targetAnchorName, String xpath,
FetchDescendantsOption fetchDescendantsOption);
+
+ /**
+ * Retrieves the delta between an anchor and JSON payload by xpath, using dataspace name and anchor name.
+ *
+ * @param dataspaceName source dataspace name
+ * @param sourceAnchorName source anchor name
+ * @param xpath xpath
+ * @param yangResourcesNameToContentMap YANG resources (files) map where key is a name and value is content
+ * @param targetData target data to be compared in JSON string format
+ * @param fetchDescendantsOption defines the scope of data to fetch: defaulted to INCLUDE_ALL_DESCENDANTS
+ * @return list containing {@link DeltaReport} objects
+ */
+ List<DeltaReport> getDeltaByDataspaceAnchorAndPayload(String dataspaceName, String sourceAnchorName, String xpath,
+ Map<String, String> yangResourcesNameToContentMap,
+ String targetData,
+ FetchDescendantsOption fetchDescendantsOption);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
index bdd361458e..931209c998 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
@@ -155,4 +155,37 @@ public interface CpsModuleService {
Collection<ModuleReference> identifyNewModuleReferences(
Collection<ModuleReference> moduleReferencesToCheck);
+ /**
+ * Retrieves module references based on the provided dataspace name, anchor name and attribute filters
+ * for both parent and child fragments.
+
+ * This method constructs and executes a SQL query to find module references from a database, using
+ * the specified `dataspaceName`, `anchorName` and two sets of attribute filters: one for parent fragments
+ * and one for child fragments. The method applies these filters to identify the appropriate fragments
+ * and schema sets, and then retrieves the corresponding module references.
+
+ * The SQL query is dynamically built based on the provided attribute filters:
+ * - The `parentAttributes` map is used to filter the parent fragments. The entries in this map are
+ * converted into a WHERE clause for the parent fragments.
+ * - The `childAttributes` map is used to filter the child fragments. This is applied to the child fragments
+ * after filtering the parent fragments.
+ *
+ * @param dataspaceName the name of the dataspace to filter on. It is used to locate the relevant dataspace
+ * in the database.
+ * @param anchorName the name of the anchor to filter on. It is used to locate the relevant anchor within
+ * the dataspace.
+ * @param parentAttributes a map of attributes to filter parent fragments. Each entry in this map represents
+ * an attribute key-value pair used in the WHERE clause for parent fragments.
+ * @param childAttributes a map of attributes to filter child fragments. Each entry in this map represents
+ * an attribute key-value pair used in the WHERE clause for child fragments.
+ * @return a collection of {@link ModuleReference} objects that match the given criteria. Each
+ * {@code ModuleReference} contains information about a module's name and revision.
+ * @implNote The method assumes that both `parentAttributes` and `childAttributes` maps contain at least
+ * one entry. The first entry from `parentAttributes` is used to filter parent fragments,
+ * and the first entry from `childAttributes` is used to filter child fragments.
+ */
+ Collection<ModuleReference> getModuleReferencesByAttribute(final String dataspaceName, final String anchorName,
+ final Map<String, String> parentAttributes,
+ final Map<String, String> childAttributes);
+
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java
index aa9c45d09a..5ca0fe63d4 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAnchorServiceImpl.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.
@@ -23,10 +23,10 @@ package org.onap.cps.api.impl;
import java.util.Collection;
import lombok.RequiredArgsConstructor;
import org.onap.cps.api.CpsAnchorService;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.CpsDataPersistenceService;
import org.onap.cps.spi.model.Anchor;
-import org.onap.cps.spi.utils.CpsValidator;
import org.springframework.stereotype.Service;
@Service
@@ -44,28 +44,36 @@ public class CpsAnchorServiceImpl implements CpsAnchorService {
}
@Override
+ public Anchor getAnchor(final String dataspaceName, final String anchorName) {
+ cpsValidator.validateNameCharacters(dataspaceName, anchorName);
+ return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName);
+ }
+
+ @Override
public Collection<Anchor> getAnchors(final String dataspaceName) {
cpsValidator.validateNameCharacters(dataspaceName);
return cpsAdminPersistenceService.getAnchors(dataspaceName);
}
@Override
- public Collection<Anchor> getAnchors(final String dataspaceName, final String schemaSetName) {
- cpsValidator.validateNameCharacters(dataspaceName, schemaSetName);
- return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetName);
+ public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> anchorNames) {
+ cpsValidator.validateNameCharacters(dataspaceName);
+ cpsValidator.validateNameCharacters(anchorNames);
+ return cpsAdminPersistenceService.getAnchors(dataspaceName, anchorNames);
}
@Override
- public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) {
- cpsValidator.validateNameCharacters(dataspaceName);
- cpsValidator.validateNameCharacters(schemaSetNames);
- return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetNames);
+ public Collection<Anchor> getAnchorsBySchemaSetName(final String dataspaceName, final String schemaSetName) {
+ cpsValidator.validateNameCharacters(dataspaceName, schemaSetName);
+ return cpsAdminPersistenceService.getAnchorsBySchemaSetName(dataspaceName, schemaSetName);
}
@Override
- public Anchor getAnchor(final String dataspaceName, final String anchorName) {
- cpsValidator.validateNameCharacters(dataspaceName, anchorName);
- return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName);
+ public Collection<Anchor> getAnchorsBySchemaSetNames(final String dataspaceName,
+ final Collection<String> schemaSetNames) {
+ cpsValidator.validateNameCharacters(dataspaceName);
+ cpsValidator.validateNameCharacters(schemaSetNames);
+ return cpsAdminPersistenceService.getAnchorsBySchemaSetNames(dataspaceName, schemaSetNames);
}
@Override
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
index f556f40647..951770b053 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -30,6 +30,7 @@ import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -41,6 +42,7 @@ import org.onap.cps.api.CpsDeltaService;
import org.onap.cps.cpspath.parser.CpsPathUtil;
import org.onap.cps.events.CpsDataUpdateEventsService;
import org.onap.cps.events.model.Data.Operation;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.CpsDataPersistenceService;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.exceptions.DataValidationException;
@@ -48,8 +50,10 @@ import org.onap.cps.spi.model.Anchor;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.DataNodeBuilder;
import org.onap.cps.spi.model.DeltaReport;
-import org.onap.cps.spi.utils.CpsValidator;
import org.onap.cps.utils.ContentType;
+import org.onap.cps.utils.DataMapUtils;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.onap.cps.utils.PrefixResolver;
import org.onap.cps.utils.YangParser;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.springframework.stereotype.Service;
@@ -61,6 +65,7 @@ public class CpsDataServiceImpl implements CpsDataService {
private static final String ROOT_NODE_XPATH = "/";
private static final long DEFAULT_LOCK_TIMEOUT_IN_MILLISECONDS = 300L;
+ private static final String NO_DATA_NODES = "No data nodes.";
private final CpsDataPersistenceService cpsDataPersistenceService;
private final CpsDataUpdateEventsService cpsDataUpdateEventsService;
@@ -69,6 +74,8 @@ public class CpsDataServiceImpl implements CpsDataService {
private final CpsValidator cpsValidator;
private final YangParser yangParser;
private final CpsDeltaService cpsDeltaService;
+ private final JsonObjectMapper jsonObjectMapper;
+ private final PrefixResolver prefixResolver;
@Override
public void saveData(final String dataspaceName, final String anchorName, final String nodeData,
@@ -83,7 +90,8 @@ public class CpsDataServiceImpl implements CpsDataService {
final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
- final Collection<DataNode> dataNodes = buildDataNodes(anchor, ROOT_NODE_XPATH, nodeData, contentType);
+ final Collection<DataNode> dataNodes =
+ buildDataNodesWithParentNodeXpath(anchor, ROOT_NODE_XPATH, nodeData, contentType);
cpsDataPersistenceService.storeDataNodes(dataspaceName, anchorName, dataNodes);
sendDataUpdatedEvent(anchor, ROOT_NODE_XPATH, Operation.CREATE, observedTimestamp);
}
@@ -102,7 +110,8 @@ public class CpsDataServiceImpl implements CpsDataService {
final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
- final Collection<DataNode> dataNodes = buildDataNodes(anchor, parentNodeXpath, nodeData, contentType);
+ final Collection<DataNode> dataNodes =
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
cpsDataPersistenceService.addChildDataNodes(dataspaceName, anchorName, parentNodeXpath, dataNodes);
sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.CREATE, observedTimestamp);
}
@@ -110,12 +119,13 @@ public class CpsDataServiceImpl implements CpsDataService {
@Override
@Timed(value = "cps.data.service.list.element.save",
description = "Time taken to save list elements")
- public void saveListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath,
- final String jsonData, final OffsetDateTime observedTimestamp) {
+ public void saveListElements(final String dataspaceName, final String anchorName,
+ final String parentNodeXpath, final String nodeData,
+ final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
final Collection<DataNode> listElementDataNodeCollection =
- buildDataNodes(anchor, parentNodeXpath, jsonData, ContentType.JSON);
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
if (isRootNodeXpath(parentNodeXpath)) {
cpsDataPersistenceService.storeDataNodes(dataspaceName, anchorName, listElementDataNodeCollection);
} else {
@@ -150,11 +160,11 @@ public class CpsDataServiceImpl implements CpsDataService {
@Timed(value = "cps.data.service.datanode.leaves.update",
description = "Time taken to update a batch of leaf data nodes")
public void updateNodeLeaves(final String dataspaceName, final String anchorName, final String parentNodeXpath,
- final String jsonData, final OffsetDateTime observedTimestamp) {
+ final String nodeData, final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
- final Collection<DataNode> dataNodesInPatch = buildDataNodes(anchor, parentNodeXpath, jsonData,
- ContentType.JSON);
+ final Collection<DataNode> dataNodesInPatch =
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
final Map<String, Map<String, Serializable>> xpathToUpdatedLeaves = dataNodesInPatch.stream()
.collect(Collectors.toMap(DataNode::getXpath, DataNode::getLeaves));
cpsDataPersistenceService.batchUpdateDataLeaves(dataspaceName, anchorName, xpathToUpdatedLeaves);
@@ -171,7 +181,7 @@ public class CpsDataServiceImpl implements CpsDataService {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
final Collection<DataNode> dataNodeUpdates =
- buildDataNodes(anchor, parentNodeXpath, dataNodeUpdatesAsJson, ContentType.JSON);
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, dataNodeUpdatesAsJson, ContentType.JSON);
for (final DataNode dataNodeUpdate : dataNodeUpdates) {
processDataNodeUpdate(anchor, dataNodeUpdate);
}
@@ -215,15 +225,39 @@ public class CpsDataServiceImpl implements CpsDataService {
return cpsDeltaService.getDeltaReports(sourceDataNodes, targetDataNodes);
}
+ @Timed(value = "cps.data.service.get.deltaBetweenAnchorAndPayload",
+ description = "Time taken to get delta between anchor and a payload")
+ @Override
+ public List<DeltaReport> getDeltaByDataspaceAnchorAndPayload(final String dataspaceName,
+ final String sourceAnchorName, final String xpath,
+ final Map<String, String> yangResourcesNameToContentMap,
+ final String targetData,
+ final FetchDescendantsOption fetchDescendantsOption) {
+
+ final Anchor sourceAnchor = cpsAnchorService.getAnchor(dataspaceName, sourceAnchorName);
+
+ final Collection<DataNode> sourceDataNodes = getDataNodes(dataspaceName,
+ sourceAnchorName, xpath, fetchDescendantsOption);
+
+ final Collection<DataNode> sourceDataNodesRebuilt =
+ new ArrayList<>(rebuildSourceDataNodes(xpath, sourceAnchor, sourceDataNodes));
+
+ final Collection<DataNode> targetDataNodes =
+ new ArrayList<>(buildTargetDataNodes(sourceAnchor, xpath, yangResourcesNameToContentMap, targetData));
+
+ return cpsDeltaService.getDeltaReports(sourceDataNodesRebuilt, targetDataNodes);
+ }
+
@Override
@Timed(value = "cps.data.service.datanode.descendants.update",
description = "Time taken to update a data node and descendants")
public void updateDataNodeAndDescendants(final String dataspaceName, final String anchorName,
- final String parentNodeXpath, final String jsonData,
- final OffsetDateTime observedTimestamp) {
+ final String parentNodeXpath, final String nodeData,
+ final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
- final Collection<DataNode> dataNodes = buildDataNodes(anchor, parentNodeXpath, jsonData, ContentType.JSON);
+ final Collection<DataNode> dataNodes =
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
cpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName, dataNodes);
sendDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp);
}
@@ -232,13 +266,13 @@ public class CpsDataServiceImpl implements CpsDataService {
@Timed(value = "cps.data.service.datanode.descendants.batch.update",
description = "Time taken to update a batch of data nodes and descendants")
public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName,
- final Map<String, String> nodesJsonData,
- final OffsetDateTime observedTimestamp) {
+ final Map<String, String> nodeDataPerXPath,
+ final OffsetDateTime observedTimestamp, final ContentType contentType) {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
- final Collection<DataNode> dataNodes = buildDataNodes(anchor, nodesJsonData);
+ final Collection<DataNode> dataNodes = buildDataNodesWithParentNodeXpath(anchor, nodeDataPerXPath, contentType);
cpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName, dataNodes);
- nodesJsonData.keySet().forEach(nodeXpath ->
+ nodeDataPerXPath.keySet().forEach(nodeXpath ->
sendDataUpdatedEvent(anchor, nodeXpath, Operation.UPDATE, observedTimestamp));
}
@@ -250,7 +284,7 @@ public class CpsDataServiceImpl implements CpsDataService {
cpsValidator.validateNameCharacters(dataspaceName, anchorName);
final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
final Collection<DataNode> newListElements =
- buildDataNodes(anchor, parentNodeXpath, jsonData, ContentType.JSON);
+ buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, jsonData, ContentType.JSON);
replaceListContent(dataspaceName, anchorName, parentNodeXpath, newListElements, observedTimestamp);
}
@@ -324,16 +358,69 @@ public class CpsDataServiceImpl implements CpsDataService {
sendDataUpdatedEvent(anchor, listNodeXpath, Operation.DELETE, observedTimestamp);
}
- private Collection<DataNode> buildDataNodes(final Anchor anchor, final Map<String, String> nodesJsonData) {
+
+ private Collection<DataNode> rebuildSourceDataNodes(final String xpath, final Anchor sourceAnchor,
+ final Collection<DataNode> sourceDataNodes) {
+
+ final Collection<DataNode> sourceDataNodesRebuilt = new ArrayList<>();
+ if (sourceDataNodes != null) {
+ final String sourceDataNodesAsJson = getDataNodesAsJson(sourceAnchor, sourceDataNodes);
+ sourceDataNodesRebuilt.addAll(
+ buildDataNodesWithAnchorAndXpath(sourceAnchor, xpath, sourceDataNodesAsJson, ContentType.JSON));
+ }
+ return sourceDataNodesRebuilt;
+ }
+
+ private Collection<DataNode> buildTargetDataNodes(final Anchor sourceAnchor, final String xpath,
+ final Map<String, String> yangResourcesNameToContentMap,
+ final String targetData) {
+ if (yangResourcesNameToContentMap.isEmpty()) {
+ return buildDataNodesWithAnchorAndXpath(sourceAnchor, xpath, targetData, ContentType.JSON);
+ } else {
+ return buildDataNodesWithYangResourceAndXpath(yangResourcesNameToContentMap, xpath,
+ targetData, ContentType.JSON);
+ }
+ }
+
+ private String getDataNodesAsJson(final Anchor anchor, final Collection<DataNode> dataNodes) {
+
+ final List<Map<String, Object>> prefixToDataNodes = prefixResolver(anchor, dataNodes);
+ final Map<String, Object> targetDataAsJsonObject = getNodeDataAsJsonString(prefixToDataNodes);
+ return jsonObjectMapper.asJsonString(targetDataAsJsonObject);
+ }
+
+ private Map<String, Object> getNodeDataAsJsonString(final List<Map<String, Object>> prefixToDataNodes) {
+ final Map<String, Object> nodeDataAsJson = new HashMap<>();
+ for (final Map<String, Object> prefixToDataNode : prefixToDataNodes) {
+ nodeDataAsJson.putAll(prefixToDataNode);
+ }
+ return nodeDataAsJson;
+ }
+
+ private List<Map<String, Object>> prefixResolver(final Anchor anchor, final Collection<DataNode> dataNodes) {
+ final List<Map<String, Object>> prefixToDataNodes = new ArrayList<>(dataNodes.size());
+ for (final DataNode dataNode: dataNodes) {
+ final String prefix = prefixResolver
+ .getPrefix(anchor.getDataspaceName(), anchor.getName(), dataNode.getXpath());
+ final Map<String, Object> prefixToDataNode = DataMapUtils.toDataMapWithIdentifier(dataNode, prefix);
+ prefixToDataNodes.add(prefixToDataNode);
+ }
+ return prefixToDataNodes;
+ }
+
+ private Collection<DataNode> buildDataNodesWithParentNodeXpath(final Anchor anchor,
+ final Map<String, String> nodesJsonData,
+ final ContentType contentType) {
final Collection<DataNode> dataNodes = new ArrayList<>();
for (final Map.Entry<String, String> nodeJsonData : nodesJsonData.entrySet()) {
- dataNodes.addAll(buildDataNodes(anchor, nodeJsonData.getKey(), nodeJsonData.getValue(), ContentType.JSON));
+ dataNodes.addAll(buildDataNodesWithParentNodeXpath(anchor, nodeJsonData.getKey(),
+ nodeJsonData.getValue(), contentType));
}
return dataNodes;
}
- private Collection<DataNode> buildDataNodes(final Anchor anchor, final String parentNodeXpath,
- final String nodeData, final ContentType contentType) {
+ private Collection<DataNode> buildDataNodesWithParentNodeXpath(final Anchor anchor, final String parentNodeXpath,
+ final String nodeData, final ContentType contentType) {
if (ROOT_NODE_XPATH.equals(parentNodeXpath)) {
final ContainerNode containerNode = yangParser.parseData(contentType, nodeData, anchor, "");
@@ -341,7 +428,7 @@ public class CpsDataServiceImpl implements CpsDataService {
.withContainerNode(containerNode)
.buildCollection();
if (dataNodes.isEmpty()) {
- throw new DataValidationException("No data nodes.", "No data nodes provided");
+ throw new DataValidationException(NO_DATA_NODES, "No data nodes provided");
}
return dataNodes;
}
@@ -353,11 +440,67 @@ public class CpsDataServiceImpl implements CpsDataService {
.withContainerNode(containerNode)
.buildCollection();
if (dataNodes.isEmpty()) {
- throw new DataValidationException("No data nodes.", "No data nodes provided");
+ throw new DataValidationException(NO_DATA_NODES, "No data nodes provided");
+ }
+ return dataNodes;
+ }
+
+ private Collection<DataNode> buildDataNodesWithParentNodeXpath(
+ final Map<String, String> yangResourcesNameToContentMap, final String xpath,
+ final String nodeData, final ContentType contentType) {
+
+ if (isRootNodeXpath(xpath)) {
+ final ContainerNode containerNode = yangParser.parseData(contentType, nodeData,
+ yangResourcesNameToContentMap, "");
+ final Collection<DataNode> dataNodes = new DataNodeBuilder()
+ .withContainerNode(containerNode)
+ .buildCollection();
+ if (dataNodes.isEmpty()) {
+ throw new DataValidationException(NO_DATA_NODES, "Data nodes were not found under the xpath " + xpath);
+ }
+ return dataNodes;
+ }
+ final String normalizedParentNodeXpath = CpsPathUtil.getNormalizedXpath(xpath);
+ final ContainerNode containerNode =
+ yangParser.parseData(contentType, nodeData, yangResourcesNameToContentMap, normalizedParentNodeXpath);
+ final Collection<DataNode> dataNodes = new DataNodeBuilder()
+ .withParentNodeXpath(normalizedParentNodeXpath)
+ .withContainerNode(containerNode)
+ .buildCollection();
+ if (dataNodes.isEmpty()) {
+ throw new DataValidationException(NO_DATA_NODES, "Data nodes were not found under the xpath " + xpath);
}
return dataNodes;
}
+ private Collection<DataNode> buildDataNodesWithAnchorAndXpath(final Anchor anchor, final String xpath,
+ final String nodeData,
+ final ContentType contentType) {
+
+ if (!isRootNodeXpath(xpath)) {
+ final String parentNodeXpath = CpsPathUtil.getNormalizedParentXpath(xpath);
+ if (parentNodeXpath.isEmpty()) {
+ return buildDataNodesWithParentNodeXpath(anchor, ROOT_NODE_XPATH, nodeData, contentType);
+ }
+ return buildDataNodesWithParentNodeXpath(anchor, parentNodeXpath, nodeData, contentType);
+ }
+ return buildDataNodesWithParentNodeXpath(anchor, xpath, nodeData, contentType);
+ }
+
+ private Collection<DataNode> buildDataNodesWithYangResourceAndXpath(
+ final Map<String, String> yangResourcesNameToContentMap, final String xpath,
+ final String nodeData, final ContentType contentType) {
+ if (!isRootNodeXpath(xpath)) {
+ final String parentNodeXpath = CpsPathUtil.getNormalizedParentXpath(xpath);
+ if (parentNodeXpath.isEmpty()) {
+ return buildDataNodesWithParentNodeXpath(yangResourcesNameToContentMap, ROOT_NODE_XPATH,
+ nodeData, contentType);
+ }
+ return buildDataNodesWithParentNodeXpath(yangResourcesNameToContentMap, parentNodeXpath,
+ nodeData, contentType);
+ }
+ return buildDataNodesWithParentNodeXpath(yangResourcesNameToContentMap, xpath, nodeData, contentType);
+ }
private static boolean isRootNodeXpath(final String xpath) {
return ROOT_NODE_XPATH.equals(xpath);
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataspaceServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataspaceServiceImpl.java
index a7f5da4874..6bccf2a865 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataspaceServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataspaceServiceImpl.java
@@ -26,9 +26,9 @@ package org.onap.cps.api.impl;
import java.util.Collection;
import lombok.RequiredArgsConstructor;
import org.onap.cps.api.CpsDataspaceService;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.model.Dataspace;
-import org.onap.cps.spi.utils.CpsValidator;
import org.springframework.stereotype.Service;
@Service
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDeltaServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDeltaServiceImpl.java
index 2f99dbf7bb..7819568ae1 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDeltaServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDeltaServiceImpl.java
@@ -20,7 +20,6 @@
package org.onap.cps.api.impl;
-
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@@ -179,7 +178,7 @@ public class CpsDeltaServiceImpl implements CpsDeltaService {
final List<DeltaReport> updatedDeltaReportEntries) {
for (final Map.Entry<Map<String, Serializable>, Map<String, Serializable>> entry:
updatedLeavesAsSourceDataToTargetData.entrySet()) {
- final DeltaReport updatedDataForDeltaReport = new DeltaReportBuilder().actionUpdate()
+ final DeltaReport updatedDataForDeltaReport = new DeltaReportBuilder().actionReplace()
.withXpath(xpath).withSourceData(entry.getKey()).withTargetData(entry.getValue()).build();
updatedDeltaReportEntries.add(updatedDataForDeltaReport);
}
@@ -195,7 +194,7 @@ public class CpsDeltaServiceImpl implements CpsDeltaService {
for (final Map.Entry<String, DataNode> entry: xpathToAddedNodes.entrySet()) {
final String xpath = entry.getKey();
final DataNode dataNode = entry.getValue();
- final DeltaReport addedDataForDeltaReport = new DeltaReportBuilder().actionAdd().withXpath(xpath)
+ final DeltaReport addedDataForDeltaReport = new DeltaReportBuilder().actionCreate().withXpath(xpath)
.withTargetData(dataNode.getLeaves()).build();
addedDeltaReportEntries.add(addedDataForDeltaReport);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
index 14b949e5ae..a600b22b61 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
@@ -30,6 +30,7 @@ import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.onap.cps.api.CpsAnchorService;
import org.onap.cps.api.CpsModuleService;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.CascadeDeleteAllowed;
import org.onap.cps.spi.CpsModulePersistenceService;
import org.onap.cps.spi.exceptions.SchemaSetInUseException;
@@ -37,7 +38,6 @@ import org.onap.cps.spi.model.Anchor;
import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.spi.model.ModuleReference;
import org.onap.cps.spi.model.SchemaSet;
-import org.onap.cps.spi.utils.CpsValidator;
import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder;
import org.onap.cps.yang.YangTextSchemaSourceSet;
import org.springframework.stereotype.Service;
@@ -97,7 +97,7 @@ public class CpsModuleServiceImpl implements CpsModuleService {
public void deleteSchemaSet(final String dataspaceName, final String schemaSetName,
final CascadeDeleteAllowed cascadeDeleteAllowed) {
cpsValidator.validateNameCharacters(dataspaceName, schemaSetName);
- final Collection<Anchor> anchors = cpsAnchorService.getAnchors(dataspaceName, schemaSetName);
+ final Collection<Anchor> anchors = cpsAnchorService.getAnchorsBySchemaSetName(dataspaceName, schemaSetName);
if (!anchors.isEmpty() && isCascadeDeleteProhibited(cascadeDeleteAllowed)) {
throw new SchemaSetInUseException(dataspaceName, schemaSetName);
}
@@ -114,8 +114,9 @@ public class CpsModuleServiceImpl implements CpsModuleService {
public void deleteSchemaSetsWithCascade(final String dataspaceName, final Collection<String> schemaSetNames) {
cpsValidator.validateNameCharacters(dataspaceName);
cpsValidator.validateNameCharacters(schemaSetNames);
- final Collection<String> anchorNames = cpsAnchorService.getAnchors(dataspaceName, schemaSetNames)
- .stream().map(Anchor::getName).collect(Collectors.toSet());
+ final Collection<String> anchorNames =
+ cpsAnchorService.getAnchorsBySchemaSetNames(dataspaceName, schemaSetNames)
+ .stream().map(Anchor::getName).collect(Collectors.toSet());
cpsAnchorService.deleteAnchors(dataspaceName, anchorNames);
cpsModulePersistenceService.deleteSchemaSets(dataspaceName, schemaSetNames);
cpsModulePersistenceService.deleteUnusedYangResourceModules();
@@ -170,6 +171,17 @@ public class CpsModuleServiceImpl implements CpsModuleService {
return cpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck);
}
+ @Timed(value = "cps.module.service.module.reference.query",
+ description = "Time taken to query list of module references")
+ @Override
+ public Collection<ModuleReference> getModuleReferencesByAttribute(final String dataspaceName,
+ final String anchorName,
+ final Map<String, String> parentAttributes,
+ final Map<String, String> childAttributes) {
+ return cpsModulePersistenceService.getModuleReferencesByAttribute(dataspaceName, anchorName, parentAttributes,
+ childAttributes);
+ }
+
private boolean isCascadeDeleteProhibited(final CascadeDeleteAllowed cascadeDeleteAllowed) {
return CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED == cascadeDeleteAllowed;
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java
index 1d7a7ceeb0..d1c98986e6 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java
@@ -25,11 +25,11 @@ import io.micrometer.core.annotation.Timed;
import java.util.Collection;
import lombok.RequiredArgsConstructor;
import org.onap.cps.api.CpsQueryService;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.CpsDataPersistenceService;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.PaginationOption;
import org.onap.cps.spi.model.DataNode;
-import org.onap.cps.spi.utils.CpsValidator;
import org.springframework.stereotype.Service;
@Service
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java b/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java
index 4fdae5a307..8b85dfca32 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java
@@ -27,8 +27,8 @@ import io.micrometer.core.instrument.Metrics;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.RequiredArgsConstructor;
+import org.onap.cps.impl.utils.CpsValidator;
import org.onap.cps.spi.CpsModulePersistenceService;
-import org.onap.cps.spi.utils.CpsValidator;
import org.onap.cps.yang.YangTextSchemaSourceSet;
import org.onap.cps.yang.YangTextSchemaSourceSetBuilder;
import org.springframework.cache.annotation.CacheConfig;
diff --git a/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java b/cps-service/src/main/java/org/onap/cps/impl/utils/CpsValidator.java
index ceb75c09b2..fd677eb2d2 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/utils/CpsValidator.java
+++ b/cps-service/src/main/java/org/onap/cps/impl/utils/CpsValidator.java
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.spi.utils;
+package org.onap.cps.impl.utils;
import org.onap.cps.spi.PaginationOption;
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
index 2b21619cb7..25830a55de 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2022 Nordix Foundation.
+ * Copyright (C) 2020-2024 Nordix Foundation.
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -73,30 +73,48 @@ public interface CpsAdminPersistenceService {
void createAnchor(String dataspaceName, String schemaSetName, String anchorName);
/**
- * Read all anchors associated with the given schema-set in the given dataspace.
+ * Get an anchor in the given dataspace using the anchor name.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @return an anchor
+ */
+ Anchor getAnchor(String dataspaceName, String anchorName);
+
+ /**
+ * Read all anchors in the given a dataspace.
*
* @param dataspaceName dataspace name
- * @param schemaSetName schema-set name
* @return a collection of anchors
*/
- Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName);
+ Collection<Anchor> getAnchors(String dataspaceName);
/**
- * Read all anchors associated with multiple schema-sets in the given dataspace.
+ * Read all anchors in the given dataspace with the anchor names.
*
- * @param dataspaceName dataspace name
- * @param schemaSetNames schema-set names
+ * @param dataspaceName dataspace name
+ * @param anchorNames anchor names
* @return a collection of anchors
*/
- Collection<Anchor> getAnchors(String dataspaceName, Collection<String> schemaSetNames);
+ Collection<Anchor> getAnchors(String dataspaceName, Collection<String> anchorNames);
/**
- * Read all anchors in the given a dataspace.
+ * Read all anchors associated with the given schema-set in the given dataspace.
*
* @param dataspaceName dataspace name
+ * @param schemaSetName schema-set name
* @return a collection of anchors
*/
- Collection<Anchor> getAnchors(String dataspaceName);
+ Collection<Anchor> getAnchorsBySchemaSetName(String dataspaceName, String schemaSetName);
+
+ /**
+ * Read all anchors associated with multiple schema-sets in the given dataspace.
+ *
+ * @param dataspaceName dataspace name
+ * @param schemaSetNames schema-set names
+ * @return a collection of anchors
+ */
+ Collection<Anchor> getAnchorsBySchemaSetNames(String dataspaceName, Collection<String> schemaSetNames);
/**
* Query anchor names for the given module names in the provided dataspace.
@@ -110,15 +128,6 @@ public interface CpsAdminPersistenceService {
Collection<String> queryAnchorNames(String dataspaceName, Collection<String> moduleNames);
/**
- * Get an anchor in the given dataspace using the anchor name.
- *
- * @param dataspaceName dataspace name
- * @param anchorName anchor name
- * @return an anchor
- */
- Anchor getAnchor(String dataspaceName, String anchorName);
-
- /**
* Delete anchor by name in given dataspace.
*
* @param dataspaceName dataspace name
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
index eeaaa47991..793f38e4bc 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
@@ -153,4 +153,20 @@ public interface CpsModulePersistenceService {
Collection<ModuleReference> identifyNewModuleReferences(
Collection<ModuleReference> moduleReferencesToCheck);
+ /**
+ * Retrieves module references based on the specified dataspace, anchor, and attribute filters.
+
+ * Constructs and executes a SQL query to find module references by applying filters for parent and child fragments.
+ * Uses `parentAttributes` for filtering parent fragments and `childAttributes` for filtering child fragments.
+ *
+ * @param dataspaceName the name of the dataspace to filter on.
+ * @param anchorName the name of the anchor to filter on.
+ * @param parentAttributes a map of attributes for filtering parent fragments.
+ * @param childAttributes a map of attributes for filtering child fragments.
+ * @return a collection of {@link ModuleReference} objects matching the criteria.
+ */
+ Collection<ModuleReference> getModuleReferencesByAttribute(final String dataspaceName, final String anchorName,
+ final Map<String, String> parentAttributes,
+ final Map<String, String> childAttributes);
+
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReport.java b/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReport.java
index fb9c1971b2..c6270a41d2 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReport.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReport.java
@@ -20,6 +20,7 @@
package org.onap.cps.spi.model;
+import com.fasterxml.jackson.annotation.JsonInclude;
import java.io.Serializable;
import java.util.Map;
import lombok.AccessLevel;
@@ -28,11 +29,12 @@ import lombok.Setter;
@Setter(AccessLevel.PROTECTED)
@Getter
+@JsonInclude(JsonInclude.Include.NON_NULL)
public class DeltaReport {
- public static final String ADD_ACTION = "add";
+ public static final String CREATE_ACTION = "create";
public static final String REMOVE_ACTION = "remove";
- public static final String UPDATE_ACTION = "update";
+ public static final String REPLACE_ACTION = "replace";
DeltaReport() {}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReportBuilder.java b/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReportBuilder.java
index 1e151eeb2d..a7e7aae215 100644
--- a/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReportBuilder.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/model/DeltaReportBuilder.java
@@ -48,8 +48,8 @@ public class DeltaReportBuilder {
return this;
}
- public DeltaReportBuilder actionAdd() {
- this.action = DeltaReport.ADD_ACTION;
+ public DeltaReportBuilder actionCreate() {
+ this.action = DeltaReport.CREATE_ACTION;
return this;
}
@@ -58,8 +58,8 @@ public class DeltaReportBuilder {
return this;
}
- public DeltaReportBuilder actionUpdate() {
- this.action = DeltaReport.UPDATE_ACTION;
+ public DeltaReportBuilder actionReplace() {
+ this.action = DeltaReport.REPLACE_ACTION;
return this;
}
diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangParser.java b/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
index 6299ef39f4..dc23c6bc4a 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2024 Nordix Foundation.
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,20 +22,25 @@
package org.onap.cps.utils;
import io.micrometer.core.annotation.Timed;
+import java.util.Map;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.onap.cps.api.impl.YangTextSchemaSourceSetCache;
import org.onap.cps.spi.exceptions.DataValidationException;
import org.onap.cps.spi.model.Anchor;
+import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.springframework.stereotype.Service;
+@Slf4j
@Service
@RequiredArgsConstructor
public class YangParser {
private final YangParserHelper yangParserHelper;
private final YangTextSchemaSourceSetCache yangTextSchemaSourceSetCache;
+ private final TimedYangTextSchemaSourceSetBuilder timedYangTextSchemaSourceSetBuilder;
/**
* Parses data into (normalized) ContainerNode according to schema context for the given anchor.
@@ -58,11 +64,33 @@ public class YangParser {
return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
}
+ /**
+ * Parses data into (normalized) ContainerNode according to schema context for the given yang resource.
+ *
+ * @param nodeData data string
+ * @param yangResourcesNameToContentMap yang resource to content map
+ * @return the NormalizedNode object
+ */
+ @Timed(value = "cps.utils.yangparser.nodedata.with.parent.with.yangResourceMap.parse",
+ description = "Time taken to parse node data with a parent")
+ public ContainerNode parseData(final ContentType contentType,
+ final String nodeData,
+ final Map<String, String> yangResourcesNameToContentMap,
+ final String parentNodeXpath) {
+ final SchemaContext schemaContext = getSchemaContext(yangResourcesNameToContentMap);
+ return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
+ }
+
private SchemaContext getSchemaContext(final Anchor anchor) {
return yangTextSchemaSourceSetCache.get(anchor.getDataspaceName(),
anchor.getSchemaSetName()).getSchemaContext();
}
+ private SchemaContext getSchemaContext(final Map<String, String> yangResourcesNameToContentMap) {
+ return timedYangTextSchemaSourceSetBuilder.getYangTextSchemaSourceSet(yangResourcesNameToContentMap)
+ .getSchemaContext();
+ }
+
private void invalidateCache(final Anchor anchor) {
yangTextSchemaSourceSetCache.removeFromCache(anchor.getDataspaceName(), anchor.getSchemaSetName());
}
diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java b/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
index 5cadd29368..597164598a 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
@@ -120,13 +120,9 @@ public class YangParserHelper {
try (jsonParserStream) {
jsonParserStream.parse(jsonReader);
- } catch (final IOException | JsonSyntaxException exception) {
+ } catch (final IOException | JsonSyntaxException | IllegalStateException | IllegalArgumentException exception) {
throw new DataValidationException(
- "Failed to parse json data: " + jsonData, exception.getMessage(), exception);
- } catch (final IllegalStateException | IllegalArgumentException exception) {
- throw new DataValidationException(
- "Failed to parse json data. Unsupported xpath or json data:" + jsonData, exception
- .getMessage(), exception);
+ "Data Validation Failed", "Failed to parse json data. " + exception.getMessage(), exception);
}
return dataContainerNodeBuilder.build();
}
@@ -168,7 +164,7 @@ public class YangParserHelper {
} catch (final XMLStreamException | URISyntaxException | IOException | SAXException | NullPointerException
| ParserConfigurationException | TransformerException exception) {
throw new DataValidationException(
- "Failed to parse xml data: " + xmlData, exception.getMessage(), exception);
+ "Data Validation Failed", "Failed to parse xml data: " + exception.getMessage(), exception);
}
final DataContainerChild dataContainerChild =
(DataContainerChild) getFirstChildXmlRoot(normalizedNodeResult.getResult());
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy
index c7865386bc..ccf943a470 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAnchorServiceImplSpec.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.
@@ -20,11 +20,11 @@
package org.onap.cps.api.impl
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.spi.CpsAdminPersistenceService
import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException
import org.onap.cps.spi.model.Anchor
-import org.onap.cps.spi.utils.CpsValidator
import spock.lang.Specification
class CpsAnchorServiceImplSpec extends Specification {
@@ -59,9 +59,9 @@ class CpsAnchorServiceImplSpec extends Specification {
def 'Retrieve all anchors for schema-set.'() {
given: 'that anchor is associated with the dataspace and schemaset'
def anchors = [new Anchor()]
- mockCpsAdminPersistenceService.getAnchors('someDataspace', 'someSchemaSet') >> anchors
+ mockCpsAdminPersistenceService.getAnchorsBySchemaSetName('someDataspace', 'someSchemaSet') >> anchors
when: 'get anchors is called for a dataspace name and schema set name'
- def result = objectUnderTest.getAnchors('someDataspace', 'someSchemaSet')
+ def result = objectUnderTest.getAnchorsBySchemaSetName('someDataspace', 'someSchemaSet')
then: 'the collection provided by persistence service is returned as result'
result == anchors
and: 'the CpsValidator is called on the dataspaceName, schemaSetName'
@@ -71,9 +71,9 @@ class CpsAnchorServiceImplSpec extends Specification {
def 'Retrieve all anchors for multiple schema-sets.'() {
given: 'that anchor is associated with the dataspace and schemasets'
def anchors = [new Anchor(), new Anchor()]
- mockCpsAdminPersistenceService.getAnchors('someDataspace', _ as Collection<String>) >> anchors
+ mockCpsAdminPersistenceService.getAnchorsBySchemaSetNames('someDataspace', _ as Collection<String>) >> anchors
when: 'get anchors is called for a dataspace name and schema set names'
- def result = objectUnderTest.getAnchors('someDataspace', ['schemaSet1', 'schemaSet2'])
+ def result = objectUnderTest.getAnchorsBySchemaSetNames('someDataspace', ['schemaSet1', 'schemaSet2'])
then: 'the collection provided by persistence service is returned as result'
result == anchors
and: 'the CpsValidator is called on the dataspace name and schema-set names'
@@ -93,6 +93,21 @@ class CpsAnchorServiceImplSpec extends Specification {
1 * mockCpsValidator.validateNameCharacters('someDataspace', 'someAnchor')
}
+ def 'Retrieve multiple anchors for dataspace and provided anchor names.'() {
+ given: 'multiple anchors names to get'
+ def anchorNames = ['anchor1', 'anchor2']
+ and: 'that anchors are associated with the dataspace and anchor names'
+ def anchors = [new Anchor(), new Anchor()]
+ mockCpsAdminPersistenceService.getAnchors('someDataspace', anchorNames) >> anchors
+ when: 'get anchors is called for a dataspace name and anchor names'
+ def result = objectUnderTest.getAnchors('someDataspace', anchorNames)
+ then: 'the collection provided by persistence service is returned as result'
+ result == anchors
+ and: 'the CpsValidator is called on the dataspace name and anchor names'
+ 1 * mockCpsValidator.validateNameCharacters('someDataspace')
+ 1 * mockCpsValidator.validateNameCharacters(anchorNames)
+ }
+
def 'Delete anchor.'() {
when: 'delete anchor is invoked'
objectUnderTest.deleteAnchor('someDataspace','someAnchor')
@@ -105,15 +120,17 @@ class CpsAnchorServiceImplSpec extends Specification {
}
def 'Delete multiple anchors.'() {
+ given: 'multiple anchors to delete'
+ def anchorNames = ['anchor1', 'anchor2']
when: 'delete anchors is invoked'
- objectUnderTest.deleteAnchors('someDataspace', ['anchor1', 'anchor2'])
+ objectUnderTest.deleteAnchors('someDataspace', anchorNames)
then: 'delete data nodes is invoked on the data service with expected parameters'
- 1 * mockCpsDataPersistenceService.deleteDataNodes('someDataspace', _ as Collection<String>)
+ 1 * mockCpsDataPersistenceService.deleteDataNodes('someDataspace', anchorNames)
and: 'the persistence service method is invoked with same parameters to delete anchor'
- 1 * mockCpsAdminPersistenceService.deleteAnchors('someDataspace',_ as Collection<String>)
+ 1 * mockCpsAdminPersistenceService.deleteAnchors('someDataspace', anchorNames)
and: 'the CpsValidator is called on the dataspace name and anchor names'
1 * mockCpsValidator.validateNameCharacters('someDataspace')
- 1 * mockCpsValidator.validateNameCharacters(_)
+ 1 * mockCpsValidator.validateNameCharacters(anchorNames)
}
def 'Query all anchor identifiers for a dataspace and module names.'() {
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
index fcbfd0561a..9846b30158 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -26,10 +26,12 @@ package org.onap.cps.api.impl
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.core.read.ListAppender
+import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.TestUtils
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDeltaService
import org.onap.cps.events.CpsDataUpdateEventsService
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.exceptions.ConcurrencyException
@@ -39,28 +41,37 @@ import org.onap.cps.spi.exceptions.SessionManagerException
import org.onap.cps.spi.exceptions.SessionTimeoutException
import org.onap.cps.spi.model.Anchor
import org.onap.cps.spi.model.DataNodeBuilder
-import org.onap.cps.spi.utils.CpsValidator
import org.onap.cps.utils.ContentType
+import org.onap.cps.utils.JsonObjectMapper
+import org.onap.cps.utils.PrefixResolver
import org.onap.cps.utils.YangParser
import org.onap.cps.utils.YangParserHelper
+import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder
import org.onap.cps.yang.YangTextSchemaSourceSet
import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import spock.lang.Shared
import spock.lang.Specification
+
import java.time.OffsetDateTime
+import static org.onap.cps.events.model.Data.Operation.DELETE
+
class CpsDataServiceImplSpec extends Specification {
def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
def mockCpsAnchorService = Mock(CpsAnchorService)
def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache)
def mockCpsValidator = Mock(CpsValidator)
- def yangParser = new YangParser(new YangParserHelper(), mockYangTextSchemaSourceSetCache)
+ def mockTimedYangTextSchemaSourceSetBuilder = Mock(TimedYangTextSchemaSourceSetBuilder)
+ def yangParser = new YangParser(new YangParserHelper(), mockYangTextSchemaSourceSetCache, mockTimedYangTextSchemaSourceSetBuilder)
def mockCpsDeltaService = Mock(CpsDeltaService);
def mockDataUpdateEventsService = Mock(CpsDataUpdateEventsService)
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def mockPrefixResolver = Mock(PrefixResolver)
- def objectUnderTest = new CpsDataServiceImpl(mockCpsDataPersistenceService, mockDataUpdateEventsService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)
+ def objectUnderTest = new CpsDataServiceImpl(mockCpsDataPersistenceService, mockDataUpdateEventsService, mockCpsAnchorService,
+ mockCpsValidator, yangParser, mockCpsDeltaService, jsonObjectMapper, mockPrefixResolver)
def logger = (Logger) LoggerFactory.getLogger(objectUnderTest.class)
def loggingListAppender
@@ -122,8 +133,8 @@ class CpsDataServiceImplSpec extends Specification {
where: 'given parameters'
scenario | invalidData | contentType || expectedMessage
'no data nodes' | '{}' | ContentType.JSON || 'No data nodes'
- 'invalid json' | '{invalid json' | ContentType.JSON || 'Failed to parse json data'
- 'invalid xml' | '<invalid xml' | ContentType.XML || 'Failed to parse xml data'
+ 'invalid json' | '{invalid json' | ContentType.JSON || 'Data Validation Failed'
+ 'invalid xml' | '<invalid xml' | ContentType.XML || 'Data Validation Failed'
}
def 'Saving list element data fragment under Root node.'() {
@@ -131,7 +142,7 @@ class CpsDataServiceImplSpec extends Specification {
setupSchemaSetMocks('bookstore.yang')
when: 'save data method is invoked with list element json data'
def jsonData = '{"bookstore-address":[{"bookstore-name":"Easons","address":"Dublin,Ireland","postal-code":"D02HA21"}]}'
- objectUnderTest.saveListElements(dataspaceName, anchorName, '/', jsonData, observedTimestamp)
+ objectUnderTest.saveListElements(dataspaceName, anchorName, '/', jsonData, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.storeDataNodes(dataspaceName, anchorName,
{ dataNodeCollection ->
@@ -159,12 +170,11 @@ class CpsDataServiceImplSpec extends Specification {
1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
}
- def 'Saving list element data fragment under existing node.'() {
+ def 'Saving list element data fragment under existing JSON/XML node.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
- when: 'save data method is invoked with list element json data'
- def jsonData = '{"branch": [{"name": "A"}, {"name": "B"}]}'
- objectUnderTest.saveListElements(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp)
+ when: 'save data method is invoked with list element data'
+ objectUnderTest.saveListElements(dataspaceName, anchorName, '/test-tree', data, observedTimestamp, contentType)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.addListElements(dataspaceName, anchorName, '/test-tree',
{ dataNodeCollection ->
@@ -177,16 +187,23 @@ class CpsDataServiceImplSpec extends Specification {
)
and: 'the CpsValidator is called on the dataspaceName and AnchorName'
1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
+ where:
+ data | contentType
+ '{"branch": [{"name": "A"}, {"name": "B"}]}' | ContentType.JSON
+ '<test-tree xmlns="org:onap:cps:test:test-tree"><branch><name>A</name></branch><branch><name>B</name></branch></test-tree>' | ContentType.XML
}
- def 'Saving empty list element data fragment.'() {
+ def 'Saving empty list element data fragment for JSON/XML data.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'save data method is invoked with an empty list'
- def jsonData = '{"branch": []}'
- objectUnderTest.saveListElements(dataspaceName, anchorName, '/test-tree', jsonData, observedTimestamp)
+ objectUnderTest.saveListElements(dataspaceName, anchorName, '/test-tree', data, observedTimestamp, contentType)
then: 'invalid data exception is thrown'
thrown(DataValidationException)
+ where:
+ data | contentType
+ '{"branch": []}' | ContentType.JSON
+ '<test-tree><branch></branch></test-tree>' | ContentType.XML
}
def 'Get all data nodes #scenario.'() {
@@ -230,33 +247,89 @@ class CpsDataServiceImplSpec extends Specification {
1 * mockCpsDeltaService.getDeltaReports(sourceDataNodes, targetDataNodes)
}
+ def 'Get delta between anchor and payload with user provided schema #scenario'() {
+ given: 'user provided schema set '
+ def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('bookstore.yang')
+ setupSchemaSetMocksForDelta(yangResourcesNameToContentMap)
+ when: 'attempt to get delta between an anchor and a JSON payload'
+ objectUnderTest.getDeltaByDataspaceAnchorAndPayload(dataspaceName, anchorName, xpath, yangResourcesNameToContentMap, jsonData, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+ then: 'dataspacename and anchor names are validated'
+ 1 * mockCpsValidator.validateNameCharacters(['some-dataspace', 'some-anchor'])
+ and: 'source data nodes are fetched using appropriate persistence layer method'
+ 1 * mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> sourceDataNodes
+ and: 'appropriate delta service method is invoked once with correct source and target data nodes'
+ 1 * mockCpsDeltaService.getDeltaReports({sourceDataNodesRebuilt -> sourceDataNodesRebuilt.xpath[0] == expectedNodeXpath}, {targetDataNodes -> targetDataNodes.xpath[0] == expectedNodeXpath})
+ where: 'following data was used'
+ scenario | xpath | sourceDataNodes | jsonData || expectedNodeXpath
+ 'root node xpath' | '/' | [new DataNodeBuilder().withXpath('/bookstore').build()] | '{"bookstore":{"bookstore-name":"Easons"}}' || '/bookstore'
+ 'parent xpath' | '/bookstore' | [new DataNodeBuilder().withXpath('/bookstore').build()] | '{"bookstore":{"bookstore-name":"Easons"}}' || '/bookstore'
+ 'non-root xpath' | '/bookstore/categories[@code="02"]' | [new DataNodeBuilder().withXpath('/bookstore/categories[@code="02"]').withLeaves(["code":"02"]).build()] | '{"categories":[{"name":"kids","code":"02"}]}' || '/bookstore/categories[@code=\'02\']'
+ }
+
+ def 'Get delta between anchor and payload by using schema from anchor #scenario'() {
+ given: 'schema set for a given dataspace and anchor'
+ setupSchemaSetMocks("bookstore.yang")
+ when: 'attempt to get delta between an anchor and a JSON payload'
+ objectUnderTest.getDeltaByDataspaceAnchorAndPayload(dataspaceName, anchorName, xpath, [:], jsonData, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+ then: 'dataspacename and anchor names are validated'
+ 1 * mockCpsValidator.validateNameCharacters(['some-dataspace', 'some-anchor'])
+ and: 'source data nodes are fetched using appropriate persistence layer method'
+ 1 * mockCpsDataPersistenceService.getDataNodes(dataspaceName, anchorName, xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> sourceDataNodes
+ and: 'appropriate delta service method is invoked once with correct source and target data nodes'
+ 1 * mockCpsDeltaService.getDeltaReports({sourceDataNodesRebuilt -> sourceDataNodesRebuilt.xpath[0] == expectedNodeXpath}, {targetDataNodes -> targetDataNodes.xpath[0] == expectedNodeXpath})
+ where: 'following data was used'
+ scenario | xpath | sourceDataNodes | jsonData || expectedNodeXpath
+ 'root node xpath' | '/' | [new DataNodeBuilder().withXpath('/bookstore').build()] | '{"bookstore":{"bookstore-name":"Easons"}}' || '/bookstore'
+ 'parent xpath' | '/bookstore' | [new DataNodeBuilder().withXpath('/bookstore').build()] | '{"bookstore":{"bookstore-name":"Easons"}}' || '/bookstore'
+ 'non-root xpath' | '/bookstore/categories[@code="02"]' | [new DataNodeBuilder().withXpath('/bookstore/categories[@code="02"]').withLeaves(["code":"02"]).build()] | '{"categories":[{"name":"kids","code":"02"}]}' || '/bookstore/categories[@code=\'02\']'
+ }
+
+ def 'Delta between anchor and payload error scenario #scenario'() {
+ given: 'schema set for given anchor and dataspace references bookstore model'
+ def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('bookstore.yang')
+ setupSchemaSetMocksForDelta(yangResourcesNameToContentMap)
+ when: 'attempt to get delta between anchor and payload'
+ objectUnderTest.getDeltaByDataspaceAnchorAndPayload(dataspaceName, anchorName, xpath, yangResourcesNameToContentMap, jsonData, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+ then: 'expected exception is thrown'
+ thrown(DataValidationException)
+ where: 'following parameters were used'
+ scenario | xpath | jsonData
+ 'invalid json data with root node xpath' | '/' | '{"some-key": "some-value"'
+ 'empty json data with root node xpath' | '/' | '{}'
+ 'invalid json data with parent node xpath' | '/bookstore' | '{"some-key": "some-value"'
+ 'empty json data with parent node xpath' | '/bookstore' | '{}'
+ 'empty json data with xpath' | "/bookstore/categories[@code='02']" | '{}'
+ }
+
def 'Update data node leaves: #scenario.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
- when: 'update data method is invoked with json data #jsonData and parent node xpath #parentNodeXpath'
- objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, jsonData, observedTimestamp)
+ when: 'update data method is invoked with node data #nodeData and parent node xpath #parentNodeXpath'
+ objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, nodeData, observedTimestamp, contentType)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.batchUpdateDataLeaves(dataspaceName, anchorName, {dataNode -> dataNode.keySet()[0] == expectedNodeXpath})
and: 'the CpsValidator is called on the dataspaceName and AnchorName'
1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
where: 'following parameters were used'
- scenario | parentNodeXpath | jsonData || expectedNodeXpath
- 'top level node' | '/' | '{"test-tree": {"branch": []}}' || '/test-tree'
- 'level 2 node' | '/test-tree' | '{"branch": [{"name":"Name"}]}' || '/test-tree/branch[@name=\'Name\']'
+ scenario | parentNodeXpath | nodeData || expectedNodeXpath | contentType
+ 'JSON content: top level node' | '/' | '{"test-tree": {"branch": []}}' || '/test-tree' | ContentType.JSON
+ 'JSON content: level 2 node' | '/test-tree' | '{"branch": [{"name":"Name"}]}' || '/test-tree/branch[@name=\'Name\']' | ContentType.JSON
+ 'XML content: level 2 node' | '/test-tree' | '<branch><name>Name</name></branch>' || '/test-tree/branch[@name=\'Name\']' | ContentType.XML
}
def 'Update list-element data node with : #scenario.'() {
given: 'schema set for given anchor and dataspace references bookstore model'
setupSchemaSetMocks('bookstore.yang')
- when: 'update data method is invoked with json data #jsonData and parent node xpath'
+ when: 'update data method is invoked with node data #nodeData and parent node xpath'
objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, '/bookstore/categories[@code=2]',
- jsonData, observedTimestamp)
+ nodeData, observedTimestamp, contentType)
then: 'the persistence service method is invoked with correct parameters'
thrown(DataValidationException)
where: 'following parameters were used'
- scenario | jsonData
- 'multiple expectedLeaves' | '{"code": "01","name": "some-name"}'
- 'one leaf' | '{"name": "some-name"}'
+ scenario || nodeData | contentType
+ 'JSON content: multiple expectedLeaves' || '{"code": "03","name": "some-name"}' | ContentType.JSON
+ 'JSON content: one leaf' || '{"name": "some-name"}' | ContentType.JSON
+ 'XML content: multiple expectedLeaves' || '<code>1</code><name>some-name</name>' | ContentType.XML
}
def 'Update data nodes in different containers.' () {
@@ -266,7 +339,7 @@ class CpsDataServiceImplSpec extends Specification {
def parentNodeXpath = '/'
def updatedJsonData = '{"first-container":{"a-leaf":"a-new-Value"},"last-container":{"x-leaf":"x-new-value"}}'
when: 'update operation is performed on multiple data nodes'
- objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, updatedJsonData, observedTimestamp)
+ objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, updatedJsonData, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.batchUpdateDataLeaves(dataspaceName, anchorName, {dataNode -> dataNode.keySet()[index] == expectedNodeXpath})
and: 'the CpsValidator is called on the dataspaceName and AnchorName'
@@ -296,11 +369,11 @@ class CpsDataServiceImplSpec extends Specification {
1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
}
- def 'Replace data node using singular data node: #scenario.'() {
+ def 'Replace data node using singular JSON data node: #scenario.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace data method is invoked with json data #jsonData and parent node xpath #parentNodeXpath'
- objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath, jsonData, observedTimestamp)
+ objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath, jsonData, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
{ dataNode -> dataNode.xpath == expectedNodeXpath})
@@ -313,30 +386,63 @@ class CpsDataServiceImplSpec extends Specification {
'json list' | '/test-tree' | '{"branch": [{"name":"Name1"}, {"name":"Name2"}]}' || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
}
- def 'Replace data node using multiple data nodes: #scenario.'() {
+ def 'Replace data node using singular XML data node: #scenario.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace data method is invoked with XML data #xmlData and parent node xpath #parentNodeXpath'
+ objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath, xmlData, observedTimestamp, ContentType.XML)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
+ { dataNode -> dataNode.xpath == expectedNodeXpath })
+ and: 'the CpsValidator is called on the dataspaceName and AnchorName'
+ 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
+ where: 'following parameters were used'
+ scenario | parentNodeXpath | xmlData || expectedNodeXpath
+ 'level 2 node' | '/test-tree' | '<branch><name>Name</name></branch>' || ['/test-tree/branch[@name=\'Name\']']
+ 'xml list' | '/test-tree' | '<test-tree xmlns="org:onap:cps:test:test-tree"><branch><name>Name1</name></branch>' + '<branch><name>Name2</name></branch></test-tree>' || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
+ }
+
+ def 'Replace data node using multiple JSON data nodes: #scenario.'() {
given: 'schema set for given anchor and dataspace references test-tree model'
setupSchemaSetMocks('test-tree.yang')
when: 'replace data method is invoked with a map of xpaths and json data'
- objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, nodesJsonData, observedTimestamp)
+ objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, nodeDataPerXPath, observedTimestamp, ContentType.JSON)
then: 'the persistence service method is invoked with correct parameters'
1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
{ dataNode -> dataNode.xpath == expectedNodeXpath})
and: 'the CpsValidator is called on the dataspaceName and AnchorName'
1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
where: 'following parameters were used'
- scenario | nodesJsonData || expectedNodeXpath
+ scenario | nodeDataPerXPath || expectedNodeXpath
'top level node' | ['/' : '{"test-tree": {"branch": []}}', '/test-tree' : '{"branch": [{"name":"Name"}]}'] || ["/test-tree", "/test-tree/branch[@name='Name']"]
'level 2 node' | ['/test-tree' : '{"branch": [{"name":"Name"}]}', '/test-tree/branch[@name=\'Name\']':'{"nest":{"name":"nestName"}}'] || ["/test-tree/branch[@name='Name']", "/test-tree/branch[@name='Name']/nest"]
'json list' | ['/test-tree' : '{"branch": [{"name":"Name1"}, {"name":"Name2"}]}'] || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
}
+ def 'Replace data node using multiple XML data nodes: #scenario.'() {
+ given: 'schema set for given anchor and dataspace references test-tree model'
+ setupSchemaSetMocks('test-tree.yang')
+ when: 'replace data method is invoked with a map of xpaths and XML data'
+ objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, nodeXmlDataPerXPath, observedTimestamp, ContentType.XML)
+ then: 'the persistence service method is invoked with correct parameters'
+ 1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
+ { dataNode -> dataNode.xpath == expectedNodeXpath })
+ and: 'the CpsValidator is called on the dataspaceName and AnchorName'
+ 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
+ where: 'following parameters were used'
+ scenario | nodeXmlDataPerXPath || expectedNodeXpath
+ 'top level node' | ['/test-tree': '<branch><name>Name</name></branch>'] || ["/test-tree/branch[@name='Name']"]
+ 'level 2 node' | ['/test-tree': '<branch><name>Name</name></branch>', '/test-tree/branch[@name=\'Name\']': '<nest><name>nestName</name></nest>'] || ["/test-tree/branch[@name='Name']", "/test-tree/branch[@name='Name']/nest"]
+ 'xml list' | ['/test-tree': '<test-tree xmlns="org:onap:cps:test:test-tree"><branch><name>Name1</name></branch>' + '<branch><name>Name2</name></branch></test-tree>'] || ["/test-tree/branch[@name='Name1']", "/test-tree/branch[@name='Name2']"]
+ }
+
def 'Replace data node with concurrency exception in persistence layer.'() {
given: 'the persistence layer throws an concurrency exception'
def originalException = new ConcurrencyException('message', 'details')
mockCpsDataPersistenceService.updateDataNodesAndDescendants(*_) >> { throw originalException }
setupSchemaSetMocks('test-tree.yang')
when: 'attempt to replace data node'
- objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, ['/' : '{"test-tree": {}}'] , observedTimestamp)
+ objectUnderTest.updateDataNodesAndDescendants(dataspaceName, anchorName, ['/' : '{"test-tree": {}}'] , observedTimestamp, ContentType.JSON)
then: 'the same exception is thrown up'
def thrownUp = thrown(ConcurrencyException)
assert thrownUp == originalException
@@ -425,15 +531,19 @@ class CpsDataServiceImplSpec extends Specification {
def 'Delete all data nodes for given dataspace and multiple anchors.'() {
given: 'schema set for given anchors and dataspace references test tree model'
setupSchemaSetMocks('test-tree.yang')
- mockCpsAnchorService.getAnchors(dataspaceName, ['anchor1', 'anchor2']) >>
- [new Anchor(name: 'anchor1', dataspaceName: dataspaceName),
- new Anchor(name: 'anchor2', dataspaceName: dataspaceName)]
+ def anchor1 = new Anchor(name: 'anchor1', dataspaceName: dataspaceName)
+ def anchor2 = new Anchor(name: 'anchor2', dataspaceName: dataspaceName)
+ mockCpsAnchorService.getAnchors(dataspaceName, ['anchor1', 'anchor2']) >> [anchor1, anchor2]
when: 'delete data node method is invoked with correct parameters'
objectUnderTest.deleteDataNodes(dataspaceName, ['anchor1', 'anchor2'], observedTimestamp)
then: 'the CpsValidator is called on the dataspace name and the anchor names'
- 2 * mockCpsValidator.validateNameCharacters(_)
+ 1 * mockCpsValidator.validateNameCharacters(dataspaceName)
+ 1 * mockCpsValidator.validateNameCharacters(['anchor1', 'anchor2'])
and: 'the persistence service method is invoked with the correct parameters'
1 * mockCpsDataPersistenceService.deleteDataNodes(dataspaceName, _ as Collection<String>)
+ and: 'a data update event is sent for each anchor'
+ 1 * mockDataUpdateEventsService.publishCpsDataUpdateEvent(anchor1, '/', DELETE, observedTimestamp)
+ 1 * mockDataUpdateEventsService.publishCpsDataUpdateEvent(anchor2, '/', DELETE, observedTimestamp)
}
def 'Start session.'() {
@@ -486,7 +596,7 @@ class CpsDataServiceImplSpec extends Specification {
when: 'publisher set to throw an exception'
mockDataUpdateEventsService.publishCpsDataUpdateEvent(_, _, _, _) >> { throw new Exception("publishing failed")}
and: 'an update event is performed'
- objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, '/', '{"test-tree": {"branch": []}}', observedTimestamp)
+ objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, '/', '{"test-tree": {"branch": []}}', observedTimestamp, ContentType.JSON)
then: 'the exception is not bubbled up'
noExceptionThrown()
and: "the exception message is logged"
@@ -501,4 +611,12 @@ class CpsDataServiceImplSpec extends Specification {
mockYangTextSchemaSourceSet.getSchemaContext() >> schemaContext
}
+ def setupSchemaSetMocksForDelta(Map<String, String> yangResourcesNameToContentMap) {
+ def mockYangTextSchemaSourceSet = Mock(YangTextSchemaSourceSet)
+ mockTimedYangTextSchemaSourceSetBuilder.getYangTextSchemaSourceSet(yangResourcesNameToContentMap) >> mockYangTextSchemaSourceSet
+ mockYangTextSchemaSourceSetCache.get(_, _) >> mockYangTextSchemaSourceSet
+ def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap).getSchemaContext()
+ mockYangTextSchemaSourceSet.getSchemaContext() >> schemaContext
+ }
+
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataspaceServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataspaceServiceImplSpec.groovy
index 8e17594bd1..ac7d4c0aa7 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataspaceServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataspaceServiceImplSpec.groovy
@@ -20,9 +20,9 @@
package org.onap.cps.api.impl
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.spi.CpsAdminPersistenceService
import org.onap.cps.spi.model.Dataspace
-import org.onap.cps.spi.utils.CpsValidator
import spock.lang.Specification
class CpsDataspaceServiceImplSpec extends Specification {
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDeltaServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDeltaServiceImplSpec.groovy
index 42d75f3eab..f12afe61ec 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDeltaServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDeltaServiceImplSpec.groovy
@@ -51,8 +51,8 @@ class CpsDeltaServiceImplSpec extends Specification{
def 'Get delta between data nodes for ADDED data'() {
when: 'attempt to get delta between 2 data nodes'
def result = objectUnderTest.getDeltaReports([], targetDataNodeWithLeafData)
- then: 'the delta report contains expected "add" action'
- assert result[0].action.equals('add')
+ then: 'the delta report contains expected "create" action'
+ assert result[0].action.equals('create')
and: 'the delta report contains expected xpath'
assert result[0].xpath == '/parent'
and: 'the delta report contains no source data'
@@ -68,12 +68,12 @@ class CpsDeltaServiceImplSpec extends Specification{
when: 'attempt to get delta between 2 data nodes'
def result = objectUnderTest.getDeltaReports(sourceDataNode, targetDataNode)
then: 'the delta report contains expected details for parent node'
- assert result[0].action.equals('update')
+ assert result[0].action.equals('replace')
assert result[0].xpath == '/parent'
assert result[0].sourceData == ['parent-leaf': 'parent-payload']
assert result[0].targetData == ['parent-leaf': 'parent-payload-updated']
and: 'the delta report contains expected details for child node'
- assert result[1].action.equals('update')
+ assert result[1].action.equals('replace')
assert result[1].xpath == '/parent/child'
assert result[1].sourceData == ['child-leaf': 'child-payload']
assert result[1].targetData == ['child-leaf': 'child-payload-updated']
@@ -82,8 +82,8 @@ class CpsDeltaServiceImplSpec extends Specification{
def 'Delta report between leaves, #scenario'() {
when: 'attempt to get delta between 2 data nodes'
def result = objectUnderTest.getDeltaReports(sourceDataNode, targetDataNode)
- then: 'the delta report contains expected "update" action'
- assert result[0].action.equals('update')
+ then: 'the delta report contains expected "replace" action'
+ assert result[0].action.equals('replace')
and: 'the delta report contains expected xpath'
assert result[0].xpath == '/parent'
and: 'the delta report contains expected source and target data'
@@ -100,7 +100,7 @@ class CpsDeltaServiceImplSpec extends Specification{
def 'Get delta between data nodes for updated data, where source and target data nodes have no leaves '() {
when: 'attempt to get delta between 2 data nodes'
def result = objectUnderTest.getDeltaReports(sourceDataNodeWithoutLeafData, targetDataNodeWithoutLeafData)
- then: 'the delta report contains "update" action with right data'
+ then: 'the delta report is empty'
assert result.isEmpty()
}
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
index 0bad0de6ac..1831506563 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
@@ -23,19 +23,15 @@
package org.onap.cps.api.impl
-import org.onap.cps.api.CpsAnchorService
-
-import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED
-import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED
-
import org.onap.cps.TestUtils
+import org.onap.cps.api.CpsAnchorService
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.spi.CpsModulePersistenceService
import org.onap.cps.spi.exceptions.DuplicatedYangResourceException
import org.onap.cps.spi.exceptions.ModelValidationException
import org.onap.cps.spi.exceptions.SchemaSetInUseException
-import org.onap.cps.spi.model.ModuleDefinition
-import org.onap.cps.spi.utils.CpsValidator
import org.onap.cps.spi.model.Anchor
+import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.spi.model.SchemaSet
import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder
@@ -43,6 +39,9 @@ import org.onap.cps.yang.YangTextSchemaSourceSet
import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
import spock.lang.Specification
+import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED
+import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED
+
class CpsModuleServiceImplSpec extends Specification {
def mockCpsModulePersistenceService = Mock(CpsModulePersistenceService)
@@ -134,7 +133,7 @@ class CpsModuleServiceImplSpec extends Specification {
def 'Delete schema-set when cascade is allowed.'() {
given: '#numberOfAnchors anchors are associated with schemaset'
def associatedAnchors = createAnchors(numberOfAnchors)
- mockCpsAnchorService.getAnchors('my-dataspace', 'my-schemaset') >> associatedAnchors
+ mockCpsAnchorService.getAnchorsBySchemaSetName('my-dataspace', 'my-schemaset') >> associatedAnchors
when: 'schema set deletion is requested with cascade allowed'
objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_ALLOWED)
then: 'anchor deletion is called #numberOfAnchors times'
@@ -153,7 +152,7 @@ class CpsModuleServiceImplSpec extends Specification {
def 'Delete schema-set when cascade is prohibited.'() {
given: 'no anchors are associated with schemaset'
- mockCpsAnchorService.getAnchors('my-dataspace', 'my-schemaset') >> Collections.emptyList()
+ mockCpsAnchorService.getAnchorsBySchemaSetName('my-dataspace', 'my-schemaset') >> Collections.emptyList()
when: 'schema set deletion is requested with cascade allowed'
objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_PROHIBITED)
then: 'no anchors are deleted'
@@ -170,7 +169,7 @@ class CpsModuleServiceImplSpec extends Specification {
def 'Delete schema-set when cascade is prohibited and schema-set has anchors.'() {
given: '2 anchors are associated with schemaset'
- mockCpsAnchorService.getAnchors('my-dataspace', 'my-schemaset') >> createAnchors(2)
+ mockCpsAnchorService.getAnchorsBySchemaSetName('my-dataspace', 'my-schemaset') >> createAnchors(2)
when: 'schema set deletion is requested with cascade allowed'
objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_PROHIBITED)
then: 'Schema-Set in Use exception is thrown'
@@ -179,7 +178,7 @@ class CpsModuleServiceImplSpec extends Specification {
def 'Delete multiple schema-sets when cascade is allowed.'() {
given: '#numberOfAnchors anchors are associated with each schemaset'
- mockCpsAnchorService.getAnchors('my-dataspace', ['my-schemaset1', 'my-schemaset2']) >> createAnchors(numberOfAnchors * 2)
+ mockCpsAnchorService.getAnchorsBySchemaSetNames('my-dataspace', ['my-schemaset1', 'my-schemaset2']) >> createAnchors(numberOfAnchors * 2)
when: 'schema set deletion is requested with cascade allowed'
objectUnderTest.deleteSchemaSetsWithCascade('my-dataspace', ['my-schemaset1', 'my-schemaset2'])
then: 'anchor deletion is called #numberOfAnchors times'
@@ -238,6 +237,23 @@ class CpsModuleServiceImplSpec extends Specification {
1 * mockCpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck)
}
+ def 'Get module references when queried by attributes'() {
+ given: 'a valid dataspace name and anchor name'
+ def dataspaceName = 'someDataspace'
+ def anchorName = 'someAnchor'
+ and: 'a set of parent attributes and child attributes used for filtering'
+ def parentAttributes = ['some-property-key1': 'some-property-val1']
+ def childAttributes = ['some-property-key2': 'some-property-val2']
+ and: 'a list of expected module references returned by the persistence service'
+ def expectedModuleReferences = [new ModuleReference(moduleName: 'some-name', revision: 'some-revision')]
+ mockCpsModulePersistenceService.getModuleReferencesByAttribute(dataspaceName, anchorName, parentAttributes, childAttributes) >> expectedModuleReferences
+ when: 'the method is invoked to retrieve module references by attributes'
+ def actualModuleReferences = objectUnderTest.getModuleReferencesByAttribute(dataspaceName, anchorName, parentAttributes, childAttributes)
+ then: 'the retrieved module references should match the expected module references'
+ assert actualModuleReferences == expectedModuleReferences
+ }
+
+
def 'Getting module definitions with module name'() {
given: 'module persistence service returns module definitions for module name'
def moduleDefinitionsFromPersistenceService = [ new ModuleDefinition('name', 'revision', 'content' ) ]
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
index 1ad5017919..3b10669ddb 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
@@ -21,10 +21,10 @@
package org.onap.cps.api.impl
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.PaginationOption
-import org.onap.cps.spi.utils.CpsValidator
import spock.lang.Specification
class CpsQueryServiceImplSpec extends Specification {
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
index 57f2f8ea7c..05c8983fc2 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
@@ -23,15 +23,18 @@
package org.onap.cps.api.impl
+import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.TestUtils
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDeltaService
import org.onap.cps.events.CpsDataUpdateEventsService
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.CpsModulePersistenceService
import org.onap.cps.spi.model.Anchor
-import org.onap.cps.spi.utils.CpsValidator
import org.onap.cps.utils.ContentType
+import org.onap.cps.utils.JsonObjectMapper
+import org.onap.cps.utils.PrefixResolver
import org.onap.cps.utils.YangParser
import org.onap.cps.utils.YangParserHelper
import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder
@@ -45,15 +48,17 @@ class E2ENetworkSliceSpec extends Specification {
def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache)
def mockCpsValidator = Mock(CpsValidator)
def timedYangTextSchemaSourceSetBuilder = new TimedYangTextSchemaSourceSetBuilder()
- def yangParser = new YangParser(new YangParserHelper(), mockYangTextSchemaSourceSetCache)
+ def yangParser = new YangParser(new YangParserHelper(), mockYangTextSchemaSourceSetCache, timedYangTextSchemaSourceSetBuilder)
def mockCpsDeltaService = Mock(CpsDeltaService)
+ def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+ def mockPrefixResolver = Mock(PrefixResolver)
def cpsModuleServiceImpl = new CpsModuleServiceImpl(mockModuleStoreService,
mockYangTextSchemaSourceSetCache, mockCpsAnchorService, mockCpsValidator,timedYangTextSchemaSourceSetBuilder)
def mockDataUpdateEventsService = Mock(CpsDataUpdateEventsService)
- def cpsDataServiceImpl = new CpsDataServiceImpl(mockDataStoreService, mockDataUpdateEventsService, mockCpsAnchorService, mockCpsValidator, yangParser, mockCpsDeltaService)
-
+ def cpsDataServiceImpl = new CpsDataServiceImpl(mockDataStoreService, mockDataUpdateEventsService, mockCpsAnchorService, mockCpsValidator,
+ yangParser, mockCpsDeltaService, jsonObjectMapper, mockPrefixResolver)
def dataspaceName = 'someDataspace'
def anchorName = 'someAnchor'
def schemaSetName = 'someSchemaSet'
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy
index a9f50ee5b0..189e28521b 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/YangTextSchemaSourceSetCacheSpec.groovy
@@ -22,6 +22,7 @@
package org.onap.cps.api.impl
import org.onap.cps.TestUtils
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.spi.CpsModulePersistenceService
import org.onap.cps.yang.YangTextSchemaSourceSet
import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
@@ -34,8 +35,6 @@ import org.springframework.cache.annotation.EnableCaching
import org.springframework.cache.caffeine.CaffeineCacheManager
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
-import org.onap.cps.spi.utils.CpsValidator
-
@SpringBootTest
@EnableCaching
diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/model/DeltaReportBuilderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/model/DeltaReportBuilderSpec.groovy
index e19d120421..00b5499c2f 100644
--- a/cps-service/src/test/groovy/org/onap/cps/spi/model/DeltaReportBuilderSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/spi/model/DeltaReportBuilderSpec.groovy
@@ -24,20 +24,20 @@ import spock.lang.Specification
class DeltaReportBuilderSpec extends Specification{
- def 'Generating delta report with for add action'() {
+ def 'Generating delta report for "create" action'() {
when: 'delta report is generated'
def result = new DeltaReportBuilder()
- .actionAdd()
+ .actionCreate()
.withXpath('/xpath')
.withTargetData(['data':'leaf-data'])
.build()
- then: 'the delta report contains the "add" action with expected target data'
- assert result.action == 'add'
+ then: 'the delta report contains the "create" action with expected target data'
+ assert result.action == 'create'
assert result.xpath == '/xpath'
assert result.targetData == ['data': 'leaf-data']
}
- def 'Generating delta report with attributes for remove action'() {
+ def 'Generating delta report with attributes for "remove" action'() {
when: 'delta report is generated'
def result = new DeltaReportBuilder()
.actionRemove()
diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/JsonObjectMapperSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/JsonObjectMapperSpec.groovy
index 8cbd493550..09d45b92c0 100644
--- a/cps-service/src/test/groovy/org/onap/cps/utils/JsonObjectMapperSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/utils/JsonObjectMapperSpec.groovy
@@ -42,7 +42,7 @@ class JsonObjectMapperSpec extends Specification {
def contentMap = new JsonSlurper().parseText(new String(content))
and: 'the parsed content is as expected'
assert contentMap.'test:bookstore'.'bookstore-name' == 'Chapters/Easons'
- where: 'the following data stores are used'
+ where: 'the following content types are used'
type << ['String', 'bytes']
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy
index 99070fe729..18d0502e30 100644
--- a/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,9 +21,12 @@
package org.onap.cps.utils
+import org.onap.cps.TestUtils
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.Anchor
+import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder
import org.onap.cps.yang.YangTextSchemaSourceSet
+import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode
import org.opendaylight.yangtools.yang.model.api.SchemaContext
import spock.lang.Specification
@@ -32,10 +36,12 @@ class YangParserSpec extends Specification {
def mockYangParserHelper = Mock(YangParserHelper)
def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache)
+ def mockTimedYangTextSchemaSourceSetBuilder = Mock(TimedYangTextSchemaSourceSetBuilder)
- def objectUnderTest = new YangParser(mockYangParserHelper, mockYangTextSchemaSourceSetCache)
+ def objectUnderTest = new YangParser(mockYangParserHelper, mockYangTextSchemaSourceSetCache, mockTimedYangTextSchemaSourceSetBuilder)
def anchor = new Anchor(dataspaceName: 'my dataspace', schemaSetName: 'my schema')
+ def yangResourcesNameToContentMap = TestUtils.getYangResourcesAsMap('bookstore.yang')
def mockYangTextSchemaSourceSet = Mock(YangTextSchemaSourceSet)
def mockSchemaContext = Mock(SchemaContext)
def containerNodeFromYangUtils = Mock(ContainerNode)
@@ -82,4 +88,15 @@ class YangParserSpec extends Specification {
1 * mockYangTextSchemaSourceSetCache.removeFromCache('my dataspace', 'my schema')
}
+ def 'Parsing data with yang resource to context map.'() {
+ given: 'the schema source set for the yang resource map is returned'
+ mockTimedYangTextSchemaSourceSetBuilder.getYangTextSchemaSourceSet(yangResourcesNameToContentMap) >> mockYangTextSchemaSourceSet
+ when: 'parsing some json data'
+ def result = objectUnderTest.parseData(ContentType.JSON, 'some json', yangResourcesNameToContentMap, noParent)
+ then: 'the yang parser helper always returns a container node'
+ 1 * mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent) >> containerNodeFromYangUtils
+ and: 'the result is the same container node as return from yang utils'
+ assert result == containerNodeFromYangUtils
+ }
+
}
diff --git a/csit/install-deps.sh b/csit/install-deps.sh
new file mode 100755
index 0000000000..ef0b96a799
--- /dev/null
+++ b/csit/install-deps.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# Copyright 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.
+#
+
+echo "---> install-deps.sh"
+echo "Installing dependencies"
+
+# Create directory for downloaded binaries.
+mkdir -p bin
+touch bin/.gitignore
+
+# Add it to the PATH, so downloaded versions will be used.
+export PATH="$(pwd)/bin:$PATH"
+
+# Download docker-compose.
+if [ ! -x bin/docker-compose ]; then
+ echo " Downloading docker-compose"
+ curl -s -L https://github.com/docker/compose/releases/download/v2.29.2/docker-compose-linux-x86_64 > bin/docker-compose
+ chmod +x bin/docker-compose
+else
+ echo " docker-compose already installed"
+fi
+docker-compose version
diff --git a/csit/plans/cps/pnfsim/docker-compose.yml b/csit/plans/cps/pnfsim/docker-compose.yml
index e0f21a2ce6..869df22789 100644
--- a/csit/plans/cps/pnfsim/docker-compose.yml
+++ b/csit/plans/cps/pnfsim/docker-compose.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Modifications Copyright (C) 2022 Nordix Foundation
+# Modifications Copyright (C) 2022-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.
@@ -16,7 +16,7 @@
services:
netconf-pnp-simulator:
- image: nexus3.onap.org:10001/onap/integration/simulators/netconf-pnp-simulator:2.8.6
+ image: blueonap/netconf-pnp-simulator:v2.8.6
container_name: netconf-simulator
restart: always
ports:
@@ -24,3 +24,4 @@ services:
- "6512:6513"
volumes:
- ./netconf-config:/config/modules/stores
+ - ./tls:/config/tls
diff --git a/csit/plans/cps/pnfsim/tls/ca.pem b/csit/plans/cps/pnfsim/tls/ca.pem
new file mode 100644
index 0000000000..4c4473815c
--- /dev/null
+++ b/csit/plans/cps/pnfsim/tls/ca.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID2zCCAsOgAwIBAgIUWDactJMMP2Q2mw0yBnUfQXRsXZMwDQYJKoZIhvcNAQEF
+BQAwfTELMAkGA1UEBhMCSUUxEjAQBgNVBAgMCVdlc3RtZWF0aDEQMA4GA1UEBwwH
+QXRobG9uZTEPMA0GA1UECgwGTm9yZGl4MRMwEQYDVQQDDApleGFtcGxlIENBMSIw
+IAYJKoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTI0MDcyNDExMzMw
+N1oXDTM0MDcyMjExMzMwN1owfTELMAkGA1UEBhMCSUUxEjAQBgNVBAgMCVdlc3Rt
+ZWF0aDEQMA4GA1UEBwwHQXRobG9uZTEPMA0GA1UECgwGTm9yZGl4MRMwEQYDVQQD
+DApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1mNXPz3Vx4l9zhKt7uBm
+8RFebZchO1WjAN5NiIVhVG9Vfktz3DVCbWYpZKwjRrf0g1vBbZk//6qCp6qhHB9m
+4KoDPR1Eu9SX9rri3TD1HWW05HRgxa5j/pk5PCt3/4+eZ31hKcJGsfJ1SwYDk3F/
+bUzgfZ5e4+2LDMgKmKtuhTzQP6ITmqpCN02nEKElDUXgTffo8QBwqnUN91vRmYnC
+9nfD68ipu2Nl19Jam0MRVue2kaZUXF4nisomY4Zmpcf45D6XAdUKMx5wr/kWULIc
+Dz2jE0BkOb/2GCT+sOMnI9riq2X3CoII2wn0NUw0oLYA6lKO5ICZ40w9LfCjeo/r
+yQIDAQABo1MwUTAdBgNVHQ4EFgQUa9fiOtMAq5lM20SZe3jHUnwaQHMwHwYDVR0j
+BBgwFoAUa9fiOtMAq5lM20SZe3jHUnwaQHMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQUFAAOCAQEADys2rDXMYcjzhMhx0XJtty8STfBsWcsBfcVgwmt1vVwt
+buVn03vCVd90lj+5yqzr9OIntGEt/Mcw4Ca6rxl9bs+XGFxWo0McTxxXEZ5SRFK5
+ISRhWXWfmkxfiZalEymqKT4Xia8+Kydt0jsl93nUNA90GCQki7ngSCkOwoR4yizI
+eT6D/G5oTymEaKt8CuU+eBxQdD1kd6sSeKqXn4WY0dAClPk2VCjMuMYeYB6UWSL3
+HjSaDV4SQnCrvRNQzMJs/zONLPnt05N2GUho30LrXQ0h7zmkYl8AglfEtoCdXnRn
+ikOwkZ/N9V5K8NWJ0yQ5axftH6uxLMQgWIdhL32S0Q==
+-----END CERTIFICATE-----
diff --git a/csit/plans/cps/pnfsim/tls/server_cert.pem b/csit/plans/cps/pnfsim/tls/server_cert.pem
new file mode 100644
index 0000000000..a022dc56ca
--- /dev/null
+++ b/csit/plans/cps/pnfsim/tls/server_cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDijCCAnICFHAVskmbiSw4Q3eiKO6EJw48IS9EMA0GCSqGSIb3DQEBBQUAMH0x
+CzAJBgNVBAYTAklFMRIwEAYDVQQIDAlXZXN0bWVhdGgxEDAOBgNVBAcMB0F0aGxv
+bmUxDzANBgNVBAoMBk5vcmRpeDETMBEGA1UEAwwKZXhhbXBsZSBDQTEiMCAGCSqG
+SIb3DQEJARYTZXhhbXBsZWNhQGxvY2FsaG9zdDAeFw0yNDA3MjQxMTMzMzhaFw0z
+NDA3MjIxMTMzMzhaMIGFMQswCQYDVQQGEwJJRTESMBAGA1UECAwJV2VzdG1lYXRo
+MRAwDgYDVQQHDAdBdGhsb25lMQ8wDQYDVQQKDAZOb3JkaXgxFzAVBgNVBAMMDmV4
+YW1wbGUgc2VydmVyMSYwJAYJKoZIhvcNAQkBFhdleGFtcGxlc2VydmVyQGxvY2Fs
+aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALyFCBXEqZ39N7ZZ
+TEU8VJ03bY+kbTCfx9SOL/rP3X9zFOfv0g1TXEx2Yzl/LfRe1N5SgOB24tE34obA
+f++bOGXrsptrZMC5aqlG7cOfjELybUJaUIqMEDX+dte1f7OmPGs0mt2gG4DSU47j
+zGg3KshexLZUGc1fwPnUrBnEPFRCMWIqgSWkC4RrhB9R/uo/eBMh1coH+rSUE/Ba
+vcHlI8orbPu/mupt7tBKapb85nmSglatkZ/YCmfrrm4g5n8jap3e5rO8bs62yYeN
+BF2mHRLOwU+2VmQ1h6L+X0m6hC54UF9WdWyEd02o0HHDr1hDrg3aqrah+dnU+rgM
+hPu8ofkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAzoHPz0msIst3sT0fQxjqYxYo
+TnU0XzFsMvGC08wbz/iNOS+nvcMuRgG06CUj53BJvdmZPhSfqiYcInM3F4m1MrbM
+dK6L6Vk2eWaL4GwV6B7FR0CWjtTdlETkLSMBNufiqgHebZCT88JDAZAeqhdEbsqk
+7bnZVDdD0qA1Z9ClXFU3jO6n8f5EFn9Ai7FhD7floLHb9M0lheE8xO60RPXNmq/r
+Vf8HrBGHqpiumsMyAuwJONliuSEXNGuB+J+XeQJG91O1oR4Of34HUEZBT/BkoM0X
+iFB+xrLbShsTh1RbAdd1+t76Lsc1lkDVoupaTpdTXA0EmouS9O3CAFWfTjlcGg==
+-----END CERTIFICATE-----
diff --git a/csit/plans/cps/pnfsim/tls/server_key.pem b/csit/plans/cps/pnfsim/tls/server_key.pem
new file mode 100644
index 0000000000..02fd68846d
--- /dev/null
+++ b/csit/plans/cps/pnfsim/tls/server_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8hQgVxKmd/Te2
+WUxFPFSdN22PpG0wn8fUji/6z91/cxTn79INU1xMdmM5fy30XtTeUoDgduLRN+KG
+wH/vmzhl67Kba2TAuWqpRu3Dn4xC8m1CWlCKjBA1/nbXtX+zpjxrNJrdoBuA0lOO
+48xoNyrIXsS2VBnNX8D51KwZxDxUQjFiKoElpAuEa4QfUf7qP3gTIdXKB/q0lBPw
+Wr3B5SPKK2z7v5rqbe7QSmqW/OZ5koJWrZGf2Apn665uIOZ/I2qd3uazvG7OtsmH
+jQRdph0SzsFPtlZkNYei/l9JuoQueFBfVnVshHdNqNBxw69YQ64N2qq2ofnZ1Pq4
+DIT7vKH5AgMBAAECggEAAJNHWwmmmtzS9rN/EBcHCxPIOc/+pU9XhMaKTvGjc2ge
+gDazJWdDuNgDpYFF2qEPdT47NnQmbQ0Gm/KqcUi/+0+k0+SYAh6OvMWCpD4wZ2Pm
+AXXVGRckVYXZRv8+zIWNWaZncpWyf8okhyMa1JaWgtYHM6c+DOpl5F1JySpYJMmt
+laWH0fMCYdYM5N8RisXfImmf+bBcehIZFvq47f5LefvPBHCss/L+Nym/ypMl+qo1
+MvVPkMNIhJFb/NQSYknp5ino2uo06RNOhftu/ig8CgzuSYvK18Ia9NEAKd2kS/y7
+MtYipgBCQqax5ulYmDAmnSrm+KpNhfk+CcMBlW9yoQKBgQDboMRpUMyinK9jrY7R
+GqISWcrDRFEwKfPr0rFtBZM/0ODjZBXMDSej28LwCo+6Vo8dF4G9fValuyyrNMQl
+T0OpcDxBKV3yCHZoXmzTKx/vcF56hOgkpwT8gHWpVsqVxcjIyERZrynblMnZixcv
+ppF33YJv8A7oParHGnj9zqWvVwKBgQDbvWlV7/CV5y5kYnNKLIZ51xaTZpAt1CE7
+N4B4x41y+jTGtscQoDlIMgOydC8F+dBeolvMXEyN002pYj8K9yxQcHCz2F62A2na
+ZA+Vj6xTq2/YGhBBrJ21eaEOcKBc9rrP0s2lzhzVb/fbPq0hkgWqQuJKsHaq2y9O
+fYUBfbB3LwKBgEexPgwmzPXT8ci28eS+LeORngeJuHrhZvc26qXs6Pku5Qo1NIxM
+SwFJDmQu/mXUNZlIgBhr3qnw5I7qhZCsRCj+Mx0ONNV5/7ToBdwUurL9WkniMqks
+QAtwn3fsleq4CmfIP8+Kxz4fXph9t87dL6USEK8bjLIw1xtxP8eR+jG3AoGAcuM4
+ZLcbqbSCW/fhYWGgOanMYurX7S4g5c4h/IQRH5FT8KV1tOqgqG+F4VK/lzdCy4fF
+yTZkzC4zR6FXZstOvwva0R0Kf82PFaEFSOQibGiRBIK0BzJSDqT2IQ+fuJtDlw8X
+eF4oUyvEgjvl10x6a8emeviCQthwhnA4D0yA6/8CgYEA14WLsOllb6IjO3c+mwFp
+Gs8pDrB/XPH7bPH1fVO+60OMT5OMTlEa/cVlhbNWuHVR7+yVQCh7HuzVPBtSdyNW
+4+8UuAz3eLm93he6DiH7D4U7Zx2TKB2B6PBbHz9aEh96l67TfAHy+u3x0mVFziZ7
+HNe49uMd7A5r4QgflshgDgs=
+-----END PRIVATE KEY-----
diff --git a/csit/plans/cps/sdnc/certs/keys0.zip b/csit/plans/cps/sdnc/certs/keys0.zip
index 48b4d90a10..b2dec5c7b2 100644
--- a/csit/plans/cps/sdnc/certs/keys0.zip
+++ b/csit/plans/cps/sdnc/certs/keys0.zip
Binary files differ
diff --git a/csit/plans/cps/setup.sh b/csit/plans/cps/setup.sh
index 80829eba14..036f14b82f 100755
--- a/csit/plans/cps/setup.sh
+++ b/csit/plans/cps/setup.sh
@@ -1,7 +1,6 @@
#!/bin/bash
#
# Copyright 2016-2017 Huawei Technologies Co., Ltd.
-# Modifications Copyright (C) 2022 Nordix Foundation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,7 +18,7 @@
# Modifications copyright (c) 2020-2021 Samsung Electronics Co., Ltd.
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2021 Bell Canada.
-# Modifications Copyright (C) 2021 Nordix Foundation.
+# Modifications Copyright (C) 2021-2024 Nordix Foundation.
#
# Branched from ccsdk/distribution to this repository Feb 23, 2021
#
@@ -59,10 +58,6 @@ export $(cut -d= -f1 $WORKSPACE/plans/cps/test.properties)
###################### setup cps-ncmp ############################
cd $CPS_HOME/docker-compose
-curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > docker-compose
-chmod +x docker-compose
-docker-compose version
-
# start CPS/NCMP, DMI Plugin, and PostgreSQL containers with docker compose
docker-compose --profile dmi-service up -d
@@ -82,4 +77,4 @@ check_health $DMI_HOST:$DMI_PORT 'dmi-plugin'
###################### ROBOT Configurations ##########################
# Pass variables required for Robot test suites in ROBOT_VARIABLES
-ROBOT_VARIABLES="-v CPS_CORE_HOST:$CPS_CORE_HOST -v CPS_CORE_PORT:$CPS_CORE_PORT -v DMI_HOST:$LOCAL_IP -v DMI_PORT:$DMI_PORT -v DMI_CSIT_STUB_HOST:$LOCAL_IP -v DMI_CSIT_STUB_PORT:$DMI_DEMO_STUB_PORT -v DMI_AUTH_ENABLED:$DMI_AUTH_ENABLED -v DATADIR_CPS_CORE:$WORKSPACE/data/cps-core -v DATADIR_NCMP:$WORKSPACE/data/ncmp -v DATADIR_SUBS_NOTIFICATION:$WORKSPACE/data/subscription-notification --exitonfailure" \ No newline at end of file
+ROBOT_VARIABLES="-v CPS_CORE_HOST:$CPS_CORE_HOST -v CPS_CORE_PORT:$CPS_CORE_PORT -v DMI_HOST:$LOCAL_IP -v DMI_PORT:$DMI_PORT -v DMI_CSIT_STUB_HOST:$LOCAL_IP -v DMI_CSIT_STUB_PORT:$DMI_DEMO_STUB_PORT -v DMI_AUTH_ENABLED:$DMI_AUTH_ENABLED -v DATADIR_CPS_CORE:$WORKSPACE/data/cps-core -v DATADIR_NCMP:$WORKSPACE/data/ncmp -v DATADIR_SUBS_NOTIFICATION:$WORKSPACE/data/subscription-notification --exitonfailure"
diff --git a/csit/plans/cps/teardown.sh b/csit/plans/cps/teardown.sh
index 7beb90722e..e2ecd885be 100755
--- a/csit/plans/cps/teardown.sh
+++ b/csit/plans/cps/teardown.sh
@@ -17,18 +17,24 @@
# Modifications copyright (c) 2017 AT&T Intellectual Property
# Modifications copyright (c) 2020 Samsung Electronics Co., Ltd.
# Modifications Copyright (C) 2021 Pantheon.tech
-# Modifications Copyright (C) 2021 Nordix Foundation
+# Modifications Copyright (C) 2021-2024 Nordix Foundation
# Branched from ccsdk/distribution to this repository Feb 23, 2021
#
echo '================================== docker info =========================='
docker ps -a
echo '================================== CPS-NCMP Logs ========================'
-docker logs cps-and-ncmp
+for CONTAINER_ID in $(docker ps --filter "name=cps-and-ncmp" --format "{{.ID}}"); do
+ echo "CPS-NCMP Logs for container: $CONTAINER_ID"
+ docker logs "$CONTAINER_ID"
+done
echo '================================== DMI Logs ============================='
docker logs ncmp-dmi-plugin
+echo '================================== DMI Stub Logs ========================'
+docker logs ncmp-dmi-plugin-demo-and-csit-stub
+
echo '================================== SDNC Logs ============================'
docker logs sdnc
diff --git a/csit/plans/cps/test.properties b/csit/plans/cps/test.properties
index 15485b7e28..396bdd3009 100644
--- a/csit/plans/cps/test.properties
+++ b/csit/plans/cps/test.properties
@@ -21,7 +21,7 @@ DMI_SERVICE_URL=http://$LOCAL_IP:$DMI_PORT
DOCKER_REPO=nexus3.onap.org:10003
CPS_VERSION=latest
-DMI_VERSION=1.5.0-SNAPSHOT-latest
+DMI_VERSION=1.6.0-SNAPSHOT-latest
ADVISED_MODULES_SYNC_SLEEP_TIME_MS=2000
CMHANDLE_DATA_SYNC_SLEEP_TIME_MS=2000
diff --git a/csit/plans/cps/testplanNcmp.txt b/csit/plans/cps/testplanNcmp.txt
index e80f0d98a0..24c7745c71 100644
--- a/csit/plans/cps/testplanNcmp.txt
+++ b/csit/plans/cps/testplanNcmp.txt
@@ -21,4 +21,4 @@ cps-data-sync
ncmp-passthrough
cm-handle-query
cps-trust-level
-cps-data-operations \ No newline at end of file
+cps-data-operations
diff --git a/csit/prepare-csit.sh b/csit/prepare-csit.sh
index fbd5dc5f0d..1b8578e0ce 100755
--- a/csit/prepare-csit.sh
+++ b/csit/prepare-csit.sh
@@ -71,7 +71,7 @@ echo "Versioning information:"
python3 --version
echo "Installing confluent kafka library for robot framework:"
-pip install robotframework-confluentkafkalibrary
+pip install robotframework-confluentkafkalibrary==2.4.0-2
pip freeze
python3 -m robot.run --version || : \ No newline at end of file
diff --git a/csit/pylibs.txt b/csit/pylibs.txt
index 32bfa6faca..3eeb1ab9ec 100644
--- a/csit/pylibs.txt
+++ b/csit/pylibs.txt
@@ -9,7 +9,7 @@ robotframework-requests==0.9.3
robotframework-selenium2library==3.0.0
robotframework-extendedselenium2library
robotframework-sshlibrary
-robotframework-confluentkafkalibrary
+robotframework-confluentkafkalibrary==2.4.0-2
scapy
# Module jsonpath is needed by current AAA idmlite suite.
jsonpath-rw
diff --git a/csit/run-csit.sh b/csit/run-csit.sh
index 0981fc6edd..93941e2163 100755
--- a/csit/run-csit.sh
+++ b/csit/run-csit.sh
@@ -2,6 +2,7 @@
#
# Copyright 2016-2017 Huawei Technologies Co., Ltd.
# Modification Copyright 2019-2021 © Samsung Electronics Co., Ltd.
+# Modification 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.
diff --git a/csit/run-project-csit.sh b/csit/run-project-csit.sh
index fcb3c925c1..f362cc7130 100755
--- a/csit/run-project-csit.sh
+++ b/csit/run-project-csit.sh
@@ -2,6 +2,7 @@
#
# Copyright 2020-2021 © Samsung Electronics Co., Ltd.
# Modifications Copyright (C) 2021 Pantheon.tech
+# Modifications 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.
@@ -28,6 +29,8 @@ rm -rf ${WORKSPACE}/archives
mkdir -p ${WORKSPACE}/archives
cd ${WORKSPACE}
+source install-deps.sh
+
# Execute all test-suites defined under plans subdirectory
for dir in plans/*/
do
diff --git a/csit/tests/cps-data-operations/cps-data-operations.robot b/csit/tests/cps-data-operations/cps-data-operations.robot
index 17dce16446..96212ff632 100644
--- a/csit/tests/cps-data-operations/cps-data-operations.robot
+++ b/csit/tests/cps-data-operations/cps-data-operations.robot
@@ -26,6 +26,7 @@ Library OperatingSystem
Library RequestsLibrary
Library BuiltIn
Library ConfluentKafkaLibrary
+Library String
Suite Setup Create Session CPS_URL http://${CPS_CORE_HOST}:${CPS_CORE_PORT}
@@ -48,7 +49,7 @@ NCMP Data Operation, forwarded to DMI, response on Client Topic
POST On Session CPS_URL ncmpInventory/v1/ch headers=${headers} data=${newCmHandleRequestBody}
${getCmHandleUri}= Set Variable ${ncmpBasePath}/v1/ch/CMHandle1
${getCmHandleHeaders}= Create Dictionary Authorization=${auth}
- Wait Until Keyword Succeeds 8sec 100ms Is CM Handle READY ${getCmHandleUri} ${getCmHandleHeaders} CMHandle1
+ Wait Until Keyword Succeeds 20sec 200ms Is CM Handle READY ${getCmHandleUri} ${getCmHandleHeaders} CMHandle1
${response}= POST On Session CPS_URL ${uri} params=${params} headers=${headers} data=${dataOperationReqBody}
Set Global Variable ${expectedRequestId} ${response.json()}[requestId]
Should Be Equal As Strings ${response.status_code} 200
@@ -63,7 +64,7 @@ Consume cloud event from client topic
Compare Header Values ${header_key_value_pair[0]} ${header_key_value_pair[1]} "ce_specversion" "1.0"
Compare Header Values ${header_key_value_pair[0]} ${header_key_value_pair[1]} "ce_type" "org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent"
Compare Header Values ${header_key_value_pair[0]} ${header_key_value_pair[1]} "ce_correlationid" "${expectedRequestId}"
- Compare Header Values ${header_key_value_pair[0]} ${header_key_value_pair[1]} "ce_source" "DMI"
+ Compare Header Values ${header_key_value_pair[0]} ${header_key_value_pair[1]} "ce_source" "DMI"
END
[Teardown] Basic Teardown ${group_id}
@@ -78,12 +79,20 @@ Is CM Handle READY
[Arguments] ${uri} ${headers} ${cmHandle}
${response}= GET On Session CPS_URL ${uri} headers=${headers}
Should Be Equal As Strings ${response.status_code} 200
+ ${number_of_items}= Count Items In JSON Response ${response}
+ Should Be True ${number_of_items} > 0
FOR ${item} IN ${response.json()}
IF "${item['cmHandle']}" == "${cmHandle}"
Should Be Equal As Strings ${item['state']['cmHandleState']} READY
END
END
+Count Items In JSON Response
+ [Arguments] ${response}
+ ${json_data}= Evaluate json.loads('${response.content.decode("utf-8")}') json
+ ${number_of_items}= Get Length ${json_data}
+ RETURN ${number_of_items}
+
Basic Teardown
[Arguments] ${group_id}
Unsubscribe ${group_id}
diff --git a/csit/tests/cps-data-sync/cps-data-sync.robot b/csit/tests/cps-data-sync/cps-data-sync.robot
index c0ee4da67b..b8ba479e7c 100644
--- a/csit/tests/cps-data-sync/cps-data-sync.robot
+++ b/csit/tests/cps-data-sync/cps-data-sync.robot
@@ -35,11 +35,6 @@ ${ncmpBasePath} /ncmp
*** Test Cases ***
-Check if ietfYang-PNFDemo is READY
- ${uri}= Set Variable ${ncmpBasePath}/v1/ch/ietfYang-PNFDemo
- ${headers}= Create Dictionary Authorization=${auth}
- Wait Until Keyword Succeeds 10sec 100ms Is CM Handle READY ${uri} ${headers} ietfYang-PNFDemo
-
Operational state goes to UNSYNCHRONIZED when data sync (flag) is enabled
${uri}= Set Variable ${ncmpBasePath}/v1/ch/ietfYang-PNFDemo/data-sync
${params}= Create Dictionary dataSyncEnabled=true
@@ -54,18 +49,9 @@ Operational state goes to UNSYNCHRONIZED when data sync (flag) is enabled
Operational state goes to SYNCHRONIZED after sometime when data sync (flag) is enabled
${uri}= Set Variable ${ncmpBasePath}/v1/ch/ietfYang-PNFDemo/state
${headers}= Create Dictionary Authorization=${auth}
- Wait Until Keyword Succeeds 10sec 100ms Is CM Handle State SYNCHRONIZED ${uri} ${headers}
+ Wait Until Keyword Succeeds 40sec 100ms Is CM Handle State SYNCHRONIZED ${uri} ${headers}
*** Keywords ***
-Is CM Handle READY
- [Arguments] ${uri} ${headers} ${cmHandle}
- ${response}= GET On Session CPS_URL ${uri} headers=${headers}
- Should Be Equal As Strings ${response.status_code} 200
- FOR ${item} IN ${response.json()}
- IF "${item['cmHandle']}" == "${cmHandle}"
- Should Be Equal As Strings ${item['state']['cmHandleState']} READY
- END
- END
Is CM Handle State SYNCHRONIZED
[Arguments] ${uri} ${headers}
diff --git a/csit/tests/cps-model-sync/cps-model-sync.robot b/csit/tests/cps-model-sync/cps-model-sync.robot
index bb881f6a67..514076f085 100644
--- a/csit/tests/cps-model-sync/cps-model-sync.robot
+++ b/csit/tests/cps-model-sync/cps-model-sync.robot
@@ -25,6 +25,7 @@ Library Collections
Library OperatingSystem
Library RequestsLibrary
Library BuiltIn
+Library String
Suite Setup Create Session CPS_URL http://${CPS_CORE_HOST}:${CPS_CORE_PORT}
@@ -88,13 +89,40 @@ Get cm handle details and confirm it has been deleted
${headers}= Create Dictionary Authorization=${auth}
${response}= GET On Session CPS_URL ${uri} headers=${headers} expected_status=404
+Check if ietfYang-PNFDemo is READY
+ ${uri}= Set Variable ${ncmpBasePath}/v1/ch/ietfYang-PNFDemo
+ ${headers}= Create Dictionary Authorization=${auth}
+ Wait Until Keyword Succeeds 20sec 200ms Is CM Handle READY ${uri} ${headers} ietfYang-PNFDemo
+
Get modules for registered data node
${uri}= Set Variable ${ncmpBasePath}/v1/ch/ietfYang-PNFDemo/modules
${headers}= Create Dictionary Authorization=${auth}
${response}= GET On Session CPS_URL ${uri} headers=${headers}
Should Be Equal As Strings ${response.status_code} 200
+ ${number_of_items}= Count Items In JSON Response ${response}
+ Should Be True ${number_of_items} > 0
FOR ${item} IN @{response.json()}
IF "${item['moduleName']}" == "stores"
Should Be Equal As Strings "${item['revision']}" "2020-09-15"
END
- END \ No newline at end of file
+ END
+
+*** Keywords ***
+
+Is CM Handle READY
+ [Arguments] ${uri} ${headers} ${cmHandle}
+ ${response}= GET On Session CPS_URL ${uri} headers=${headers}
+ Should Be Equal As Strings ${response.status_code} 200
+ ${number_of_items}= Count Items In JSON Response ${response}
+ Should Be True ${number_of_items} > 0
+ FOR ${item} IN ${response.json()}
+ IF "${item['cmHandle']}" == "${cmHandle}"
+ Should Be Equal As Strings ${item['state']['cmHandleState']} READY
+ END
+ END
+
+Count Items In JSON Response
+ [Arguments] ${response}
+ ${json_data}= Evaluate json.loads('${response.content.decode("utf-8")}') json
+ ${number_of_items}= Get Length ${json_data}
+ RETURN ${number_of_items} \ No newline at end of file
diff --git a/csit/tests/cps-trust-level/cps-trust-level.robot b/csit/tests/cps-trust-level/cps-trust-level.robot
index e4deeff32b..810bcf4d12 100644
--- a/csit/tests/cps-trust-level/cps-trust-level.robot
+++ b/csit/tests/cps-trust-level/cps-trust-level.robot
@@ -36,7 +36,7 @@ ${ncmpBasePath} /ncmp/v1
${dmiUrl} http://${DMI_HOST}:${DMI_PORT}
${jsonCreateCmHandles} {"dmiPlugin":"${dmiUrl}","dmiDataPlugin":"","dmiModelPlugin":"","createdCmHandles":[{"trustLevel":"COMPLETE","cmHandle":"CH-1"},{"trustLevel":"COMPLETE","cmHandle":"CH-2"},{"cmHandle":"CH-3"},{"trustLevel":"NONE","cmHandle":"CH-4"}]}
${jsonTrustLevelPropertyQueryParameters} {"cmHandleQueryParameters": [{"conditionName": "cmHandleWithTrustLevel", "conditionParameters": [ {"trustLevel": "COMPLETE"} ] }]}
-${jsonTrustLevelQueryResponse} {"data":{"attributeValueChange":[{"attributeName":"trustLevel","newAttributeValue":"NONE"}]}}
+${jsonTrustLevelEventPayload} {"data":{"attributeValueChange":[{"attributeName":"trustLevel","newAttributeValue":"NONE"}]}}
*** Test Cases ***
Register data node
@@ -57,7 +57,7 @@ Verify notification
Compare Header Values ${header_key_value_pair[0]} ${header_key_value_pair[1]} "ce_type" "org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent"
Compare Header Values ${header_key_value_pair[0]} ${header_key_value_pair[1]} "ce_correlationid" "CH-4"
END
- Should Be Equal As Strings ${payload} ${jsonTrustLevelQueryResponse}
+ Should Be Equal As Strings ${payload} ${jsonTrustLevelEventPayload}
[Teardown] Basic Teardown ${group_id}
Retrieve CM Handle ids where query parameters Match (trust level query)
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml
deleted file mode 100644
index e62c01d6ca..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ============LICENSE_START=======================================================
- 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.
- 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=========================================================
--->
-
-<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.onap.cps</groupId>
- <artifactId>dmi-plugin-demo-and-csit-stub</artifactId>
- <version>3.5.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>dmi-plugin-demo-and-csit-stub-app</artifactId>
-
- <properties>
- <app>org.onap.cps.ncmp.dmi.rest.stub.DmiDemoApplication</app>
- <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
- <base.image>${docker.pull.registry}/onap/integration-java17:12.0.0</base.image>
- <image.tag>${project.version}-${maven.build.timestamp}</image.tag>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
-
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>com.google.cloud.tools</groupId>
- <artifactId>jib-maven-plugin</artifactId>
- <configuration>
- <container>
- <mainClass>${app}</mainClass>
- <creationTime>USE_CURRENT_TIMESTAMP</creationTime>
- </container>
- <from>
- <image>${base.image}</image>
- </from>
- <to>
- <tags>
- <tag>latest</tag>
- </tags>
- <image>${docker.push.registry}/onap/${image.name}:${image.tag}</image>
- </to>
- </configuration>
- <executions>
- <execution>
- <phase>package</phase>
- <id>build</id>
- <goals>
- <goal>dockerBuild</goal>
- </goals>
- </execution>
- <execution>
- <phase>deploy</phase>
- <id>buildAndPush</id>
- <goals>
- <goal>build</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
-
- <profiles>
- <profile>
- <id>docker</id>
- <activation>
- <activeByDefault>true</activeByDefault>
- </activation>
- <properties>
- <image.name>dmi-plugin-demo-and-csit-stub</image.name>
- </properties>
- <build>
- <plugins>
- <plugin>
- <groupId>com.google.cloud.tools</groupId>
- <artifactId>jib-maven-plugin</artifactId>
- <version>3.3.2</version>
- </plugin>
- </plugins>
- </build>
- </profile>
- </profiles>
- <dependencies>
- <dependency>
- <groupId>org.onap.cps</groupId>
- <artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId>
- <version>${project.version}</version>
- <exclusions>
- <exclusion>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
-</project> \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml
deleted file mode 100644
index c0b4eadb1e..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<!--
- ============LICENSE_START=======================================================
- 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.
- 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=========================================================
--->
-
-<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.onap.cps</groupId>
- <artifactId>dmi-plugin-demo-and-csit-stub</artifactId>
- <version>3.5.0-SNAPSHOT</version>
- </parent>
- <artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-tomcat</artifactId>
- </exclusion>
- </exclusions>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>com.googlecode.json-simple</groupId>
- <artifactId>json-simple</artifactId>
- <version>1.1.1</version>
- <exclusions>
- <exclusion>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <dependency>
- <groupId>org.onap.cps</groupId>
- <artifactId>cps-ncmp-rest</artifactId>
- </dependency>
- </dependencies>
-</project>
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java
deleted file mode 100644
index a596afdce2..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * 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.
- * 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.rest.stub.controller;
-
-import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESS;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import io.cloudevents.CloudEvent;
-import io.cloudevents.core.builder.CloudEventBuilder;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.json.simple.parser.JSONParser;
-import org.json.simple.parser.ParseException;
-import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter;
-import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.DataOperationRequest;
-import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.DmiDataOperationRequest;
-import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.DmiOperationCmHandle;
-import org.onap.cps.ncmp.dmi.rest.stub.utils.ResourceFileReaderUtil;
-import org.onap.cps.ncmp.events.async1_0_0.Data;
-import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent;
-import org.onap.cps.ncmp.events.async1_0_0.Response;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.kafka.core.KafkaTemplate;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestHeader;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping("${rest.api.dmi-stub-base-path}")
-@RequiredArgsConstructor
-@Slf4j
-public class DmiRestStubController {
-
- private static final String DEFAULT_TAG = "tagD";
- private static final String dataOperationEventType = "org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent";
- private static final Map<String, String> moduleSetTagPerCmHandleId = new HashMap<>();
- private final KafkaTemplate<String, CloudEvent> cloudEventKafkaTemplate;
- private final ObjectMapper objectMapper;
- private final ApplicationContext applicationContext;
- @Value("${app.ncmp.async-m2m.topic}")
- private String ncmpAsyncM2mTopic;
- @Value("${delay.module-references-delay-ms}")
- private long moduleReferencesDelayMs;
- @Value("${delay.module-resources-delay-ms}")
- private long moduleResourcesDelayMs;
- @Value("${delay.data-for-cm-handle-delay-ms}")
- private long dataForCmHandleDelayMs;
-
- /**
- * This code defines a REST API endpoint for adding new the module set tag mapping. The endpoint receives the
- * cmHandleId and moduleSetTag as request body and add into moduleSetTagPerCmHandleId map with the provided
- * values.
- *
- * @param requestBody map of cmHandleId and moduleSetTag
- * @return a ResponseEntity object containing the updated moduleSetTagPerCmHandleId map as the response body
- */
- @PostMapping("/v1/tagMapping")
- public ResponseEntity<Map<String, String>> addTagForMapping(@RequestBody final Map<String, String> requestBody) {
- moduleSetTagPerCmHandleId.putAll(requestBody);
- return new ResponseEntity<>(requestBody, HttpStatus.CREATED);
- }
-
- /**
- * This code defines a GET endpoint of module set tag mapping.
- *
- * @return The map represents the module set tag mapping.
- */
- @GetMapping("/v1/tagMapping")
- public ResponseEntity<Map<String, String>> getTagMapping() {
- return ResponseEntity.ok(moduleSetTagPerCmHandleId);
- }
-
- /**
- * This code defines a GET endpoint of module set tag by cm handle ID.
- *
- * @return The map represents the module set tag mapping filtered by cm handle ID.
- */
- @GetMapping("/v1/tagMapping/ch/{cmHandleId}")
- public ResponseEntity<String> getTagMappingByCmHandleId(@PathVariable final String cmHandleId) {
- return ResponseEntity.ok(moduleSetTagPerCmHandleId.get(cmHandleId));
- }
-
- /**
- * This code defines a REST API endpoint for updating the module set tag mapping. The endpoint receives the
- * cmHandleId and moduleSetTag as request body and updates the moduleSetTagPerCmHandleId map with the provided
- * values.
- *
- * @param requestBody map of cmHandleId and moduleSetTag
- * @return a ResponseEntity object containing the updated moduleSetTagPerCmHandleId map as the response body
- */
-
- @PutMapping("/v1/tagMapping")
- public ResponseEntity<Map<String, String>> updateTagMapping(@RequestBody final Map<String, String> requestBody) {
- moduleSetTagPerCmHandleId.putAll(requestBody);
- return ResponseEntity.noContent().build();
- }
-
- /**
- * It contains a method to delete an entry from the moduleSetTagPerCmHandleId map.
- * The method takes a cmHandleId as a parameter and removes the corresponding entry from the map.
- *
- * @return a ResponseEntity containing the updated map.
- */
- @DeleteMapping("/v1/tagMapping/ch/{cmHandleId}")
- public ResponseEntity<String> deleteTagMappingByCmHandleId(@PathVariable final String cmHandleId) {
- moduleSetTagPerCmHandleId.remove(cmHandleId);
- return ResponseEntity.ok(String.format("Mapping of %s is deleted successfully", cmHandleId));
- }
-
- /**
- * Get all modules for given cm handle.
- *
- * @param cmHandleId The identifier for a network function, network element, subnetwork,
- * or any other cm object by managed Network CM Proxy
- * @param moduleReferencesRequest module references request body
- * @return ResponseEntity response entity having module response as json string.
- */
- @PostMapping("/v1/ch/{cmHandleId}/modules")
- public ResponseEntity<String> getModuleReferences(@PathVariable("cmHandleId") final String cmHandleId,
- @RequestBody final Object moduleReferencesRequest) {
- delay(moduleReferencesDelayMs);
- try {
- log.info("Incoming DMI request body: {}",
- objectMapper.writeValueAsString(moduleReferencesRequest));
- } catch (final JsonProcessingException jsonProcessingException) {
- log.info("Unable to parse dmi data operation request to json string");
- }
- final String moduleResponseContent = getModuleResourceResponse(cmHandleId,
- "ModuleResponse.json");
- log.info("cm handle: {} requested for modules", cmHandleId);
- return ResponseEntity.ok(moduleResponseContent);
- }
-
- /**
- * Retrieves module resources for a given cmHandleId.
- *
- * @param cmHandleId The identifier for a network function, network element, subnetwork,
- * or any other cm object by managed Network CM Proxy
- * @param moduleResourcesReadRequest module resources read request body
- * @return ResponseEntity response entity having module resources response as json string.
- */
- @PostMapping("/v1/ch/{cmHandleId}/moduleResources")
- public ResponseEntity<String> retrieveModuleResources(
- @PathVariable("cmHandleId") final String cmHandleId,
- @RequestBody final Object moduleResourcesReadRequest) {
- delay(moduleResourcesDelayMs);
- final String moduleResourcesResponseContent = getModuleResourceResponse(cmHandleId,
- "ModuleResourcesResponse.json");
- log.info("cm handle: {} requested for modules resources", cmHandleId);
- return ResponseEntity.ok(moduleResourcesResponseContent);
- }
-
- /**
- * Create resource data from passthrough operational or running for a cm handle.
- *
- * @param cmHandleId The identifier for a network function, network element, subnetwork,
- * or any other cm object by managed Network CM Proxy
- * @param datastoreName datastore name
- * @param resourceIdentifier resource identifier
- * @param options options
- * @param topic client given topic name
- * @return (@ code ResponseEntity) response entity
- */
- @PostMapping("/v1/ch/{cmHandleId}/data/ds/{datastoreName}")
- public ResponseEntity<String> getResourceDataForCmHandle(
- @PathVariable("cmHandleId") final String cmHandleId,
- @PathVariable("datastoreName") final String datastoreName,
- @RequestParam(value = "resourceIdentifier") final String resourceIdentifier,
- @RequestParam(value = "options", required = false) final String options,
- @RequestParam(value = "topic", required = false) final String topic,
- @RequestParam(value = "moduleSetTag", required = false) final String moduleSetTag,
- @RequestHeader(value = "Authorization", required = false) final String authorization) {
- log.info("DMI AUTH HEADER: {}", authorization);
- delay(dataForCmHandleDelayMs);
- log.info("Module set tag received: {}", moduleSetTag);
-
- final String sampleJson = ResourceFileReaderUtil.getResourceFileContent(applicationContext.getResource(
- ResourceLoader.CLASSPATH_URL_PREFIX + "data/operational/ietf-network-topology-sample-rfc8345.json"));
- return ResponseEntity.ok(sampleJson);
- }
-
- /**
- * This method is not implemented for ONAP DMI plugin.
- *
- * @param topic client given topic name
- * @param requestId requestId generated by NCMP as an ack for client
- * @param dmiDataOperationRequest list of operation details
- * @return (@ code ResponseEntity) response entity
- */
- @PostMapping("/v1/data")
- public ResponseEntity<Void> getResourceDataForCmHandleDataOperation(
- @RequestParam(value = "topic") final String topic,
- @RequestParam(value = "requestId") final String requestId,
- @RequestBody final DmiDataOperationRequest dmiDataOperationRequest) {
- delay(dataForCmHandleDelayMs);
- try {
- log.info("Request received from the NCMP to DMI Plugin: {}",
- objectMapper.writeValueAsString(dmiDataOperationRequest));
- } catch (final JsonProcessingException jsonProcessingException) {
- log.info("Unable to process dmi data operation request to json string");
- }
- dmiDataOperationRequest.getOperations().forEach(dmiDataOperation -> {
- final DataOperationEvent dataOperationEvent = getDataOperationEvent(dmiDataOperation);
- dmiDataOperation.getCmHandles().forEach(dmiOperationCmHandle -> {
- log.info("Module Set Tag received: {}", dmiOperationCmHandle.getModuleSetTag());
- dataOperationEvent.getData().getResponses().get(0).setIds(List.of(dmiOperationCmHandle.getId()));
- final CloudEvent cloudEvent = buildAndGetCloudEvent(topic, requestId, dataOperationEvent);
- cloudEventKafkaTemplate.send(ncmpAsyncM2mTopic, UUID.randomUUID().toString(), cloudEvent);
- });
- });
- return new ResponseEntity<>(HttpStatus.ACCEPTED);
- }
-
- private CloudEvent buildAndGetCloudEvent(final String topic, final String requestId,
- final DataOperationEvent dataOperationEvent) {
- CloudEvent cloudEvent = null;
- try {
- cloudEvent = CloudEventBuilder.v1()
- .withId(UUID.randomUUID().toString())
- .withSource(URI.create("DMI"))
- .withType(dataOperationEventType)
- .withDataSchema(URI.create("urn:cps:" + dataOperationEventType + ":1.0.0"))
- .withTime(EventDateTimeFormatter.toIsoOffsetDateTime(
- EventDateTimeFormatter.getCurrentIsoFormattedDateTime()))
- .withData(objectMapper.writeValueAsBytes(dataOperationEvent))
- .withExtension("destination", topic)
- .withExtension("correlationid", requestId)
- .build();
- } catch (final JsonProcessingException jsonProcessingException) {
- log.error("Unable to parse event into bytes. cause : {}", jsonProcessingException.getMessage());
- }
- return cloudEvent;
- }
-
- private DataOperationEvent getDataOperationEvent(final DataOperationRequest dataOperationRequest) {
- final Response response = new Response();
-
- response.setOperationId(dataOperationRequest.getOperationId());
- response.setStatusCode(SUCCESS.getCode());
- response.setStatusMessage(SUCCESS.getMessage());
- response.setIds(dataOperationRequest.getCmHandles().stream().map(DmiOperationCmHandle::getId).toList());
- response.setResourceIdentifier(dataOperationRequest.getResourceIdentifier());
- response.setOptions(dataOperationRequest.getOptions());
- final String ietfNetworkTopologySample = ResourceFileReaderUtil
- .getResourceFileContent(applicationContext.getResource(
- ResourceLoader.CLASSPATH_URL_PREFIX
- + "data/operational/ietf-network-topology-sample-rfc8345.json"));
- final JSONParser jsonParser = new JSONParser();
- try {
- response.setResult(jsonParser.parse(ietfNetworkTopologySample));
- } catch (final ParseException parseException) {
- log.error("Unable to parse event result as json object. cause : {}", parseException.getMessage());
- }
- final List<Response> responseList = new ArrayList<>(1);
- responseList.add(response);
- final Data data = new Data();
- data.setResponses(responseList);
- final DataOperationEvent dataOperationEvent = new DataOperationEvent();
- dataOperationEvent.setData(data);
- return dataOperationEvent;
- }
-
- private String getModuleResourceResponse(final String cmHandleId, final String moduleResponseType) {
- if (moduleSetTagPerCmHandleId.isEmpty()) {
- log.info("Using default module responses of type ietfYang");
- return ResourceFileReaderUtil.getResourceFileContent(applicationContext.getResource(
- ResourceLoader.CLASSPATH_URL_PREFIX
- + String.format("module/ietfYang-%s", moduleResponseType)));
- }
- final String moduleSetTag = moduleSetTagPerCmHandleId.getOrDefault(cmHandleId, DEFAULT_TAG);
- final String moduleResponseFilePath = String.format("module/%s-%s", moduleSetTag, moduleResponseType);
- final Resource moduleResponseResource = applicationContext.getResource(
- ResourceLoader.CLASSPATH_URL_PREFIX + moduleResponseFilePath);
- log.info("Using module responses from : {}", moduleResponseFilePath);
- return ResourceFileReaderUtil.getResourceFileContent(moduleResponseResource);
- }
-
- private void delay(final long milliseconds) {
- try {
- Thread.sleep(milliseconds);
- } catch (final InterruptedException e) {
- log.error("Thread sleep interrupted: {}", e.getMessage());
- Thread.currentThread().interrupt();
- }
- }
-}
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DataOperationRequest.java b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DataOperationRequest.java
deleted file mode 100644
index 410774932b..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DataOperationRequest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * ============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.rest.stub.model.data.operational;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import java.util.ArrayList;
-import java.util.List;
-import lombok.Getter;
-import lombok.Setter;
-
-@JsonInclude(JsonInclude.Include.NON_NULL)
-@Setter
-@Getter
-public class DataOperationRequest {
- private String operation;
- private String operationId;
- private String datastore;
- private String options;
- private String resourceIdentifier;
- private List<DmiOperationCmHandle> cmHandles = new ArrayList<>();
-}
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/utils/ResourceFileReaderUtil.java b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/utils/ResourceFileReaderUtil.java
deleted file mode 100644
index 0d2adee43e..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/utils/ResourceFileReaderUtil.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * ============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.rest.stub.utils;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.core.io.Resource;
-import org.springframework.util.StreamUtils;
-
-/**
- * Common convenience methods for reading resource file content.
- */
-@Slf4j
-public class ResourceFileReaderUtil {
-
- /**
- * Converts a resource file content into string.
- *
- * @param fileClasspath to name of the file in test/resources
- * @return the content of the file as a String
- * @throws IOException when there is an IO issue
- */
- public static String getResourceFileContent(final Resource fileClasspath) {
- String fileContent = null;
- try {
- fileContent = StreamUtils.copyToString(fileClasspath.getInputStream(), StandardCharsets.UTF_8);
- } catch (final IOException ioException) {
- log.debug("unable to read resource file content. cause : {}", ioException.getMessage());
- }
- return fileContent;
- }
-}
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml
deleted file mode 100644
index b78a5b2db5..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/application.yml
+++ /dev/null
@@ -1,64 +0,0 @@
-# ============LICENSE_START=======================================================
-# 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.
-# 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=========================================================
-server:
- port: 8092
- jetty:
- threads:
- max: 25
-
-rest:
- api:
- dmi-stub-base-path: /dmi
-
-spring:
- main:
- banner-mode: "off"
- application:
- name: "dmi-plugin-demo-and-csit-stub"
-
- kafka:
- bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVER:localhost:19092}
- security:
- protocol: PLAINTEXT
- producer:
- value-serializer: io.cloudevents.kafka.CloudEventSerializer
- client-id: cps-core
-
-management:
- endpoints:
- web:
- exposure:
- include: health
-
-app:
- ncmp:
- async-m2m:
- topic: ${NCMP_ASYNC_M2M_TOPIC:ncmp-async-m2m}
-
-delay:
- module-references-delay-ms: ${MODULE_REFERENCES_DELAY_MS:100}
- module-resources-delay-ms: ${MODULE_RESOURCES_DELAY_MS:1000}
- data-for-cm-handle-delay-ms: ${DATA_FOR_CM_HANDLE_DELAY_MS:2500}
-
-logging:
- level:
- org:
- springframework:
- web:
- filter:
- CommonsRequestLoggingFilter: DEBUG \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/data/operational/ietf-network-topology-sample-rfc8345.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/data/operational/ietf-network-topology-sample-rfc8345.json
deleted file mode 100644
index 8f9dbc2259..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/data/operational/ietf-network-topology-sample-rfc8345.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "ietf-network:networks": {
- "network": [
- {
- "network-types": {
- },
- "network-id": "otn-hc",
- "node": [
- {
- "node-id": "D1",
- "termination-point": [
- {
- "tp-id": "1-0-1"
- },
- {
- "tp-id": "1-2-1"
- },
- {
- "tp-id": "1-3-1"
- }
- ]
- },
- {
- "node-id": "D2",
- "termination-point": [
- {
- "tp-id": "2-0-1"
- },
- {
- "tp-id": "2-1-1"
- },
- {
- "tp-id": "2-3-1"
- }
- ]
- },
- {
- "node-id": "D3",
- "termination-point": [
- {
- "tp-id": "3-1-1"
- },
- {
- "tp-id": "3-2-1"
- }
- ]
- }
- ],
- "ietf-network-topology:link": [
- {
- "link-id": "D1,1-2-1,D2,2-1-1",
- "source": {
- "source-node": "D1",
- "source-tp": "1-2-1"
- },
- "destination": {
- "dest-node": "D2",
- "dest-tp": "2-1-1"
- }
- },
- {
- "link-id": "D2,2-1-1,D1,1-2-1",
- "source": {
- "source-node": "D2",
- "source-tp": "2-1-1"
- },
- "destination": {
- "dest-node": "D1",
- "dest-tp": "1-2-1"
- }
- }
- ]
- }
- ]
- }
- }
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResourcesResponse.json
deleted file mode 100644
index 4326733f5e..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResourcesResponse.json
+++ /dev/null
@@ -1,52 +0,0 @@
-[
- {
- "moduleName": "ietf-yang-types-1",
- "revision": "2013-07-15",
- "yangSource": "module ietf-yang-types-1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-15 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-2",
- "revision": "2013-07-16",
- "yangSource": "module ietf-yang-types-2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-16 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-3",
- "revision": "2013-07-17",
- "yangSource": "module ietf-yang-types-3 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-3\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-17 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-4",
- "revision": "2013-07-18",
- "yangSource": "module ietf-yang-types-4 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-4\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-18 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-5",
- "revision": "2013-07-19",
- "yangSource": "module ietf-yang-types-5 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-5\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-19 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-6",
- "revision": "2013-07-20",
- "yangSource": "module ietf-yang-types-6 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-6\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-20 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-7",
- "revision": "2013-07-21",
- "yangSource": "module ietf-yang-types-7 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-7\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-21 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-8",
- "revision": "2013-07-22",
- "yangSource": "module ietf-yang-types-8 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-8\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-22 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-9",
- "revision": "2013-07-23",
- "yangSource": "module ietf-yang-types-9 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-9\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-23 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "ietf-yang-types-10",
- "revision": "2013-07-24",
- "yangSource": "module ietf-yang-types-10 {\n\n namespace \"urn:ietf:params:xml:ns:yang:ietf-yang-types-10\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2013-07-24 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResponse.json
deleted file mode 100644
index 2cbd8d1313..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/ietfYang-ModuleResponse.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "ietf-yang-types-1",
- "revision": "2013-07-15"
- },
- {
- "moduleName": "ietf-yang-types-2",
- "revision": "2013-07-16"
- },
- {
- "moduleName": "ietf-yang-types-3",
- "revision": "2013-07-17"
- },
- {
- "moduleName": "ietf-yang-types-4",
- "revision": "2013-07-18"
- },
- {
- "moduleName": "ietf-yang-types-5",
- "revision": "2013-07-19"
- },
- {
- "moduleName": "ietf-yang-types-6",
- "revision": "2013-07-20"
- },
- {
- "moduleName": "ietf-yang-types-7",
- "revision": "2013-07-21"
- },
- {
- "moduleName": "ietf-yang-types-8",
- "revision": "2013-07-22"
- },
- {
- "moduleName": "ietf-yang-types-9",
- "revision": "2013-07-23"
- },
- {
- "moduleName": "ietf-yang-types-10",
- "revision": "2013-07-24"
- }
- ]
-} \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResourcesResponse.json
deleted file mode 100644
index 5d713914d6..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResourcesResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "moduleName": "M1",
- "revision": "2024-01-01",
- "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "M2",
- "revision": "2024-01-02",
- "yangSource": "module M2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-02 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResponse.json
deleted file mode 100644
index 9f20564f04..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagA-ModuleResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "M1",
- "revision": "2024-01-01"
- },
- {
- "moduleName": "M2",
- "revision": "2024-01-02"
- }
- ]
-} \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResourcesResponse.json
deleted file mode 100644
index ef9b85f926..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResourcesResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "moduleName": "M1",
- "revision": "2024-01-01",
- "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "M3",
- "revision": "2024-01-03",
- "yangSource": "module M3 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M3\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-03 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResponse.json
deleted file mode 100644
index 513c749a26..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagB-ModuleResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "M1",
- "revision": "2024-01-01"
- },
- {
- "moduleName": "M3",
- "revision": "2024-01-03"
- }
- ]
-} \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResourcesResponse.json
deleted file mode 100644
index 8fb696bb7b..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResourcesResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "moduleName": "M4",
- "revision": "2024-01-04",
- "yangSource": "module M4 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-04 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "M5",
- "revision": "2024-01-05",
- "yangSource": "module M5 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-05 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResponse.json
deleted file mode 100644
index ea22d8b6dd..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagC-ModuleResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "M4",
- "revision": "2024-01-04"
- },
- {
- "moduleName": "M5",
- "revision": "2024-01-05"
- }
- ]
-} \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResourcesResponse.json
deleted file mode 100644
index 5d713914d6..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResourcesResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "moduleName": "M1",
- "revision": "2024-01-01",
- "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- },
- {
- "moduleName": "M2",
- "revision": "2024-01-02",
- "yangSource": "module M2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-02 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
- }
-] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResponse.json
deleted file mode 100644
index 9f20564f04..0000000000
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/tagD-ModuleResponse.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "schemas": [
- {
- "moduleName": "M1",
- "revision": "2024-01-01"
- },
- {
- "moduleName": "M2",
- "revision": "2024-01-02"
- }
- ]
-} \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/pom.xml b/dmi-plugin-demo-and-csit-stub/pom.xml
deleted file mode 100644
index 0719272523..0000000000
--- a/dmi-plugin-demo-and-csit-stub/pom.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ============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=========================================================
--->
-
-<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.onap.cps</groupId>
- <artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
- <relativePath>../cps-parent/pom.xml</relativePath>
- </parent>
-
- <artifactId>dmi-plugin-demo-and-csit-stub</artifactId>
- <packaging>pom</packaging>
-
- <properties>
- <parent.directory>${project.parent.basedir}/..</parent.directory>
- <sonar.skip>true</sonar.skip>
- <jacoco.skip>true</jacoco.skip>
- </properties>
-
- <modules>
- <module>dmi-plugin-demo-and-csit-stub-service</module>
- <module>dmi-plugin-demo-and-csit-stub-app</module>
- </modules>
-</project> \ No newline at end of file
diff --git a/docker-compose/config/grafana/jvm-micrometer-dashboard.json b/docker-compose/config/grafana/jvm-micrometer-dashboard.json
new file mode 100644
index 0000000000..8f7747c596
--- /dev/null
+++ b/docker-compose/config/grafana/jvm-micrometer-dashboard.json
@@ -0,0 +1,3613 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "datasource",
+ "uid": "grafana"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "limit": 100,
+ "name": "Annotations & Alerts",
+ "showIn": 0,
+ "type": "dashboard"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "enable": true,
+ "expr": "resets(process_uptime_seconds{application=\"$application\", instance=\"$instance\"}[1m]) > 0",
+ "iconColor": "rgba(255, 96, 96, 1)",
+ "name": "Restart Detection",
+ "showIn": 0,
+ "step": "1m",
+ "tagKeys": "restart-tag",
+ "textFormat": "uptime reset",
+ "titleFormat": "Restart"
+ }
+ ]
+ },
+ "description": "Dashboard for Micrometer instrumented applications (Java, Spring Boot, Micronaut)",
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "gnetId": 4701,
+ "graphTooltip": 1,
+ "id": 1,
+ "links": [],
+ "panels": [
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 139,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Quick Facts",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "decimals": 1,
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ }
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 0,
+ "y": 1
+ },
+ "id": 63,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.1.4",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_uptime_seconds{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "",
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Uptime",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ }
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "dateTimeAsIso"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 6,
+ "y": 1
+ },
+ "id": 92,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.1.4",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_start_time_seconds{application=\"$application\", instance=\"$instance\"}*1000",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "",
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Start time",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "decimals": 2,
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ }
+ ],
+ "max": 100,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "rgba(50, 172, 45, 0.97)",
+ "value": null
+ },
+ {
+ "color": "rgba(237, 129, 40, 0.89)",
+ "value": 70
+ },
+ {
+ "color": "rgba(245, 54, 54, 0.9)",
+ "value": 90
+ }
+ ]
+ },
+ "unit": "percent"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 12,
+ "y": 1
+ },
+ "id": 65,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.1.4",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Heap used",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "decimals": 2,
+ "mappings": [
+ {
+ "options": {
+ "match": "null",
+ "result": {
+ "text": "N/A"
+ }
+ },
+ "type": "special"
+ },
+ {
+ "options": {
+ "from": -1e+32,
+ "result": {
+ "text": "N/A"
+ },
+ "to": 0
+ },
+ "type": "range"
+ }
+ ],
+ "max": 100,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "rgba(50, 172, 45, 0.97)",
+ "value": null
+ },
+ {
+ "color": "rgba(237, 129, 40, 0.89)",
+ "value": 70
+ },
+ {
+ "color": "rgba(245, 54, 54, 0.9)",
+ "value": 90
+ }
+ ]
+ },
+ "unit": "percent"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 6,
+ "x": 18,
+ "y": 1
+ },
+ "id": 75,
+ "maxDataPoints": 100,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "percentChangeColorMode": "standard",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showPercentChange": false,
+ "textMode": "auto",
+ "wideLayout": true
+ },
+ "pluginVersion": "11.1.4",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 14400
+ }
+ ],
+ "title": "Non-Heap used",
+ "type": "stat"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 4
+ },
+ "id": 140,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "I/O Overview",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "ops"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 5
+ },
+ "id": 111,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\"}[1m]))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "HTTP",
+ "refId": "A"
+ }
+ ],
+ "title": "Rate",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "ops"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "HTTP"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#890f02",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "HTTP - 5xx"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#bf1b00",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 6,
+ "y": 5
+ },
+ "id": 112,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\", status=~\"5..\"}[1m]))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "HTTP - 5xx",
+ "refId": "A"
+ }
+ ],
+ "title": "Errors",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 12,
+ "y": 5
+ },
+ "id": 113,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(rate(http_server_requests_seconds_sum{application=\"$application\", instance=\"$instance\", status!~\"5..\"}[1m]))/sum(rate(http_server_requests_seconds_count{application=\"$application\", instance=\"$instance\", status!~\"5..\"}[1m]))",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "HTTP - AVG",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "max(http_server_requests_seconds_max{application=\"$application\", instance=\"$instance\", status!~\"5..\"})",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "HTTP - MAX",
+ "refId": "B"
+ }
+ ],
+ "title": "Duration",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 5
+ },
+ "id": 119,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "tomcat_threads_busy_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "TOMCAT - BSY",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "tomcat_threads_current_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "TOMCAT - CUR",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "tomcat_threads_config_max_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "TOMCAT - MAX",
+ "refId": "C"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jetty_threads_busy{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "JETTY - BSY",
+ "refId": "D"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jetty_threads_current{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "JETTY - CUR",
+ "refId": "E"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jetty_threads_config_max{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "JETTY - MAX",
+ "refId": "F"
+ }
+ ],
+ "title": "Utilisation",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 12
+ },
+ "id": 141,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Memory",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 13
+ },
+ "id": 24,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "committed",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "refId": "C",
+ "step": 2400
+ }
+ ],
+ "title": "JVM Heap",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 6,
+ "y": 13
+ },
+ "id": 25,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "committed",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "refId": "C",
+ "step": 2400
+ }
+ ],
+ "title": "JVM Non-Heap",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 12,
+ "y": 13
+ },
+ "id": 26,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "committed",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "refId": "C",
+ "step": 2400
+ }
+ ],
+ "title": "JVM Total",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 13
+ },
+ "id": 86,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_memory_vss_bytes{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": true,
+ "intervalFactor": 2,
+ "legendFormat": "vss",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_memory_rss_bytes{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "rss",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "swap",
+ "refId": "C"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_memory_rss_bytes{application=\"$application\", instance=\"$instance\"} + process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "total",
+ "refId": "D"
+ }
+ ],
+ "title": "JVM Process Memory",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 20
+ },
+ "id": 142,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Misc",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "max": 1,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "percentunit"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 21
+ },
+ "id": 106,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "system_cpu_usage{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "system",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_cpu_usage{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "process",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "avg_over_time(process_cpu_usage{application=\"$application\", instance=\"$instance\"}[15m])",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "process-15m",
+ "refId": "C"
+ }
+ ],
+ "title": "CPU Usage",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 6,
+ "y": 21
+ },
+ "id": 93,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "system_load_average_1m{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "system-1m",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "system_cpu_count{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "cpus",
+ "refId": "B"
+ }
+ ],
+ "title": "Load",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 12,
+ "y": 21
+ },
+ "id": 32,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_threads_live_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "live",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_threads_daemon_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "daemon",
+ "metric": "",
+ "refId": "B",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_threads_peak_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "peak",
+ "refId": "C",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "process",
+ "refId": "D",
+ "step": 2400
+ }
+ ],
+ "title": "Threads",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "blocked"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#bf1b00",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "new"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#fce2de",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "runnable"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#7eb26d",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "terminated"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#511749",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "timed-waiting"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#c15c17",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "waiting"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#eab839",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 21
+ },
+ "id": 124,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_threads_states_threads{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{state}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Thread States",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "description": "The percent of time spent on Garbage Collection over all CPUs assigned to the JVM process.",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "max": 1,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "percentunit"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 0,
+ "y": 28
+ },
+ "id": 138,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "sum(rate(jvm_gc_pause_seconds_sum{application=\"$application\", instance=\"$instance\"}[1m])) by (application, instance) / on(application, instance) system_cpu_count",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "CPU time spent on GC",
+ "refId": "A"
+ }
+ ],
+ "title": "GC Pressure",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "opm"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "debug"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#1F78C1",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "error"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#BF1B00",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "info"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#508642",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "trace"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#6ED0E0",
+ "mode": "fixed"
+ }
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "warn"
+ },
+ "properties": [
+ {
+ "id": "color",
+ "value": {
+ "fixedColor": "#EAB839",
+ "mode": "fixed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 6,
+ "y": 28
+ },
+ "id": 91,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "increase(logback_events_total{application=\"$application\", instance=\"$instance\"}[1m])",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{level}}",
+ "metric": "",
+ "refId": "A",
+ "step": 1200
+ }
+ ],
+ "title": "Log Events",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "log": 10,
+ "type": "log"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 28
+ },
+ "id": 61,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_files_open_files{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "open",
+ "metric": "",
+ "refId": "A",
+ "step": 2400
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "process_files_max_files{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "metric": "",
+ "refId": "B",
+ "step": 2400
+ }
+ ],
+ "title": "File Descriptors",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 35
+ },
+ "id": 143,
+ "panels": [],
+ "repeat": "persistence_counts",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Memory Pools (Heap)",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 36
+ },
+ "id": 3,
+ "options": {
+ "legend": {
+ "calcs": [
+ "lastNotNull",
+ "max"
+ ],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "repeat": "jvm_memory_pool_heap",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "commited",
+ "metric": "",
+ "refId": "B",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "metric": "",
+ "refId": "C",
+ "step": 1800
+ }
+ ],
+ "title": "$jvm_memory_pool_heap",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 43
+ },
+ "id": 144,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "JVM Memory Pools (Non-Heap)",
+ "type": "row"
+ },
+ {
+ "aliasColors": {},
+ "autoMigrateFrom": "graph",
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {
+ "leftLogBase": 1,
+ "rightLogBase": 1
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 44
+ },
+ "id": 78,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": true,
+ "max": true,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "maxPerRow": 3,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": "jvm_memory_pool_nonheap",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "metric": "",
+ "refId": "A",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "commited",
+ "metric": "",
+ "refId": "B",
+ "step": 1800
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "max",
+ "metric": "",
+ "refId": "C",
+ "step": 1800
+ }
+ ],
+ "thresholds": [],
+ "title": "$jvm_memory_pool_nonheap",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "timeseries",
+ "x-axis": true,
+ "xaxis": {
+ "mode": "time",
+ "show": true,
+ "values": []
+ },
+ "y-axis": true,
+ "y_formats": [
+ "mbytes",
+ "short"
+ ],
+ "yaxes": [
+ {
+ "format": "bytes",
+ "logBase": 1,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 58
+ },
+ "id": 145,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Garbage Collection",
+ "type": "row"
+ },
+ {
+ "aliasColors": {},
+ "autoMigrateFrom": "graph",
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 59
+ },
+ "id": 98,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 1,
+ "legendFormat": "{{action}} ({{cause}})",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "title": "Collections",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "timeseries",
+ "xaxis": {
+ "mode": "time",
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "logBase": 1,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "autoMigrateFrom": "graph",
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 59
+ },
+ "id": 101,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "rate(jvm_gc_pause_seconds_sum{application=\"$application\", instance=\"$instance\"}[1m])/rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])",
+ "format": "time_series",
+ "hide": false,
+ "instant": false,
+ "intervalFactor": 1,
+ "legendFormat": "avg {{action}} ({{cause}})",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_gc_pause_seconds_max{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "hide": false,
+ "instant": false,
+ "intervalFactor": 1,
+ "legendFormat": "max {{action}} ({{cause}})",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "title": "Pause Durations",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "timeseries",
+ "xaxis": {
+ "mode": "time",
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "logBase": 1,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "autoMigrateFrom": "graph",
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 59
+ },
+ "id": 99,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "rate(jvm_gc_memory_allocated_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 1,
+ "legendFormat": "allocated",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "rate(jvm_gc_memory_promoted_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 1,
+ "legendFormat": "promoted",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "title": "Allocated/Promoted",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "timeseries",
+ "xaxis": {
+ "mode": "time",
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "logBase": 1,
+ "min": "0",
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 66
+ },
+ "id": 146,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Classloading",
+ "type": "row"
+ },
+ {
+ "aliasColors": {},
+ "autoMigrateFrom": "graph",
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {
+ "leftLogBase": 1,
+ "rightLogBase": 1
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 67
+ },
+ "id": 37,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_classes_loaded_classes{application=\"$application\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "loaded",
+ "metric": "",
+ "refId": "A",
+ "step": 1200
+ }
+ ],
+ "thresholds": [],
+ "title": "Classes loaded",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "timeseries",
+ "x-axis": true,
+ "xaxis": {
+ "mode": "time",
+ "show": true,
+ "values": []
+ },
+ "y-axis": true,
+ "y_formats": [
+ "short",
+ "short"
+ ],
+ "yaxes": [
+ {
+ "format": "short",
+ "logBase": 1,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "autoMigrateFrom": "graph",
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "editable": true,
+ "error": false,
+ "fill": 1,
+ "grid": {
+ "leftLogBase": 1,
+ "rightLogBase": 1
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 67
+ },
+ "id": 38,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "delta(jvm_classes_loaded_classes{application=\"$application\",instance=\"$instance\"}[1m])",
+ "format": "time_series",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 1,
+ "legendFormat": "delta-1m",
+ "metric": "",
+ "refId": "A",
+ "step": 1200
+ }
+ ],
+ "thresholds": [],
+ "title": "Class delta",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "timeseries",
+ "x-axis": true,
+ "xaxis": {
+ "mode": "time",
+ "show": true,
+ "values": []
+ },
+ "y-axis": true,
+ "y_formats": [
+ "ops",
+ "short"
+ ],
+ "yaxes": [
+ {
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapsed": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 74
+ },
+ "id": 147,
+ "panels": [],
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Buffer Pools",
+ "type": "row"
+ },
+ {
+ "aliasColors": {},
+ "autoMigrateFrom": "graph",
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "fill": 1,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 75
+ },
+ "id": 131,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "maxPerRow": 3,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": "jvm_buffer_pool",
+ "seriesOverrides": [
+ {
+ "alias": "count",
+ "yaxis": 2
+ },
+ {
+ "alias": "buffers",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_buffer_pool\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "used",
+ "refId": "A"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_buffer_pool\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "capacity",
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "expr": "jvm_buffer_count_buffers{application=\"$application\", instance=\"$instance\", id=~\"$jvm_buffer_pool\"}",
+ "format": "time_series",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "buffers",
+ "refId": "C"
+ }
+ ],
+ "thresholds": [],
+ "title": "$jvm_buffer_pool",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "timeseries",
+ "xaxis": {
+ "mode": "time",
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "decbytes",
+ "logBase": 1,
+ "min": "0",
+ "show": true
+ },
+ {
+ "decimals": 0,
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "min": "0",
+ "show": true
+ }
+ ]
+ }
+ ],
+ "refresh": "auto",
+ "schemaVersion": 39,
+ "tags": [],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "isNone": true,
+ "selected": false,
+ "text": "None",
+ "value": ""
+ },
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "definition": "",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Application",
+ "multi": false,
+ "name": "application",
+ "options": [],
+ "query": "label_values(application)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {
+ "selected": false,
+ "text": "docker-compose-cps-and-ncmp-1:8080",
+ "value": "docker-compose-cps-and-ncmp-1:8080"
+ },
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "definition": "",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Instance",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "instance",
+ "options": [],
+ "query": "label_values(jvm_memory_used_bytes{application=\"$application\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {
+ "selected": false,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "definition": "",
+ "hide": 2,
+ "includeAll": true,
+ "label": "JVM Memory Pools Heap",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "jvm_memory_pool_heap",
+ "options": [],
+ "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"},id)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {
+ "selected": false,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "definition": "",
+ "hide": 2,
+ "includeAll": true,
+ "label": "JVM Memory Pools Non-Heap",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "jvm_memory_pool_nonheap",
+ "options": [],
+ "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"},id)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 2,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allFormat": "glob",
+ "current": {
+ "selected": false,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": {
+ "type": "prometheus",
+ "uid": "PBFA97CFB590B2093"
+ },
+ "definition": "",
+ "hide": 2,
+ "includeAll": true,
+ "label": "JVM Buffer Pools",
+ "multi": false,
+ "multiFormat": "glob",
+ "name": "jvm_buffer_pool",
+ "options": [],
+ "query": "label_values(jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\"},id)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-30m",
+ "to": "now"
+ },
+ "timepicker": {
+ "now": true,
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "browser",
+ "title": "JVM (Micrometer)",
+ "uid": "bdvp1kgecrda8f",
+ "version": 1,
+ "weekStart": ""
+}
diff --git a/docker-compose/config/grafana/provisioning/dashboards/dashboard.yml b/docker-compose/config/grafana/provisioning/dashboards/dashboard.yml
new file mode 100644
index 0000000000..b6dba86680
--- /dev/null
+++ b/docker-compose/config/grafana/provisioning/dashboards/dashboard.yml
@@ -0,0 +1,9 @@
+apiVersion: 1
+
+providers:
+ - name: default
+ orgId: 1
+ type: file
+ options:
+ path: /var/lib/grafana/dashboards
+ foldersFromFilesStructure: true
diff --git a/docker-compose/config/grafana/provisioning/datasources/datasource.yml b/docker-compose/config/grafana/provisioning/datasources/datasource.yml
new file mode 100644
index 0000000000..86fd3465e1
--- /dev/null
+++ b/docker-compose/config/grafana/provisioning/datasources/datasource.yml
@@ -0,0 +1,8 @@
+apiVersion: 1
+
+datasources:
+ - name: Prometheus
+ type: prometheus
+ access: proxy
+ url: http://prometheus:9090
+ isDefault: true
diff --git a/docker-compose/config/nginx/nginx.conf b/docker-compose/config/nginx/nginx.conf
new file mode 100644
index 0000000000..17fad1b876
--- /dev/null
+++ b/docker-compose/config/nginx/nginx.conf
@@ -0,0 +1,52 @@
+# ============LICENSE_START===============================================
+# Copyright (C) 2024 Nordix Foundation. All rights reserved.
+# ========================================================================
+# 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.
+# ============LICENSE_END=================================================
+
+events { }
+
+http {
+
+ # Add more server entries here for scaling or load balancing
+ upstream cps-and-ncmp {
+ server cps-and-ncmp:8080;
+ }
+
+ server {
+ listen 80;
+
+ # Root location proxying
+ location / {
+ proxy_pass http://cps-and-ncmp;
+ include /etc/nginx/proxy_params; # Include common proxy parameters
+ }
+
+ location /swagger-ui/ { # Swagger UI location
+ proxy_pass http://cps-and-ncmp/swagger-ui/;
+ }
+
+ location /v3/api-docs/ { # API docs location
+ proxy_pass http://cps-and-ncmp/v3/api-docs/;
+ }
+
+ location /actuator/health { # Actuator health endpoint
+ proxy_pass http://cps-and-ncmp/actuator/health;
+ }
+
+ location /actuator/health/readiness { # Actuator readiness endpoint
+ proxy_pass http://cps-and-ncmp/actuator/health/readiness;
+ }
+
+ }
+}
diff --git a/docker-compose/config/nginx/proxy_params b/docker-compose/config/nginx/proxy_params
new file mode 100644
index 0000000000..ab092a98f3
--- /dev/null
+++ b/docker-compose/config/nginx/proxy_params
@@ -0,0 +1,4 @@
+proxy_set_header Host $host;
+proxy_set_header X-Real-IP $remote_addr;
+proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+proxy_set_header X-Forwarded-Proto $scheme; \ No newline at end of file
diff --git a/docker-compose/postgres-init.sql b/docker-compose/config/postgres-init.sql
index 0c96de5b55..0c96de5b55 100644
--- a/docker-compose/postgres-init.sql
+++ b/docker-compose/config/postgres-init.sql
diff --git a/docker-compose/prometheus.yml b/docker-compose/config/prometheus.yml
index 9640709089..89af4a6800 100644
--- a/docker-compose/prometheus.yml
+++ b/docker-compose/config/prometheus.yml
@@ -3,8 +3,10 @@ global:
evaluation_interval: 5s
scrape_configs:
- - job_name: 'cps-and-ncm'
+ - job_name: 'cps-and-ncmp'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
static_configs:
- - targets: ['cps-and-ncmp:8080']
+ - targets:
+ - 'docker-compose-cps-and-ncmp-1:8080'
+ - 'docker-compose-cps-and-ncmp-2:8080'
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index a604b06527..1e47d47382 100644
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -20,6 +20,8 @@ services:
### docker-compose --profile dmi-service up -d -> run CPS services incl. dmi-plugin ###
### docker-compose --profile dmi-stub --profile monitoring up -d -> run CPS with stubbed dmi-plugin (for registration performance testing)
+ ### docker-compose --profile dmi-stub --profile tracing up -d -> run CPS with stubbed dmi-plugin (for open telemetry tracing testing make ONAP_TRACING_ENABLED "true" later "http://localhost:16686" can be accessed from browser)
+ ### docker-compose --profile dmi-stub --profile policy-executor-stub up -d -> run CPS with stubbed dmi-plugin and policy executor stub (for policy executor service testing make POLICY_SERVICE_ENABLED "true")
### to disable notifications make notification.enabled to false & comment out kafka/zookeeper services ###
dbpostgresql:
@@ -32,7 +34,7 @@ services:
POSTGRES_USER: ${DB_USERNAME:-cps}
POSTGRES_PASSWORD: ${DB_PASSWORD:-cps}
volumes:
- - ./postgres-init.sql:/docker-entrypoint-initdb.d/postgres-init.sql
+ - ./config/postgres-init.sql:/docker-entrypoint-initdb.d/postgres-init.sql
deploy:
resources:
reservations:
@@ -43,11 +45,7 @@ services:
memory: 3G
cps-and-ncmp:
- container_name: cps-and-ncmp
image: ${DOCKER_REPO:-nexus3.onap.org:10003}/onap/cps-and-ncmp:${CPS_VERSION:-latest}
- ports:
- - ${CPS_CORE_PORT:-8883}:8080
- - ${CPS_CORE_DEBUG_PORT:-5005}:5005
environment:
CPS_USERNAME: ${CPS_CORE_USERNAME:-cpsuser}
CPS_PASSWORD: ${CPS_CORE_PASSWORD:-cpsr0cks!}
@@ -58,11 +56,15 @@ services:
DMI_PASSWORD: ${DMI_PASSWORD:-cpsr0cks!}
KAFKA_BOOTSTRAP_SERVER: kafka:29092
notification.enabled: 'true'
- JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
+ ONAP_TRACING_ENABLED: 'false'
+ ONAP_OTEL_SAMPLER_JAEGER_REMOTE_ENDPOINT: http://jaeger-service:14250
+ ONAP_OTEL_EXPORTER_ENDPOINT: http://jaeger-service:4317
+ POLICY_SERVICE_ENABLED: 'false'
restart: unless-stopped
depends_on:
- dbpostgresql
deploy:
+ replicas: 2
resources:
reservations:
cpus: '2'
@@ -71,6 +73,17 @@ services:
cpus: '3'
memory: 3G
+ nginx:
+ container_name: nginx-loadbalancer
+ image: nginx:latest
+ ports:
+ - ${CPS_CORE_PORT:-8883}:80
+ depends_on:
+ - cps-and-ncmp
+ volumes:
+ - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
+ - ./config/nginx/proxy_params:/etc/nginx/proxy_params
+
### if kafka is not required comment out zookeeper and kafka ###
zookeeper:
image: confluentinc/cp-zookeeper:6.2.1
@@ -96,7 +109,7 @@ services:
ncmp-dmi-plugin:
container_name: ncmp-dmi-plugin
- image: ${DOCKER_REPO:-nexus3.onap.org:10003}/onap/ncmp-dmi-plugin:${DMI_VERSION:-1.5.0-SNAPSHOT-latest}
+ image: ${DOCKER_REPO:-nexus3.onap.org:10003}/onap/ncmp-dmi-plugin:${DMI_VERSION:-1.6.0-SNAPSHOT-latest}
ports:
- ${DMI_PORT:-8783}:8080
environment:
@@ -128,35 +141,48 @@ services:
KAFKA_BOOTSTRAP_SERVER: kafka:29092
NCMP_CONSUMER_GROUP_ID: ncmp-group
NCMP_ASYNC_M2M_TOPIC: ncmp-async-m2m
+ MODULE_INITIAL_PROCESSING_DELAY_MS: 0
MODULE_REFERENCES_DELAY_MS: 100
MODULE_RESOURCES_DELAY_MS: 1000
- DATA_FOR_CM_HANDLE_DELAY_MS: 2500
+ READ_DATA_FOR_CM_HANDLE_DELAY_MS: 300
+ WRITE_DATA_FOR_CM_HANDLE_DELAY_MS: 670
restart: unless-stopped
profiles:
- dmi-stub
- dmi-service
+ policy-executor-stub:
+ container_name: policy-executor-stub
+ image: ${DOCKER_REPO:-nexus3.onap.org:10003}/onap/policy-executor-stub:latest
+ ports:
+ - 8785:8093
+ restart: unless-stopped
+ profiles:
+ - policy-executor-stub
+
prometheus:
- container_name: prometheus-container
+ container_name: prometheus
image: prom/prometheus:latest
ports:
- 9090:9090
restart: always
volumes:
- - ./prometheus.yml:/etc/prometheus/prometheus.yml
+ - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
profiles:
- monitoring
grafana:
image: grafana/grafana-oss:latest
user: ""
- container_name: grafana-container
+ container_name: grafana
depends_on:
prometheus:
condition: service_started
ports:
- 3000:3000
volumes:
+ - ./config/grafana/provisioning/:/etc/grafana/provisioning/
+ - ./config/grafana/jvm-micrometer-dashboard.json:/var/lib/grafana/dashboards/jvm-micrometer-dashboard.json
- grafana:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
@@ -164,5 +190,26 @@ services:
profiles:
- monitoring
+ kafka-ui:
+ container_name: kafka-ui
+ image: provectuslabs/kafka-ui:latest
+ ports:
+ - 8089:8080
+ environment:
+ DYNAMIC_CONFIG_ENABLED: 'true'
+ KAFKA_CLUSTERS_0_NAME: 'cps-kafka-local'
+ KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092
+ profiles:
+ - monitoring
+
+ jaeger-service:
+ container_name: jaeger-service
+ image: jaegertracing/all-in-one:latest
+ ports:
+ - 16686:16686
+ restart: unless-stopped
+ profiles:
+ - tracing
+
volumes:
grafana:
diff --git a/docs/_static/cps-delta-mechanism.png b/docs/_static/cps-delta-mechanism.png
index ab78ad9a1b..07923d4c26 100644
--- a/docs/_static/cps-delta-mechanism.png
+++ b/docs/_static/cps-delta-mechanism.png
Binary files differ
diff --git a/docs/_static/logo_onap_2024.png b/docs/_static/logo_onap_2024.png
new file mode 100644
index 0000000000..55d307fc34
--- /dev/null
+++ b/docs/_static/logo_onap_2024.png
Binary files differ
diff --git a/docs/admin-guide.rst b/docs/admin-guide.rst
index 1c4d7455f0..4a40f9b29c 100644
--- a/docs/admin-guide.rst
+++ b/docs/admin-guide.rst
@@ -111,9 +111,9 @@ Execute CPS service that you want to calculate total elapsed time and log as sho
.. code-block::
- 2022-01-28 18:39:17.679 DEBUG [cps-application,e17da1571e518c59,e17da1571e518c59] 11128 --- [tp1901272535-29] o.onap.cps.aop.CpsLoggingAspectService : Execution time of : DataspaceRepository.getByName() with argument[s] = [test42] having result = org.onap.cps.spi.entities.DataspaceEntity@68ded236 :: 205 ms
+ 2022-01-28 18:39:17.679 DEBUG [cps-application,e17da1571e518c59,e17da1571e518c59] 11128 --- [tp1901272535-29] o.onap.cps.aop.CpsLoggingAspectService : Execution time of : DataspaceRepository.getByName() with argument[s] = [test42] having result = org.onap.cps.impl.models.DataspaceEntity@68ded236 :: 205 ms
- 2022-01-28 18:39:17.726 DEBUG [cps-application,e17da1571e518c59,e17da1571e518c59] 11128 --- [tp1901272535-29] o.onap.cps.aop.CpsLoggingAspectService : Execution time of : AnchorRepository.getByDataspaceAndName() with argument[s] = [org.onap.cps.spi.entities.DataspaceEntity@68ded236, bookstore] having result = org.onap.cps.spi.entities.AnchorEntity@71c47fb1 :: 46 ms
+ 2022-01-28 18:39:17.726 DEBUG [cps-application,e17da1571e518c59,e17da1571e518c59] 11128 --- [tp1901272535-29] o.onap.cps.aop.CpsLoggingAspectService : Execution time of : AnchorRepository.getByDataspaceAndName() with argument[s] = [org.onap.cps.impl.models.DataspaceEntity@68ded236, bookstore] having result = org.onap.cps.impl.models.AnchorEntity@71c47fb1 :: 46 ms
2022-01-28 18:39:17.768 DEBUG [cps-application,e17da1571e518c59,e17da1571e518c59] 11128 --- [tp1901272535-29] o.onap.cps.aop.CpsLoggingAspectService : Execution time of : CpsAdminPersistenceServiceImpl.getAnchor() with argument[s] = [test42, bookstore] having result = Anchor(name=bookstore, dataspaceName=test42, schemaSetName=bookstore) :: 299 ms
diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml
index 2798b78643..d6cca6e687 100644
--- a/docs/api/swagger/cps/openapi.yaml
+++ b/docs/api/swagger/cps/openapi.yaml
@@ -9,11 +9,7 @@ info:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0
title: ONAP Open API v3 Configuration Persistence Service
- version: 1.0.0
- x-planned-retirement-date: "202212"
- x-component: Modeling
- x-logo:
- url: cps_logo.png
+ version: 3.5.2
servers:
- url: /cps/api
security:
@@ -40,7 +36,7 @@ paths:
responses:
"201":
content:
- text/plain:
+ application/json:
schema:
example: my-resource
type: string
@@ -364,7 +360,7 @@ paths:
responses:
"201":
content:
- text/plain:
+ application/json:
schema:
example: my-resource
type: string
@@ -711,7 +707,7 @@ paths:
responses:
"201":
content:
- text/plain:
+ application/json:
schema:
example: my-resource
type: string
@@ -1346,6 +1342,13 @@ paths:
schema:
example: 2021-03-21T00:10:34.030-0100
type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: true
+ schema:
+ example: application/json
+ type: string
requestBody:
content:
application/json:
@@ -1354,7 +1357,16 @@ paths:
$ref: '#/components/examples/dataSample'
value: null
schema:
+ type: string
+ application/xml:
+ examples:
+ dataSample:
+ $ref: '#/components/examples/dataSampleXml'
+ value: null
+ schema:
type: object
+ xml:
+ name: stores
required: true
responses:
"200":
@@ -1446,7 +1458,7 @@ paths:
schema:
example: 2021-03-21T00:10:34.030-0100
type: string
- - description: Content type header
+ - description: Content type in header
in: header
name: Content-Type
required: true
@@ -1475,7 +1487,7 @@ paths:
responses:
"201":
content:
- text/plain:
+ application/json:
schema:
example: my-resource
type: string
@@ -1571,6 +1583,13 @@ paths:
schema:
example: 2021-03-21T00:10:34.030-0100
type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: true
+ schema:
+ example: application/json
+ type: string
requestBody:
content:
application/json:
@@ -1579,7 +1598,16 @@ paths:
$ref: '#/components/examples/dataSample'
value: null
schema:
+ type: string
+ application/xml:
+ examples:
+ dataSample:
+ $ref: '#/components/examples/dataSampleXml'
+ value: null
+ schema:
type: object
+ xml:
+ name: stores
required: true
responses:
"200":
@@ -1746,6 +1774,13 @@ paths:
schema:
example: 2021-03-21T00:10:34.030-0100
type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: true
+ schema:
+ example: application/json
+ type: string
requestBody:
content:
application/json:
@@ -1754,12 +1789,21 @@ paths:
$ref: '#/components/examples/dataSample'
value: null
schema:
+ type: string
+ application/xml:
+ examples:
+ dataSample:
+ $ref: '#/components/examples/dataSampleXml'
+ value: null
+ schema:
type: object
+ xml:
+ name: stores
required: true
responses:
"201":
content:
- text/plain:
+ application/json:
schema:
example: my-resource
type: string
@@ -1896,7 +1940,7 @@ paths:
summary: Replace list content
tags:
- cps-data
- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta:
+ /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta:
get:
description: Get delta between two anchors within a given dataspace
operationId: getDeltaByDataspaceAndAnchors
@@ -1908,9 +1952,9 @@ paths:
schema:
example: my-dataspace
type: string
- - description: anchor-name
+ - description: source-anchor-name
in: path
- name: anchor-name
+ name: source-anchor-name
required: true
schema:
example: my-anchor
@@ -1989,6 +2033,95 @@ paths:
tags:
- cps-data
x-codegen-request-body-name: xpath
+ post:
+ description: Get delta between an anchor in a dataspace and JSON payload
+ operationId: getDeltaByDataspaceAnchorAndPayload
+ parameters:
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: source-anchor-name
+ in: path
+ name: source-anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ $ref: '#/components/schemas/getDeltaByDataspaceAnchorAndPayload_request'
+ responses:
+ "200":
+ content:
+ application/json:
+ examples:
+ dataSample:
+ $ref: '#/components/examples/deltaReportSample'
+ value: null
+ schema:
+ type: object
+ description: OK
+ "400":
+ content:
+ application/json:
+ example:
+ status: 400
+ message: Bad Request
+ details: The provided request is not valid
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Bad Request
+ "401":
+ content:
+ application/json:
+ example:
+ status: 401
+ message: Unauthorized request
+ details: This request is unauthorized
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Unauthorized
+ "403":
+ content:
+ application/json:
+ example:
+ status: 403
+ message: Request Forbidden
+ details: This request is forbidden
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Forbidden
+ "500":
+ content:
+ application/json:
+ example:
+ status: 500
+ message: Internal Server Error
+ details: Internal Server Error occurred
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Internal Server Error
+ summary: Get delta between an anchor and JSON payload
+ tags:
+ - cps-data
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
get:
deprecated: true
@@ -2270,7 +2403,7 @@ components:
dataSampleXml:
value: <stores xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <bookstore xmlns="org:onap:ccsdk:sample">
<bookstore-name>Chapters</bookstore-name> <categories> <code>1</code> <name>SciFi</name>
- </categories> </bookstore> </stores>
+ <code>2</code> <name>kids</name> </categories> </bookstore> </stores>
deltaReportSample:
value:
- action: ADD
@@ -2409,8 +2542,8 @@ components:
schema:
example: 2021-03-21T00:10:34.030-0100
type: string
- contentTypeHeader:
- description: Content type header
+ contentTypeInHeader:
+ description: Content type in header
in: header
name: Content-Type
required: true
@@ -2429,6 +2562,14 @@ components:
required: true
schema:
type: string
+ sourceAnchorNameInPath:
+ description: source-anchor-name
+ in: path
+ name: source-anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
targetAnchorNameInQuery:
description: target-anchor-name
in: query
@@ -2471,7 +2612,7 @@ components:
responses:
Created:
content:
- text/plain:
+ application/json:
schema:
example: my-resource
type: string
@@ -2530,6 +2671,16 @@ components:
schema:
type: object
description: OK
+ Unauthorized:
+ content:
+ application/json:
+ example:
+ status: 401
+ message: Unauthorized request
+ details: This request is unauthorized
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Unauthorized
schemas:
ErrorMessage:
properties:
@@ -2619,6 +2770,24 @@ components:
type: string
title: Module reference object
type: object
+ getDeltaByDataspaceAnchorAndPayload_request:
+ properties:
+ json:
+ example:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 1
+ name: SciFi
+ - code: 2
+ name: kids
+ type: object
+ file:
+ format: binary
+ type: string
+ required:
+ - json
+ type: object
securitySchemes:
basicAuth:
scheme: basic
diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml
index 4f5180d510..d710316fc3 100644
--- a/docs/api/swagger/ncmp/openapi-inventory.yaml
+++ b/docs/api/swagger/ncmp/openapi-inventory.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.3
info:
description: NCMP Inventory API
title: NCMP Inventory API
- version: "1.0"
+ version: 3.5.2
servers:
- url: /ncmpInventory
security:
diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml
index 9f6a1b2b66..a227addda5 100644
--- a/docs/api/swagger/ncmp/openapi.yaml
+++ b/docs/api/swagger/ncmp/openapi.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.3
info:
description: NCMP to CPS Proxy API
title: NCMP to CPS Proxy API
- version: "1.0"
+ version: 3.5.2
servers:
- url: /ncmp
security:
@@ -28,8 +28,7 @@ paths:
schema:
example: my-cm-handle
type: string
- - allowReserved: true
- description: The format of resource identifier depend on the associated DMI
+ - description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
it can really be anything.
examples:
@@ -139,8 +138,7 @@ paths:
schema:
example: my-cm-handle
type: string
- - allowReserved: true
- description: The format of resource identifier depend on the associated DMI
+ - description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
it can really be anything.
examples:
@@ -158,8 +156,7 @@ paths:
required: true
schema:
type: string
- - allowReserved: true
- description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
+ - description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
\ in parenthesis'()'. The format of options parameter depend on the associated\
\ DMI Plugin implementation."
examples:
@@ -177,8 +174,7 @@ paths:
required: false
schema:
type: string
- - allowReserved: true
- description: topic parameter in query.
+ - description: topic parameter in query.
examples:
sample 1:
value:
@@ -276,8 +272,7 @@ paths:
schema:
example: my-cm-handle
type: string
- - allowReserved: true
- description: The format of resource identifier depend on the associated DMI
+ - description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
it can really be anything.
examples:
@@ -390,8 +385,7 @@ paths:
schema:
example: my-cm-handle
type: string
- - allowReserved: true
- description: The format of resource identifier depend on the associated DMI
+ - description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
it can really be anything.
examples:
@@ -509,8 +503,7 @@ paths:
schema:
example: my-cm-handle
type: string
- - allowReserved: true
- description: The format of resource identifier depend on the associated DMI
+ - description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
it can really be anything.
examples:
@@ -615,12 +608,11 @@ paths:
post:
description: This request will be handled asynchronously using messaging to
the supplied topic. The rest response will be an acknowledge with a requestId
- to identify the relevant messages. A maximum of 50 cm handles per operation
+ to identify the relevant messages. A maximum of 200 cm handles per operation
is supported.
operationId: executeDataOperationForCmHandles
parameters:
- - allowReserved: true
- description: mandatory topic parameter in query.
+ - description: mandatory topic parameter in query.
examples:
sample 1:
value:
@@ -736,8 +728,7 @@ paths:
schema:
default: /
type: string
- - allowReserved: true
- description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
+ - description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
\ in parenthesis'()'. The format of options parameter depend on the associated\
\ DMI Plugin implementation."
examples:
@@ -755,8 +746,7 @@ paths:
required: false
schema:
type: string
- - allowReserved: true
- description: topic parameter in query.
+ - description: topic parameter in query.
examples:
sample 1:
value:
@@ -1484,7 +1474,6 @@ components:
example: my-cm-handle
type: string
resourceIdentifierInQuery:
- allowReserved: true
description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but it
can really be anything.
@@ -1504,7 +1493,6 @@ components:
schema:
type: string
optionsParamInQuery:
- allowReserved: true
description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
\ in parenthesis'()'. The format of options parameter depend on the associated\
\ DMI Plugin implementation."
@@ -1524,7 +1512,6 @@ components:
schema:
type: string
topicParamInQuery:
- allowReserved: true
description: topic parameter in query.
examples:
sample 1:
@@ -1561,7 +1548,6 @@ components:
example: application/yang-data+json
type: string
requiredTopicParamInQuery:
- allowReserved: true
description: mandatory topic parameter in query.
examples:
sample 1:
diff --git a/docs/api/swagger/policy-executor/openapi.yaml b/docs/api/swagger/policy-executor/openapi.yaml
new file mode 100644
index 0000000000..6b73d98ed6
--- /dev/null
+++ b/docs/api/swagger/policy-executor/openapi.yaml
@@ -0,0 +1,198 @@
+# ============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=========================================================
+
+openapi: 3.0.3
+info:
+ title: Policy Executor
+ description: "Allows NCMP to execute a policy defined by a third party implementation before proceeding with a CM operation"
+ version: 1.0.0
+tags:
+ - name: policy-executor
+ description: "Execute all your policies"
+paths:
+ /policy-executor/api/v1/{action}:
+ post:
+ description: "Fire a Policy action"
+ operationId: executePolicyAction
+ parameters:
+ - $ref: '#/components/parameters/authorizationInHeader'
+ - $ref: '#/components/parameters/actionInPath'
+ requestBody:
+ required: true
+ description: "The action request body"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PolicyExecutionRequest'
+ tags:
+ - policy-executor
+ responses:
+ '200':
+ description: "Successful policy execution"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PolicyExecutionResponse'
+ '400':
+ $ref: '#/components/responses/BadRequest'
+ '401':
+ $ref: '#/components/responses/Unauthorized'
+ '403':
+ $ref: '#/components/responses/Forbidden'
+ '500':
+ $ref: '#/components/responses/InternalServerError'
+
+components:
+ securitySchemes:
+ bearerAuth:
+ type: http
+ description: "Bearer token (from client that called CPS-NCMP),used by policies to identify the client"
+ scheme: bearer
+ schemas:
+ ErrorMessage:
+ type: object
+ title: Error
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ details:
+ type: string
+
+ Request:
+ type: object
+ properties:
+ schema:
+ type: string
+ description: "The schema for the data in this request. The schema name should include the type of operation"
+ example: "org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0"
+ data:
+ type: object
+ description: "The data related to the request. The format of the object is determined by the schema"
+ required:
+ - schema
+ - data
+
+ PolicyExecutionRequest:
+ type: object
+ properties:
+ decisionType:
+ type: string
+ description: "The type of decision. Currently supported options: 'allow'"
+ example: "allow"
+ requests:
+ type: array
+ items:
+ $ref: '#/components/schemas/Request'
+ required:
+ - decisionType
+ - requests
+
+ PolicyExecutionResponse:
+ type: object
+ properties:
+ decisionId:
+ type: string
+ description: "Unique ID for the decision (for auditing purposes)"
+ example: "550e8400-e29b-41d4-a716-446655440000"
+ decision:
+ type: string
+ description: "The decision outcome. Currently supported values: 'allow','deny'"
+ example: "deny"
+ message:
+ type: string
+ description: "Additional information regarding the decision outcome"
+ example: "Object locked due to recent change"
+ required:
+ - decisionId
+ - decision
+ - message
+
+ responses:
+ BadRequest:
+ description: "Bad request"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 400
+ message: "Bad Request"
+ details: "The provided request is not valid"
+ Unauthorized:
+ description: "Unauthorized request"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 401
+ message: "Unauthorized request"
+ details: "This request is unauthorized"
+ Forbidden:
+ description: "Request forbidden"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 403
+ message: "Request Forbidden"
+ details: "This request is forbidden"
+
+ InternalServerError:
+ description: "Internal server error"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 500
+ message: "Internal Server Error"
+ details: "Internal server error occurred"
+
+ NotImplemented:
+ description: "Method not (yet) implemented"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 501
+ message: "Not Implemented"
+ details: "Method not implemented"
+
+ parameters:
+ actionInPath:
+ name: action
+ in: path
+ description: "The policy action. Currently supported options: 'execute'"
+ required: true
+ schema:
+ type: string
+ example: "execute"
+ authorizationInHeader:
+ name: Authorization
+ in: header
+ description: "Bearer token may be used to identify client as part of a policy"
+ schema:
+ type: string
+
+security:
+ - bearerAuth: []
diff --git a/docs/cm-notification-subscriptions.rst b/docs/cm-notification-subscriptions.rst
new file mode 100644
index 0000000000..14e871addc
--- /dev/null
+++ b/docs/cm-notification-subscriptions.rst
@@ -0,0 +1,48 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2024 Nordix Foundation
+
+.. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING
+.. _cmNotificationSubscriptions:
+
+
+CM Data Subscriptions
+#####################
+
+.. toctree::
+ :maxdepth: 1
+
+Introduction
+============
+CM Subscriptions are created to subscribe to notifications for CM related changes that happened in the network based on predicates.
+Predicates can be used to filter on CM Handle (id), Datastore and Xpath.
+
+The CM Subscription flow is event driven and adheres to the CNCF Cloud Events Specifications.
+
+Event to create and delete a subscription.
+
+:download:`CM Subscription Event Schema <schemas/ncmp-in-event-schema-1.0.0.json>`
+
+Event to receive status of participants in a subscription.
+
+:download:`CM Subscription Response Event Schema <schemas/ncmp-out-event-schema-1.0.0.json>`
+
+CM Subscriptions Creation
+-------------------------
+To create a subscription, a client sends an event to a configured topic to register its interest with NCMP allowing the client to receive notifications based on the subscription.
+
+CM Subscriptions Deletion
+-------------------------
+If a client no longer wishes to receive notifications based on a registered subscription, the client can delete the subscription by providing the subscription id.
+
+CM Subscriptions Response
+-------------------------
+The response for the involved subscription participants for the Create and Delete flow can be as follows based on how the DMI Plugin responds back to NCMP.
+ - **ACCEPTED:** DMI Plugin successfully applied the subscription.
+ - **REJECTED:** DMI Plugin failed to apply the subscription.
+ - **PENDING:** DMI Plugin failed to respond within a configured time.
+
+**Note.** The Cm Subscription feature relies on the DMI Plugin support for applying the subscriptions. This support is currently not implemented in the ONAP DMI Plugin.
+
+
+
diff --git a/docs/conf.py b/docs/conf.py
index e8bb6630f3..5d7a79941d 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -31,7 +31,7 @@ html_theme = "sphinx_rtd_theme"
html_theme_options = {
"style_nav_header_background": "white",
"sticky_navigation": "False" }
-html_logo = "_static/logo_onap_2017.png"
+html_logo = "_static/logo_onap_2024.png"
html_favicon = "_static/favicon.ico"
html_static_path = ["_static"]
html_show_sphinx = False
diff --git a/docs/cps-delta-endpoints.rst b/docs/cps-delta-endpoints.rst
index b2e4e6041b..ecb7550f44 100644
--- a/docs/cps-delta-endpoints.rst
+++ b/docs/cps-delta-endpoints.rst
@@ -38,7 +38,7 @@ Sample Delta Report
[
{
- "action": "ADD",
+ "action": "create",
"xpath": "/bookstore/categories/[@code=3]",
"target-data": {
"code": "3,",
@@ -46,7 +46,7 @@ Sample Delta Report
}
},
{
- "action": "REMOVE",
+ "action": "remove",
"xpath": "/bookstore/categories/[@code=1]",
"source-data": {
"code": "1,",
@@ -54,7 +54,7 @@ Sample Delta Report
}
},
{
- "action": "UPDATE",
+ "action": "replace",
"xpath": "/bookstore/categories/[@code=2]",
"source-data": {
"name": "Funny"
diff --git a/docs/cps-delta-feature.rst b/docs/cps-delta-feature.rst
index f3a2f947e4..34aa43df53 100644
--- a/docs/cps-delta-feature.rst
+++ b/docs/cps-delta-feature.rst
@@ -22,10 +22,10 @@ Delta Report Format
-------------------
The Delta Report is based on the RFC 9144, which defines a set of parameters to be included in the Delta Report. In CPS only the relevant parameters defined in RFC 9144 are used. These include:
- - **action:** This parameter defines how the data nodes changed between two configurations. If data nodes are added, deleted or modified then the 'action' parameter in the delta report will be set to ADD, DELETE or UPDATE respectively for each data node.
+ - **action:** This parameter defines how the data nodes changed between two configurations. If data nodes are added, deleted or modified then the 'action' parameter in the delta report will be set to 'create', 'remove' or 'replace' respectively for each data node.
- **xpath:** This parameter will provide the xpath of each data node that has been either added, deleted or modified.
- - **source-data:** this parameter is added to the delta report when a data node is deleted or updated, this represents the source/reference data against which the delta is being generated. In case of newly added data node this field is not included in the delta report.
- - **target-data:** this parameter is added to the delta report when a data node is added or updated, this represents the data values that are being compared to the source data. In case of a data node being deleted this field is not included in the delta report.
+ - **source-data:** this parameter is added to the delta report when a data node is removed or updated, this represents the source/reference data against which the delta is being generated. In case of newly added data node this field is not included in the delta report.
+ - **target-data:** this parameter is added to the delta report when a data node is added or updated, this represents the data values that are being compared to the source data. In case of a data node being removed this field is not included in the delta report.
**Note.** In case of an existing data node being modified, both the source-data and target-data fields are present in the delta report.
diff --git a/docs/cps-events.rst b/docs/cps-events.rst
index 25a253bada..47aa73f12e 100644
--- a/docs/cps-events.rst
+++ b/docs/cps-events.rst
@@ -13,6 +13,7 @@ CPS Events
cm-handle-lcm-events.rst
data-operation-events.rst
+ cm-notification-subscriptions.rst
.. note::
Legacy async response on a client supplied topic for single cm handle data request are no longer supported. Click link below for the legacy specification.
diff --git a/docs/cps-ncmp-message-status-codes.rst b/docs/cps-ncmp-message-status-codes.rst
index 0c6ce0e712..e0a3f0308b 100644
--- a/docs/cps-ncmp-message-status-codes.rst
+++ b/docs/cps-ncmp-message-status-codes.rst
@@ -14,7 +14,7 @@ CPS-NCMP Message Status Codes
+=================+======================================================+===================================+
| 0 | Successfully applied changes | Data Operation |
+-----------------+------------------------------------------------------+-----------------------------------+
- | 1 | successfully applied subscription | CM Data Notification Subscription |
+ | 1 | ACCEPTED | CM Data Notification Subscription |
+-----------------+------------------------------------------------------+-----------------------------------+
| 100 | cm handle id(s) is(are) not found | All features |
+-----------------+------------------------------------------------------+-----------------------------------+
@@ -24,11 +24,7 @@ CPS-NCMP Message Status Codes
+-----------------+------------------------------------------------------+-----------------------------------+
| 103 | dmi plugin service is not able to read resource data | Data Operation |
+-----------------+------------------------------------------------------+-----------------------------------+
- | 104 | partially applied subscription | CM Data Notification Subscription |
- +-----------------+------------------------------------------------------+-----------------------------------+
- | 105 | subscription not applicable for all cm handles | CM Data Notification Subscription |
- +-----------------+------------------------------------------------------+-----------------------------------+
- | 106 | subscription pending for all cm handles | CM Data Notification Subscription |
+ | 104 | REJECTED | CM Data Notification Subscription |
+-----------------+------------------------------------------------------+-----------------------------------+
| 107 | southbound system is busy | Data Operation |
+-----------------+------------------------------------------------------+-----------------------------------+
diff --git a/docs/design.rst b/docs/design.rst
index af1f5abd4a..52f977a99a 100644
--- a/docs/design.rst
+++ b/docs/design.rst
@@ -60,11 +60,20 @@ and CPS-NCMP-Inventory using the drop down table in the top right:
Consumed APIs
=============
-CPS Core uses API's from the following ONAP components
+DMI-Plugin
+----------
-* DMI-Plugin: REST based interface which is used to provide integration
- and allow the DMI registry API's have access to the corresponding NCMP API's within CPS Core.
- More information on the DMI-Plugins offered APIs can be found on the :ref:`DMI-Plugin's Design Page <onap-cps-ncmp-dmi-plugin:design>`.
+DMI-Plugin is a REST based interface which is used to provide integration
+and allow the DMI registry API's have access to the corresponding NCMP API's within CPS Core.
+More information on the DMI-Plugins offered APIs can be found on the :ref:`DMI-Plugin's Design Page <onap-cps-ncmp-dmi-plugin:design>`.
+
+Policy-Executor
+---------------
+
+.. toctree::
+ :maxdepth: 1
+
+ policy-executor.rst
CPS Path
========
diff --git a/docs/ncmp-inventory-querying.rst b/docs/ncmp-inventory-querying.rst
index 349b984963..084eaaf696 100644
--- a/docs/ncmp-inventory-querying.rst
+++ b/docs/ncmp-inventory-querying.rst
@@ -156,3 +156,23 @@ With the *cmHandleWithDmiPlugin* condition, we can provide a dmiPluginName. The
}
]
}
+
+CM Handle search with CPS Path
+------------------------------
+
+The *cmHandleWithCpsPath* condition allows any data of the CM Handle to be queried as long as it is accessible by CPS path. CPS path is described in detail in :doc:`cps-path`. For this endpoint, the ancestor axis for CM Handles is appended automatically so that a CM Handle is always returned. For example ``/dmi-registry/cm-handles[@module-set-tag='']`` will become ``/dmi-registry/cm-handles[@module-set-tag='']/ancestor::cm-handles``.
+
+.. code-block:: json
+
+ {
+ "cmHandleQueryParameters": [
+ {
+ "conditionName": "cmHandleWithCpsPath",
+ "conditionParameters": [
+ {
+ "cpsPath": "/dmi-registry/cm-handles[@module-set-tag='some-value or empty']"
+ }
+ ]
+ }
+ ]
+ } \ No newline at end of file
diff --git a/docs/policy-executor.rst b/docs/policy-executor.rst
new file mode 100644
index 0000000000..b934a579b1
--- /dev/null
+++ b/docs/policy-executor.rst
@@ -0,0 +1,23 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2024 Nordix Foundation
+
+.. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING
+.. _policy_executor:
+
+
+Policy Executor
+###############
+
+.. toctree::
+ :maxdepth: 1
+
+Introduction
+============
+
+Work In Progress: This feature is not yet completed and does not affect current NCMP functionality.
+
+Consumed APIs
+-------------
+
+:download:`Policy Executor OpenApi Specification <api/swagger/policy-executor/openapi.yaml>`
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
index 82a890d79c..9b23fbc16b 100644
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -12,12 +12,12 @@ CPS Release Notes
:depth: 2
..
-.. =========================
-.. * * * NEW DELHI * * *
-.. =========================
+.. ====================
+.. * * * OSLO * * *
+.. ====================
-Version: 3.4.10
-===============
+Version: 3.5.3
+==============
Release Data
------------
@@ -26,10 +26,10 @@ Release Data
| **CPS Project** | |
| | |
+--------------------------------------+--------------------------------------------------------+
-| **Docker images** | onap/cps-and-ncmp:3.4.10 |
+| **Docker images** | onap/cps-and-ncmp:3.5.3 |
| | |
+--------------------------------------+--------------------------------------------------------+
-| **Release designation** | 3.4.10 New Delhi |
+| **Release designation** | 3.5.3 Oslo |
| | |
+--------------------------------------+--------------------------------------------------------+
| **Release date** | Not yet released |
@@ -38,10 +38,112 @@ Release Data
Bug Fixes
---------
-3.4.10
+3.5.3
+
+Features
+--------
+3.5.3
+
+
+Version: 3.5.2
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project** | |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images** | onap/cps-and-ncmp:3.5.2 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation** | 3.5.2 Oslo |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release date** | 2024 August 21 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.5.2
+ - `CPS-2306 <https://jira.onap.org/browse/CPS-2306>`_ Update response message for data validation failure and make it consistent across APIs
+ - `CPS-2319 <https://jira.onap.org/browse/CPS-2319>`_ Fix "Create a node" and "Add List Elements" APIs response code
+ - `CPS-2372 <https://jira.onap.org/browse/CPS-2372>`_ Blank alternate ID overwrites existing one
+
+Features
+--------
+3.5.2
+ - `CPS-1812 <https://jira.onap.org/browse/CPS-1812>`_ CM Data Subscriptions ( Create, Delete and Merging ) with positive scenarios
+ - `CPS-2326 <https://jira.onap.org/browse/CPS-2326>`_ Uplift liquibase-core dependency to 4.28.0
+ - `CPS-2353 <https://jira.onap.org/browse/CPS-2353>`_ Improve registration performance with moduleSetTag
+ - `CPS-2366 <https://jira.onap.org/browse/CPS-2366>`_ Improve registration performance with use of alternateID
+
+Version: 3.5.1
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project** | |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images** | onap/cps-and-ncmp:3.5.1 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation** | 3.5.1 Oslo |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release date** | 2024 July 15 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.5.1
+ - `CPS-2302 <https://jira.onap.org/browse/CPS-2302>`_ Fix handling of special characters in moduleSetTag.
Features
--------
+3.5.1
+ - `CPS-2121 <https://jira.onap.org/browse/CPS-2121>`_ Enabled http client prometheus metrics and manage high cardinality using URL template.
+ - `CPS-2289 <https://jira.onap.org/browse/CPS-2289>`_ Support for CPS Path Query in NCMP Inventory Cm Handle Search.
+
+Version: 3.5.0
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project** | |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images** | onap/cps-and-ncmp:3.5.0 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation** | 3.5.0 Oslo |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release date** | 2024 June 20 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.5.0
+
+Features
+--------
+3.5.0
+ - `CPS-989 <https://jira.onap.org/browse/CPS-989>`_ Replace RestTemplate with WebClient.
+ - `CPS-2172 <https://jira.onap.org/browse/CPS-2172>`_ Support for OpenTelemetry Tracing.
+
+.. =========================
+.. * * * NEW DELHI * * *
+.. =========================
Version: 3.4.9
==============
@@ -70,6 +172,8 @@ Bug Fixes
Features
--------
+3.4.9
+ - `CPS-1836 <https://jira.onap.org/browse/CPS-1836>`_ Delta between anchor and JSON payload.
Version: 3.4.8
==============
diff --git a/docs/schemas/ncmp-in-event-schema-1.0.0.json b/docs/schemas/ncmp-in-event-schema-1.0.0.json
new file mode 100644
index 0000000000..f8b6c2e680
--- /dev/null
+++ b/docs/schemas/ncmp-in-event-schema-1.0.0.json
@@ -0,0 +1,73 @@
+{
+ "$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-ncmp-in-event:1.0.0",
+ "$ref": "#/definitions/NcmpInEvent",
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "definitions": {
+ "NcmpInEvent": {
+ "description": "The payload for subscription merge event.",
+ "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent",
+ "properties": {
+ "data": {
+ "properties": {
+ "subscriptionId": {
+ "description": "The subscription details.",
+ "type": "string"
+ },
+ "predicates": {
+ "type": "array",
+ "description": "Additional values to be added into the subscription",
+ "items": {
+ "type": "object",
+ "properties": {
+ "targetFilter": {
+ "description": "CM Handles to be targeted by the subscription",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "scopeFilter": {
+ "type": "object",
+ "properties": {
+ "datastore": {
+ "description": "Datastore which is to be used by the subscription",
+ "type": "string",
+ "enum": ["ncmp-datastore:passthrough-operational", "ncmp-datastore:passthrough-running"]
+ },
+ "xpathFilter": {
+ "description": "Filter to be applied to the CM Handles through this event",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "xpathFilter"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "targetFilter"
+ ]
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": [
+ "subscriptionId"
+ ],
+ "type": "object",
+ "additionalProperties": false
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "data"
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-out-event-schema-1.0.0.json b/docs/schemas/ncmp-out-event-schema-1.0.0.json
index d9db3ffb97..d6ef55d063 100644
--- a/cps-ncmp-events/src/main/resources/schemas/cmnotificationsubscription/cm-notification-subscription-ncmp-out-event-schema-1.0.0.json
+++ b/docs/schemas/ncmp-out-event-schema-1.0.0.json
@@ -1,12 +1,12 @@
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"$id": "urn:cps:org.onap.cps.ncmp.events:cm-notification-subscription-ncmp-out-event-schema:1.0.0",
- "$ref": "#/definitions/CmNotificationSubscriptionNcmpOutEvent",
+ "$ref": "#/definitions/NcmpOutEvent",
"definitions": {
- "CmNotificationSubscriptionNcmpOutEvent": {
+ "NcmpOutEvent": {
"type": "object",
"description": "The payload applied cm subscription merge event coming out from NCMP.",
- "javaType": "org.onap.cps.ncmp.events.cmsubscription_merge1_0_0.ncmp_to_client.CmNotificationSubscriptionNcmpOutEvent",
+ "javaType": "org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.ncmp_to_client.NcmpOutEvent",
"additionalProperties": false,
"properties": {
"data": {
@@ -16,7 +16,7 @@
"required": [
"data"
],
- "title": "CmNotificationSubscriptionNcmpOutEvent"
+ "title": "NcmpOutEvent"
},
"Data": {
"type": "object",
@@ -27,21 +27,21 @@
"type": "string",
"description": "The unique subscription id"
},
- "accepted-targets": {
+ "acceptedTargets": {
"type": "array",
"description": "List of accepted targets",
"items": {
"type": "string"
}
},
- "rejected-targets": {
+ "rejectedTargets": {
"type": "array",
"description": "List of rejected targets",
"items": {
"type": "string"
}
},
- "pending-targets": {
+ "pendingTargets": {
"type": "array",
"description": "List of pending targets",
"items": {
@@ -50,10 +50,10 @@
}
},
"required": [
- "accepted-targets",
- "pending-targets",
- "rejected-targets",
- "subscriptionId"
+ "subscriptionId",
+ "acceptedTargets",
+ "rejectedTargets",
+ "pendingTargets"
],
"title": "Data"
}
diff --git a/docs/schemas/policy-executor/ncmp-create-schema-1.0.0.json b/docs/schemas/policy-executor/ncmp-create-schema-1.0.0.json
new file mode 100644
index 0000000000..4d98bc8632
--- /dev/null
+++ b/docs/schemas/policy-executor/ncmp-create-schema-1.0.0.json
@@ -0,0 +1,29 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "urn:cps:org.onap.cps.ncmp.policy-executor.ncmp-create-schema:1.0.0",
+ "$ref": "#/definitions/NcmpCreate",
+ "definitions": {
+ "NcmpCreate": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "cmHandleId": {
+ "type": "string"
+ },
+ "resourceIdentifier": {
+ "type": "string"
+ },
+ "targetIdentifier": {
+ "type": "string"
+ },
+ "cmChangeRequest": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "targetIdentifier",
+ "cmChangeRequest"
+ ]
+ }
+ }
+}
diff --git a/docs/schemas/policy-executor/ncmp-delete-schema-1.0.0.json b/docs/schemas/policy-executor/ncmp-delete-schema-1.0.0.json
new file mode 100644
index 0000000000..1246d9d815
--- /dev/null
+++ b/docs/schemas/policy-executor/ncmp-delete-schema-1.0.0.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "urn:cps:org.onap.cps.ncmp.policy-executor.ncmp-delete-schema:1.0.0",
+ "$ref": "#/definitions/NcmpDelete",
+ "definitions": {
+ "NcmpDelete": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "cmHandleId": {
+ "type": "string"
+ },
+ "resourceIdentifier": {
+ "type": "string"
+ },
+ "targetIdentifier": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "targetIdentifier"
+ ]
+ }
+ }
+}
diff --git a/docs/schemas/policy-executor/ncmp-patch-schema-1.0.0.json b/docs/schemas/policy-executor/ncmp-patch-schema-1.0.0.json
new file mode 100644
index 0000000000..4917aea146
--- /dev/null
+++ b/docs/schemas/policy-executor/ncmp-patch-schema-1.0.0.json
@@ -0,0 +1,29 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "urn:cps:org.onap.cps.ncmp.policy-executor.ncmp-patch-schema:1.0.0",
+ "$ref": "#/definitions/NcmpPatch",
+ "definitions": {
+ "NcmpPatch": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "cmHandleId": {
+ "type": "string"
+ },
+ "resourceIdentifier": {
+ "type": "string"
+ },
+ "targetIdentifier": {
+ "type": "string"
+ },
+ "cmChangeRequest": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "targetIdentifier",
+ "cmChangeRequest"
+ ]
+ }
+ }
+}
diff --git a/docs/schemas/policy-executor/ncmp-update-schema-1.0.0.json b/docs/schemas/policy-executor/ncmp-update-schema-1.0.0.json
new file mode 100644
index 0000000000..831526cd52
--- /dev/null
+++ b/docs/schemas/policy-executor/ncmp-update-schema-1.0.0.json
@@ -0,0 +1,29 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "urn:cps:org.onap.cps.ncmp.policy-executor.ncmp-update-schema:1.0.0",
+ "$ref": "#/definitions/NcmpUpdate",
+ "definitions": {
+ "NcmpUpdate": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "cmHandleId": {
+ "type": "string"
+ },
+ "resourceIdentifier": {
+ "type": "string"
+ },
+ "targetIdentifier": {
+ "type": "string"
+ },
+ "cmChangeRequest": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "targetIdentifier",
+ "cmChangeRequest"
+ ]
+ }
+ }
+}
diff --git a/integration-test/pom.xml b/integration-test/pom.xml
index f228e01194..ef8fdc819e 100644
--- a/integration-test/pom.xml
+++ b/integration-test/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -107,6 +107,11 @@
<artifactId>spock</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-json</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<profiles>
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
index 6952b2ad37..587cbae619 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023-2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -20,14 +21,7 @@
package org.onap.cps.integration.base
-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.NCMP_DMI_REGISTRY_PARENT
-
-import java.time.OffsetDateTime
-import java.time.format.DateTimeFormatter
import okhttp3.mockwebserver.MockWebServer
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsDataspaceService
@@ -35,19 +29,24 @@ import org.onap.cps.api.CpsModuleService
import org.onap.cps.api.CpsQueryService
import org.onap.cps.integration.DatabaseTestContainer
import org.onap.cps.integration.KafkaTestContainer
-import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
+import org.onap.cps.ncmp.impl.data.NetworkCmProxyQueryService
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.inventory.ParameterizedCmHandleQueryService
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.sync.ModuleSyncWatchdog
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
+import org.onap.cps.ri.repository.DataspaceRepository
+import org.onap.cps.ri.utils.SessionManager
import org.onap.cps.spi.exceptions.DataspaceNotFoundException
import org.onap.cps.spi.model.DataNode
-import org.onap.cps.spi.repository.DataspaceRepository
-import org.onap.cps.spi.utils.SessionManager
+import org.onap.cps.utils.ContentType
import org.onap.cps.utils.JsonObjectMapper
import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
@@ -60,13 +59,20 @@ import spock.lang.Shared
import spock.lang.Specification
import spock.util.concurrent.PollingConditions
+import java.time.OffsetDateTime
+import java.time.format.DateTimeFormatter
+
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService])
@Testcontainers
@EnableAutoConfiguration
@AutoConfigureMockMvc
@EnableJpaRepositories(basePackageClasses = [DataspaceRepository])
@ComponentScan(basePackages = ['org.onap.cps'])
-@EntityScan('org.onap.cps.spi.entities')
+@EntityScan('org.onap.cps.ri.models')
abstract class CpsIntegrationSpecBase extends Specification {
@Shared
@@ -97,10 +103,13 @@ abstract class CpsIntegrationSpecBase extends Specification {
SessionManager sessionManager
@Autowired
- NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService
+ ParameterizedCmHandleQueryService networkCmProxyCmHandleQueryService
+
+ @Autowired
+ NetworkCmProxyFacade networkCmProxyFacade
@Autowired
- NetworkCmProxyDataService networkCmProxyDataService
+ NetworkCmProxyInventoryFacade NetworkCmProxyInventoryFacade
@Autowired
NetworkCmProxyQueryService networkCmProxyQueryService
@@ -114,16 +123,32 @@ abstract class CpsIntegrationSpecBase extends Specification {
@Autowired
InventoryPersistence inventoryPersistence
- MockWebServer mockDmiServer = null
- DmiDispatcher dmiDispatcher = new DmiDispatcher()
+ @Autowired
+ AlternateIdMatcher alternateIdMatcher
+
- def DMI_URL = null
+ @Value('${ncmp.policy-executor.server.port:8080}')
+ private String policyServerPort;
+
+ MockWebServer mockDmiServer1 = new MockWebServer()
+ MockWebServer mockDmiServer2 = new MockWebServer()
+ MockWebServer mockPolicyServer = new MockWebServer()
+
+ DmiDispatcher dmiDispatcher1 = new DmiDispatcher()
+ DmiDispatcher dmiDispatcher2 = new DmiDispatcher()
+
+ PolicyDispatcher policyDispatcher = new PolicyDispatcher();
+
+ def DMI1_URL = null
+ def DMI2_URL = null
static NO_MODULE_SET_TAG = ''
+ static NO_ALTERNATE_ID = ''
static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
+ static MODULE_SYNC_WAIT_TIME_IN_SECONDS = 10
- def static initialized = false
+ static initialized = false
def now = OffsetDateTime.now()
def setup() {
@@ -132,14 +157,24 @@ abstract class CpsIntegrationSpecBase extends Specification {
createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
initialized = true
}
- mockDmiServer = new MockWebServer()
- mockDmiServer.setDispatcher(dmiDispatcher)
- mockDmiServer.start()
- DMI_URL = String.format("http://%s:%s", mockDmiServer.getHostName(), mockDmiServer.getPort())
+ mockDmiServer1.setDispatcher(dmiDispatcher1)
+ mockDmiServer1.start()
+
+ mockDmiServer2.setDispatcher(dmiDispatcher2)
+ mockDmiServer2.start()
+
+ mockPolicyServer.setDispatcher(policyDispatcher)
+ mockPolicyServer.start(Integer.valueOf(policyServerPort))
+
+ DMI1_URL = String.format("http://%s:%s", mockDmiServer1.getHostName(), mockDmiServer1.getPort())
+ DMI2_URL = String.format("http://%s:%s", mockDmiServer2.getHostName(), mockDmiServer2.getPort())
+
}
def cleanup() {
- mockDmiServer.shutdown()
+ mockDmiServer1.shutdown()
+ mockDmiServer2.shutdown()
+ mockPolicyServer.shutdown()
}
def static readResourceDataFile(filename) {
@@ -205,11 +240,14 @@ abstract class CpsIntegrationSpecBase extends Specification {
// *** NCMP Integration Test Utilities ***
def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag) {
- def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag)
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
- new PollingConditions().within(3, () -> {
- CmHandleState.READY == networkCmProxyDataService.getCmHandleCompositeState(cmHandleId).cmHandleState
+ registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, NO_ALTERNATE_ID)
+ }
+
+ def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, alternateId) {
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag, alternateId: alternateId)
+ networkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
+ CmHandleState.READY == networkCmProxyInventoryFacade.getCmHandleCompositeState(cmHandleId).cmHandleState
})
}
@@ -218,7 +256,7 @@ abstract class CpsIntegrationSpecBase extends Specification {
}
def deregisterCmHandles(dmiPlugin, cmHandleIds) {
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
+ networkCmProxyInventoryFacade.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
}
def overrideCmHandleLastUpdateTime(cmHandleId, newUpdateTime) {
@@ -226,6 +264,6 @@ abstract class CpsIntegrationSpecBase extends Specification {
DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
def jsonForUpdate = '{ "state": { "last-update-time": "%s" } }'.formatted(ISO_TIMESTAMP_FORMATTER.format(newUpdateTime))
cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
- NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='${cmHandleId}']", jsonForUpdate, now)
+ NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='${cmHandleId}']", jsonForUpdate, now, ContentType.JSON)
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy
index 6676cb74c2..35a7b6a7c2 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy
@@ -20,16 +20,18 @@
package org.onap.cps.integration.base
-import static org.onap.cps.integration.base.CpsIntegrationSpecBase.readResourceDataFile
-
-import org.springframework.http.HttpHeaders
-import java.util.regex.Matcher
+import groovy.json.JsonSlurper
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.RecordedRequest
+import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
+import java.util.regex.Matcher
+
+import static org.onap.cps.integration.base.CpsIntegrationSpecBase.readResourceDataFile
+
/**
* This class simulates responses from the DMI server in NCMP integration tests.
*
@@ -54,51 +56,95 @@ class DmiDispatcher extends Dispatcher {
def isAvailable = true
- Map<String, List<String>> moduleNamesPerCmHandleId = [:]
+ def jsonSlurper = new JsonSlurper()
+ def moduleNamesPerCmHandleId = [:]
+ def receivedSubJobs = [:]
+ def lastAuthHeaderReceived
+ def dmiResourceDataUrl
@Override
MockResponse dispatch(RecordedRequest request) {
if (!isAvailable) {
- return new MockResponse().setResponseCode(HttpStatus.SERVICE_UNAVAILABLE.value())
+ return mockResponse(HttpStatus.SERVICE_UNAVAILABLE)
+ }
+ if (request.path == '/actuator/health') {
+ return mockResponseWithBody(HttpStatus.OK, '{"status":"UP"}')
}
+
+ lastAuthHeaderReceived = request.getHeader('Authorization')
switch (request.path) {
- case ~/^\/dmi\/v1\/ch\/(.*)\/modules$/:
+ // get module references for a CM-handle
+ case ~'^/dmi/v1/ch/(.*)/modules$':
def cmHandleId = Matcher.lastMatcher[0][1]
return getModuleReferencesResponse(cmHandleId)
- case ~/^\/dmi\/v1\/ch\/(.*)\/moduleResources$/:
+ // get module resources for a CM-handle
+ case ~'^/dmi/v1/ch/(.*)/moduleResources$':
def cmHandleId = Matcher.lastMatcher[0][1]
return getModuleResourcesResponse(cmHandleId)
+ // pass-through data operation for a CM-handle
+ case ~'^/dmi/v1/ch/(.*)/data/ds/(.*)$':
+ dmiResourceDataUrl = request.path
+ return mockResponseWithBody(HttpStatus.OK, '{}')
+
+ // legacy pass-through batch data operation
+ case ~'^/dmi/v1/data$':
+ return mockResponseWithBody(HttpStatus.ACCEPTED, '{}')
+
+ // get data job status
+ case ~'^/dmi/v1/cmwriteJob/dataProducer/(.*)/dataProducerJob/(.*)/status$':
+ return mockResponseWithBody(HttpStatus.OK, '{"status":"status details from mock service"}')
+
+ // get data job result
+ case ~'^/dmi/v1/cmwriteJob/dataProducer/(.*)/dataProducerJob/(.*)/result(.*)$':
+ return mockResponseWithBody(HttpStatus.OK, '{ "result": "some result"}')
+
+ // get write sub job response
+ case ~'^/dmi/v1/cmwriteJob(.*)$':
+ return mockWriteJobResponse(request)
+
default:
- throw new IllegalArgumentException('Mock DMI does not handle path ' + request.path)
+ throw new IllegalArgumentException('Mock DMI does not implement endpoint ' + request.path)
}
}
- private getModuleReferencesResponse(cmHandleId) {
+ def mockWriteJobResponse(request) {
+ def destination = Matcher.lastMatcher[0][1]
+ def subJobWriteRequest = jsonSlurper.parseText(request.getBody().readUtf8())
+ this.receivedSubJobs.put(destination, subJobWriteRequest)
+ def response = '{"subJobId":"some sub job id", "dmiServiceName":"some dmi service name", "dataProducerId":"some data producer id"}'
+ return mockResponseWithBody(HttpStatus.OK, response)
+ }
+
+ def getModuleReferencesResponse(cmHandleId) {
def moduleReferences = '{"schemas":[' + getModuleNamesForCmHandle(cmHandleId).collect {
MODULE_REFERENCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it)
}.join(',') + ']}'
- return mockOkResponseWithBody(moduleReferences)
+ return mockResponseWithBody(HttpStatus.OK, moduleReferences)
}
- private getModuleResourcesResponse(cmHandleId) {
+ def getModuleResourcesResponse(cmHandleId) {
def moduleResources = '[' + getModuleNamesForCmHandle(cmHandleId).collect {
MODULE_RESOURCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it)
}.join(',') + ']'
- return mockOkResponseWithBody(moduleResources)
+ return mockResponseWithBody(HttpStatus.OK, moduleResources)
}
- private getModuleNamesForCmHandle(cmHandleId) {
+ def getModuleNamesForCmHandle(cmHandleId) {
if (!moduleNamesPerCmHandleId.containsKey(cmHandleId)) {
throw new IllegalArgumentException('Mock DMI has no modules configured for ' + cmHandleId)
}
return moduleNamesPerCmHandleId.get(cmHandleId)
}
- private static mockOkResponseWithBody(responseBody) {
+ def static mockResponse(status) {
+ return new MockResponse().setResponseCode(status.value())
+ }
+
+ def static mockResponseWithBody(status, responseBody) {
return new MockResponse()
- .setResponseCode(HttpStatus.OK.value())
+ .setResponseCode(status.value())
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
.setBody(responseBody)
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
new file mode 100644
index 0000000000..69792d7ed8
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
@@ -0,0 +1,74 @@
+/*
+ * ============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.integration.base
+
+
+import okhttp3.mockwebserver.Dispatcher
+import okhttp3.mockwebserver.MockResponse
+import okhttp3.mockwebserver.RecordedRequest
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper
+
+/**
+ * This class simulates responses from the Policy Execution server in NCMP integration tests.
+ */
+class PolicyDispatcher extends Dispatcher {
+
+ def objectMapper = new ObjectMapper()
+ def expectedAuthorizationToken = 'ABC'
+ def allowAll = true; // Prevents legacy test being affected
+
+ @Override
+ MockResponse dispatch(RecordedRequest recordedRequest) {
+
+ if (!allowAll && !recordedRequest.getHeader('Authorization').contains(expectedAuthorizationToken)) {
+ return new MockResponse().setResponseCode(401)
+ }
+
+ if (recordedRequest.path != '/policy-executor/api/v1/execute') {
+ return new MockResponse().setResponseCode(400)
+ }
+
+ def body = objectMapper.readValue(recordedRequest.getBody().readUtf8(), Map.class)
+ def targetIdentifier = body.get('requests').get(0).get('data').get('targetIdentifier')
+ def responseAsMap = [:]
+ responseAsMap.put('decisionId',1)
+ if (allowAll || targetIdentifier == 'fdn1') {
+ responseAsMap.put('decision','allow')
+ responseAsMap.put('message','')
+ } else {
+ responseAsMap.put('decision','deny')
+ responseAsMap.put('message','I only like fdn1')
+ }
+ def responseAsString = objectMapper.writeValueAsString(responseAsMap)
+
+ return mockResponseWithBody(HttpStatus.OK, responseAsString)
+ }
+
+ static mockResponseWithBody(status, responseBody) {
+ return new MockResponse()
+ .setResponseCode(status.value())
+ .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+ .setBody(responseBody)
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
deleted file mode 100644
index 302c7e512c..0000000000
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ============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.integration.functional
-
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING;
-import org.onap.cps.integration.base.CpsIntegrationSpecBase;
-import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionPersistenceService;
-import org.springframework.beans.factory.annotation.Autowired;
-
-class NcmpCmNotificationSubscriptionSpec extends CpsIntegrationSpecBase {
-
- @Autowired
- CmNotificationSubscriptionPersistenceService cmNotificationSubscriptionPersistenceService;
-
- def 'Adding a new cm notification subscription'() {
- given: 'there is no ongoing cm subscription for the following'
- def datastoreType = PASSTHROUGH_RUNNING
- def cmHandleId = 'ch-1'
- def xpath = '/x/y'
- assert cmNotificationSubscriptionPersistenceService.
- getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() == 0
- when: 'we add a new cm notification subscription'
- cmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(datastoreType,cmHandleId,xpath,
- 'subId-1')
- then: 'there is an ongoing cm subscription for that CM handle and xpath'
- assert cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType,cmHandleId,xpath)
- and: 'only one subscription id is related to now ongoing cm subscription'
- assert cmNotificationSubscriptionPersistenceService.
- getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() == 1
- }
-
- def 'Adding a cm notification subscription to the already existing'() {
- given: 'an ongoing cm subscription with the following details'
- def datastoreType = PASSTHROUGH_RUNNING
- def cmHandleId = 'ch-1'
- def xpath = '/x/y'
- when: 'a new cm notification subscription is made for the SAME CM handle and xpath'
- cmNotificationSubscriptionPersistenceService.addCmNotificationSubscription(datastoreType,cmHandleId,xpath,
- 'subId-2')
- then: 'it is added to the ongoing list of subscription ids'
- def subscriptionIds = cmNotificationSubscriptionPersistenceService.getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath)
- assert subscriptionIds.size() == 2
- and: 'both subscription ids exists for the CM handle and xpath'
- assert subscriptionIds.contains("subId-1") && subscriptionIds.contains("subId-2")
- }
-
- def 'Removing cm notification subscriber among other subscribers'() {
- given: 'an ongoing cm subscription with the following details'
- def datastoreType = PASSTHROUGH_RUNNING
- def cmHandleId = 'ch-1'
- def xpath = '/x/y'
- and: 'the number of subscribers is as follows'
- def originalNumberOfSubscribers =
- cmNotificationSubscriptionPersistenceService.getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size()
- when: 'a subscriber is removed'
- cmNotificationSubscriptionPersistenceService.removeCmNotificationSubscription(datastoreType,cmHandleId,xpath,'subId-2')
- then: 'the number of subscribers is reduced by 1'
- def updatedNumberOfSubscribers =
- cmNotificationSubscriptionPersistenceService.getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size()
- assert updatedNumberOfSubscribers == originalNumberOfSubscribers-1
- }
-
- def 'Removing the LAST cm notification subscriber for a given cm handle, datastore and xpath'() {
- given: 'an ongoing cm subscription with the following details'
- def datastoreType = PASSTHROUGH_RUNNING
- def cmHandleId = 'ch-1'
- def xpath = '/x/y'
- and: 'there is only one subscriber'
- assert cmNotificationSubscriptionPersistenceService
- .getOngoingCmNotificationSubscriptionIds(datastoreType,cmHandleId,xpath).size() == 1
- when: 'only subscriber is removed'
- cmNotificationSubscriptionPersistenceService.removeCmNotificationSubscription(datastoreType,cmHandleId,xpath,'subId-1')
- then: 'there are no longer any subscriptions for the cm handle, datastore and xpath'
- assert !cmNotificationSubscriptionPersistenceService.isOngoingCmNotificationSubscription(datastoreType, cmHandleId, xpath)
- }
-
-}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAnchorServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/AnchorServiceIntegrationSpec.groovy
index 4bba8a5751..240ff5114b 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsAnchorServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/AnchorServiceIntegrationSpec.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023-2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -18,17 +19,18 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.cps
import java.time.OffsetDateTime
import org.onap.cps.api.CpsAnchorService
-import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.integration.base.FunctionalSpecBase
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.exceptions.AnchorNotFoundException
+import org.onap.cps.utils.ContentType
-class CpsAnchorServiceIntegrationSpec extends CpsIntegrationSpecBase {
+class AnchorServiceIntegrationSpec extends FunctionalSpecBase {
CpsAnchorService objectUnderTest
@@ -61,9 +63,9 @@ class CpsAnchorServiceIntegrationSpec extends CpsIntegrationSpecBase {
then: 'there are 3 anchors in the general test database'
assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE).size() == 3
and: 'there are 2 anchors associated with bookstore schema set'
- assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).size() == 2
+ assert objectUnderTest.getAnchorsBySchemaSetName(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).size() == 2
and: 'there is 1 anchor associated with other schema set'
- assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE, 'otherSchemaSet').size() == 1
+ assert objectUnderTest.getAnchorsBySchemaSetName(GENERAL_TEST_DATASPACE, 'otherSchemaSet').size() == 1
}
def 'Querying anchor(name)s (depends on previous test!).'() {
@@ -110,7 +112,7 @@ class CpsAnchorServiceIntegrationSpec extends CpsIntegrationSpecBase {
objectUnderTest.updateAnchorSchemaSet(GENERAL_TEST_DATASPACE, 'anchor4', 'anotherTreeSchemaSet')
when: 'updated tree data node with new leaves'
def updatedTreeJsonData = readResourceDataFile('tree/updated-test-tree.json')
- cpsDataService.updateNodeLeaves(GENERAL_TEST_DATASPACE, "anchor4", "/test-tree/branch[@name='left']", updatedTreeJsonData, OffsetDateTime.now())
+ cpsDataService.updateNodeLeaves(GENERAL_TEST_DATASPACE, "anchor4", "/test-tree/branch[@name='left']", updatedTreeJsonData, OffsetDateTime.now(), ContentType.JSON)
then: 'updated tree data node can be retrieved by its normalized xpath'
def birdsName = cpsDataService.getDataNodes(GENERAL_TEST_DATASPACE, 'anchor4',"/test-tree/branch[@name='left']/nest", FetchDescendantsOption.DIRECT_CHILDREN_ONLY)[0].leaves['birds'] as List
assert birdsName.size() == 3
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
index f967c62037..d49931eb7e 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataServiceIntegrationSpec.groovy
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023-2024 Nordix Foundation
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Modifications Copyright (C) 2023-2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.cps
import org.onap.cps.api.CpsDataService
import org.onap.cps.integration.base.FunctionalSpecBase
@@ -33,12 +33,13 @@ import org.onap.cps.spi.exceptions.DataNodeNotFoundExceptionBatch
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.exceptions.DataspaceNotFoundException
import org.onap.cps.spi.model.DeltaReport
+import org.onap.cps.utils.ContentType
import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
+class DataServiceIntegrationSpec extends FunctionalSpecBase {
CpsDataService objectUnderTest
def originalCountBookstoreChildNodes
@@ -223,7 +224,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'a new (multiple-data-tree:invoice) datanodes'
def json = '{"bookstore-address":[{"bookstore-name":"Easons","address":"Bangalore,India","postal-code":"560043"}]}'
when: 'the new list elements are saved'
- objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/', json, now)
+ objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/', json, now, ContentType.JSON)
then: 'they can be retrieved by their xpaths'
objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore-address[@bookstore-name="Easons"]', INCLUDE_ALL_DESCENDANTS)
and: 'there is one extra datanode'
@@ -238,7 +239,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'two new (categories) data nodes'
def json = '{"categories": [ {"code":"new1"}, {"code":"new2" } ] }'
when: 'the new list elements are saved'
- objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
+ objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now, ContentType.JSON)
then: 'they can be retrieved by their xpaths'
objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="new1"]', DIRECT_CHILDREN_ONLY).size() == 1
objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="new2"]', DIRECT_CHILDREN_ONLY).size() == 1
@@ -255,7 +256,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'two (categories) data nodes, one new and one existing'
def json = '{"categories": [ {"code":"1"}, {"code":"new1"} ] }'
when: 'attempt to save the list element'
- objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
+ objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now, ContentType.JSON)
then: 'an exception that (one cps paths is) already defined is thrown '
def exceptionThrown = thrown(AlreadyDefinedException)
exceptionThrown.alreadyDefinedObjectNames == ['/bookstore/categories[@code=\'1\']' ] as Set
@@ -269,7 +270,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'a new (categories) data nodes'
def json = '{"categories": [ {"code":"new1"} ] }'
and: 'the new list element is saved'
- objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
+ objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now, ContentType.JSON)
when: 'the new element is deleted'
objectUnderTest.deleteListOrListElement(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="new1"]', now)
then: 'the original number of data nodes is restored'
@@ -280,7 +281,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'two new (categories) data nodes in a single batch'
def json = '{"categories": [ {"code":"new1"}, {"code":"new2"} ] }'
when: 'the batches of new list element(s) are saved'
- objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
+ objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now, ContentType.JSON)
then: 'they can be retrieved by their xpaths'
assert objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="new1"]', DIRECT_CHILDREN_ONLY).size() == 1
assert objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="new2"]', DIRECT_CHILDREN_ONLY).size() == 1
@@ -297,7 +298,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'one existing and one new (categories) data nodes in a single batch'
def json = '{"categories": [ {"code":"new1"}, {"code":"1"} ] }'
when: 'the batches of new list element(s) are saved'
- objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
+ objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now, ContentType.JSON)
then: 'an already defined (batch) exception is thrown for the existing path'
def exceptionThrown = thrown(AlreadyDefinedException)
assert exceptionThrown.alreadyDefinedObjectNames == ['/bookstore/categories[@code=\'1\']' ] as Set
@@ -366,7 +367,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
objectUnderTest.saveData(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
when: 'update is performed to add a leaf'
def updatedJson = '{"webinfo": {"domain-name":"new leaf data"}}'
- objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, "/bookstore", updatedJson, now)
+ objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, "/bookstore", updatedJson, now, ContentType.JSON)
then: 'the updated data nodes are retrieved'
def result = cpsDataService.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, "/bookstore/webinfo", INCLUDE_ALL_DESCENDANTS)
and: 'the leaf value is updated as expected'
@@ -377,7 +378,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
def 'Update multiple data leaves error scenario: #scenario.'() {
when: 'attempt to update data node for #scenario'
- objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, xpath, 'irrelevant json data', now)
+ objectUnderTest.updateNodeLeaves(dataspaceName, anchorName, xpath, 'irrelevant json data', now, ContentType.JSON)
then: 'a #expectedException is thrown'
thrown(expectedException)
where: 'the following data is used'
@@ -395,7 +396,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
objectUnderTest.saveData(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
when: 'the webinfo (container) is updated'
json = '{"webinfo": {"domain-name":"newdomain.com" ,"contact-email":"info@newdomain.com" }}'
- objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now)
+ objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now, ContentType.JSON)
then: 'webinfo has been updated with teh new details'
def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/webinfo', DIRECT_CHILDREN_ONLY)
result.leaves.'domain-name'[0] == 'newdomain.com'
@@ -407,7 +408,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
def 'Update bookstore top-level container data node.'() {
when: 'the bookstore top-level container is updated'
def json = '{ "bookstore": { "bookstore-name": "new bookstore" }}'
- objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/', json, now)
+ objectUnderTest.updateDataNodeAndDescendants(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/', json, now, ContentType.JSON)
then: 'bookstore name has been updated'
def result = objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', DIRECT_CHILDREN_ONLY)
result.leaves.'bookstore-name'[0] == 'new bookstore'
@@ -419,7 +420,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'Updated json for bookstore data'
def jsonData = "{'book-store:books':{'lang':'English/French','price':100,'title':'Matilda'}}"
when: 'update is performed for leaves'
- objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now)
+ objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now, ContentType.JSON)
then: 'the updated data nodes are retrieved'
def result = cpsDataService.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code=1]/books[@title='Matilda']", INCLUDE_ALL_DESCENDANTS)
and: 'the leaf values are updated as expected'
@@ -433,7 +434,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'Updated json for bookstore data'
def jsonData = "{'book-store:books':{'title':'Matilda', 'authors': ['beta', 'alpha', 'gamma', 'delta']}}"
when: 'update is performed for leaves'
- objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now)
+ objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now, ContentType.JSON)
and: 'the updated data nodes are retrieved'
def result = cpsDataService.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code=1]/books[@title='Matilda']", INCLUDE_ALL_DESCENDANTS)
then: 'the leaf-list values have expected order'
@@ -446,7 +447,7 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
given: 'Updated json for bookstore data'
def jsonData = "{'book-store:books':{'title':'Matilda', 'editions': [2011, 1988, 2001, 2022, 2025]}}"
when: 'update is performed for leaves'
- objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now)
+ objectUnderTest.updateNodeLeaves(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code='1']", jsonData, now, ContentType.JSON)
and: 'the updated data nodes are retrieved'
def result = cpsDataService.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_2, "/bookstore/categories[@code=1]/books[@title='Matilda']", INCLUDE_ALL_DESCENDANTS)
then: 'the leaf-list values have natural order'
@@ -455,20 +456,22 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
restoreBookstoreDataAnchor(2)
}
- def 'Get delta between 2 anchors for when #scenario'() {
+ def 'Get delta between 2 anchors'() {
when: 'attempt to get delta report between anchors'
def result = objectUnderTest.getDeltaByDataspaceAndAnchors(FUNCTIONAL_TEST_DATASPACE_3, BOOKSTORE_ANCHOR_3, BOOKSTORE_ANCHOR_5, '/', OMIT_DESCENDANTS)
+ and: 'report is ordered based on xpath'
+ result = result.toList().sort { it.xpath }
then: 'delta report contains expected number of changes'
result.size() == 3
- and: 'delta report contains UPDATE action with expected xpath'
- assert result[0].getAction() == 'update'
+ and: 'delta report contains REPLACE action with expected xpath'
+ assert result[0].getAction() == 'replace'
assert result[0].getXpath() == '/bookstore'
+ and: 'delta report contains CREATE action with expected xpath'
+ assert result[1].getAction() == 'create'
+ assert result[1].getXpath() == "/bookstore-address[@bookstore-name='Crossword Bookstores']"
and: 'delta report contains REMOVE action with expected xpath'
- assert result[1].getAction() == 'remove'
- assert result[1].getXpath() == "/bookstore-address[@bookstore-name='Easons-1']"
- and: 'delta report contains ADD action with expected xpath'
- assert result[2].getAction() == 'add'
- assert result[2].getXpath() == "/bookstore-address[@bookstore-name='Crossword Bookstores']"
+ assert result[2].getAction() == 'remove'
+ assert result[2].getXpath() == "/bookstore-address[@bookstore-name='Easons-1']"
}
def 'Get delta between 2 anchors returns empty response when #scenario'() {
@@ -512,11 +515,11 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
'is empty' | "/bookstore/container-without-leaves"
}
- def 'Get delta between anchors for add action, where target data node #scenario'() {
+ def 'Get delta between anchors for "create" action, where target data node #scenario'() {
when: 'attempt to get delta between leaves of data nodes present in 2 anchors'
def result = objectUnderTest.getDeltaByDataspaceAndAnchors(FUNCTIONAL_TEST_DATASPACE_3, BOOKSTORE_ANCHOR_3, BOOKSTORE_ANCHOR_5, parentNodeXpath, INCLUDE_ALL_DESCENDANTS)
then: 'the expected action is present in delta report'
- result.get(0).getAction() == 'add'
+ result.get(0).getAction() == 'create'
and: 'the expected xapth is present in delta report'
result.get(0).getXpath() == parentNodeXpath
where: 'following data was used'
@@ -530,8 +533,8 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
def 'Get delta between anchors when leaves of existing data nodes are updated,: #scenario'() {
when: 'attempt to get delta between leaves of existing data nodes'
def result = objectUnderTest.getDeltaByDataspaceAndAnchors(FUNCTIONAL_TEST_DATASPACE_3, sourceAnchor, targetAnchor, xpath, OMIT_DESCENDANTS)
- then: 'expected action is update'
- assert result[0].getAction() == 'update'
+ then: 'expected action is "replace"'
+ assert result[0].getAction() == 'replace'
and: 'the payload has expected leaf values'
def sourceData = result[0].getSourceData()
def targetData = result[0].getTargetData()
@@ -547,8 +550,8 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
def 'Get delta between anchors when child data nodes under existing parent data nodes are updated: #scenario'() {
when: 'attempt to get delta between leaves of existing data nodes'
def result = objectUnderTest.getDeltaByDataspaceAndAnchors(FUNCTIONAL_TEST_DATASPACE_3, sourceAnchor, targetAnchor, xpath, DIRECT_CHILDREN_ONLY)
- then: 'expected action is update'
- assert result[0].getAction() == 'update'
+ then: 'expected action is "replace"'
+ assert result[0].getAction() == 'replace'
and: 'the delta report has expected child node xpaths'
def deltaReportEntities = getDeltaReportEntities(result)
def childNodeXpathsInDeltaReport = deltaReportEntities.get('xpaths')
@@ -570,8 +573,8 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
when: 'attempt to get delta between leaves of existing data nodes'
def result = objectUnderTest.getDeltaByDataspaceAndAnchors(FUNCTIONAL_TEST_DATASPACE_3, BOOKSTORE_ANCHOR_3, BOOKSTORE_ANCHOR_5, parentNodeXpath, INCLUDE_ALL_DESCENDANTS)
def deltaReportEntities = getDeltaReportEntities(result)
- then: 'expected action is update'
- assert result[0].getAction() == 'update'
+ then: 'expected action is "replace"'
+ assert result[0].getAction() == 'replace'
and: 'the payload has expected parent node xpath'
assert deltaReportEntities.get('xpaths').contains(parentNodeXpath)
and: 'delta report has expected source and target data'
@@ -584,6 +587,46 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
assert deltaReportEntities.get('targetPayload').containsAll(expectedTargetDataInChildNode)
}
+ def 'Get delta between anchor and JSON payload'() {
+ when: 'attempt to get delta report between anchor and JSON payload'
+ def jsonPayload = "{\"book-store:bookstore\":{\"bookstore-name\":\"Crossword Bookstores\"},\"book-store:bookstore-address\":{\"address\":\"Bangalore, India\",\"postal-code\":\"560062\",\"bookstore-name\":\"Crossword Bookstores\"}}"
+ def result = objectUnderTest.getDeltaByDataspaceAnchorAndPayload(FUNCTIONAL_TEST_DATASPACE_3, BOOKSTORE_ANCHOR_3, '/', [:], jsonPayload, OMIT_DESCENDANTS)
+ then: 'delta report contains expected number of changes'
+ result.size() == 3
+ and: 'delta report contains "replace" action with expected xpath'
+ assert result[0].getAction() == 'replace'
+ assert result[0].getXpath() == '/bookstore'
+ and: 'delta report contains "remove" action with expected xpath'
+ assert result[1].getAction() == 'remove'
+ assert result[1].getXpath() == "/bookstore-address[@bookstore-name='Easons-1']"
+ and: 'delta report contains "create" action with expected xpath'
+ assert result[2].getAction() == 'create'
+ assert result[2].getXpath() == "/bookstore-address[@bookstore-name='Crossword Bookstores']"
+ }
+
+ def 'Get delta between anchor and payload returns empty response when JSON payload is identical to anchor data'() {
+ when: 'attempt to get delta report between anchor and JSON payload (replacing the string Easons with Easons-1 because the data in JSON file is modified, to append anchor number, during the setup process of the integration tests)'
+ def jsonPayload = readResourceDataFile('bookstore/bookstoreData.json').replace('Easons', 'Easons-1')
+ def result = objectUnderTest.getDeltaByDataspaceAnchorAndPayload(FUNCTIONAL_TEST_DATASPACE_3, BOOKSTORE_ANCHOR_3, '/', [:], jsonPayload, INCLUDE_ALL_DESCENDANTS)
+ then: 'delta report is empty'
+ assert result.isEmpty()
+ }
+
+ def 'Get delta between anchor and payload error scenario: #scenario'() {
+ when: 'attempt to get delta between anchor and json payload'
+ objectUnderTest.getDeltaByDataspaceAnchorAndPayload(dataspaceName, sourceAnchor, xpath, [:], jsonPayload, INCLUDE_ALL_DESCENDANTS)
+ then: 'expected exception is thrown'
+ thrown(expectedException)
+ where: 'following data was used'
+ scenario | dataspaceName | sourceAnchor | xpath | jsonPayload || expectedException
+ 'invalid dataspace name' | 'Invalid dataspace' | 'not-relevant' | '/' | '{some-json}' || DataValidationException
+ 'invalid anchor name' | FUNCTIONAL_TEST_DATASPACE_3 | 'invalid anchor' | '/' | '{some-json}' || DataValidationException
+ 'non-existing dataspace' | 'non-existing' | 'not-relevant' | '/' | '{some-json}' || DataspaceNotFoundException
+ 'non-existing anchor' | FUNCTIONAL_TEST_DATASPACE_3 | 'non-existing-anchor' | '/' | '{some-json}' || AnchorNotFoundException
+ 'empty json payload with root node xpath' | FUNCTIONAL_TEST_DATASPACE_3 | BOOKSTORE_ANCHOR_3 | '/' | '' || DataValidationException
+ 'empty json payload with non-root node xpath' | FUNCTIONAL_TEST_DATASPACE_3 | BOOKSTORE_ANCHOR_3 | '/bookstore' | '' || DataValidationException
+ }
+
def getDeltaReportEntities(List<DeltaReport> deltaReport) {
def xpaths = []
def action = []
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataspaceServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy
index 739e802244..d69f6cca0c 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataspaceServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy
@@ -18,15 +18,15 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.cps
import org.onap.cps.api.CpsDataspaceService
-import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.integration.base.FunctionalSpecBase
import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.exceptions.DataspaceInUseException
import org.onap.cps.spi.exceptions.DataspaceNotFoundException
-class CpsDataspaceServiceIntegrationSpec extends CpsIntegrationSpecBase {
+class DataspaceServiceIntegrationSpec extends FunctionalSpecBase {
CpsDataspaceService objectUnderTest
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy
index b7b6fa11a7..0e465d84a0 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.cps
import org.onap.cps.api.CpsModuleService
import org.onap.cps.integration.base.FunctionalSpecBase
@@ -31,7 +31,7 @@ import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
-class CpsModuleServiceIntegrationSpec extends FunctionalSpecBase {
+class ModuleServiceIntegrationSpec extends FunctionalSpecBase {
CpsModuleService objectUnderTest
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy
index 146ea95e8b..5c2a4fc665 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/QueryServiceIntegrationSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
+ * Copyright (C) 2023-2024 Nordix Foundation
* Modifications Copyright (C) 2023 TechMahindra Ltd
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
@@ -19,7 +19,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.cps
import java.time.OffsetDateTime
import org.onap.cps.api.CpsQueryService
@@ -33,7 +33,7 @@ import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
import static org.onap.cps.spi.PaginationOption.NO_PAGINATION
-class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase {
+class QueryServiceIntegrationSpec extends FunctionalSpecBase {
CpsQueryService objectUnderTest
@@ -382,7 +382,7 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase {
def result = objectUnderTest.queryDataNodesAcrossAnchors(FUNCTIONAL_TEST_DATASPACE_1, '/bookstore', OMIT_DESCENDANTS, new PaginationOption(pageIndex, pageSize))
then: 'correct bookstore names are queried'
def bookstoreNames = result.collect { it.getLeaves().get('bookstore-name') }
- assert bookstoreNames.toList() == expectedBookstoreNames
+ assert bookstoreNames.toSet() == expectedBookstoreNames.toSet()
and: 'the correct number of page size is returned'
assert result.size() == expectedPageSize
and: 'the queried nodes have expected anchor names'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/SessionManagerIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/SessionManagerIntegrationSpec.groovy
index e0a2602b23..ad153d6a4a 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/SessionManagerIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/SessionManagerIntegrationSpec.groovy
@@ -18,11 +18,11 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.cps
import org.onap.cps.integration.base.FunctionalSpecBase
+import org.onap.cps.ri.utils.SessionManager
import org.onap.cps.spi.exceptions.SessionManagerException
-import org.onap.cps.spi.utils.SessionManager
class SessionManagerIntegrationSpec extends FunctionalSpecBase {
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy
new file mode 100644
index 0000000000..222b3c0f6f
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy
@@ -0,0 +1,54 @@
+/*
+ * ============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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+
+class AlternateIdSpec extends CpsIntegrationSpecBase {
+
+ def setup() {
+ dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'alternateId')
+ }
+
+ def cleanup() {
+ deregisterCmHandle(DMI1_URL, 'ch-1')
+ }
+
+ def 'AlternateId in pass-through data operations should return OK status.'() {
+ given: 'the URL for the pass-through data request'
+ def url = '/ncmp/v1/ch/alternateId/data/ds/ncmp-datastore:passthrough-running'
+ when: 'a pass-through data request is sent to NCMP'
+ def response = mvc.perform(get(url)
+ .queryParam('resourceIdentifier', 'my-resource-id')
+ .contentType(MediaType.APPLICATION_JSON))
+ .andReturn().response
+ then: 'response status is Ok'
+ assert response.status == HttpStatus.OK.value()
+ }
+
+
+
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/BearerTokenPassthroughSpec.groovy
index 4ffe586a99..99e80323c2 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/BearerTokenPassthroughSpec.groovy
@@ -18,51 +18,30 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.springframework.http.HttpHeaders
+import org.springframework.http.MediaType
+import spock.util.concurrent.PollingConditions
-import static org.springframework.http.HttpMethod.GET
import static org.springframework.http.HttpMethod.DELETE
+import static org.springframework.http.HttpMethod.GET
import static org.springframework.http.HttpMethod.PATCH
import static org.springframework.http.HttpMethod.POST
import static org.springframework.http.HttpMethod.PUT
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
-import okhttp3.mockwebserver.Dispatcher
-import okhttp3.mockwebserver.MockResponse
-import okhttp3.mockwebserver.RecordedRequest
-import org.jetbrains.annotations.NotNull
-import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.springframework.http.HttpHeaders
-import org.springframework.http.HttpStatus
-import org.springframework.http.MediaType
-import spock.util.concurrent.PollingConditions
-
-class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
-
- def lastAuthHeaderReceived = null
+class BearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
def setup() {
- dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
- registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG)
-
- mockDmiServer.setDispatcher(new Dispatcher() {
- @Override
- MockResponse dispatch(@NotNull RecordedRequest request) throws InterruptedException {
- if (request.path == '/actuator/health') {
- return new MockResponse()
- .addHeader("Content-Type", MediaType.APPLICATION_JSON).setBody('{"status":"UP"}')
- .setResponseCode(HttpStatus.OK.value())
- } else {
- lastAuthHeaderReceived = request.getHeader('Authorization')
- return new MockResponse().setResponseCode(HttpStatus.OK.value())
- }
- }
- })
+ dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG)
}
def cleanup() {
- deregisterCmHandle(DMI_URL, 'ch-1')
+ deregisterCmHandle(DMI1_URL, 'ch-1')
}
def 'Bearer token is passed from NCMP to DMI in pass-through data operations.'() {
@@ -75,7 +54,7 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI has received request with bearer token'
- lastAuthHeaderReceived == 'Bearer some-bearer-token'
+ assert dmiDispatcher1.lastAuthHeaderReceived == 'Bearer some-bearer-token'
where: 'all HTTP operations are applied'
httpMethod << [GET, POST, PUT, PATCH, DELETE]
@@ -91,7 +70,7 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI has received request with no authorization header'
- lastAuthHeaderReceived == null
+ assert dmiDispatcher1.lastAuthHeaderReceived == null
where: 'all HTTP operations are applied'
httpMethod << [GET, POST, PUT, PATCH, DELETE]
@@ -115,7 +94,7 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
then: 'DMI will receive the async request with bearer token'
new PollingConditions().within(3, () -> {
- assert lastAuthHeaderReceived == 'Bearer some-bearer-token'
+ assert dmiDispatcher1.lastAuthHeaderReceived == 'Bearer some-bearer-token'
})
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy
index 5c337f179b..10a9f15e21 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy
@@ -18,44 +18,46 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.ncmp
-import java.time.Duration
-import java.time.OffsetDateTime
import org.apache.kafka.common.TopicPartition
import org.apache.kafka.common.serialization.StringDeserializer
import org.onap.cps.integration.KafkaTestContainer
import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.api.NcmpResponseStatus
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.events.lcm.v1.LcmEvent
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
import spock.util.concurrent.PollingConditions
-class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
+import java.time.Duration
+import java.time.OffsetDateTime
+
+class CmHandleCreateSpec extends CpsIntegrationSpecBase {
- NetworkCmProxyDataService objectUnderTest
+ NetworkCmProxyInventoryFacade objectUnderTest
def kafkaConsumer = KafkaTestContainer.getConsumer('ncmp-group', StringDeserializer.class)
def setup() {
- objectUnderTest = networkCmProxyDataService
+ objectUnderTest = networkCmProxyInventoryFacade
}
def 'CM Handle registration is successful.'() {
given: 'DMI will return modules when requested'
- dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
+ dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
and: 'consumer subscribed to topic'
kafkaConsumer.subscribe(['ncmp-events'])
when: 'a CM-handle is registered for creation'
def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
- def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI1_URL, createdCmHandles: [cmHandleToCreate])
+ def dmiPluginRegistrationResponse = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'registration gives successful response'
assert dmiPluginRegistrationResponse.createdCmHandles == [CmHandleRegistrationResponse.createSuccessResponse('ch-1')]
@@ -63,11 +65,8 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
and: 'CM-handle is initially in ADVISED state'
assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
- when: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
-
- then: 'CM-handle goes to READY state'
- new PollingConditions().within(3, () -> {
+ and: 'CM-handle goes to READY state after module sync'
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
})
@@ -83,23 +82,20 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
cleanup: 'deregister CM handle'
- deregisterCmHandle(DMI_URL, 'ch-1')
+ deregisterCmHandle(DMI1_URL, 'ch-1')
}
def 'CM Handle goes to LOCKED state when DMI gives error during module sync.'() {
given: 'DMI is not available to handle requests'
- dmiDispatcher.isAvailable = false
+ dmiDispatcher1.isAvailable = false
when: 'a CM-handle is registered for creation'
def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
-
- and: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI1_URL, createdCmHandles: [cmHandleToCreate])
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'CM-handle goes to LOCKED state with reason MODULE_SYNC_FAILED'
- new PollingConditions().within(3, () -> {
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState('ch-1')
assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_SYNC_FAILED
@@ -109,23 +105,22 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
assert objectUnderTest.getYangResourcesModuleReferences('ch-1').empty
cleanup: 'deregister CM handle'
- deregisterCmHandle(DMI_URL, 'ch-1')
+ deregisterCmHandle(DMI1_URL, 'ch-1')
}
def 'Create a CM-handle with existing moduleSetTag.'() {
given: 'DMI will return modules when requested'
- dmiDispatcher.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']]
+ dmiDispatcher1.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']]
and: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
- registerCmHandle(DMI_URL, 'ch-1', 'A')
- registerCmHandle(DMI_URL, 'ch-2', 'B')
+ registerCmHandle(DMI1_URL, 'ch-1', 'A')
+ registerCmHandle(DMI1_URL, 'ch-2', 'B')
when: 'a CM-handle is registered for creation with moduleSetTag "B"'
def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-3', moduleSetTag: 'B')
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate]))
+ objectUnderTest.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI1_URL, createdCmHandles: [cmHandleToCreate]))
- then: 'the CM-handle goes to READY state after module sync'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
- new PollingConditions().within(3, () -> {
+ then: 'the CM-handle goes to READY state'
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-3').cmHandleState
})
@@ -136,53 +131,71 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-3').moduleName.sort()
cleanup: 'deregister CM handles'
- deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2', 'ch-3'])
+ deregisterCmHandles(DMI1_URL, ['ch-1', 'ch-2', 'ch-3'])
+ }
+
+ def 'Create CM-handles with alternate IDs.'() {
+ given: 'DMI will return modules for all CM-handles when requested'
+ dmiDispatcher1.moduleNamesPerCmHandleId = (1..7).collectEntries{ ['ch-'+it, ['M1']] }
+ and: 'an existing CM-handle with an alternate ID'
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'existing-alt-id')
+ and: 'an existing CM-handle with no alternate ID'
+ registerCmHandle(DMI1_URL, 'ch-2', NO_MODULE_SET_TAG, NO_ALTERNATE_ID)
+
+ when: 'a batch of CM-handles is registered for creation with various alternate IDs'
+ def cmHandlesToCreate = [
+ new NcmpServiceCmHandle(cmHandleId: 'ch-3', alternateId: NO_ALTERNATE_ID),
+ new NcmpServiceCmHandle(cmHandleId: 'ch-4', alternateId: 'unique-alt-id'),
+ new NcmpServiceCmHandle(cmHandleId: 'ch-5', alternateId: 'existing-alt-id'),
+ new NcmpServiceCmHandle(cmHandleId: 'ch-6', alternateId: 'duplicate-alt-id'),
+ new NcmpServiceCmHandle(cmHandleId: 'ch-7', alternateId: 'duplicate-alt-id'),
+ ]
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI1_URL, createdCmHandles: cmHandlesToCreate)
+ def dmiPluginRegistrationResponse = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+
+ then: 'registration gives expected responses'
+ assert dmiPluginRegistrationResponse.createdCmHandles.sort { it.cmHandle } == [
+ CmHandleRegistrationResponse.createSuccessResponse('ch-3'),
+ CmHandleRegistrationResponse.createSuccessResponse('ch-4'),
+ CmHandleRegistrationResponse.createFailureResponse('ch-5', NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED),
+ CmHandleRegistrationResponse.createSuccessResponse('ch-6'),
+ CmHandleRegistrationResponse.createFailureResponse('ch-7', NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED),
+ ]
+
+ cleanup: 'deregister CM handles'
+ deregisterCmHandles(DMI1_URL, (1..7).collect{ 'ch-'+it })
}
def 'CM Handle retry after failed module sync.'() {
given: 'DMI is not initially available to handle requests'
- dmiDispatcher.isAvailable = false
+ dmiDispatcher1.isAvailable = false
when: 'CM-handles are registered for creation'
def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'ch-1'), new NcmpServiceCmHandle(cmHandleId: 'ch-2')]
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: cmHandlesToCreate)
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
- and: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI1_URL, createdCmHandles: cmHandlesToCreate)
+ objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'CM-handles go to LOCKED state'
- new PollingConditions().within(3, () -> {
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.LOCKED
- assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.LOCKED
})
- when: 'we wait for LOCKED CM handle retry time (actually just subtract 3 minutes from handles lastUpdateTime)'
- overrideCmHandleLastUpdateTime('ch-1', OffsetDateTime.now().minusMinutes(3))
- overrideCmHandleLastUpdateTime('ch-2', OffsetDateTime.now().minusMinutes(3))
- and: 'failed CM handles are reset'
- moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
- then: 'CM-handles are ADVISED state'
- assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.ADVISED
- assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.ADVISED
-
when: 'DMI is available for retry'
- dmiDispatcher.isAvailable = true
- and: 'DMI will return expected modules'
- dmiDispatcher.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']]
- and: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
- then: 'CM-handles go to READY state'
- new PollingConditions().within(3, () -> {
- assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.READY
- assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.READY
+ dmiDispatcher1.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M2']]
+ dmiDispatcher1.isAvailable = true
+
+ then: 'Both CM-handles go to READY state'
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
+ ['ch-1', 'ch-2'].each { cmHandleId ->
+ assert objectUnderTest.getCmHandleCompositeState(cmHandleId).cmHandleState == CmHandleState.READY
+ }
})
- and: 'CM-handles have expected modules'
- assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
- assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-2').moduleName.sort()
- and: 'CM-handles have expected module set tags (blank)'
- assert objectUnderTest.getNcmpServiceCmHandle('ch-1').moduleSetTag == ''
- assert objectUnderTest.getNcmpServiceCmHandle('ch-2').moduleSetTag == ''
- cleanup: 'deregister CM handle'
- deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2'])
+ and: 'Both CM-handles have expected modules'
+ ['ch-1', 'ch-2'].each { cmHandleId ->
+ assert objectUnderTest.getYangResourcesModuleReferences(cmHandleId).moduleName.sort() == ['M1', 'M2']
+ }
+
+ cleanup: 'deregister CM handles'
+ deregisterCmHandles(DMI1_URL, ['ch-1', 'ch-2'])
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy
new file mode 100644
index 0000000000..2d1588ecf9
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy
@@ -0,0 +1,89 @@
+/*
+ * ============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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.NcmpResponseStatus
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+
+class CmHandleUpdateSpec extends CpsIntegrationSpecBase {
+
+ NetworkCmProxyInventoryFacade objectUnderTest
+
+ def setup() {
+ objectUnderTest = networkCmProxyInventoryFacade
+ }
+
+ def 'Update of CM-handle with new or unchanged alternate ID succeeds.'() {
+ given: 'DMI will return modules when requested'
+ dmiDispatcher1.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2']]
+ and: "existing CM-handle with alternate ID: $oldAlternateId"
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, oldAlternateId)
+
+ when: "CM-handle is registered for update with new alternate ID: $newAlternateId"
+ def cmHandleToUpdate = new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: newAlternateId)
+ def dmiPluginRegistrationResponse =
+ objectUnderTest.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI1_URL, updatedCmHandles: [cmHandleToUpdate]))
+
+ then: 'registration gives successful response'
+ assert dmiPluginRegistrationResponse.updatedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse('ch-1')]
+
+ and: 'the CM-handle has expected alternate ID'
+ assert objectUnderTest.getNcmpServiceCmHandle('ch-1').alternateId == expectedAlternateId
+
+ cleanup: 'deregister CM handles'
+ deregisterCmHandle(DMI1_URL, 'ch-1')
+
+ where:
+ oldAlternateId | newAlternateId || expectedAlternateId
+ '' | '' || ''
+ '' | 'new' || 'new'
+ 'old' | 'old' || 'old'
+ 'old' | null || 'old'
+ 'old' | '' || 'old'
+ 'old' | ' ' || 'old'
+ }
+
+ def 'Update of CM-handle with previously set alternate ID fails.'() {
+ given: 'DMI will return modules when requested'
+ dmiDispatcher1.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2']]
+ and: 'existing CM-handle with alternate ID'
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'original')
+
+ when: 'a CM-handle is registered for update with new alternate ID'
+ def cmHandleToUpdate = new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: 'new')
+ def dmiPluginRegistrationResponse =
+ objectUnderTest.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI1_URL, updatedCmHandles: [cmHandleToUpdate]))
+
+ then: 'registration gives failure response, due to alternate ID being already associated'
+ assert dmiPluginRegistrationResponse.updatedCmHandles == [CmHandleRegistrationResponse.createFailureResponse('ch-1', NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED)]
+
+ and: 'the CM-handle still has the old alternate ID'
+ assert objectUnderTest.getNcmpServiceCmHandle('ch-1').alternateId == 'original'
+
+ cleanup: 'deregister CM handles'
+ deregisterCmHandle(DMI1_URL, 'ch-1')
+ }
+
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy
index 4d1d77e694..f93f58ce20 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy
@@ -18,38 +18,38 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.ncmp
import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.UpgradedCmHandles
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.inventory.models.UpgradedCmHandles
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
import spock.util.concurrent.PollingConditions
-class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
+class CmHandleUpgradeSpec extends CpsIntegrationSpecBase {
- NetworkCmProxyDataService objectUnderTest
+ NetworkCmProxyInventoryFacade objectUnderTest
static final CM_HANDLE_ID = 'ch-1'
static final CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG = 'ch-2'
def setup() {
- objectUnderTest = networkCmProxyDataService
+ objectUnderTest = networkCmProxyInventoryFacade
}
def 'Upgrade CM-handle with new moduleSetTag or no moduleSetTag.'() {
given: 'a CM-handle is created with expected initial modules: M1 and M2'
- dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
- registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag)
+ dmiDispatcher1.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
+ registerCmHandle(DMI1_URL, CM_HANDLE_ID, initialModuleSetTag)
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
when: "the CM-handle is upgraded with given moduleSetTag '${updatedModuleSetTag}'"
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: updatedModuleSetTag)
- def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
- new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+ def dmiPluginRegistrationResponse = objectUnderTest.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI1_URL, upgradedCmHandles: cmHandlesToUpgrade))
then: 'registration gives successful response'
assert dmiPluginRegistrationResponse.upgradedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(CM_HANDLE_ID)]
@@ -61,15 +61,12 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
assert cmHandleCompositeState.lockReason.details == "Upgrade to ModuleSetTag: ${updatedModuleSetTag}"
when: 'DMI will return different modules for upgrade: M1 and M3'
- dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M3']
- and: 'module sync runs'
- moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ dmiDispatcher1.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M3']
then: 'CM-handle goes to READY state'
- new PollingConditions().eventually {
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
- }
+ })
and: 'the CM-handle has expected moduleSetTag'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
@@ -78,7 +75,7 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
cleanup: 'deregister CM-handle'
- deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+ deregisterCmHandle(DMI1_URL, CM_HANDLE_ID)
where:
initialModuleSetTag | updatedModuleSetTag
@@ -90,31 +87,27 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
def 'Upgrade CM-handle with existing moduleSetTag.'() {
given: 'DMI will return modules for registration'
- dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
- dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG] = ['M1', 'M3']
+ dmiDispatcher1.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
+ dmiDispatcher1.moduleNamesPerCmHandleId[CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG] = ['M1', 'M3']
and: "an existing CM-handle handle with moduleSetTag '${updatedModuleSetTag}'"
- registerCmHandle(DMI_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, updatedModuleSetTag)
+ registerCmHandle(DMI1_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, updatedModuleSetTag)
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG).moduleName.sort()
and: "a CM-handle with moduleSetTag '${initialModuleSetTag}' which will be upgraded"
- registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag)
+ registerCmHandle(DMI1_URL, CM_HANDLE_ID, initialModuleSetTag)
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
when: "CM-handle is upgraded to moduleSetTag '${updatedModuleSetTag}'"
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: updatedModuleSetTag)
- def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
- new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+ def dmiPluginRegistrationResponse = objectUnderTest.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI1_URL, upgradedCmHandles: cmHandlesToUpgrade))
then: 'registration gives successful response'
assert dmiPluginRegistrationResponse.upgradedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(CM_HANDLE_ID)]
- when: 'module sync runs'
- moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
-
- then: 'CM-handle goes to READY state'
- new PollingConditions().eventually {
+ and: 'CM-handle goes to READY state'
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
- }
+ })
and: 'the CM-handle has expected moduleSetTag'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
@@ -123,7 +116,7 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
cleanup: 'deregister CM-handle'
- deregisterCmHandles(DMI_URL, [CM_HANDLE_ID, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG])
+ deregisterCmHandles(DMI1_URL, [CM_HANDLE_ID, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG])
where:
initialModuleSetTag | updatedModuleSetTag
@@ -133,14 +126,14 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
def 'Skip upgrade of CM-handle with same moduleSetTag as before.'() {
given: 'an existing CM-handle with expected initial modules: M1 and M2'
- dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
- registerCmHandle(DMI_URL, CM_HANDLE_ID, 'same')
+ dmiDispatcher1.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
+ registerCmHandle(DMI1_URL, CM_HANDLE_ID, 'same')
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
when: 'CM-handle is upgraded with the same moduleSetTag'
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: 'same')
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
- new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+ objectUnderTest.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI1_URL, upgradedCmHandles: cmHandlesToUpgrade))
then: 'CM-handle remains in READY state'
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
@@ -152,37 +145,33 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
cleanup: 'deregister CM-handle'
- deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+ deregisterCmHandle(DMI1_URL, CM_HANDLE_ID)
}
def 'Upgrade of CM-handle fails due to DMI error.'() {
given: 'a CM-handle exists'
- dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
- registerCmHandle(DMI_URL, CM_HANDLE_ID, 'oldTag')
+ dmiDispatcher1.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
+ registerCmHandle(DMI1_URL, CM_HANDLE_ID, 'oldTag')
and: 'DMI is not available for upgrade'
- dmiDispatcher.isAvailable = false
+ dmiDispatcher1.isAvailable = false
when: 'the CM-handle is upgraded'
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: 'newTag')
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
- new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
-
- and: 'module sync runs'
- moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ objectUnderTest.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI1_URL, upgradedCmHandles: cmHandlesToUpgrade))
then: 'CM-handle goes to LOCKED state with reason MODULE_UPGRADE_FAILED'
- new PollingConditions(timeout: 3).eventually {
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID)
assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE_FAILED
- }
+ })
and: 'the CM-handle has same moduleSetTag as before'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == 'oldTag'
cleanup: 'deregister CM-handle'
- deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+ deregisterCmHandle(DMI1_URL, CM_HANDLE_ID)
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmNotificationSubscriptionSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmNotificationSubscriptionSpec.groovy
new file mode 100644
index 0000000000..a5f7d08c58
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmNotificationSubscriptionSpec.groovy
@@ -0,0 +1,112 @@
+/*
+ * ============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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService
+import org.springframework.beans.factory.annotation.Autowired
+
+import static org.onap.cps.ncmp.api.data.models.DatastoreType.PASSTHROUGH_RUNNING
+
+class CmNotificationSubscriptionSpec extends CpsIntegrationSpecBase {
+
+ @Autowired
+ CmSubscriptionPersistenceService cmSubscriptionPersistenceService
+
+ def 'Adding a new cm notification subscription'() {
+ given: 'there is no ongoing cm subscription for the following'
+ def datastoreType = PASSTHROUGH_RUNNING
+ def cmHandleId = 'ch-1'
+ def xpath = '/x/y'
+ assert cmSubscriptionPersistenceService.
+ getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() == 0
+ when: 'we add a new cm notification subscription'
+ cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandleId, xpath,
+ 'subId-1')
+ then: 'there is an ongoing cm subscription for that CM handle and xpath'
+ assert cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, xpath)
+ and: 'only one subscription id is related to now ongoing cm subscription'
+ assert cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() == 1
+ }
+
+ def 'Adding a cm notification subscription to the already existing cm handle but non existing xpath'() {
+ given: 'an ongoing cm subscription with the following details'
+ def datastoreType = PASSTHROUGH_RUNNING
+ def cmHandleId = 'ch-1'
+ def existingXpath = '/x/y'
+ assert cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, existingXpath)
+ and: 'a non existing cm subscription with same datastore name and cm handle but different xpath'
+ def nonExistingXpath = '/x2/y2'
+ assert !cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, nonExistingXpath)
+ when: 'a new cm notification subscription is made for the existing cm handle and non existing xpath'
+ cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandleId, nonExistingXpath,
+ 'subId-2')
+ then: 'there is an ongoing cm subscription for that CM handle and xpath'
+ assert cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, nonExistingXpath)
+ and: 'only one subscription id is related to now ongoing cm subscription'
+ assert cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, nonExistingXpath).size() == 1
+ }
+
+ def 'Adding a cm notification subscription to the already existing cm handle and xpath'() {
+ given: 'an ongoing cm subscription with the following details'
+ def datastoreType = PASSTHROUGH_RUNNING
+ def cmHandleId = 'ch-1'
+ def xpath = '/x/y'
+ when: 'a new cm notification subscription is made for the SAME CM handle and xpath'
+ cmSubscriptionPersistenceService.addCmSubscription(datastoreType, cmHandleId, xpath,
+ 'subId-3')
+ then: 'it is added to the ongoing list of subscription ids'
+ def subscriptionIds = cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath)
+ assert subscriptionIds.size() == 2
+ and: 'both subscription ids exists for the CM handle and xpath'
+ assert subscriptionIds.contains("subId-1") && subscriptionIds.contains("subId-3")
+ }
+
+ def 'Removing cm notification subscriber among other subscribers'() {
+ given: 'an ongoing cm subscription with the following details'
+ def datastoreType = PASSTHROUGH_RUNNING
+ def cmHandleId = 'ch-1'
+ def xpath = '/x/y'
+ and: 'the number of subscribers is as follows'
+ def originalNumberOfSubscribers =
+ cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size()
+ when: 'a subscriber is removed'
+ cmSubscriptionPersistenceService.removeCmSubscription(datastoreType, cmHandleId, xpath, 'subId-3')
+ then: 'the number of subscribers is reduced by 1'
+ def updatedNumberOfSubscribers = cmSubscriptionPersistenceService.getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size()
+ assert updatedNumberOfSubscribers == originalNumberOfSubscribers - 1
+ }
+
+ def 'Removing the LAST cm notification subscriber for a given cm handle, datastore and xpath'() {
+ given: 'an ongoing cm subscription with the following details'
+ def datastoreType = PASSTHROUGH_RUNNING
+ def cmHandleId = 'ch-1'
+ def xpath = '/x/y'
+ and: 'there is only one subscriber'
+ assert cmSubscriptionPersistenceService
+ .getOngoingCmSubscriptionIds(datastoreType, cmHandleId, xpath).size() == 1
+ when: 'only subscriber is removed'
+ cmSubscriptionPersistenceService.removeCmSubscription(datastoreType, cmHandleId, xpath, 'subId-1')
+ then: 'there are no longer any subscriptions for the cm handle, datastore and xpath'
+ assert !cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType, cmHandleId, xpath)
+ }
+
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobResultServiceSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobResultServiceSpec.groovy
new file mode 100644
index 0000000000..4d04eeeb81
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobResultServiceSpec.groovy
@@ -0,0 +1,44 @@
+/*
+ * ============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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.datajobs.DataJobResultService
+import org.springframework.beans.factory.annotation.Autowired
+
+class DataJobResultServiceSpec extends CpsIntegrationSpecBase {
+
+ @Autowired
+ DataJobResultService dataJobResultService;
+
+ def 'Get the status of a data job from DMI.'() {
+ given: 'the required data about the data job'
+ def authorization = 'my authorization header'
+ def dmiServiceName = DMI1_URL
+ def dataProducerId = 'some-data-producer-id'
+ def dataProducerJobId = 'some-data-producer-job-id'
+ def destination = 'some-destination'
+ when: 'the data job status checked'
+ def result = dataJobResultService.getDataJobResult(authorization, dmiServiceName, dataProducerId, dataProducerJobId, destination)
+ then: 'the status is that defined in the mock service.'
+ assert result == '{ "result": "some result"}'
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy
new file mode 100644
index 0000000000..6e5c0e40c2
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DataJobStatusServiceSpec.groovy
@@ -0,0 +1,23 @@
+package org.onap.cps.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.datajobs.DataJobStatusService
+import org.springframework.beans.factory.annotation.Autowired
+
+class DataJobStatusServiceSpec extends CpsIntegrationSpecBase {
+
+ @Autowired
+ DataJobStatusService dataJobStatusService
+
+ def 'Get the status of a data job from DMI.'() {
+ given: 'the required data about the data job'
+ def dmiServiceName = DMI1_URL
+ def dataProducerId = 'some-data-producer-id'
+ def dataProducerJobId = 'some-data-producer-job-id'
+ def authorization = 'my authorization header'
+ when: 'the data job status checked'
+ def result = dataJobStatusService.getDataJobStatus(authorization, dmiServiceName, dataProducerId, dataProducerJobId)
+ then: 'the status is that defined in the mock service.'
+ assert result == 'status details from mock service'
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DmiUrlEncodingPassthroughSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DmiUrlEncodingPassthroughSpec.groovy
new file mode 100644
index 0000000000..4e9b809eff
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/DmiUrlEncodingPassthroughSpec.groovy
@@ -0,0 +1,65 @@
+/*
+ * ============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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.springframework.http.MediaType
+
+import static org.springframework.http.HttpMethod.DELETE
+import static org.springframework.http.HttpMethod.GET
+import static org.springframework.http.HttpMethod.PATCH
+import static org.springframework.http.HttpMethod.POST
+import static org.springframework.http.HttpMethod.PUT
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
+
+class DmiUrlEncodingPassthroughSpec extends CpsIntegrationSpecBase {
+
+ def setup() {
+ dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG)
+ }
+
+ def cleanup() {
+ deregisterCmHandle(DMI1_URL, 'ch-1')
+ }
+
+ def 'DMI URL encoding for pass-through operational data operations with GET request'() {
+ when: 'sending a GET pass-through data request to NCMP'
+ mvc.perform(request(GET, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-operational')
+ .queryParam('resourceIdentifier', 'parent/child')
+ .queryParam('options', '(a=1,b=2)'))
+ .andExpect(status().is2xxSuccessful())
+ then: 'verify that DMI received the request with the correctly encoded URL'
+ assert dmiDispatcher1.dmiResourceDataUrl == '/dmi/v1/ch/ch-1/data/ds/ncmp-datastore%3Apassthrough-operational?resourceIdentifier=parent%2Fchild&options=%28a%3D1%2Cb%3D2%29'
+ }
+
+ def 'DMI URL encoding for pass-through running data operations with POST request'() {
+ when: 'sending a pass-through data request to NCMP with various HTTP methods'
+ mvc.perform(request(POST, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running')
+ .queryParam('resourceIdentifier', 'parent/child')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content('{ "some-json": "data" }'))
+ .andExpect(status().is2xxSuccessful())
+ then: 'verify that DMI received the request with the correctly encoded URL'
+ assert dmiDispatcher1.dmiResourceDataUrl == '/dmi/v1/ch/ch-1/data/ds/ncmp-datastore%3Apassthrough-running?resourceIdentifier=parent%2Fchild'
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy
new file mode 100644
index 0000000000..99f245ae8c
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy
@@ -0,0 +1,63 @@
+/*
+ * ============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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.springframework.http.HttpHeaders
+import org.springframework.http.MediaType
+
+import static org.springframework.http.HttpMethod.POST
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
+
+class PolicyExecutorIntegrationSpec extends CpsIntegrationSpecBase {
+
+ def setup() {
+ // Enable mocked policy executor logic
+ policyDispatcher.allowAll = false;
+ //minimum setup for 2 cm handles with alternate ids
+ dmiDispatcher1.moduleNamesPerCmHandleId = ['ch-1': [], 'ch-2': []]
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'fdn1')
+ registerCmHandle(DMI1_URL, 'ch-2', NO_MODULE_SET_TAG, 'fdn2')
+ }
+
+ def cleanup() {
+ deregisterCmHandle(DMI1_URL, 'ch-1')
+ deregisterCmHandle(DMI1_URL, 'ch-2')
+ }
+
+ def 'Policy Executor create request with #scenario.'() {
+ when: 'a pass-through write request is sent to NCMP'
+ def response = mvc.perform(request(POST, "/ncmp/v1/ch/$cmHandle/data/ds/ncmp-datastore:passthrough-running")
+ .queryParam('resourceIdentifier', 'my-resource-id')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content('{ "some-json": "data" }')
+ .header(HttpHeaders.AUTHORIZATION, authorization))
+ .andReturn().response
+ then: 'the expected status code is returned'
+ response.getStatus() == execpectedStatusCode
+ where: 'following parameters are used'
+ scenario | cmHandle | authorization || execpectedStatusCode
+ 'accepted cm handle' | 'ch-1' | 'mock expects "ABC"' || 201
+ 'un-accepted cm handle' | 'ch-2' | 'mock expects "ABC"' || 409
+ 'invalid authorization' | 'ch-1' | 'something else' || 500
+ }
+
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/RestApiSpec.groovy
index 5325f1a86e..1e1af556f1 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/RestApiSpec.groovy
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.integration.functional
+package org.onap.cps.integration.functional.ncmp
import static org.hamcrest.Matchers.containsInAnyOrder
import static org.hamcrest.Matchers.hasSize
@@ -31,29 +31,27 @@ import org.onap.cps.integration.base.CpsIntegrationSpecBase
import org.springframework.http.MediaType
import spock.util.concurrent.PollingConditions
-class NcmpRestApiSpec extends CpsIntegrationSpecBase {
+class RestApiSpec extends CpsIntegrationSpecBase {
def 'Register CM Handles using REST API.'() {
given: 'DMI will return modules'
- dmiDispatcher.moduleNamesPerCmHandleId = [
+ dmiDispatcher1.moduleNamesPerCmHandleId = [
'ch-1': ['M1', 'M2'],
'ch-2': ['M1', 'M2'],
'ch-3': ['M1', 'M3']
]
- and: 'a POST request is made to register the CM Handles'
- def requestBody = '{"dmiPlugin":"'+DMI_URL+'","createdCmHandles":[{"cmHandle":"ch-1"},{"cmHandle":"ch-2"},{"cmHandle":"ch-3"}]}'
+ when: 'a POST request is made to register the CM Handles'
+ def requestBody = '{"dmiPlugin":"'+DMI1_URL+'","createdCmHandles":[{"cmHandle":"ch-1","alternateId":"alt-1"},{"cmHandle":"ch-2","alternateId":"alt-2"},{"cmHandle":"ch-3","alternateId":"alt-3"}]}'
mvc.perform(post('/ncmpInventory/v1/ch').contentType(MediaType.APPLICATION_JSON).content(requestBody))
.andExpect(status().is2xxSuccessful())
- when: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handles go to READY state'
- new PollingConditions().eventually {
+ new PollingConditions().within(MODULE_SYNC_WAIT_TIME_IN_SECONDS, () -> {
(1..3).each {
mvc.perform(get('/ncmp/v1/ch/ch-'+it))
.andExpect(status().isOk())
.andExpect(jsonPath('$.state.cmHandleState').value('READY'))
}
- }
+ })
}
def 'Search for CM Handles by module using REST API.'() {
@@ -78,9 +76,30 @@ class NcmpRestApiSpec extends CpsIntegrationSpecBase {
'M3' || ['ch-3']
}
+ def 'Search for CM Handles using Cps Path Query.'() {
+ given: 'a JSON request body containing search parameter'
+ def requestBodyWithSearchCondition = """{
+ "cmHandleQueryParameters": [
+ {
+ "conditionName": "cmHandleWithCpsPath",
+ "conditionParameters": [ {"cpsPath" : "%s"} ]
+ }
+ ]
+ }""".formatted(cpsPath)
+ expect: "a search for cps path ${cpsPath} returns expected CM handles"
+ mvc.perform(post('/ncmp/v1/ch/id-searches').contentType(MediaType.APPLICATION_JSON).content(requestBodyWithSearchCondition))
+ .andExpect(status().is2xxSuccessful())
+ .andExpect(jsonPath('$[*]', containsInAnyOrder(expectedCmHandles.toArray())))
+ .andExpect(jsonPath('$', hasSize(expectedCmHandles.size())));
+ where:
+ scenario | cpsPath || expectedCmHandles
+ 'All Ready CM handles' | "//state[@cm-handle-state='READY']" || ['ch-1', 'ch-2', 'ch-3']
+ 'Having Alternate ID alt-3' | "//cm-handles[@alternate-id='alt-3']" || ['ch-3']
+ }
+
def 'De-register CM handles using REST API.'() {
when: 'a POST request is made to deregister the CM Handle'
- def requestBody = '{"dmiPlugin":"'+DMI_URL+'", "removedCmHandles": ["ch-1", "ch-2", "ch-3"]}'
+ def requestBody = '{"dmiPlugin":"'+DMI1_URL+'", "removedCmHandles": ["ch-1", "ch-2", "ch-3"]}'
mvc.perform(post('/ncmpInventory/v1/ch').contentType(MediaType.APPLICATION_JSON).content(requestBody))
.andExpect(status().is2xxSuccessful())
then: 'the CM handles are not found using GET'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy
new file mode 100644
index 0000000000..834e1399e3
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/WriteSubJobSpec.groovy
@@ -0,0 +1,75 @@
+/*
+ * ============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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.datajobs.DataJobService
+import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata
+import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest
+import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse
+import org.onap.cps.ncmp.api.datajobs.models.WriteOperation
+import org.springframework.beans.factory.annotation.Autowired
+
+class WriteSubJobSpec extends CpsIntegrationSpecBase {
+
+ @Autowired
+ DataJobService dataJobService
+
+ def setup() {
+ dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1']
+ dmiDispatcher1.moduleNamesPerCmHandleId['ch-2'] = ['M2']
+ dmiDispatcher2.moduleNamesPerCmHandleId['ch-3'] = ['M3']
+ registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'p1')
+ registerCmHandle(DMI1_URL, 'ch-2', NO_MODULE_SET_TAG, 'p2')
+ registerCmHandle(DMI2_URL, 'ch-3', NO_MODULE_SET_TAG, 'p3')
+ }
+
+ def cleanup() {
+ deregisterCmHandle(DMI1_URL, 'ch-1')
+ deregisterCmHandle(DMI1_URL, 'ch-2')
+ deregisterCmHandle(DMI2_URL, 'ch-3')
+ }
+
+ def 'Create a sub-job write request.'() {
+ given: 'the required input data for the write job'
+ def authorization = 'my authorization header'
+ def dataJobWriteRequest = new DataJobWriteRequest([new WriteOperation('p1', '', '', null), new WriteOperation('p2', '', '', null), new WriteOperation('p3', '', '', null)])
+ def myDataJobMetadata = new DataJobMetadata('d1', '', '')
+ def dataJobId = 'my-data-job-id'
+ when: 'sending a write job to NCMP with 2 sub-jobs for DMI 1 and 1 sub-job for DMI 2'
+ def response = dataJobService.writeDataJob(authorization, dataJobId, myDataJobMetadata, dataJobWriteRequest)
+ then: 'each DMI received the expected sub-jobs and the response has the expected values'
+ assert response.size() == 2
+ assert response[0].class == SubJobWriteResponse.class
+ assert response[0].subJobId == "some sub job id"
+ assert response[0].dmiServiceName == "some dmi service name"
+ assert response[0].dataProducerId == "some data producer id"
+ and: 'dmi 1 received the correct job details'
+ def receivedSubJobsForDispatcher1 = dmiDispatcher1.receivedSubJobs['?destination=d1']['data'].collect()
+ assert receivedSubJobsForDispatcher1.size() == 2
+ assert receivedSubJobsForDispatcher1[0]['path'] == 'p1'
+ assert receivedSubJobsForDispatcher1[1]['path'] == 'p2'
+ and: 'dmi 2 received the correct job details'
+ def receivedSubJobsForDispatcher2 = dmiDispatcher2.receivedSubJobs['?destination=d1']['data'].collect()
+ assert receivedSubJobsForDispatcher2.size() == 1
+ assert receivedSubJobsForDispatcher2[0]['path'] == 'p3'
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy
index cbbf1d9be0..f6ae27d129 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023-2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -20,11 +21,12 @@
package org.onap.cps.integration.performance.base
-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 org.onap.cps.integration.ResourceMeter
import org.onap.cps.spi.FetchDescendantsOption
+import org.onap.cps.utils.ContentType
+
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
class NcmpPerfTestBase extends PerfTestBase {
@@ -79,7 +81,7 @@ class NcmpPerfTestBase extends PerfTestBase {
def batchSize = 100
for (def i = 0; i < TOTAL_CM_HANDLES; i += batchSize) {
def data = '{ "cm-handles": [' + (1..batchSize).collect { innerNodeJsonTemplate.replace('CMHANDLE_ID_HERE', (it + i).toString()) }.join(',') + ']}'
- cpsDataService.saveListElements(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, '/dmi-registry', data, now)
+ cpsDataService.saveListElements(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, '/dmi-registry', data, now, ContentType.JSON)
}
}
@@ -91,7 +93,7 @@ class NcmpPerfTestBase extends PerfTestBase {
innerNodeJsonTemplate.replace('CM_HANDLE_ID_HERE', (it + i).toString())
.replace('ALTERNATE_ID_AS_PATH', (it + i).toString())
}.join(',') + ']}'
- cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry', data, now)
+ cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry', data, now, ContentType.JSON)
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy
index e1235272fe..ab8ffe7c76 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/CpsDataspaceServiceLimitsPerfTest.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.
@@ -33,7 +33,7 @@ class CpsDataspaceServiceLimitsPerfTest extends CpsPerfTestBase {
given: 'more than 32,766 schema set names'
def schemaSetNames = (0..40_000).collect { "size-of-this-name-does-not-matter-for-limit-" + it }
when: 'single get is executed to get all the anchors'
- objectUnderTest.getAnchors(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetNames)
+ objectUnderTest.getAnchorsBySchemaSetNames(CPS_PERFORMANCE_TEST_DATASPACE, schemaSetNames)
then: 'a database exception is not thrown'
noExceptionThrown()
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
index 1d3943f36b..03abdb4b3f 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/UpdatePerfTest.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023-2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -22,6 +23,7 @@ package org.onap.cps.integration.performance.cps
import java.time.OffsetDateTime
import org.onap.cps.api.CpsDataService
+import org.onap.cps.utils.ContentType
import org.onap.cps.integration.performance.base.CpsPerfTestBase
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
@@ -48,7 +50,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
given: 'replacement JSON for node containing list of device nodes'
def jsonData = '{ "openroadm-devices": ' + generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves) + '}'
when: 'the container node is updated'
- objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now)
+ objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now, ContentType.JSON)
then: 'there are the expected number of total nodes'
assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
where:
@@ -66,7 +68,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
def jsonData = '{ "openroadm-devices": ' + generateJsonForOpenRoadmDevices(startId, totalNodes, changeLeaves) + '}'
when: 'the container node is updated'
resourceMeter.start()
- objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now)
+ objectUnderTest.updateDataNodeAndDescendants(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, '/', jsonData, now, ContentType.JSON)
resourceMeter.stop()
then: 'there are the expected number of total nodes'
assert totalNodes == countDataNodes('/openroadm-devices/openroadm-device')
@@ -121,7 +123,7 @@ class UpdatePerfTest extends CpsPerfTestBase {
def jsonDataUpdated = "{'openroadm-device':[" + (1..100).collect {"{'device-id':'C201-7-1A-" + it + "','status':'fail','ne-state':'jeopardy'}" }.join(",") + "]}"
when: 'update is performed for leaves'
resourceMeter.start()
- objectUnderTest.updateNodeLeaves(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, "/openroadm-devices", jsonDataUpdated, now)
+ objectUnderTest.updateNodeLeaves(CPS_PERFORMANCE_TEST_DATASPACE, UPDATE_TEST_ANCHOR, "/openroadm-devices", jsonDataUpdated, now, ContentType.JSON)
resourceMeter.stop()
then: 'data leaves have expected values'
assert 100 == countDataNodes('/openroadm-devices/openroadm-device[@status="fail"]')
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
index 0195611740..9f6c78d5f5 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/WritePerfTest.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023-2024 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -20,6 +21,8 @@
package org.onap.cps.integration.performance.cps
+import org.onap.cps.utils.ContentType
+
import java.time.OffsetDateTime
import org.onap.cps.integration.performance.base.CpsPerfTestBase
@@ -87,7 +90,7 @@ class WritePerfTest extends CpsPerfTestBase {
']}'
when: 'device nodes are added'
resourceMeter.start()
- cpsDataService.saveListElements(CPS_PERFORMANCE_TEST_DATASPACE, WRITE_TEST_ANCHOR, '/openroadm-devices', jsonListData, OffsetDateTime.now())
+ cpsDataService.saveListElements(CPS_PERFORMANCE_TEST_DATASPACE, WRITE_TEST_ANCHOR, '/openroadm-devices', jsonListData, OffsetDateTime.now(), ContentType.JSON)
resourceMeter.stop()
then: 'the operation takes less than #expectedDuration and memory used is within limit'
recordAndAssertResourceUsage("Saving list of ${totalNodes} devices",
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
index fc2f8cf00d..11f2a43db5 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2023 Nordix Foundation
+ * Modifications Copyright (C) 2024 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -23,6 +24,7 @@ package org.onap.cps.integration.performance.ncmp
import org.onap.cps.api.CpsQueryService
import org.onap.cps.integration.performance.base.NcmpPerfTestBase
import org.onap.cps.spi.model.DataNode
+import org.onap.cps.utils.ContentType
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
@@ -86,7 +88,7 @@ class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
// Around 8.5 seconds for long strings, 4.8 with short strings
// cpsDataService.updateDataNodeAndDescendants(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, parentPath, json, now)
// Around 6.5 seconds for long strings, 3.3 seconds with short strings
- cpsDataService.updateNodeLeaves(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, parentPath, json, now)
+ cpsDataService.updateNodeLeaves(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, parentPath, json, now, ContentType.JSON)
}
resourceMeter.stop()
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy
index 4f33d030ed..a2d3a4aeac 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryByAlternateIdPerfTest.groovy
@@ -22,26 +22,26 @@ package org.onap.cps.integration.performance.ncmp
import org.onap.cps.integration.ResourceMeter
import org.onap.cps.integration.performance.base.NcmpPerfTestBase
-import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
import java.util.stream.Collectors
-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.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
class CmHandleQueryByAlternateIdPerfTest extends NcmpPerfTestBase {
- InventoryPersistence objectUnderTest
+ AlternateIdMatcher objectUnderTest
ResourceMeter resourceMeter = new ResourceMeter()
- def setup() { objectUnderTest = inventoryPersistence }
+ def setup() { objectUnderTest = alternateIdMatcher }
def 'Query cm handle by longest match alternate id'() {
when: 'an alternate id as cps path query'
resourceMeter.start()
def cpsPath = "/a/b/c/d-5/e/f/g/h/i"
- def dataNodes = objectUnderTest.getCmHandleDataNodeByLongestMatchAlternateId(cpsPath, '/')
+ def dataNodes = objectUnderTest.getCmHandleDataNodeByLongestMatchingAlternateId(cpsPath, '/')
and: 'the ids of the result are extracted and converted to xpath'
def cpsXpaths = dataNodes.stream().map(dataNode -> "/dmi-registry/cm-handles[@id='${dataNode.leaves.id}']".toString() ).collect(Collectors.toSet())
and: 'a single get is executed to get all the parent objects and their descendants'
diff --git a/integration-test/src/test/java/org/onap/cps/integration/DmiStubTestContainer.java b/integration-test/src/test/java/org/onap/cps/integration/DmiStubTestContainer.java
new file mode 100644
index 0000000000..1bffb35c14
--- /dev/null
+++ b/integration-test/src/test/java/org/onap/cps/integration/DmiStubTestContainer.java
@@ -0,0 +1,61 @@
+/*
+ * ============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.integration;
+
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.utility.DockerImageName;
+
+public class DmiStubTestContainer extends GenericContainer<DmiStubTestContainer> {
+
+ public static final String IMAGE_NAME_AND_VERSION =
+ "nexus3.onap.org:10003/onap/dmi-plugin-demo-and-csit-stub:latest";
+ public static final String DMI_STUB_URL = "http://localhost:8784";
+
+ private static DmiStubTestContainer dmiStubTestContainer;
+
+ private DmiStubTestContainer() {
+ super(DockerImageName.parse(IMAGE_NAME_AND_VERSION));
+ }
+
+ /**
+ * Provides an instance of the Dmi Plugin Stub test container wrapper.
+ * This will allow to interact with the DMI Stub in our acceptance tests.
+ *
+ * @return DmiStubTestContainer
+ */
+ public static DmiStubTestContainer getInstance() {
+ if (dmiStubTestContainer == null) {
+ dmiStubTestContainer = new DmiStubTestContainer();
+ dmiStubTestContainer.addFixedExposedPort(8784, 8092);
+ Runtime.getRuntime().addShutdownHook(new Thread(dmiStubTestContainer::close));
+ }
+ return dmiStubTestContainer;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ }
+
+ @Override
+ public void stop() {
+ // Method intentionally left blank
+ }
+}
diff --git a/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java b/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java
index f8a2ecb4df..46bfcf69e6 100644
--- a/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.java
+++ b/integration-test/src/test/java/org/onap/cps/integration/ResourceMeter.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.
@@ -20,6 +20,8 @@
package org.onap.cps.integration;
+import static org.awaitility.Awaitility.await;
+
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
@@ -71,7 +73,7 @@ public class ResourceMeter {
static void performGcAndWait() {
final long gcCountBefore = getGcCount();
System.gc();
- while (getGcCount() == gcCountBefore) {}
+ await().until(() -> getGcCount() > gcCountBefore);
}
private static long getGcCount() {
@@ -94,4 +96,3 @@ public class ResourceMeter {
.forEach(MemoryPoolMXBean::resetPeakUsage);
}
}
-
diff --git a/integration-test/src/test/resources/application.yml b/integration-test/src/test/resources/application.yml
index a4b9ea9c40..760dad01af 100644
--- a/integration-test/src/test/resources/application.yml
+++ b/integration-test/src/test/resources/application.yml
@@ -179,9 +179,9 @@ ncmp:
timers:
advised-modules-sync:
- sleep-time-ms: 100000
+ sleep-time-ms: 1000
locked-modules-sync:
- sleep-time-ms: 300000
+ sleep-time-ms: 1000
cm-handle-data-sync:
sleep-time-ms: 30000
subscription-forwarding:
@@ -213,9 +213,29 @@ ncmp:
init:
mode: ALWAYS
+ policy-executor:
+ enabled: true
+ server:
+ address: http://localhost
+ port: 8790
+ httpclient:
+ all-services:
+ maximumInMemorySizeInMegabytes: 1
+ maximumConnectionsTotal: 10
+ pendingAcquireMaxCount: 10
+ connectionTimeoutInSeconds: 30
+ readTimeoutInSeconds: 30
+ writeTimeoutInSeconds: 30
+
hazelcast:
cluster-name: cps-and-ncmp-test-caches
mode:
kubernetes:
enabled: false
service-name: cps-and-ncmp-service
+
+cps:
+ tracing:
+ enabled: false
+ exporter:
+ protocol: grpc
diff --git a/jacoco-report/pom.xml b/jacoco-report/pom.xml
index 447614f396..503500f529 100644
--- a/jacoco-report/pom.xml
+++ b/jacoco-report/pom.xml
@@ -5,7 +5,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -58,6 +58,12 @@
<artifactId>integration-test</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>policy-executor-stub</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
</dependencies>
<build>
diff --git a/k6-tests/README.md b/k6-tests/README.md
new file mode 100644
index 0000000000..9a385e100a
--- /dev/null
+++ b/k6-tests/README.md
@@ -0,0 +1,24 @@
+# k6 tests
+
+[k6](https://k6.io/) is used for performance tests.
+k6 tests are written in JavaScript.
+
+## k6 installation
+Follow the instructions in the [build from source guide](https://github.com/mostafa/xk6-kafka) to get started.
+
+## Running the k6 test suites
+Simply run the main script. (The script assumes k6 and docker-compose have been installed).
+```shell
+./run-k6-tests.sh
+```
+
+## Running k6 tests manually
+Before running tests, ensure CPS/NCMP is running:
+```shell
+docker-compose -f docker-compose/docker-compose.yml --profile dmi-stub up
+```
+
+To run an individual test from command line, use
+```shell
+k6 run ncmp/ncmp-kpi.js
+```
diff --git a/k6-tests/install-deps.sh b/k6-tests/install-deps.sh
new file mode 100755
index 0000000000..bb5deb93dd
--- /dev/null
+++ b/k6-tests/install-deps.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# Copyright 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.
+#
+
+echo "---> install-deps.sh"
+echo "Installing dependencies"
+
+# Create directory for downloaded binaries.
+mkdir -p bin
+touch bin/.gitignore
+
+# Add it to the PATH, so downloaded versions will be used.
+export PATH="$(pwd)/bin:$PATH"
+
+# Download docker-compose.
+if [ ! -x bin/docker-compose ]; then
+ echo " Downloading docker-compose"
+ curl -s -L https://github.com/docker/compose/releases/download/v2.29.2/docker-compose-linux-x86_64 > bin/docker-compose
+ chmod +x bin/docker-compose
+else
+ echo " docker-compose already installed"
+fi
+docker-compose version
+
+# Download k6 with kafka extension.
+if [ ! -x bin/k6 ]; then
+ echo " Downloading k6 with kafka extension"
+ curl -s -L https://github.com/mostafa/xk6-kafka/releases/download/v0.26.0/xk6-kafka_v0.26.0_linux_amd64.tar.gz | tar -xz
+ mv dist/xk6-kafka_v0.26.0_linux_amd64 bin/k6 && rmdir dist
+ chmod +x bin/k6
+else
+ echo " k6 already installed"
+fi
+k6 --version
diff --git a/k6-tests/ncmp/common/cmhandle-crud.js b/k6-tests/ncmp/common/cmhandle-crud.js
new file mode 100644
index 0000000000..7fab62abd8
--- /dev/null
+++ b/k6-tests/ncmp/common/cmhandle-crud.js
@@ -0,0 +1,72 @@
+/*
+ * ============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=========================================================
+ */
+
+import { sleep } from 'k6';
+import { performPostRequest, NCMP_BASE_URL, DMI_PLUGIN_URL, TOTAL_CM_HANDLES, MODULE_SET_TAGS
+} from './utils.js';
+import { executeCmHandleIdSearch } from './search-base.js';
+
+export function createCmHandles(cmHandleIds) {
+ const url = `${NCMP_BASE_URL}/ncmpInventory/v1/ch`;
+ const payload = JSON.stringify(createCmHandlePayload(cmHandleIds));
+ return performPostRequest(url, payload, 'createCmHandles');
+}
+
+export function deleteCmHandles(cmHandleIds) {
+ const url = `${NCMP_BASE_URL}/ncmpInventory/v1/ch`;
+ const payload = JSON.stringify({
+ "dmiPlugin": DMI_PLUGIN_URL,
+ "removedCmHandles": cmHandleIds,
+ });
+ return performPostRequest(url, payload, 'deleteCmHandles');
+}
+
+export function waitForAllCmHandlesToBeReady() {
+ const POLLING_INTERVAL_SECONDS = 5;
+ let cmHandlesReady = 0;
+ do {
+ sleep(POLLING_INTERVAL_SECONDS);
+ cmHandlesReady = getNumberOfReadyCmHandles();
+ console.log(`${cmHandlesReady}/${TOTAL_CM_HANDLES} CM handles are READY`);
+ } while (cmHandlesReady < TOTAL_CM_HANDLES);
+}
+
+function createCmHandlePayload(cmHandleIds) {
+ return {
+ "dmiPlugin": DMI_PLUGIN_URL,
+ "createdCmHandles": cmHandleIds.map((cmHandleId, index) => ({
+ "cmHandle": cmHandleId,
+ "alternateId": cmHandleId.replace('ch-', 'alt-'),
+ "moduleSetTag": MODULE_SET_TAGS[index % MODULE_SET_TAGS.length],
+ "cmHandleProperties": {"neType": "RadioNode"},
+ "publicCmHandleProperties": {
+ "Color": "yellow",
+ "Size": "small",
+ "Shape": "cube"
+ }
+ })),
+ };
+}
+
+function getNumberOfReadyCmHandles() {
+ const response = executeCmHandleIdSearch('readyCmHandles');
+ const arrayOfCmHandleIds = JSON.parse(response.body);
+ return arrayOfCmHandleIds.length;
+}
diff --git a/k6-tests/ncmp/common/passthrough-crud.js b/k6-tests/ncmp/common/passthrough-crud.js
new file mode 100644
index 0000000000..86fcef6242
--- /dev/null
+++ b/k6-tests/ncmp/common/passthrough-crud.js
@@ -0,0 +1,74 @@
+/*
+ * ============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=========================================================
+ */
+
+import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
+import {
+ performPostRequest,
+ performGetRequest,
+ NCMP_BASE_URL,
+ LEGACY_BATCH_TOPIC_NAME,
+ TOTAL_CM_HANDLES,
+} from './utils.js';
+
+export function passthroughRead(useAlternateId) {
+ const cmHandleReference = getRandomCmHandleReference(useAlternateId);
+ const resourceIdentifier = 'my-resource-identifier';
+ const datastoreName = 'ncmp-datastore:passthrough-operational';
+ const includeDescendants = true;
+ const url = generatePassthroughUrl(cmHandleReference, datastoreName, resourceIdentifier, includeDescendants);
+ return performGetRequest(url, 'passthroughRead');
+}
+
+export function passthroughWrite(useAlternateId) {
+ const cmHandleReference = getRandomCmHandleReference(useAlternateId);
+ const resourceIdentifier = 'my-resource-identifier';
+ const datastoreName = 'ncmp-datastore:passthrough-running';
+ const includeDescendants = false;
+ const url = generatePassthroughUrl(cmHandleReference, datastoreName, resourceIdentifier, includeDescendants);
+ const payload = JSON.stringify({"neType": "BaseStation"});
+ return performPostRequest(url, payload, 'passthroughWrite');
+}
+
+export function legacyBatchRead(cmHandleIds) {
+ const url = `${NCMP_BASE_URL}/ncmp/v1/data?topic=${LEGACY_BATCH_TOPIC_NAME}`
+ const payload = JSON.stringify({
+ "operations": [
+ {
+ "resourceIdentifier": "parent/child",
+ "targetIds": cmHandleIds,
+ "datastore": "ncmp-datastore:passthrough-operational",
+ "options": "(fields=schemas/schema)",
+ "operationId": "12",
+ "operation": "read"
+ }
+ ]
+ });
+ return performPostRequest(url, payload, 'batchRead');
+}
+
+function getRandomCmHandleReference(useAlternateId) {
+ const prefix = useAlternateId ? 'alt' : 'ch';
+ return `${prefix}-${randomIntBetween(1, TOTAL_CM_HANDLES)}`;
+}
+
+function generatePassthroughUrl(cmHandleReference, datastoreName, resourceIdentifier, includeDescendants) {
+ const descendantsParam = includeDescendants ? `&include-descendants=${includeDescendants}` : '';
+ return `${NCMP_BASE_URL}/ncmp/v1/ch/${cmHandleReference}/data/ds/${datastoreName}?resourceIdentifier=${resourceIdentifier}${descendantsParam}`;
+} \ No newline at end of file
diff --git a/k6-tests/ncmp/common/search-base.js b/k6-tests/ncmp/common/search-base.js
new file mode 100644
index 0000000000..a6424fe5d0
--- /dev/null
+++ b/k6-tests/ncmp/common/search-base.js
@@ -0,0 +1,59 @@
+/*
+ * ============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=========================================================
+ */
+
+import {performPostRequest, NCMP_BASE_URL} from './utils.js';
+
+export function executeCmHandleSearch(scenario) {
+ return executeSearchRequest('searches', scenario);
+}
+
+export function executeCmHandleIdSearch(scenario) {
+ return executeSearchRequest('id-searches', scenario);
+}
+
+function executeSearchRequest(searchType, scenario) {
+ const searchParameters = SEARCH_PARAMETERS_PER_SCENARIO[scenario];
+ const payload = JSON.stringify(searchParameters);
+ const url = `${NCMP_BASE_URL}/ncmp/v1/ch/${searchType}`;
+ return performPostRequest(url, payload, searchType);
+}
+
+const SEARCH_PARAMETERS_PER_SCENARIO = {
+ "module-and-properties": {
+ "cmHandleQueryParameters": [
+ {
+ "conditionName": "hasAllModules",
+ "conditionParameters": [{"moduleName": "ietf-yang-types"}]
+ },
+ {
+ "conditionName": "hasAllProperties",
+ "conditionParameters": [{"Color": "yellow"}]
+ }
+ ]
+ },
+ "readyCmHandles": {
+ "cmHandleQueryParameters": [
+ {
+ "conditionName": "cmHandleWithCpsPath",
+ "conditionParameters": [{"cpsPath": "//state[@cm-handle-state='READY']"}]
+ }
+ ]
+ }
+};
diff --git a/k6-tests/ncmp/common/utils.js b/k6-tests/ncmp/common/utils.js
new file mode 100644
index 0000000000..8ee6d10123
--- /dev/null
+++ b/k6-tests/ncmp/common/utils.js
@@ -0,0 +1,107 @@
+/*
+ * ============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=========================================================
+ */
+
+import http from 'k6/http';
+export const NCMP_BASE_URL = 'http://localhost:8883';
+export const DMI_PLUGIN_URL = 'http://ncmp-dmi-plugin-demo-and-csit-stub:8092';
+export const TOTAL_CM_HANDLES = 20000;
+export const REGISTRATION_BATCH_SIZE = 100;
+export const READ_DATA_FOR_CM_HANDLE_DELAY_MS = 300; // must have same value as in docker-compose.yml
+export const WRITE_DATA_FOR_CM_HANDLE_DELAY_MS = 670; // must have same value as in docker-compose.yml
+export const CONTENT_TYPE_JSON_PARAM = {'Content-Type': 'application/json'};
+export const LEGACY_BATCH_THROUGHPUT_TEST_BATCH_SIZE = 200;
+export const LEGACY_BATCH_THROUGHPUT_TEST_NUMBER_OF_REQUESTS = 1000;
+export const LEGACY_BATCH_TOPIC_NAME = 'legacy_batch_topic';
+export const KAFKA_BOOTSTRAP_SERVERS = ['localhost:9092'];
+export const MODULE_SET_TAGS = ['tagA','tagB','tagC',' tagD']
+
+
+/**
+ * Generates a batch of CM-handle IDs based on batch size and number.
+ * @param {number} batchSize - Size of each batch.
+ * @param {number} batchNumber - Number of the batch.
+ * @returns {string[]} Array of CM-handle IDs, for example ['ch-201', 'ch-202' ... 'ch-300']
+ */
+export function makeBatchOfCmHandleIds(batchSize, batchNumber) {
+ const startIndex = 1 + batchNumber * batchSize;
+ return Array.from({ length: batchSize }, (_, i) => `ch-${startIndex + i}`);
+}
+
+/**
+ * Helper function to perform POST requests with JSON payload and content type.
+ * @param {string} url - The URL to send the POST request to.
+ * @param {Object} payload - The JSON payload to send in the POST request.
+ * @param {string} metricTag - A tag for the metric endpoint.
+ * @returns {Object} The response from the HTTP POST request.
+ */
+export function performPostRequest(url, payload, metricTag) {
+ const metricTags = {
+ endpoint: metricTag
+ };
+
+ return http.post(url, payload, {
+ headers: CONTENT_TYPE_JSON_PARAM,
+ tags: metricTags
+ });
+}
+
+/**
+ * Helper function to perform GET requests with metric tags.
+ *
+ * This function sends an HTTP GET request to the specified URL and attaches
+ * a metric tag to the request, which is useful for monitoring and analytics.
+ *
+ * @param {string} url - The URL to which the GET request will be sent.
+ * @param {string} metricTag - A string representing the metric tag to associate with the request.
+ * This tag is used for monitoring and tracking the request.
+ * @returns {Object} The response from the HTTP GET request. The response includes the status code,
+ * headers, body, and other related information.
+ */
+export function performGetRequest(url, metricTag) {
+ const metricTags = {
+ endpoint: metricTag
+ };
+ return http.get(url, {tags: metricTags});
+}
+
+export function makeCustomSummaryReport(testResults, scenarioConfig) {
+ const summaryCsvLines = [
+ '#,Test Name,Unit,Fs Requirement,Current Expectation,Actual',
+ makeSummaryCsvLine('0', 'HTTP request failures for all tests', 'rate of failed requests', 'http_req_failed', 0, testResults, scenarioConfig),
+ makeSummaryCsvLine('1', 'Registration of CM-handles', 'CM-handles/second', 'cmhandles_created_per_second', 110, testResults, scenarioConfig),
+ makeSummaryCsvLine('2', 'De-registration of CM-handles', 'CM-handles/second', 'cmhandles_deleted_per_second', 80, testResults, scenarioConfig),
+ makeSummaryCsvLine('3', 'CM-handle ID search with Module and Property filter', 'milliseconds', 'id_search_duration', 4000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4', 'CM-handle search with Module and Property filter', 'milliseconds', 'cm_search_duration', 30000, testResults, scenarioConfig),
+ makeSummaryCsvLine('5a', 'NCMP overhead for Synchronous single CM-handle pass-through read', 'milliseconds', 'ncmp_overhead_passthrough_read', 40, testResults, scenarioConfig),
+ makeSummaryCsvLine('5b', 'NCMP overhead for Synchronous single CM-handle pass-through read with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_read_alt_id', 60, testResults, scenarioConfig),
+ makeSummaryCsvLine('6a', 'NCMP overhead for Synchronous single CM-handle pass-through write', 'milliseconds', 'ncmp_overhead_passthrough_write', 30, testResults, scenarioConfig),
+ makeSummaryCsvLine('6b', 'NCMP overhead for Synchronous single CM-handle pass-through write with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_write_alt_id', 60, testResults, scenarioConfig),
+ makeSummaryCsvLine('7', 'Legacy batch read operation', 'events/second', 'legacy_batch_read_cmhandles_per_second', 1100, testResults, scenarioConfig),
+ ];
+ return summaryCsvLines.join('\n') + '\n';
+}
+
+function makeSummaryCsvLine(testCase, testName, unit, measurementName, currentExpectation, testResults, scenarioConfig) {
+ const thresholdArray = JSON.parse(JSON.stringify(scenarioConfig.thresholds[measurementName]));
+ const thresholdString = thresholdArray[0];
+ const [thresholdKey, thresholdOperator, thresholdValue] = thresholdString.split(/\s+/);
+ const actualValue = testResults.metrics[measurementName].values[thresholdKey].toFixed(3);
+ return `${testCase},${testName},${unit},${thresholdValue},${currentExpectation},${actualValue}`;
+}
diff --git a/k6-tests/ncmp/ncmp-kpi.js b/k6-tests/ncmp/ncmp-kpi.js
new file mode 100644
index 0000000000..f9a19c394f
--- /dev/null
+++ b/k6-tests/ncmp/ncmp-kpi.js
@@ -0,0 +1,240 @@
+/*
+ * ============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=========================================================
+ */
+
+import { check } from 'k6';
+import { Trend } from 'k6/metrics';
+import { Reader } from 'k6/x/kafka';
+import {
+ TOTAL_CM_HANDLES, READ_DATA_FOR_CM_HANDLE_DELAY_MS, WRITE_DATA_FOR_CM_HANDLE_DELAY_MS,
+ makeCustomSummaryReport, makeBatchOfCmHandleIds, LEGACY_BATCH_THROUGHPUT_TEST_BATCH_SIZE,
+ LEGACY_BATCH_TOPIC_NAME, KAFKA_BOOTSTRAP_SERVERS, REGISTRATION_BATCH_SIZE,
+ LEGACY_BATCH_THROUGHPUT_TEST_NUMBER_OF_REQUESTS
+} from './common/utils.js';
+import { createCmHandles, deleteCmHandles, waitForAllCmHandlesToBeReady } from './common/cmhandle-crud.js';
+import { executeCmHandleSearch, executeCmHandleIdSearch } from './common/search-base.js';
+import { passthroughRead, passthroughWrite, legacyBatchRead } from './common/passthrough-crud.js';
+
+let cmHandlesCreatedPerSecondTrend = new Trend('cmhandles_created_per_second', false);
+let cmHandlesDeletedPerSecondTrend = new Trend('cmhandles_deleted_per_second', false);
+let passthroughReadNcmpOverheadTrend = new Trend('ncmp_overhead_passthrough_read', true);
+let passthroughReadNcmpOverheadTrendWithAlternateId = new Trend('ncmp_overhead_passthrough_read_alt_id', true);
+let passthroughWriteNcmpOverheadTrend = new Trend('ncmp_overhead_passthrough_write', true);
+let passthroughWriteNcmpOverheadTrendWithAlternateId = new Trend('ncmp_overhead_passthrough_write_alt_id', true);
+let idSearchDurationTrend = new Trend('id_search_duration', true);
+let cmSearchDurationTrend = new Trend('cm_search_duration', true);
+let legacyBatchReadCmHandlesPerSecondTrend = new Trend('legacy_batch_read_cmhandles_per_second', false);
+
+const legacyBatchEventReader = new Reader({
+ brokers: KAFKA_BOOTSTRAP_SERVERS,
+ topic: LEGACY_BATCH_TOPIC_NAME,
+});
+
+const DURATION = '15m';
+const LEGACY_BATCH_THROUGHPUT_TEST_START_TIME = '15m30s';
+
+export const options = {
+ setupTimeout: '8m',
+ teardownTimeout: '6m',
+ scenarios: {
+ passthrough_read_scenario: {
+ executor: 'constant-vus',
+ exec: 'passthroughReadScenario',
+ vus: 4,
+ duration: DURATION,
+ },
+ passthrough_read_alt_id_scenario: {
+ executor: 'constant-vus',
+ exec: 'passthroughReadAltIdScenario',
+ vus: 4,
+ duration: DURATION,
+ },
+ passthrough_write_scenario: {
+ executor: 'constant-vus',
+ exec: 'passthroughWriteScenario',
+ vus: 4,
+ duration: DURATION,
+ },
+ passthrough_write_alt_id_scenario: {
+ executor: 'constant-vus',
+ exec: 'passthroughWriteAltIdScenario',
+ vus: 4,
+ duration: DURATION,
+ },
+ cm_handle_id_search_scenario: {
+ executor: 'constant-vus',
+ exec: 'cmHandleIdSearchScenario',
+ vus: 5,
+ duration: DURATION,
+ },
+ cm_handle_search_scenario: {
+ executor: 'constant-vus',
+ exec: 'cmHandleSearchScenario',
+ vus: 5,
+ duration: DURATION,
+ },
+ legacy_batch_produce_scenario: {
+ executor: 'shared-iterations',
+ exec: 'legacyBatchProduceScenario',
+ vus: 2,
+ iterations: LEGACY_BATCH_THROUGHPUT_TEST_NUMBER_OF_REQUESTS,
+ startTime: LEGACY_BATCH_THROUGHPUT_TEST_START_TIME,
+ },
+ legacy_batch_consume_scenario: {
+ executor: 'per-vu-iterations',
+ exec: 'legacyBatchConsumeScenario',
+ vus: 1,
+ iterations: 1,
+ startTime: LEGACY_BATCH_THROUGHPUT_TEST_START_TIME,
+ }
+ },
+ thresholds: {
+ 'http_req_failed': ['rate == 0'],
+ 'cmhandles_created_per_second': ['avg >= 22'],
+ 'cmhandles_deleted_per_second': ['avg >= 22'],
+ 'ncmp_overhead_passthrough_read': ['avg <= 40'],
+ 'ncmp_overhead_passthrough_write': ['avg <= 40'],
+ 'ncmp_overhead_passthrough_read_alt_id': ['avg <= 40'],
+ 'ncmp_overhead_passthrough_write_alt_id': ['avg <= 40'],
+ 'id_search_duration': ['avg <= 2000'],
+ 'cm_search_duration': ['avg <= 15000'],
+ 'legacy_batch_read_cmhandles_per_second': ['avg >= 150'],
+ },
+};
+
+export function setup() {
+ const startTimeInMillis = Date.now();
+
+ const TOTAL_BATCHES = Math.ceil(TOTAL_CM_HANDLES / REGISTRATION_BATCH_SIZE);
+ for (let batchNumber = 0; batchNumber < TOTAL_BATCHES; batchNumber++) {
+ const nextBatchOfCmHandleIds = makeBatchOfCmHandleIds(REGISTRATION_BATCH_SIZE, batchNumber);
+ const response = createCmHandles(nextBatchOfCmHandleIds);
+ check(response, { 'create CM-handles status equals 200': (r) => r.status === 200 });
+ }
+
+ waitForAllCmHandlesToBeReady();
+
+ const endTimeInMillis = Date.now();
+ const totalRegistrationTimeInSeconds = (endTimeInMillis - startTimeInMillis) / 1000.0;
+
+ cmHandlesCreatedPerSecondTrend.add(TOTAL_CM_HANDLES / totalRegistrationTimeInSeconds);
+}
+
+export function teardown() {
+ const startTimeInMillis = Date.now();
+
+ let DEREGISTERED_CM_HANDLES = 0
+ const TOTAL_BATCHES = Math.ceil(TOTAL_CM_HANDLES / REGISTRATION_BATCH_SIZE);
+ for (let batchNumber = 0; batchNumber < TOTAL_BATCHES; batchNumber++) {
+ const nextBatchOfCmHandleIds = makeBatchOfCmHandleIds(REGISTRATION_BATCH_SIZE, batchNumber);
+ const response = deleteCmHandles(nextBatchOfCmHandleIds);
+ if (response.error_code === 0) {
+ DEREGISTERED_CM_HANDLES += REGISTRATION_BATCH_SIZE
+ }
+ check(response, { 'delete CM-handles status equals 200': (r) => r.status === 200 });
+ }
+
+ const endTimeInMillis = Date.now();
+ const totalDeregistrationTimeInSeconds = (endTimeInMillis - startTimeInMillis) / 1000.0;
+
+ cmHandlesDeletedPerSecondTrend.add(DEREGISTERED_CM_HANDLES / totalDeregistrationTimeInSeconds);
+}
+
+export function passthroughReadScenario() {
+ const response = passthroughRead(false);
+ if (check(response, { 'passthrough read status equals 200': (r) => r.status === 200 })) {
+ const overhead = response.timings.duration - READ_DATA_FOR_CM_HANDLE_DELAY_MS;
+ passthroughReadNcmpOverheadTrend.add(overhead);
+ }
+}
+
+export function passthroughReadAltIdScenario() {
+ const response = passthroughRead(true);
+ if (check(response, { 'passthrough read with alternate Id status equals 200': (r) => r.status === 200 })) {
+ const overhead = response.timings.duration - READ_DATA_FOR_CM_HANDLE_DELAY_MS;
+ passthroughReadNcmpOverheadTrendWithAlternateId.add(overhead);
+ }
+}
+
+export function passthroughWriteScenario() {
+ const response = passthroughWrite(false);
+ if (check(response, { 'passthrough write status equals 201': (r) => r.status === 201 })) {
+ const overhead = response.timings.duration - WRITE_DATA_FOR_CM_HANDLE_DELAY_MS;
+ passthroughWriteNcmpOverheadTrend.add(overhead);
+ }
+}
+
+export function passthroughWriteAltIdScenario() {
+ const response = passthroughWrite(true);
+ if (check(response, { 'passthrough write with alternate Id status equals 201': (r) => r.status === 201 })) {
+ const overhead = response.timings.duration - WRITE_DATA_FOR_CM_HANDLE_DELAY_MS;
+ passthroughWriteNcmpOverheadTrendWithAlternateId.add(overhead);
+ }
+}
+
+export function cmHandleIdSearchScenario() {
+ const response = executeCmHandleIdSearch('module-and-properties');
+ if (check(response, { 'CM handle ID search status equals 200': (r) => r.status === 200 })
+ && check(response, { 'CM handle ID search returned expected CM-handles': (r) => r.json('#') === TOTAL_CM_HANDLES })) {
+ idSearchDurationTrend.add(response.timings.duration);
+ }
+}
+
+export function cmHandleSearchScenario() {
+ const response = executeCmHandleSearch('module-and-properties');
+ if (check(response, { 'CM handle search status equals 200': (r) => r.status === 200 })
+ && check(response, { 'CM handle search returned expected CM-handles': (r) => r.json('#') === TOTAL_CM_HANDLES })) {
+ cmSearchDurationTrend.add(response.timings.duration);
+ }
+}
+
+export function legacyBatchProduceScenario() {
+ const nextBatchOfCmHandleIds = makeBatchOfCmHandleIds(LEGACY_BATCH_THROUGHPUT_TEST_BATCH_SIZE, 0);
+ const response = legacyBatchRead(nextBatchOfCmHandleIds);
+ check(response, { 'data operation batch read status equals 200': (r) => r.status === 200 });
+}
+
+export function legacyBatchConsumeScenario() {
+ const TOTAL_MESSAGES_TO_CONSUME = LEGACY_BATCH_THROUGHPUT_TEST_NUMBER_OF_REQUESTS * LEGACY_BATCH_THROUGHPUT_TEST_BATCH_SIZE;
+ try {
+ let messagesConsumed = 0;
+ let startTime = Date.now();
+
+ while (messagesConsumed < TOTAL_MESSAGES_TO_CONSUME) {
+ let messages = legacyBatchEventReader.consume({ limit: 1000 });
+
+ if (messages.length > 0) {
+ messagesConsumed += messages.length;
+ }
+ }
+
+ let endTime = Date.now();
+ const timeToConsumeMessagesInSeconds = (endTime - startTime) / 1000.0;
+ legacyBatchReadCmHandlesPerSecondTrend.add(TOTAL_MESSAGES_TO_CONSUME / timeToConsumeMessagesInSeconds);
+ } catch (error) {
+ legacyBatchReadCmHandlesPerSecondTrend.add(0);
+ console.error(error);
+ }
+}
+
+export function handleSummary(data) {
+ return {
+ stdout: makeCustomSummaryReport(data, options),
+ };
+}
diff --git a/k6-tests/ncmp/run-all-tests.sh b/k6-tests/ncmp/run-all-tests.sh
new file mode 100755
index 0000000000..1fa661a472
--- /dev/null
+++ b/k6-tests/ncmp/run-all-tests.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# Copyright 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.
+#
+
+pushd "$(dirname "$0")" >/dev/null || exit 1
+
+number_of_failures=0
+echo "Running K6 performance tests..."
+
+# Redirecting stderr to /dev/null to prevent large log files
+k6 --quiet run ncmp-kpi.js > summary.csv 2>/dev/null || ((number_of_failures++))
+
+if [ -f summary.csv ]; then
+
+ # Output raw CSV for plotting job
+ echo '-- BEGIN CSV REPORT'
+ cat summary.csv
+ echo '-- END CSV REPORT'
+ echo
+
+ # Output human-readable report
+ echo '####################################################################################################'
+ echo '## K 6 P E R F O R M A N C E T E S T R E S U L T S ##'
+ echo '####################################################################################################'
+ column -t -s, summary.csv
+ echo
+
+ # Clean up
+ rm -f summary.csv
+
+else
+ echo "Error: Failed to generate summary.csv" >&2
+ ((number_of_failures++))
+fi
+
+popd >/dev/null || exit 1
+
+echo "NCMP TEST FAILURES: $number_of_failures"
+exit $number_of_failures
diff --git a/k6-tests/run-k6-tests.sh b/k6-tests/run-k6-tests.sh
new file mode 100755
index 0000000000..b1ad38911a
--- /dev/null
+++ b/k6-tests/run-k6-tests.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Copyright 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.
+#
+
+set -o errexit # Exit on most errors
+set -o nounset # Disallow expansion of unset variables
+set -o pipefail # Use last non-zero exit code in a pipeline
+#set -o xtrace # Uncomment for debugging
+
+on_exit() {
+ rc=$?
+ ./teardown.sh
+ popd
+ echo "TEST FAILURES: $rc"
+ exit $rc
+}
+trap on_exit EXIT
+
+pushd "$(dirname "$0")" || exit 1
+
+# Install needed dependencies.
+source install-deps.sh
+
+# Run k6 test suite.
+./setup.sh
+./ncmp/run-all-tests.sh
+NCMP_RESULT=$?
+
+# Note that the final steps are done in on_exit function after this exit!
+exit $NCMP_RESULT
diff --git a/k6-tests/setup.sh b/k6-tests/setup.sh
new file mode 100755
index 0000000000..346b9c0690
--- /dev/null
+++ b/k6-tests/setup.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright 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.
+#
+
+docker-compose -f ../docker-compose/docker-compose.yml --profile dmi-stub up -d
+
+echo "Waiting for CPS to start..."
+READY_MESSAGE="Processing module sync fetched 0 advised cm handles from DB"
+
+# Get the container IDs of the cps-and-ncmp replicas
+CONTAINER_IDS=$(docker ps --filter "name=cps-and-ncmp" --format "{{.ID}}")
+
+# Check the logs for each container
+for CONTAINER_ID in $CONTAINER_IDS; do
+ echo "Checking logs for container: $CONTAINER_ID"
+ docker logs "$CONTAINER_ID" -f | grep -m 1 "$READY_MESSAGE" >/dev/null && echo "CPS is ready in container: $CONTAINER_ID" || true
+done
diff --git a/k6-tests/teardown.sh b/k6-tests/teardown.sh
new file mode 100755
index 0000000000..7693dc03a4
--- /dev/null
+++ b/k6-tests/teardown.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright 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.
+#
+
+echo '================================== docker info =========================='
+docker ps -a
+
+echo 'Stopping, Removing containers and volumes...'
+docker_compose_cmd="docker-compose -f ../docker-compose/docker-compose.yml --profile dmi-stub down --volumes"
+# Set an environment variable CLEAN_DOCKER_IMAGES=1 to also remove docker images when done (used on jenkins job)
+if [ "${CLEAN_DOCKER_IMAGES:-0}" -eq 1 ]; then
+ $docker_compose_cmd --rmi all
+else
+ $docker_compose_cmd
+fi
diff --git a/policy-executor-stub/pom.xml b/policy-executor-stub/pom.xml
new file mode 100644
index 0000000000..35ff835505
--- /dev/null
+++ b/policy-executor-stub/pom.xml
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.cps</groupId>
+ <artifactId>cps-parent</artifactId>
+ <version>3.5.3-SNAPSHOT</version>
+ <relativePath>../cps-parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>policy-executor-stub</artifactId>
+
+ <properties>
+ <app>org.onap.cps.policyexecutor.stub.PolicyExecutorApplication</app>
+ <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+ <base.image>${docker.pull.registry}/onap/integration-java17:12.0.0</base.image>
+ <image.name>policy-executor-stub</image.name>
+ <image.tag>${project.version}-${maven.build.timestamp}</image.tag>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <!-- S P R I N G D E P E N D E N C I E S -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-tomcat</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-jetty</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
+ </dependency>
+ <!-- O P E N A P I D E P E N D E N C I E S -->
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springdoc</groupId>
+ <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+ </dependency>
+ <!-- T E S T D E P E N D E N C I E S -->
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-json</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.spockframework</groupId>
+ <artifactId>spock-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.spockframework</groupId>
+ <artifactId>spock-spring</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>com.google.cloud.tools</groupId>
+ <artifactId>jib-maven-plugin</artifactId>
+ <configuration>
+ <container>
+ <mainClass>${app}</mainClass>
+ <creationTime>USE_CURRENT_TIMESTAMP</creationTime>
+ </container>
+ <from>
+ <image>${base.image}</image>
+ </from>
+ <to>
+ <tags>
+ <tag>latest</tag>
+ </tags>
+ <image>${docker.push.registry}/onap/${image.name}:${image.tag}</image>
+ </to>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <id>build</id>
+ <goals>
+ <goal>dockerBuild</goal>
+ </goals>
+ </execution>
+ <execution>
+ <phase>deploy</phase>
+ <id>buildAndPush</id>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <!-- Swagger code generation. -->
+ <plugin>
+ <groupId>org.openapitools</groupId>
+ <artifactId>openapi-generator-maven-plugin</artifactId>
+ <version>6.6.0</version>
+ <executions>
+ <execution>
+ <id>code-gen</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>${project.parent.basedir}/../docs/api/swagger/policy-executor/openapi.yaml</inputSpec>
+ <modelPackage>org.onap.cps.policyexecutor.stub.model</modelPackage>
+ <apiPackage>org.onap.cps.policyexecutor.stub.api</apiPackage>
+ <generatorName>spring</generatorName>
+ <generateSupportingFiles>false</generateSupportingFiles>
+ <configOptions>
+ <sourceFolder>src/gen/java</sourceFolder>
+ <dateLibrary>java11</dateLibrary>
+ <interfaceOnly>true</interfaceOnly>
+ <useSpringBoot3>true</useSpringBoot3>
+ <useTags>true</useTags>
+ <openApiNullable>false</openApiNullable>
+ <skipDefaultInterface>true</skipDefaultInterface>
+ </configOptions>
+ </configuration>
+ </execution>
+ <execution>
+ <id>openapi-yaml-gen</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <inputSpec>${project.parent.basedir}/../docs/api/swagger/policy-executor/openapi.yaml</inputSpec>
+ <generatorName>openapi-yaml</generatorName>
+ <configOptions>
+ <outputFile>openapi.yaml</outputFile>
+ </configOptions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.jsonschema2pojo</groupId>
+ <artifactId>jsonschema2pojo-maven-plugin</artifactId>
+ <configuration>
+ <useJakartaValidation>true</useJakartaValidation>
+ <sourceDirectory>${project.parent.basedir}/../docs/schemas/policy-executor</sourceDirectory>
+ <targetPackage>org.onap.cps.policyexecutor.stub.model</targetPackage>
+ <generateBuilders>true</generateBuilders>
+ <serializable>true</serializable>
+ <includeJsr303Annotations>true</includeJsr303Annotations>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>docker</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.google.cloud.tools</groupId>
+ <artifactId>jib-maven-plugin</artifactId>
+ <version>3.3.2</version>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+
+</project>
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/DmiDemoApplication.java b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/PolicyExecutorApplication.java
index 2d4a2d8e82..367a470e2d 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/DmiDemoApplication.java
+++ b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/PolicyExecutorApplication.java
@@ -1,6 +1,6 @@
/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
+ * ============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.
@@ -18,15 +18,14 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.dmi.rest.stub;
+package org.onap.cps.policyexecutor.stub;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
-public class DmiDemoApplication {
-
+public class PolicyExecutorApplication {
public static void main(final String[] args) {
- SpringApplication.run(DmiDemoApplication.class, args);
+ SpringApplication.run(PolicyExecutorApplication.class, args);
}
}
diff --git a/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
new file mode 100644
index 0000000000..cdd26c96e9
--- /dev/null
+++ b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
@@ -0,0 +1,103 @@
+/*
+ * ============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.policyexecutor.stub.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.policyexecutor.stub.api.PolicyExecutorApi;
+import org.onap.cps.policyexecutor.stub.model.NcmpDelete;
+import org.onap.cps.policyexecutor.stub.model.PolicyExecutionRequest;
+import org.onap.cps.policyexecutor.stub.model.PolicyExecutionResponse;
+import org.onap.cps.policyexecutor.stub.model.Request;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequiredArgsConstructor
+@Slf4j
+public class PolicyExecutorStubController implements PolicyExecutorApi {
+
+ private final ObjectMapper objectMapper;
+ private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("(\\d{3})");
+ private int decisionCounter = 0;
+
+ @Override
+ public ResponseEntity<PolicyExecutionResponse> executePolicyAction(
+ final String action,
+ final PolicyExecutionRequest policyExecutionRequest,
+ final String authorization) {
+ log.info("Stub Policy Executor Invoked (only supports 'delete' operations)");
+ if (policyExecutionRequest.getRequests().isEmpty()) {
+ return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ }
+ final Request firstRequest = policyExecutionRequest.getRequests().iterator().next();
+ log.info("1st Request Schema:{}", firstRequest.getSchema());
+ if (firstRequest.getSchema().contains("ncmp-delete-schema:1.0.0")) {
+ return handleNcmpDeleteSchema(firstRequest);
+ }
+ log.warn("This stub only supports 'delete' operations");
+ return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ }
+
+ private ResponseEntity<PolicyExecutionResponse> handleNcmpDeleteSchema(final Request request) {
+ final NcmpDelete ncmpDelete = objectMapper.convertValue(request.getData(), NcmpDelete.class);
+
+ final String targetIdentifier = ncmpDelete.getTargetIdentifier();
+
+ if (targetIdentifier == null) {
+ return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ }
+
+ final Matcher matcher = ERROR_CODE_PATTERN.matcher(targetIdentifier);
+ if (matcher.find()) {
+ final int errorCode = Integer.parseInt(matcher.group(1));
+ return new ResponseEntity<>(HttpStatusCode.valueOf(errorCode));
+ }
+
+ return createPolicyExecutionResponse(targetIdentifier);
+ }
+
+ private ResponseEntity<PolicyExecutionResponse> createPolicyExecutionResponse(final String targetIdentifier) {
+ final String decisionId = String.valueOf(++decisionCounter);
+ final String decision;
+ final String message;
+
+ if (targetIdentifier.toLowerCase(Locale.getDefault()).contains("cps-is-great")) {
+ decision = "allow";
+ message = "All good";
+ } else {
+ decision = "deny";
+ message = "Only FDNs containing 'cps-is-great' are allowed";
+ }
+ log.info("Decision: {} ({})", decision, message);
+ final PolicyExecutionResponse policyExecutionResponse =
+ new PolicyExecutionResponse(decisionId, decision, message);
+
+ return ResponseEntity.ok(policyExecutionResponse);
+ }
+
+}
diff --git a/policy-executor-stub/src/main/resources/application.yml b/policy-executor-stub/src/main/resources/application.yml
new file mode 100644
index 0000000000..8ed5742a41
--- /dev/null
+++ b/policy-executor-stub/src/main/resources/application.yml
@@ -0,0 +1,19 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Nordix
+# ================================================================================
+# 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=========================================================
+
+server:
+ port: 8093
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DmiDataOperationRequest.java b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/PolicyExecutorApplicationSpec.groovy
index 0771e7740c..565932d9f0 100644
--- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/model/data/operational/DmiDataOperationRequest.java
+++ b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/PolicyExecutorApplicationSpec.groovy
@@ -1,6 +1,6 @@
/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
+ * ============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.
@@ -18,15 +18,17 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.dmi.rest.stub.model.data.operational;
+package org.onap.cps.policyexecutor.stub
-import java.util.List;
-import lombok.Getter;
-import lombok.Setter;
+import spock.lang.Specification
-@Setter
-@Getter
-public class DmiDataOperationRequest {
+class PolicyExecutorApplicationSpec extends Specification {
+
+ def 'Execute Policy Action.'() {
+ when: 'Starting the application (for coverage)'
+ PolicyExecutorApplication.main()
+ then: 'all goes well'
+ noExceptionThrown()
+ }
- private List<DataOperationRequest> operations;
}
diff --git a/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
new file mode 100644
index 0000000000..064e0234a3
--- /dev/null
+++ b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
@@ -0,0 +1,151 @@
+/*
+ * ============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.policyexecutor.stub.controller
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.policyexecutor.stub.model.NcmpDelete
+import org.onap.cps.policyexecutor.stub.model.PolicyExecutionRequest
+import org.onap.cps.policyexecutor.stub.model.PolicyExecutionResponse
+import org.onap.cps.policyexecutor.stub.model.Request
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.test.web.servlet.MockMvc
+import spock.lang.Specification
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+
+@WebMvcTest(PolicyExecutorStubController)
+class PolicyExecutorStubControllerSpec extends Specification {
+
+ @Autowired
+ MockMvc mockMvc
+
+ @Autowired
+ ObjectMapper objectMapper
+
+ def url = '/policy-executor/api/v1/some-action'
+
+ def 'Execute policy action.'() {
+ given: 'a policy execution request with target: #targetIdentifier'
+ def requestBody = createRequestBody(targetIdentifier)
+ when: 'request is posted'
+ def response = mockMvc.perform(post(url)
+ .header('Authorization','some string')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBody))
+ .andReturn().response
+ then: 'response status is Ok'
+ assert response.status == HttpStatus.OK.value()
+ and: 'the response body has the expected decision details'
+ def responseBody = response.contentAsString
+ def policyExecutionResponse = objectMapper.readValue(responseBody, PolicyExecutionResponse.class)
+ assert policyExecutionResponse.decisionId == expectedDecsisonId
+ assert policyExecutionResponse.decision == expectedDecision
+ assert policyExecutionResponse.message == expectedMessage
+ where: 'the following targets are used'
+ targetIdentifier || expectedDecsisonId | expectedDecision | expectedMessage
+ 'some fdn' || '1' | 'deny' | "Only FDNs containing 'cps-is-great' are allowed"
+ 'fdn with cps-is-great' || '2' | 'allow' | 'All good'
+ }
+
+ def 'Execute policy action with a HTTP error code.'() {
+ given: 'a policy execution request with a target fdn with a 3-digit error code'
+ def requestBody = createRequestBody('target with error code 418')
+ when: 'request is posted'
+ def response = mockMvc.perform(post(url)
+ .header('Authorization','some string')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBody))
+ .andReturn().response
+ then: 'response status the same error code as in target fdn'
+ assert response.status == 418
+ }
+
+ def 'Execute policy action without authorization header.'() {
+ given: 'a valid policy execution request'
+ def requestBody = createRequestBody('some target')
+ when: 'request is posted without authorization header'
+ def response = mockMvc.perform(post(url)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBody))
+ .andReturn().response
+ then: 'response status is OK'
+ assert response.status == HttpStatus.OK.value()
+ }
+
+ def 'Execute policy action with no requests.'() {
+ given: 'a policy execution request'
+ def policyExecutionRequest = new PolicyExecutionRequest('some decision type', [])
+ def requestBody = objectMapper.writeValueAsString(policyExecutionRequest)
+ when: 'request is posted'
+ def response = mockMvc.perform(post(url)
+ .header('Authorization','some string')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBody))
+ .andReturn().response
+ then: 'response status is Bad Request'
+ assert response.status == HttpStatus.BAD_REQUEST.value()
+ }
+
+ def 'Execute policy action with invalid json for request data.'() {
+ when: 'request is posted'
+ def response = mockMvc.perform(post(url)
+ .header('Authorization','some string')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content('invalid json'))
+ .andReturn().response
+ then: 'response status is Bad Request'
+ assert response.status == HttpStatus.BAD_REQUEST.value()
+ }
+
+ def 'Execute policy action with missing or invalid attributes.'() {
+ given: 'a policy execution request with decisionType=#decisionType, schema=#schema, targetIdentifier=#targetIdentifier'
+ def requestBody = createRequestBody(decisionType, schema, targetIdentifier)
+ when: 'request is posted'
+ def response = mockMvc.perform(post(url)
+ .header('Authorization','something')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBody))
+ .andReturn().response
+ then: 'response status as expected'
+ assert response.status == expectedStatus.value()
+ where: 'following parameters are used'
+ decisionType | schema | targetIdentifier || expectedStatus
+ 'something' | 'ncmp-delete-schema:1.0.0' | 'something' || HttpStatus.OK
+ null | 'ncmp-delete-schema:1.0.0' | 'something' || HttpStatus.BAD_REQUEST
+ 'something' | 'other schema' | 'something' || HttpStatus.BAD_REQUEST
+ 'something' | 'ncmp-delete-schema:1.0.0' | null || HttpStatus.BAD_REQUEST
+ }
+
+ def createRequestBody(decisionType, schema, targetIdentifier) {
+ def ncmpDelete = new NcmpDelete(targetIdentifier: targetIdentifier)
+ def request = new Request(schema, ncmpDelete)
+ def policyExecutionRequest = new PolicyExecutionRequest(decisionType, [request])
+ return objectMapper.writeValueAsString(policyExecutionRequest)
+ }
+
+ def createRequestBody(targetIdentifier) {
+ return createRequestBody('some decision type', 'ncmp-delete-schema:1.0.0', targetIdentifier)
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 4d0460237c..8347b1fe70 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
<groupId>org.onap.cps</groupId>
<artifactId>cps-aggregator</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<packaging>pom</packaging>
<name>cps</name>
@@ -61,12 +61,12 @@
<module>cps-ncmp-rest-stub</module>
<module>cps-path-parser</module>
<module>cps-ri</module>
- <module>dmi-plugin-demo-and-csit-stub</module>
<module>integration-test</module>
<module>checkstyle</module>
<module>spotbugs</module>
<module>cps-application</module>
<module>jacoco-report</module>
+ <module>policy-executor-stub</module>
</modules>
<build>
diff --git a/postman-collections/CPS Environment.postman_environment.json b/postman-collections/CPS Environment.postman_environment.json
index 84dcb642d7..7ee9c6779e 100644
--- a/postman-collections/CPS Environment.postman_environment.json
+++ b/postman-collections/CPS Environment.postman_environment.json
@@ -1,5 +1,5 @@
{
- "id": "e8e90dd2-20be-49be-813f-07db44c6a4c2",
+ "id": "fd705c16-c17e-434d-ad2e-ba040a7ed062",
"name": "CPS Environment",
"values": [
{
@@ -16,30 +16,18 @@
},
{
"key": "DMI_HOST",
- "value": "localhost",
+ "value": "ncmp-dmi-plugin-demo-and-csit-stub",
"type": "default",
"enabled": true
},
{
"key": "DMI_PORT",
- "value": "8784",
- "type": "default",
- "enabled": true
- },
- {
- "key": "SDNC_HOST",
- "value": "localhost",
- "type": "default",
- "enabled": true
- },
- {
- "key": "SDNC_PORT",
- "value": "8282",
+ "value": "8092",
"type": "default",
"enabled": true
}
],
"_postman_variable_scope": "environment",
- "_postman_exported_at": "2024-02-23T13:00:33.537Z",
- "_postman_exported_using": "Postman/10.23.4"
-} \ No newline at end of file
+ "_postman_exported_at": "2024-07-30T15:54:00.831Z",
+ "_postman_exported_using": "Postman/11.5.1"
+}
diff --git a/postman-collections/DMI Stub.postman_collection.json b/postman-collections/DMI Stub.postman_collection.json
deleted file mode 100644
index fe7250f7db..0000000000
--- a/postman-collections/DMI Stub.postman_collection.json
+++ /dev/null
@@ -1,161 +0,0 @@
-{
- "info": {
- "_postman_id": "4baf7902-0f1e-49a9-9c6a-f68f412240af",
- "name": "DMI Stub",
- "description": "A collection of the DMI Stub endpoints.",
- "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
- "_exporter_id": "17907116"
- },
- "item": [
- {
- "name": "Execute a data operation for group of cm handle ids by supplied operation details",
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{ \"operations\":\n [\n {\n \"resourceIdentifier\": \"some resource identifier\",\n \"datastore\": \"ncmp-datastore:passthrough-operational\",\n \"options\": \"some option\",\n \"operationId\": \"12\",\n \"cmHandles\": [\n {\n \"id\": \"cmHandle123\",\n \"cmHandleProperties\": {\n \"myProp\": \"some value\",\n \"otherProp\": \"other value\"\n }\n },\n {\n \"id\": \"cmHandle123\",\n \"cmHandleProperties\": {\n \"myProp\": \"some value\",\n \"otherProp\": \"other value\"\n }\n }\n ],\n \"operation\": \"read\"\n }\n ]\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{DMI_HOST}}:{{DMI_PORT}}/dmi/v1/data?topic=ncmp-async-m2m&requestId=4753fc1f-7de2-449a-b306-a6204b5370b33",
- "protocol": "http",
- "host": [
- "{{DMI_HOST}}"
- ],
- "port": "{{DMI_PORT}}",
- "path": [
- "dmi",
- "v1",
- "data"
- ],
- "query": [
- {
- "key": "topic",
- "value": "ncmp-async-m2m"
- },
- {
- "key": "requestId",
- "value": "4753fc1f-7de2-449a-b306-a6204b5370b33"
- }
- ]
- }
- },
- "response": []
- },
- {
- "name": "Retrieve module resources for one or more modules",
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{DMI_HOST}}:{{DMI_PORT}}/dmi/v1/ch/cm-bookStore/moduleResources",
- "protocol": "http",
- "host": [
- "{{DMI_HOST}}"
- ],
- "port": "{{DMI_PORT}}",
- "path": [
- "dmi",
- "v1",
- "ch",
- "cm-bookStore",
- "moduleResources"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Get all modules for given cm handle",
- "protocolProfileBehavior": {
- "disabledSystemHeaders": {
- "accept": true
- }
- },
- "request": {
- "method": "POST",
- "header": [
- {
- "key": "Accept",
- "value": "application/json",
- "type": "text"
- }
- ],
- "body": {
- "mode": "raw",
- "raw": "{}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{DMI_HOST}}:{{DMI_PORT}}/dmi/v1/ch/cm-bookStore/modules",
- "protocol": "http",
- "host": [
- "{{DMI_HOST}}"
- ],
- "port": "{{DMI_PORT}}",
- "path": [
- "dmi",
- "v1",
- "ch",
- "cm-bookStore",
- "modules"
- ]
- }
- },
- "response": []
- }
- ],
- "auth": {
- "type": "basic",
- "basic": [
- {
- "key": "password",
- "value": "cpsr0cks!",
- "type": "string"
- },
- {
- "key": "username",
- "value": "cpsuser",
- "type": "string"
- }
- ]
- },
- "event": [
- {
- "listen": "prerequest",
- "script": {
- "type": "text/javascript",
- "exec": [
- ""
- ]
- }
- },
- {
- "listen": "test",
- "script": {
- "type": "text/javascript",
- "exec": [
- ""
- ]
- }
- }
- ]
-} \ No newline at end of file
diff --git a/releases/3.5.0-container.yaml b/releases/3.5.0-container.yaml
new file mode 100644
index 0000000000..d6e3b63dbf
--- /dev/null
+++ b/releases/3.5.0-container.yaml
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.5.0
+project: cps
+log_dir: cps-maven-docker-stage-master/942/
+ref: 59575279e36572be4386f1c644db52fcb570fc9e
+containers:
+ - name: 'cps-and-ncmp'
+ version: '3.5.0-20240620T123504Z' \ No newline at end of file
diff --git a/releases/3.5.0.yaml b/releases/3.5.0.yaml
new file mode 100644
index 0000000000..81dc74660b
--- /dev/null
+++ b/releases/3.5.0.yaml
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/950/
+project: cps
+version: 3.5.0 \ No newline at end of file
diff --git a/releases/3.5.1-container.yaml b/releases/3.5.1-container.yaml
new file mode 100644
index 0000000000..ddd96ba36d
--- /dev/null
+++ b/releases/3.5.1-container.yaml
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.5.1
+project: cps
+log_dir: cps-maven-docker-stage-master/943/
+ref: 7afd73d95b2de559e728b08abb7f003e70664c44
+containers:
+ - name: 'cps-and-ncmp'
+ version: '3.5.1-20240715T100945Z' \ No newline at end of file
diff --git a/releases/3.5.1.yaml b/releases/3.5.1.yaml
new file mode 100644
index 0000000000..f265e331d0
--- /dev/null
+++ b/releases/3.5.1.yaml
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/951/
+project: cps
+version: 3.5.1 \ No newline at end of file
diff --git a/releases/3.5.2-container.yaml b/releases/3.5.2-container.yaml
new file mode 100644
index 0000000000..a1344fa19c
--- /dev/null
+++ b/releases/3.5.2-container.yaml
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.5.2
+project: cps
+log_dir: cps-maven-docker-stage-master/945/
+ref: 9002b9f6d0d64106e1cbc03d603dc0429da8badd
+containers:
+ - name: 'cps-and-ncmp'
+ version: '3.5.2-20240821T145201Z'
diff --git a/releases/3.5.2.yaml b/releases/3.5.2.yaml
new file mode 100644
index 0000000000..8467524c3b
--- /dev/null
+++ b/releases/3.5.2.yaml
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/953/
+project: cps
+version: 3.5.2
diff --git a/spotbugs/pom.xml b/spotbugs/pom.xml
index bab9551909..1433bd3a39 100644
--- a/spotbugs/pom.xml
+++ b/spotbugs/pom.xml
@@ -25,7 +25,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>spotbugs</artifactId>
- <version>3.5.0-SNAPSHOT</version>
+ <version>3.5.3-SNAPSHOT</version>
<properties>
<nexusproxy>https://nexus.onap.org</nexusproxy>
diff --git a/spotbugs/src/main/resources/spotbugs-exclude.xml b/spotbugs/src/main/resources/spotbugs-exclude.xml
index 78f61d290e..23e62cdbc7 100644
--- a/spotbugs/src/main/resources/spotbugs-exclude.xml
+++ b/spotbugs/src/main/resources/spotbugs-exclude.xml
@@ -36,6 +36,7 @@
<Bug pattern="NP_NULL_PARAM_DEREF" />
<Bug pattern="NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE" />
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" />
+ <Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE" />
<!-- https://stackoverflow.com/a/34674776. Doesn't detect Lombok All Args Constructor variables being used with map get key and value, which can lead to spotbugs being detected
on used fields -->
diff --git a/version.properties b/version.properties
index 5fdc4e3576..5b9387554a 100644
--- a/version.properties
+++ b/version.properties
@@ -22,7 +22,7 @@
major=3
minor=5
-patch=0
+patch=3
base_version=${major}.${minor}.${patch}