Merge "Update Subscription Event Schemas for merge"
authorPriyank Maheshwari <priyank.maheshwari@est.tech>
Fri, 13 Oct 2023 13:18:58 +0000 (13:18 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 13 Oct 2023 13:18:58 +0000 (13:18 +0000)
157 files changed:
INFO.yaml
checkstyle/pom.xml
cps-application/pom.xml
cps-application/src/main/java/org/onap/cps/config/WebSecurityConfig.java
cps-application/src/main/resources/application.yml
cps-bom/pom.xml
cps-dependencies/pom.xml
cps-events/pom.xml
cps-ncmp-events/pom.xml
cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
cps-ncmp-rest-stub/pom.xml
cps-ncmp-rest/docs/openapi/components.yaml
cps-ncmp-rest/pom.xml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy
cps-ncmp-service/pom.xml
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpResponseStatus.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NcmpEventResponseCode.java with 79% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/constants/DmiRegistryConstants.java [deleted file]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/EventsPublisher.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarder.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisher.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandler.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorHelper.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleQueries.java with 84% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImpl.java with 79% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleState.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java with 91% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeState.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeState.java with 97% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateBuilder.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java with 94% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateUtils.java with 92% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/DataStoreSyncState.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/DataStoreSyncState.java with 91% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java with 64% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImpl.java with 60% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/LockReasonCategory.java with 82% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/ModelledDmiServiceLeaves.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/ModelledDmiServiceLeaves.java with 93% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/NcmpPersistenceImpl.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/enums/PropertyType.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/enums/PropertyType.java with 92% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/DataSyncWatchdog.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/DataSyncWatchdog.java with 89% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java with 85% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java with 96% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/SyncUtils.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java with 74% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/config/WatchdogSchedulingConfigurer.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/config/WatchdogSchedulingConfigurer.java with 95% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/executor/AsyncTaskExecutor.java [moved from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/executor/AsyncTaskExecutor.java with 96% similarity]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/ncmppersistence/NcmpPersistence.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistence.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceImpl.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DMiPluginWatchDog.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/DataOperationEventCreator.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java [deleted file]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/SubscriptionModelLoader.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyQueryServiceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfigSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionDmiOutEventConsumerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpInEventForwarderSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/cmsubscription/CmSubscriptionNcmpOutEventPublisherSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCreatorSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/subscriptions/SubscriptionPersistenceSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtilsSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceImplSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/DataSyncWatchdogSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/config/WatchdogSchedulingConfigurerSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/executor/AsyncTaskExecutorSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponseSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/NcmpServiceCmHandleSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/SubscriptionModelLoaderSpec.groovy
cps-ncmp-service/src/test/resources/expectedStateModel.json
cps-parent/pom.xml
cps-path-parser/pom.xml
cps-rest/pom.xml
cps-ri/pom.xml
cps-ri/src/main/java/org/onap/cps/spi/entities/AnchorEntity.java
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
cps-ri/src/main/resources/hibernate.cfg.xml
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy
cps-service/pom.xml
cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
cps-service/src/main/java/org/onap/cps/yang/YangTextSchemaSourceSetBuilder.java
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
csit/tests/cps-data-operations/cps-data-operations.robot
dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml
dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml
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
dmi-plugin-demo-and-csit-stub/pom.xml
docker-compose/docker-compose.yml
docs/api/swagger/ncmp/openapi-inventory.yaml
docs/cps-ncmp-message-status-codes.rst
docs/deployment.rst
docs/design.rst
docs/release-notes.rst
integration-test/pom.xml
integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsDataServiceIntegrationSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpPerfTestBase.groovy [new file with mode: 0644]
integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpRegistryPerfTestBase.groovy [deleted file]
integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmDataSubscriptionsPerfTest.groovy [new file with mode: 0644]
integration-test/src/test/groovy/org/onap/cps/integration/performance/ncmp/CmHandleQueryPerfTest.groovy
integration-test/src/test/resources/data/cm-data-subscriptions/cm-data-subscriptions@2023-09-21.yang [new file with mode: 0644]
integration-test/src/test/resources/hibernate.cfg.xml
jacoco-report/pom.xml
pom.xml
releases/3.3.7-container.yaml [new file with mode: 0644]
releases/3.3.7.yaml [new file with mode: 0644]
releases/3.3.8-container.yaml [new file with mode: 0644]
releases/3.3.8.yaml [new file with mode: 0644]
spotbugs/pom.xml
version.properties

index cb44996..04e599d 100755 (executable)
--- a/INFO.yaml
+++ b/INFO.yaml
@@ -62,6 +62,11 @@ committers:
       company: 'Ericsson Software Technology'
       id: 'mpriyank'
       timezone: 'Europe/Dublin'
+    - name: 'Lee Anjella Macabuhay'
+      email: 'lee.anjella.macabuhay@est.tech'
+      company: 'Ericsson Software Technology'
+      id: 'emaclee'
+      timezone: 'Europe/Dublin'
 repositories:
     - cps
 tsc:
index ef52947..7d190fe 100644 (file)
@@ -26,7 +26,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>checkstyle</artifactId>
-    <version>3.3.7-SNAPSHOT</version>
+    <version>3.3.9-SNAPSHOT</version>
 
     <profiles>
         <profile>
index 15868b1..11611d1 100755 (executable)
@@ -28,7 +28,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
@@ -40,7 +40,6 @@
         <minimum-coverage>0.86</minimum-coverage>
         <base.image>${docker.pull.registry}/onap/integration-java17:12.0.0</base.image>
         <image.tag>${project.version}-${maven.build.timestamp}</image.tag>
-        <jakarta-servlet.version>5.0.0</jakarta-servlet.version>
     </properties>
 
     <dependencies>
             <groupId>org.eclipse.jetty</groupId>
             <artifactId>jetty-server</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-http</artifactId>
+        </dependency>
         <dependency>
             <groupId>jakarta.servlet</groupId>
             <artifactId>jakarta.servlet-api</artifactId>
index c8b2509..9b726ba 100644 (file)
@@ -39,9 +39,7 @@ import org.springframework.security.web.SecurityFilterChain;
 @Configuration
 @EnableWebSecurity
 public class WebSecurityConfig {
-
     private static final String USER_ROLE = "USER";
-
     private final String username;
     private final String password;
     private final String[] permitUris;
@@ -54,9 +52,9 @@ public class WebSecurityConfig {
      * @param password   password
      */
     public WebSecurityConfig(
-        @Autowired @Value("${permit-uri}") final String permitUris,
-        @Autowired @Value("${security.auth.username}") final String username,
-        @Autowired @Value("${security.auth.password}") final String password
+            @Autowired @Value("${permit-uri}") final String permitUris,
+            @Autowired @Value("${security.auth.username}") final String username,
+            @Autowired @Value("${security.auth.password}") final String password
     ) {
         super();
         this.permitUris = permitUris.isEmpty() ? new String[] {"/v3/api-docs"} : permitUris.split("\\s{0,9},\\s{0,9}");
@@ -85,7 +83,6 @@ public class WebSecurityConfig {
                 .anyRequest().authenticated()
                 .and()
                 .csrf().disable();
-
         return http.build();
     }
 
index 0163568..7beab2e 100644 (file)
@@ -37,9 +37,8 @@ spring:
         ddl-auto: create
         open-in-view: false
         properties:
-            hibernate:
-                enable_lazy_load_no_trans: true
-                dialect: org.hibernate.dialect.PostgreSQLDialect
+            hibernate.enable_lazy_load_no_trans: true
+            hibernate.dialect: org.hibernate.dialect.PostgreSQLDialect
 
     datasource:
         url: jdbc:postgresql://${DB_HOST}:${DB_PORT:5432}/cpsdb
index f3c8f78..b9da8b2 100644 (file)
@@ -25,7 +25,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-bom</artifactId>
-    <version>3.3.7-SNAPSHOT</version>
+    <version>3.3.9-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <description>This artifact contains dependencyManagement declarations of all published CPS components.</description>
index 55e7c07..203a93a 100755 (executable)
@@ -27,7 +27,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-dependencies</artifactId>
-    <version>3.3.7-SNAPSHOT</version>
+    <version>3.3.9-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <name>${project.groupId}:${project.artifactId}</name>
@@ -78,7 +78,7 @@
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-dependencies</artifactId>
-                <version>3.0.0</version>
+                <version>3.1.2</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
             <dependency>
                 <groupId>io.springfox</groupId>
                 <artifactId>springfox-boot-starter</artifactId>
-                <version>3.0.0</version>
+                <version>3.1.2</version>
             </dependency>
             <dependency>
                 <groupId>com.google.code.gson</groupId>
                 <version>31.1-jre</version>
             </dependency>
             <dependency>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-properties-migrator</artifactId>
-                <scope>runtime</scope>
-            </dependency>
-            <dependency>
-                <groupId>jakarta.validation</groupId>
-                <artifactId>jakarta.validation-api</artifactId>
-                <version>3.0.2</version>
+                <groupId>javax.validation</groupId>
+                <artifactId>validation-api</artifactId>
+                <version>2.0.1.Final</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-resources-plugin</artifactId>
                 <version>3.3.1</version>
             </dependency>
+            <dependency>
+                <groupId>jakarta.validation</groupId>
+                <artifactId>jakarta.validation-api</artifactId>
+                <version>3.0.2</version>
+            </dependency>
             <dependency>
                 <groupId>io.micrometer</groupId>
                 <artifactId>micrometer-tracing-bridge-brave</artifactId>
             <dependency>
                 <groupId>com.fasterxml.jackson.core</groupId>
                 <artifactId>jackson-databind</artifactId>
-                <version>2.14.0</version>
+                <version>2.15.2</version>
             </dependency>
             <dependency>
                 <groupId>org.eclipse.jetty</groupId>
                 <artifactId>jetty-server</artifactId>
                 <version>11.0.14</version>
             </dependency>
+            <dependency>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-http</artifactId>
+                <version>11.0.14</version>
+            </dependency>
             <dependency>
                 <groupId>jakarta.servlet</groupId>
                 <artifactId>jakarta.servlet-api</artifactId>
                 <artifactId>spring-test</artifactId>
                 <version>6.0.11</version>
             </dependency>
-            <dependency>
-                <groupId>org.spockframework</groupId>
-                <artifactId>spock-core</artifactId>
-                <version>2.4-M1-groovy-3.0</version>
-            </dependency>
-            <dependency>
-                <groupId>org.spockframework</groupId>
-                <artifactId>spock-spring</artifactId>
-                <version>2.4-M1-groovy-3.0</version>
-            </dependency>
         </dependencies>
     </dependencyManagement>
 </project>
index b305a31..6d16203 100644 (file)
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index f08142e..a59e925 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 6683a23..205a33c 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-ncmp-rest-stub</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
     </parent>
 
     <artifactId>cps-ncmp-rest-stub-app</artifactId>
index d7a5da0..83699b9 100644 (file)
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-ncmp-rest-stub</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
     </parent>
     <artifactId>cps-ncmp-rest-stub-service</artifactId>
 
index 5e9d3de..9e62ff5 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index be51643..022e2ba 100644 (file)
@@ -87,6 +87,8 @@ components:
           items:
             type: string
           example: [ my-cm-handle1, my-cm-handle2, my-cm-handle3 ]
+        upgradedCmHandles:
+          $ref: '#/components/schemas/UpgradedCmHandles'
     DmiPluginRegistrationErrorResponse:
       type: object
       properties:
@@ -102,6 +104,10 @@ components:
           type: array
           items:
             $ref: '#/components/schemas/CmHandlerRegistrationErrorResponse'
+        failedUpgradeCmHandles:
+          type: array
+          items:
+            $ref: '#/components/schemas/CmHandlerRegistrationErrorResponse'
     CmHandlerRegistrationErrorResponse:
       type: object
       properties:
@@ -135,6 +141,20 @@ components:
       additionalProperties:
         type: string
         example: my-property
+    #Module upgrade schema
+    UpgradedCmHandles:
+      required:
+        - cmHandles
+      type: object
+      properties:
+        cmHandles:
+          type: array
+          items:
+            type: string
+          example: [ my-cm-handle1, my-cm-handle2, my-cm-handle3 ]
+        moduleSetTag:
+          type: string
+          example: 'my-module-set-tag'
 
     #Response Schemas
     RestModuleReference:
@@ -225,10 +245,10 @@ components:
     CmHandlePublicProperties:
       type: object
       items:
-          type: object
-          additionalProperties:
-            type: string
-            example: 'Book Type'
+        type: object
+        additionalProperties:
+          type: string
+          example: 'Book Type'
     CmHandleCompositeState:
       type: object
       properties:
index edb7ff5..8517902 100644 (file)
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
             <exclusions>
                 <exclusion>
                     <groupId>org.junit.vintage</groupId>
         </dependency>
         <dependency>
             <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-api</artifactId>
+            <artifactId>junit-jupiter</artifactId>
         </dependency>
     </dependencies>
 
index b3f36f9..af785d5 100644 (file)
@@ -48,6 +48,9 @@ public interface NcmpRestInputMapper {
     @Mapping(source = "removedCmHandles", target = "removedCmHandles",
         nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
         nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
+    @Mapping(source = "upgradedCmHandles", target = "upgradedCmHandles",
+            nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
+            nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
     DmiPluginRegistration toDmiPluginRegistration(final RestDmiPluginRegistration restDmiPluginRegistration);
 
     @Mapping(source = "cmHandle", target = "cmHandleId")
index b81378d..6c730cb 100755 (executable)
@@ -37,8 +37,8 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
 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.inventory.CompositeState;
 import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
index 87f9d83..453abca 100755 (executable)
@@ -110,23 +110,23 @@ public class NetworkCmProxyInventoryController implements NetworkCmProxyInventor
             getFailedResponses(dmiPluginRegistrationResponse.getUpdatedCmHandles()));
         dmiPluginRegistrationErrorResponse.setFailedRemovedCmHandles(
             getFailedResponses(dmiPluginRegistrationResponse.getRemovedCmHandles()));
-
+        dmiPluginRegistrationErrorResponse.setFailedUpgradeCmHandles(
+                getFailedResponses(dmiPluginRegistrationResponse.getUpgradedCmHandles()));
         return dmiPluginRegistrationErrorResponse;
     }
 
     private List<CmHandlerRegistrationErrorResponse> getFailedResponses(
-        final List<CmHandleRegistrationResponse> cmHandleRegistrationResponseList) {
+            final List<CmHandleRegistrationResponse> cmHandleRegistrationResponseList) {
         return cmHandleRegistrationResponseList.stream()
-            .filter(cmHandleRegistrationResponse -> cmHandleRegistrationResponse.getStatus() == Status.FAILURE)
-            .map(this::toCmHandleRegistrationErrorResponse)
-            .collect(Collectors.toList());
+                .filter(cmHandleRegistrationResponse -> cmHandleRegistrationResponse.getStatus() == Status.FAILURE)
+                .map(this::toCmHandleRegistrationErrorResponse).collect(Collectors.toList());
     }
 
     private CmHandlerRegistrationErrorResponse toCmHandleRegistrationErrorResponse(
         final CmHandleRegistrationResponse registrationResponse) {
         return new CmHandlerRegistrationErrorResponse()
             .cmHandle(registrationResponse.getCmHandle())
-            .errorCode(registrationResponse.getRegistrationError().errorCode)
+            .errorCode(registrationResponse.getNcmpResponseStatus().getCode())
             .errorText(registrationResponse.getErrorText());
     }
 
index 64a9934..b436540 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * 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.
 
 package org.onap.cps.ncmp.rest.mapper;
 
+import static org.onap.cps.ncmp.api.impl.inventory.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.inventory.CompositeState;
+import org.onap.cps.ncmp.api.impl.inventory.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;
@@ -75,8 +77,10 @@ public interface CmHandleStateMapper {
     @Named("toExternalLockReason")
     static LockReason toExternalLockReason(CompositeState.LockReason internalLockReason) {
         final LockReason externalLockReason = new LockReason();
-        if (internalLockReason.getLockReasonCategory() != null) {
-            externalLockReason.setReason("LOCKED_MISBEHAVING");
+        if (internalLockReason.getLockReasonCategory() == null) {
+            externalLockReason.setReason(LOCKED_MISBEHAVING.name());
+        } else {
+            externalLockReason.setReason(internalLockReason.getLockReasonCategory().name());
         }
         externalLockReason.setDetails(internalLockReason.getDetails());
         return externalLockReason;
index 7964e32..de044d0 100644 (file)
 
 package org.onap.cps.ncmp.rest.controller
 
+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.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE
+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.DatastoreType.OPERATIONAL
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.mapstruct.factory.Mappers
 import org.onap.cps.TestUtils
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
 import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory
+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.rest.model.DataOperationRequest
 import org.onap.cps.ncmp.rest.model.DataOperationDefinition
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
@@ -58,23 +75,6 @@ import java.time.OffsetDateTime
 import java.time.ZoneOffset
 import java.time.format.DateTimeFormatter
 
-import static org.onap.cps.ncmp.api.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.inventory.CompositeState.Operational
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE
-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.DatastoreType.OPERATIONAL
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
-
 @WebMvcTest(NetworkCmProxyController)
 class NetworkCmProxyControllerSpec extends Specification {
 
@@ -600,7 +600,7 @@ class NetworkCmProxyControllerSpec extends Specification {
 
     def compositeStateTestObject() {
         new CompositeState(cmHandleState: CmHandleState.ADVISED,
-            lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED).details("lock details").build(),
+            lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
             lastUpdateTime: formattedDateAndTime.toString(),
             dataSyncEnabled: false,
             dataStores: dataStores())
@@ -615,8 +615,7 @@ class NetworkCmProxyControllerSpec extends Specification {
         def expectedContent = [
             '"state":',
             '"cmHandleState":"ADVISED"',
-            '"reason":"LOCKED_MISBEHAVING"',
-            '"details":"lock details"',
+            '"lockReason":{"reason":"MODULE_SYNC_FAILED","details":"lock details"}',
             '"lastUpdateTime":"2022-12-31T20:30:40.000+0000"',
             '"dataSyncEnabled":false',
             '"dataSyncState":',
index e755094..1d03be1 100644 (file)
@@ -219,14 +219,14 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
             responseBody.getFailedUpdatedCmHandles() == expectedFailedUpdateCmHandle
             responseBody.getFailedRemovedCmHandles() == expectedFailedRemovedCmHandle
         where:
-            scenario               | createCmHandleResponse         | updateCmHandleResponse         | removeCmHandleResponse         || expectedFailedCreatedCmHandle       | expectedFailedUpdateCmHandle        | expectedFailedRemovedCmHandle
-            'only create failed'   | failedResponse('cm-handle-1')  | successResponse('cm-handle-2') | successResponse('cm-handle-3') || [failedRestResponse('cm-handle-1')] | []                                  | []
-            'only update failed'   | successResponse('cm-handle-1') | failedResponse('cm-handle-2')  | successResponse('cm-handle-3') || []                                  | [failedRestResponse('cm-handle-2')] | []
-            'only delete failed'   | successResponse('cm-handle-1') | successResponse('cm-handle-2') | failedResponse('cm-handle-3')  || []                                  | []                                  | [failedRestResponse('cm-handle-3')]
-            'all three failed'     | failedResponse('cm-handle-1')  | failedResponse('cm-handle-2')  | failedResponse('cm-handle-3')  || [failedRestResponse('cm-handle-1')] | [failedRestResponse('cm-handle-2')] | [failedRestResponse('cm-handle-3')]
-            'create update failed' | failedResponse('cm-handle-1')  | failedResponse('cm-handle-2')  | successResponse('cm-handle-3') || [failedRestResponse('cm-handle-1')] | [failedRestResponse('cm-handle-2')] | []
-            'create delete failed' | failedResponse('cm-handle-1')  | successResponse('cm-handle-2') | failedResponse('cm-handle-3')  || [failedRestResponse('cm-handle-1')] | []                                  | [failedRestResponse('cm-handle-3')]
-            'update delete failed' | successResponse('cm-handle-1') | failedResponse('cm-handle-2')  | failedResponse('cm-handle-3')  || []                                  | [failedRestResponse('cm-handle-2')] | [failedRestResponse('cm-handle-3')]
+        scenario               | createCmHandleResponse                 | updateCmHandleResponse                 | removeCmHandleResponse                 || expectedFailedCreatedCmHandle                 | expectedFailedUpdateCmHandle                  | expectedFailedRemovedCmHandle
+        'only create failed'   | expectedFailedResponse('cm-handle-1')  | expectedSuccessResponse('cm-handle-2') | expectedSuccessResponse('cm-handle-3') || [expectedUnknownErrorResponse('cm-handle-1')] | []                                            | []
+        'only update failed'   | expectedSuccessResponse('cm-handle-1') | expectedFailedResponse('cm-handle-2')  | expectedSuccessResponse('cm-handle-3') || []                                            | [expectedUnknownErrorResponse('cm-handle-2')] | []
+        'only delete failed'   | expectedSuccessResponse('cm-handle-1') | expectedSuccessResponse('cm-handle-2') | expectedFailedResponse('cm-handle-3')  || []                                            | []                                            | [expectedUnknownErrorResponse('cm-handle-3')]
+        'all three failed'     | expectedFailedResponse('cm-handle-1')  | expectedFailedResponse('cm-handle-2')  | expectedFailedResponse('cm-handle-3')  || [expectedUnknownErrorResponse('cm-handle-1')] | [expectedUnknownErrorResponse('cm-handle-2')] | [expectedUnknownErrorResponse('cm-handle-3')]
+        'create update failed' | expectedFailedResponse('cm-handle-1')  | expectedFailedResponse('cm-handle-2')  | expectedSuccessResponse('cm-handle-3') || [expectedUnknownErrorResponse('cm-handle-1')] | [expectedUnknownErrorResponse('cm-handle-2')] | []
+        'create delete failed' | expectedFailedResponse('cm-handle-1')  | expectedSuccessResponse('cm-handle-2') | expectedFailedResponse('cm-handle-3')  || [expectedUnknownErrorResponse('cm-handle-1')] | []                                            | [expectedUnknownErrorResponse('cm-handle-3')]
+        'update delete failed' | expectedSuccessResponse('cm-handle-1') | expectedFailedResponse('cm-handle-2')  | expectedFailedResponse('cm-handle-3')  || []                                            | [expectedUnknownErrorResponse('cm-handle-2')] | [expectedUnknownErrorResponse('cm-handle-3')]
     }
 
     def 'Get all cm handle IDs by DMI plugin identifier.'() {
@@ -246,15 +246,15 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
             assert response.contentAsString.contains('cm-handle-id-2')
     }
 
-    def failedRestResponse(cmHandle) {
-        return new CmHandlerRegistrationErrorResponse('cmHandle': cmHandle, 'errorCode': '00', 'errorText': 'Failed')
+    def expectedUnknownErrorResponse(cmHandle) {
+        return new CmHandlerRegistrationErrorResponse('cmHandle': cmHandle, 'errorCode': '108', 'errorText': 'Failed')
     }
 
-    def failedResponse(cmHandle) {
+    def expectedFailedResponse(cmHandle) {
         return CmHandleRegistrationResponse.createFailureResponse(cmHandle, new RuntimeException('Failed'))
     }
 
-    def successResponse(cmHandle) {
+    def expectedSuccessResponse(cmHandle) {
         return CmHandleRegistrationResponse.createSuccessResponse(cmHandle)
     }
 
index b1133a1..f394f91 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * 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.
 
 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
+
 import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
 import org.onap.cps.ncmp.rest.model.CmHandleCompositeState
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
+import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
 import spock.lang.Ignore
 import spock.lang.Specification
 
@@ -44,7 +46,7 @@ class CmHandleStateMapperSpec extends Specification {
             def compositeState = new CompositeStateBuilder()
                 .withCmHandleState(CmHandleState.ADVISED)
                 .withLastUpdatedTime(formattedDateAndTime.toString())
-                .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, 'locked details')
+                .withLockReason(MODULE_SYNC_FAILED, 'locked details')
                 .withOperationalDataStores(DataStoreSyncState.SYNCHRONIZED, formattedDateAndTime).build()
         compositeState.setDataSyncEnabled(false)
         when: 'mapper is called'
@@ -54,7 +56,7 @@ class CmHandleStateMapperSpec extends Specification {
         and: 'mapped result should have correct values'
             assert !result.dataSyncEnabled
             assert result.lastUpdateTime == formattedDateAndTime
-            assert result.lockReason.reason == 'LOCKED_MISBEHAVING'
+            assert result.lockReason.reason == MODULE_SYNC_FAILED.name()
             assert result.lockReason.details == 'locked details'
             assert result.cmHandleState == 'ADVISED'
             assert result.dataSyncState.operational.getSyncState() != null
@@ -68,17 +70,17 @@ class CmHandleStateMapperSpec extends Specification {
 
     def 'Internal to External Lock Reason Mapping of #scenario'() {
         given: 'a LOCKED composite state with locked reason of #scenario'
-            def compositeState = new CompositeStateBuilder()
+        def compositeState = new CompositeStateBuilder()
                 .withCmHandleState(CmHandleState.LOCKED)
                 .withLockReason(lockReason, '').build()
         when: 'the composite state is mapped to a CMHandle composite state'
-            def result = objectUnderTest.toCmHandleCompositeStateExternalLockReason(compositeState)
+        def result = objectUnderTest.toCmHandleCompositeStateExternalLockReason(compositeState)
         then: 'the composite state contains the expected lock Reason and details'
-            result.getLockReason().getReason() == expectedExternalLockReason
+        result.getLockReason().getReason() == (expectedExternalLockReason as String)
         where:
-            scenario                    | lockReason                                   || expectedExternalLockReason
-            'LOCKED_MODULE_SYNC_FAILED' | LockReasonCategory.LOCKED_MODULE_SYNC_FAILED || 'LOCKED_MISBEHAVING'
-            'null value'                | null                                         || null
+        scenario             | lockReason         || expectedExternalLockReason
+        'MODULE_SYNC_FAILED' | MODULE_SYNC_FAILED || MODULE_SYNC_FAILED
+        'null value'         | null               || LOCKED_MISBEHAVING
     }
 
 }
index fa3a369..d7c1774 100644 (file)
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
     <artifactId>cps-ncmp-service</artifactId>
 
     <properties>
-        <minimum-coverage>0.98</minimum-coverage>
+        <minimum-coverage>0.96</minimum-coverage>
     </properties>
     <dependencies>
         <dependency>
@@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api;
 import lombok.Getter;
 
 @Getter
-public enum NcmpEventResponseCode {
+public enum NcmpResponseStatus {
 
     SUCCESS("0", "Successfully applied changes"),
     SUCCESSFULLY_APPLIED_SUBSCRIPTION("1", "successfully applied subscription"),
@@ -33,13 +33,16 @@ public enum NcmpEventResponseCode {
     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");
+    SUBSCRIPTION_PENDING("106", "subscription pending for all cm handles"),
+    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");
 
-    private final String statusCode;
-    private final String statusMessage;
+    private final String code;
+    private final String message;
 
-    NcmpEventResponseCode(final String statusCode, final String statusMessage) {
-        this.statusCode = statusCode;
-        this.statusMessage = statusMessage;
+    NcmpResponseStatus(final String code, final String message) {
+        this.code = code;
+        this.message = message;
     }
 }
index a65e3c4..e7ffaa6 100644 (file)
@@ -25,8 +25,8 @@ 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.inventory.CompositeState;
 import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
 import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
 import org.onap.cps.ncmp.api.models.DataOperationRequest;
index 1d390f8..7475cdd 100644 (file)
@@ -20,6 +20,7 @@
 
 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;
@@ -41,12 +42,12 @@ 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.inventory.CmHandleQueries;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.inventory.enums.PropertyType;
 import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.spi.exceptions.DataValidationException;
@@ -156,7 +157,8 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
         }
         try {
             cpsPathQueryResult = collectCmHandleIdsFromDataNodes(
-                cmHandleQueries.queryCmHandleDataNodesByCpsPath(cpsPathCondition.get("cpsPath"), OMIT_DESCENDANTS));
+                cmHandleQueries.queryCmHandleAncestorsByCpsPath(
+                        cpsPathCondition.get("cpsPath"), OMIT_DESCENDANTS));
         } catch (final PathParsingException pathParsingException) {
             throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(),
                     pathParsingException);
@@ -198,12 +200,12 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH
     }
 
     private Collection<NcmpServiceCmHandle> getAllCmHandles() {
-        final DataNode dataNode = inventoryPersistence.getDataNode("/dmi-registry").iterator().next();
+        final DataNode dataNode = inventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT).iterator().next();
         return dataNode.getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet());
     }
 
     private Collection<String> getAllCmHandleIds() {
-        final DataNode dataNode = inventoryPersistence.getDataNode("/dmi-registry", DIRECT_CHILDREN_ONLY)
+        final DataNode dataNode = inventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT, DIRECT_CHILDREN_ONLY)
                 .iterator().next();
         return collectCmHandleIdsFromDataNodes(dataNode.getChildDataNodes());
     }
index ea2f72f..692a9f2 100755 (executable)
 
 package org.onap.cps.ncmp.api.impl;
 
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+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 com.google.common.collect.Lists;
 import com.hazelcast.map.IMap;
+import java.text.MessageFormat;
 import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -44,26 +51,28 @@ 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.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.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.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.inventory.CmHandleQueries;
-import org.onap.cps.ncmp.api.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.CompositeStateUtils;
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 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.CmHandleRegistrationResponse.RegistrationError;
 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.ncmp.api.models.UpgradedCmHandles;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.exceptions.CpsException;
@@ -90,6 +99,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
     private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler;
     private final CpsDataService cpsDataService;
     private final IMap<String, Object> moduleSyncStartedOnCmHandles;
+    private final IMap<String, TrustLevel> trustLevelPerDmiPlugin;
 
     @Override
     public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
@@ -99,18 +109,26 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
         if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setRemovedCmHandles(
-                    parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles()));
+                    parseAndProcessDeletedCmHandlesInRegistration(dmiPluginRegistration.getRemovedCmHandles()));
         }
 
         if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setCreatedCmHandles(
-                    parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration));
+                    parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration));
         }
         if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) {
             dmiPluginRegistrationResponse.setUpdatedCmHandles(
                     networkCmProxyDataServicePropertyHandler
                             .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
         }
+        if (dmiPluginRegistration.getUpgradedCmHandles() != null
+                && !dmiPluginRegistration.getUpgradedCmHandles().getCmHandles().isEmpty()) {
+            dmiPluginRegistrationResponse.setUpgradedCmHandles(
+                    parseAndProcessUpgradedCmHandlesInRegistration(dmiPluginRegistration));
+        }
+
+        setTrustLevelPerDmiPlugin(dmiPluginRegistration);
+
         return dmiPluginRegistrationResponse;
     }
 
@@ -204,8 +222,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      */
     @Override
     public void setDataSyncEnabled(final String cmHandleId, final boolean dataSyncEnabled) {
-        final CompositeState compositeState = inventoryPersistence
-                .getCmHandleState(cmHandleId);
+        final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId);
         if (compositeState.getDataSyncEnabled().equals(dataSyncEnabled)) {
             log.info("Data-Sync Enabled flag is already: {} ", dataSyncEnabled);
         } else if (compositeState.getCmHandleState() != CmHandleState.READY) {
@@ -268,8 +285,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      */
     @Override
     public Map<String, String> getCmHandlePublicProperties(final String cmHandleId) {
-        final YangModelCmHandle yangModelCmHandle =
-                inventoryPersistence.getYangModelCmHandle(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);
@@ -293,7 +309,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      * @param dmiPluginRegistration dmi plugin registration information.
      * @return cm-handle registration response for create cm-handle requests.
      */
-    public List<CmHandleRegistrationResponse> parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(
+    public List<CmHandleRegistrationResponse> parseAndProcessCreatedCmHandlesInRegistration(
             final DmiPluginRegistration dmiPluginRegistration) {
         final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle = new HashMap<>();
         dmiPluginRegistration.getCreatedCmHandles()
@@ -302,18 +318,19 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
                             dmiPluginRegistration.getDmiPlugin(),
                             dmiPluginRegistration.getDmiDataPlugin(),
                             dmiPluginRegistration.getDmiModelPlugin(),
-                            cmHandle);
+                            cmHandle,
+                            cmHandle.getModuleSetTag());
                     cmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.ADVISED);
                 });
         return registerNewCmHandles(cmHandleStatePerCmHandle);
     }
 
-    protected List<CmHandleRegistrationResponse> parseAndRemoveCmHandlesInDmiRegistration(
+    protected List<CmHandleRegistrationResponse> parseAndProcessDeletedCmHandlesInRegistration(
             final List<String> tobeRemovedCmHandles) {
         final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
                 new ArrayList<>(tobeRemovedCmHandles.size());
         final Collection<YangModelCmHandle> yangModelCmHandles =
-            inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles);
+                inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles);
 
         updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING);
 
@@ -343,6 +360,42 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         return cmHandleRegistrationResponses;
     }
 
+    protected List<CmHandleRegistrationResponse> parseAndProcessUpgradedCmHandlesInRegistration(
+            final DmiPluginRegistration dmiPluginRegistration) {
+
+        final UpgradedCmHandles upgradedCmHandles = dmiPluginRegistration.getUpgradedCmHandles();
+        final String moduleSetTag = dmiPluginRegistration.getUpgradedCmHandles().getModuleSetTag();
+        final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle =
+                new HashMap<>(upgradedCmHandles.getCmHandles().size());
+        final Collection<String> notReadyCmHandles = new ArrayList<>(upgradedCmHandles.getCmHandles().size());
+        final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
+        final String formattedModuleSetTag = MessageFormat.format("new moduleSetTag: {0}", moduleSetTag);
+
+        upgradedCmHandles.getCmHandles().forEach(cmHandleId -> {
+            if (cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY)) {
+                ncmpServiceCmHandle.setCmHandleId(cmHandleId);
+                ncmpServiceCmHandle.setCompositeState(new CompositeStateBuilder()
+                        .withCmHandleState(CmHandleState.READY)
+                        .withLockReason(MODULE_UPGRADE, formattedModuleSetTag).build());
+                final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(
+                        dmiPluginRegistration.getDmiPlugin(),
+                        dmiPluginRegistration.getDmiDataPlugin(),
+                        dmiPluginRegistration.getDmiModelPlugin(),
+                        ncmpServiceCmHandle,
+                        moduleSetTag);
+                cmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED);
+            } else {
+                notReadyCmHandles.add(cmHandleId);
+            }
+        });
+
+        final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses
+                = upgradeCmHandles(cmHandleStatePerCmHandle);
+        cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses(notReadyCmHandles,
+                CM_HANDLES_NOT_READY));
+        return cmHandleRegistrationResponses;
+    }
+
     private CmHandleRegistrationResponse deleteCmHandleAndGetCmHandleRegistrationResponse(final String cmHandleId) {
         try {
             deleteCmHandleFromDbAndModuleSyncMap(cmHandleId);
@@ -350,13 +403,11 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
         } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
             log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}",
                 cmHandleId, dataNodeNotFoundException.getMessage());
-            return CmHandleRegistrationResponse.createFailureResponse(cmHandleId,
-                RegistrationError.CM_HANDLE_DOES_NOT_EXIST);
+            return CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND);
         } catch (final DataValidationException dataValidationException) {
             log.error("Unable to de-register cm-handle id: {}, caused by: {}",
                 cmHandleId, dataValidationException.getMessage());
-            return CmHandleRegistrationResponse.createFailureResponse(cmHandleId,
-                RegistrationError.CM_HANDLE_INVALID_ID);
+            return CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID);
         } catch (final Exception exception) {
             log.error("Unable to de-register cm-handle id : {} , caused by : {}", cmHandleId, exception.getMessage());
             return CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception);
@@ -372,7 +423,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private void deleteCmHandleFromDbAndModuleSyncMap(final String cmHandleId) {
         inventoryPersistence.deleteSchemaSetWithCascade(cmHandleId);
-        inventoryPersistence.deleteDataNode("/dmi-registry/cm-handles[@id='" + cmHandleId + "']");
+        inventoryPersistence.deleteDataNode(NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId
+                + "']");
         removeDeletedCmHandleFromModuleSyncMap(cmHandleId);
     }
 
@@ -384,8 +436,8 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private Collection<String> mapCmHandleIdsToXpaths(final Collection<String> cmHandles) {
         return cmHandles.stream()
-            .map(cmHandleId -> "/dmi-registry/cm-handles[@id='" + cmHandleId + "']")
-            .collect(Collectors.toSet());
+                .map(cmHandleId -> NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']")
+                .collect(Collectors.toSet());
     }
 
     // CPS-1239 Robustness cleaning of in progress cache
@@ -397,18 +449,41 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private List<CmHandleRegistrationResponse> registerNewCmHandles(final Map<YangModelCmHandle, CmHandleState>
                                                                             cmHandleStatePerCmHandle) {
-        final List<String> cmHandleIds = cmHandleStatePerCmHandle.keySet().stream().map(YangModelCmHandle::getId)
-                .collect(Collectors.toList());
+        final List<String> cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle);
         try {
             lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle);
             return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds);
         } catch (final AlreadyDefinedException alreadyDefinedException) {
             return CmHandleRegistrationResponse.createFailureResponses(
                     alreadyDefinedException.getAlreadyDefinedObjectNames(),
-                    RegistrationError.CM_HANDLE_ALREADY_EXIST);
+                    CM_HANDLE_ALREADY_EXIST);
+        } catch (final Exception exception) {
+            return CmHandleRegistrationResponse.createFailureResponses(cmHandleIds, exception);
+        }
+    }
+
+    private List<CmHandleRegistrationResponse> upgradeCmHandles(final Map<YangModelCmHandle, CmHandleState>
+                                                                        cmHandleStatePerCmHandle) {
+        final List<String> cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle);
+        log.info("Moving cm handles : {} into locked (for upgrade) state.", cmHandleIds);
+        try {
+            lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle);
+            return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds);
         } catch (final Exception exception) {
             return CmHandleRegistrationResponse.createFailureResponses(cmHandleIds, exception);
         }
     }
 
+    private static List<String> getCmHandleIds(final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle) {
+        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);
+        }
+    }
+
 }
index bbb2c0f..401b190 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  Copyright (C) 2022-2023 Nordix Foundation
  *  Modifications Copyright (C) 2022 Bell Canada
  *  Modifications Copyright (C) 2023 TechMahindra Ltd.
  *  ================================================================================
@@ -22,6 +22,8 @@
 
 package org.onap.cps.ncmp.api.impl;
 
+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;
 
@@ -36,9 +38,8 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
 import org.onap.cps.spi.exceptions.DataValidationException;
@@ -75,13 +76,12 @@ public class NetworkCmProxyDataServicePropertyHandler {
                 log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}",
                     cmHandleId, e.getMessage());
                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse
-                    .createFailureResponse(cmHandleId, RegistrationError.CM_HANDLE_DOES_NOT_EXIST));
+                    .createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND));
             } catch (final DataValidationException e) {
                 log.error("Unable to update cm handle : {}, caused by : {}",
                     cmHandleId, e.getMessage());
                 cmHandleRegistrationResponses.add(
-                    CmHandleRegistrationResponse.createFailureResponse(cmHandleId,
-                        RegistrationError.CM_HANDLE_INVALID_ID));
+                    CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID));
             } catch (final Exception exception) {
                 log.error("Unable to update cmHandle : {} , caused by : {}",
                     cmHandleId, exception.getMessage());
index 5540ecd..d8353f3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -20,7 +20,7 @@
 
 package org.onap.cps.ncmp.api.impl;
 
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
 
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
index 62a380c..8b28717 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.cps.ncmp.api.impl.config.embeddedcache;
 import com.hazelcast.config.MapConfig;
 import com.hazelcast.config.QueueConfig;
 import com.hazelcast.map.IMap;
+import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.cache.HazelcastCacheConfig;
@@ -44,6 +45,8 @@ public class SynchronizationCacheConfig extends HazelcastCacheConfig {
     private static final MapConfig moduleSyncStartedConfig = createMapConfig("moduleSyncStartedConfig");
     private static final MapConfig dataSyncSemaphoresConfig = createMapConfig("dataSyncSemaphoresConfig");
 
+    private static final MapConfig moduleSetTagCacheMapConfig = createMapConfig("moduleSetTagCacheMapConfig");
+
     /**
      * Module Sync Distributed Queue Instance.
      *
@@ -74,4 +77,15 @@ public class SynchronizationCacheConfig extends HazelcastCacheConfig {
     public IMap<String, Boolean> dataSyncSemaphores() {
         return createHazelcastInstance("dataSyncSemaphores", dataSyncSemaphoresConfig).getMap("dataSyncSemaphores");
     }
+
+    /**
+     * IMap instance for cached ModulesSetTags.
+     *
+     * @return configured map of ModuleSetTags
+     */
+    @Bean
+    public IMap<String, Set<String>> moduleSetTagCache() {
+        return createHazelcastInstance("moduleSetTags", moduleSetTagCacheMapConfig)
+                .getMap("moduleSetTagCache");
+    }
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/constants/DmiRegistryConstants.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/constants/DmiRegistryConstants.java
deleted file mode 100644 (file)
index a133cfb..0000000
+++ /dev/null
@@ -1,36 +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.ncmp.api.impl.constants;
-
-import java.time.OffsetDateTime;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-
-/**
- * DmiRegistryConstants class to be strictly used for DMI Related constants only.
- */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class DmiRegistryConstants {
-
-    public static final String NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME = "NFP-Operational";
-
-    public static final OffsetDateTime NO_TIMESTAMP = null;
-}
index 58d0d2d..355e5cd 100644 (file)
@@ -64,8 +64,8 @@ public class EventsPublisher<T> {
                 cloudEventKafkaTemplate.send(topicName, eventKey, event);
         eventFuture.whenComplete((result, e) -> {
             if (e == null) {
-                log.debug("Successfully published event to topic : {} , Event : {}",
-                        result.getRecordMetadata().topic(), result.getProducerRecord().value());
+                log.debug("Successfully published event to topic : {} , Event : {}", result.getRecordMetadata().topic(),
+                        result.getProducerRecord().value());
 
             } else {
                 log.error("Unable to publish event to topic : {} due to {}", topicName, e.getMessage());
@@ -85,14 +85,7 @@ public class EventsPublisher<T> {
     public void publishEvent(final String topicName, final String eventKey, final T event) {
         final CompletableFuture<SendResult<String, T>> eventFuture =
                 legacyKafkaEventTemplate.send(topicName, eventKey, event);
-        eventFuture.whenComplete((result, e) -> {
-            if (e == null) {
-                log.debug("Successfully published event to topic : {} , Event : {}",
-                        result.getRecordMetadata().topic(), result.getProducerRecord().value());
-            } else {
-                log.error("Unable to publish event to topic : {} due to {}", topicName, e.getMessage());
-            }
-        });
+        handleLegacyEventCallback(topicName, eventFuture);
     }
 
     /**
@@ -107,16 +100,8 @@ public class EventsPublisher<T> {
 
         final ProducerRecord<String, T> producerRecord =
                 new ProducerRecord<>(topicName, null, eventKey, event, eventHeaders);
-        final CompletableFuture<SendResult<String, T>> eventFuture =
-                legacyKafkaEventTemplate.send(producerRecord);
-        eventFuture.whenComplete((result, ex) -> {
-            if (ex != null) {
-                log.error("Unable to publish event to topic : {} due to {}", topicName, ex.getMessage());
-            } else {
-                log.debug("Successfully published event to topic : {} , Event : {}",
-                        result.getRecordMetadata().topic(), result.getProducerRecord().value());
-            }
-        });
+        final CompletableFuture<SendResult<String, T>> eventFuture = legacyKafkaEventTemplate.send(producerRecord);
+        handleLegacyEventCallback(topicName, eventFuture);
     }
 
     /**
@@ -133,6 +118,17 @@ public class EventsPublisher<T> {
         publishEvent(topicName, eventKey, convertToKafkaHeaders(eventHeaders), event);
     }
 
+    private void handleLegacyEventCallback(final String topicName,
+            final CompletableFuture<SendResult<String, T>> eventFuture) {
+        eventFuture.whenComplete((result, e) -> {
+            if (e != null) {
+                log.error("Unable to publish event to topic : {} due to {}", topicName, e.getMessage());
+            } else {
+                log.debug("Successfully published event to topic : {} , Event : {}", result.getRecordMetadata().topic(),
+                        result.getProducerRecord().value());
+            }
+        });
+    }
 
     private Headers convertToKafkaHeaders(final Map<String, Object> eventMessageHeaders) {
         final Headers eventHeaders = new RecordHeaders();
index ea2d17d..5f26db3 100644 (file)
@@ -36,13 +36,13 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.impl.config.embeddedcache.ForwardedSubscriptionEventCacheConfig;
 import org.onap.cps.ncmp.api.impl.events.EventsPublisher;
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence;
 import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus;
 import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper;
 import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.CmSubscriptionEvent;
 import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent;
 import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle;
index 473538c..a0fd81c 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.events.cmsubscription;
 
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.PARTIALLY_APPLIED_SUBSCRIPTION;
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_NOT_APPLICABLE;
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_PENDING;
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESSFULLY_APPLIED_SUBSCRIPTION;
+import static org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.ACCEPTED;
+import static org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.PENDING;
+import static org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus.REJECTED;
+
 import io.cloudevents.CloudEvent;
 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.NcmpEventResponseCode;
+import org.onap.cps.ncmp.api.NcmpResponseStatus;
 import org.onap.cps.ncmp.api.impl.events.EventsPublisher;
 import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence;
 import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus;
@@ -100,48 +107,39 @@ public class CmSubscriptionNcmpOutEventPublisher {
                     cmSubscriptionStatus.setStatus(SubscriptionStatus.fromString(status));
                     cmSubscriptionStatus.setDetails(details);
                     return cmSubscriptionStatus;
-                }).collect(Collectors.toList());
+                }).toList();
     }
 
-    private NcmpEventResponseCode decideOnNcmpEventResponseCodeForSubscription(
+    private NcmpResponseStatus decideOnNcmpEventResponseCodeForSubscription(
             final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMap) {
 
-        final boolean isAllTargetsPending = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap,
-                SubscriptionStatus.PENDING);
-
-        final boolean isAllTargetsRejected = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap,
-                SubscriptionStatus.REJECTED);
-
-        final boolean isAllTargetsAccepted = isAllTargetCmHandleStatusMatch(cmHandleIdToStatusAndDetailsAsMap,
-                SubscriptionStatus.ACCEPTED);
-
-        if (isAllTargetsAccepted) {
-            return NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION;
-        } else if (isAllTargetsRejected) {
-            return NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE;
-        } else if (isAllTargetsPending) {
-            return NcmpEventResponseCode.SUBSCRIPTION_PENDING;
-        } else {
-            return NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION;
+        if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, ACCEPTED)) {
+            return SUCCESSFULLY_APPLIED_SUBSCRIPTION;
+        }
+        if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, REJECTED)) {
+            return SUBSCRIPTION_NOT_APPLICABLE;
+        }
+        if (allTargetsHaveStatus(cmHandleIdToStatusAndDetailsAsMap, PENDING)) {
+            return SUBSCRIPTION_PENDING;
         }
+        return PARTIALLY_APPLIED_SUBSCRIPTION;
     }
 
-    private boolean isAllTargetCmHandleStatusMatch(
-            final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMap,
-            final SubscriptionStatus subscriptionStatus) {
+    private boolean allTargetsHaveStatus(final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMap,
+                                         final SubscriptionStatus subscriptionStatus) {
         return cmHandleIdToStatusAndDetailsAsMap.values().stream()
                 .allMatch(entryset -> entryset.containsValue(subscriptionStatus.toString()));
     }
 
     private CmSubscriptionNcmpOutEvent fromCmSubscriptionEvent(
             final CmSubscriptionEvent cmSubscriptionEvent,
-            final NcmpEventResponseCode ncmpEventResponseCode) {
+            final NcmpResponseStatus ncmpResponseStatus) {
 
         final CmSubscriptionNcmpOutEvent cmSubscriptionNcmpOutEvent =
                 cmSubscriptionEventToCmSubscriptionNcmpOutEventMapper.toCmSubscriptionNcmpOutEvent(
                         cmSubscriptionEvent);
-        cmSubscriptionNcmpOutEvent.getData().setStatusCode(Integer.parseInt(ncmpEventResponseCode.getStatusCode()));
-        cmSubscriptionNcmpOutEvent.getData().setStatusMessage(ncmpEventResponseCode.getStatusMessage());
+        cmSubscriptionNcmpOutEvent.getData().setStatusCode(Integer.parseInt(ncmpResponseStatus.getCode()));
+        cmSubscriptionNcmpOutEvent.getData().setStatusMessage(ncmpResponseStatus.getMessage());
 
         return cmSubscriptionNcmpOutEvent;
     }
index 2ae1188..fdee28e 100644 (file)
@@ -21,8 +21,8 @@
 package org.onap.cps.ncmp.api.impl.events.lcm;
 
 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.api.inventory.CmHandleState;
 
 /**
  * The implementation of it should handle the persisting of composite state and delegate the request to publish the
index ce19712..02368b8 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.events.lcm;
 
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED;
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED;
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED;
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY;
+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 io.micrometer.core.annotation.Timed;
 import java.util.ArrayList;
@@ -36,12 +36,12 @@ 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.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.CompositeStateUtils;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.springframework.stereotype.Service;
 
index d3b45d4..19d9ba5 100644 (file)
@@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api.impl.events.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.inventory.CmHandleState.DELETED;
+import static org.onap.cps.ncmp.api.impl.inventory.CmHandleState.DELETED;
 
 import com.google.common.collect.MapDifference;
 import com.google.common.collect.Maps;
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 import java.util.Collection;
 import java.util.List;
@@ -52,13 +52,22 @@ public interface CmHandleQueries {
      */
     List<DataNode> queryCmHandlesByState(CmHandleState cmHandleState);
 
+    /**
+     * Method to return data nodes with ancestor representing the cm handles.
+     *
+     * @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);
+
     /**
      * Method to return data nodes representing the cm handles.
      *
      * @param cpsPath cps path for which the cmHandle is requested
      * @return a list of data nodes representing the cm handles.
      */
-    List<DataNode> queryCmHandleDataNodesByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption);
+    List<DataNode> queryNcmpRegistryByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption);
 
     /**
      * Method to check the state of a cm handle with given id.
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+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.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS;
 
@@ -31,7 +34,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
-import org.onap.cps.ncmp.api.inventory.enums.PropertyType;
+import org.onap.cps.ncmp.api.impl.inventory.enums.PropertyType;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.DataNode;
@@ -41,8 +44,6 @@ import org.springframework.stereotype.Component;
 @Component
 public class CmHandleQueriesImpl implements CmHandleQueries {
 
-    private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
-    private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
     private static final String DESCENDANT_PATH = "//";
 
     private final CpsDataPersistenceService cpsDataPersistenceService;
@@ -60,15 +61,21 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
 
     @Override
     public List<DataNode> queryCmHandlesByState(final CmHandleState cmHandleState) {
-        return queryCmHandleDataNodesByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]",
+        return queryCmHandleAncestorsByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]",
             INCLUDE_ALL_DESCENDANTS);
     }
 
     @Override
-    public List<DataNode> queryCmHandleDataNodesByCpsPath(final String cpsPath,
-            final FetchDescendantsOption fetchDescendantsOption) {
+    public List<DataNode> queryNcmpRegistryByCpsPath(final String cpsPath,
+                                                     final FetchDescendantsOption fetchDescendantsOption) {
         return cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-            cpsPath + ANCESTOR_CM_HANDLES, fetchDescendantsOption);
+                cpsPath, fetchDescendantsOption);
+    }
+
+    @Override
+    public List<DataNode> queryCmHandleAncestorsByCpsPath(final String cpsPath,
+                                                          final FetchDescendantsOption fetchDescendantsOption) {
+        return queryNcmpRegistryByCpsPath(cpsPath + ANCESTOR_CM_HANDLES, fetchDescendantsOption);
     }
 
     @Override
@@ -80,7 +87,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
 
     @Override
     public List<DataNode> queryCmHandlesByOperationalSyncState(final DataStoreSyncState dataStoreSyncState) {
-        return queryCmHandleDataNodesByCpsPath("//state/datastores" + "/operational[@sync-state=\""
+        return queryCmHandleAncestorsByCpsPath("//state/datastores" + "/operational[@sync-state=\""
                 + dataStoreSyncState + "\"]", FetchDescendantsOption.OMIT_DESCENDANTS);
     }
 
@@ -113,7 +120,8 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
                 + publicPropertyQueryPair.getKey()
                 + "\" and @value=\"" + publicPropertyQueryPair.getValue() + "\"]";
 
-            final Collection<DataNode> dataNodes = queryCmHandleDataNodesByCpsPath(cpsPath, OMIT_DESCENDANTS);
+            final Collection<DataNode> dataNodes = queryCmHandleAncestorsByCpsPath(cpsPath,
+                    OMIT_DESCENDANTS);
             if (cmHandleIds == null) {
                 cmHandleIds = collectCmHandleIdsFromDataNodes(dataNodes);
             } else {
@@ -128,14 +136,14 @@ public class CmHandleQueriesImpl implements CmHandleQueries {
     }
 
     private List<DataNode> getCmHandlesByDmiPluginIdentifierAndDmiProperty(final String dmiPluginIdentifier,
-                                                             final String dmiProperty) {
+                                                                           final String dmiProperty) {
         return cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                "/dmi-registry/cm-handles[@" + dmiProperty + "='" + dmiPluginIdentifier + "']",
+                NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@" + dmiProperty + "='" + dmiPluginIdentifier + "']",
                 OMIT_DESCENDANTS);
     }
 
     private DataNode getCmHandleState(final String cmHandleId) {
-        final String xpath = "/dmi-registry/cm-handles[@id='" + cmHandleId + "']/state";
+        final String xpath = NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']/state";
         return cpsDataPersistenceService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                 xpath, OMIT_DESCENDANTS).iterator().next();
     }
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 public enum CmHandleState {
     ADVISED, READY, LOCKED, DELETING, DELETED
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * 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.
@@ -18,7 +18,7 @@
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -1,7 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  * Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2022 Nordix Foundation.
+ * Modifications 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.
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
-import org.onap.cps.ncmp.api.inventory.CompositeState.DataStores;
-import org.onap.cps.ncmp.api.inventory.CompositeState.LockReason;
-import org.onap.cps.ncmp.api.inventory.CompositeState.Operational;
+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.spi.model.DataNode;
 
 public class CompositeStateBuilder {
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * 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.
@@ -18,7 +18,7 @@
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 import java.util.function.Consumer;
 import lombok.AccessLevel;
@@ -100,7 +100,9 @@ public class CompositeStateUtils {
             compositeState.setLastUpdateTimeNow();
             final String oldLockReasonDetails = compositeState.getLockReason().getDetails();
             final CompositeState.LockReason lockReason =
-                    CompositeState.LockReason.builder().details(oldLockReasonDetails).build();
+                    CompositeState.LockReason.builder()
+                            .lockReasonCategory(compositeState.getLockReason().getLockReasonCategory())
+                            .details(oldLockReasonDetails).build();
             compositeState.setLockReason(lockReason);
         };
     }
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 public enum DataStoreSyncState {
     SYNCHRONIZED, UNSYNCHRONIZED, NONE_REQUESTED
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 import java.util.Collection;
 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.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.ModuleDefinition;
 import org.onap.cps.spi.model.ModuleReference;
 
-public interface InventoryPersistence {
+public interface InventoryPersistence extends NcmpPersistence {
 
     /**
      * Get the Cm Handle Composite State from the data node.
@@ -100,61 +100,6 @@ public interface InventoryPersistence {
      */
     void saveCmHandleBatch(Collection<YangModelCmHandle> yangModelCmHandles);
 
-    /**
-     * Method to delete a list or a list element.
-     *
-     * @param listElementXpath list element xPath
-     */
-    void deleteListOrListElement(String listElementXpath);
-
-    /**
-     * Method to delete a schema set.
-     *
-     * @param schemaSetName schema set name
-     */
-    void deleteSchemaSetWithCascade(String schemaSetName);
-
-    /**
-     * Method to delete multiple schema sets.
-     *
-     * @param schemaSetNames schema set names
-     */
-    void deleteSchemaSetsWithCascade(Collection<String> schemaSetNames);
-
-    /**
-     * Get data node via xpath.
-     *
-     * @param xpath xpath
-     * @return data node
-     */
-    Collection<DataNode> getDataNode(String xpath);
-
-    /**
-     * Get data node via xpath.
-     *
-     * @param xpath xpath
-     * @param fetchDescendantsOption fetch descendants option
-     * @return data node
-     */
-    Collection<DataNode> getDataNode(String xpath, FetchDescendantsOption fetchDescendantsOption);
-
-    /**
-     * Get collection of data nodes via xpaths.
-     *
-     * @param xpaths collection of xpaths
-     * @return collection of data nodes
-     */
-    Collection<DataNode> getDataNodes(Collection<String> xpaths);
-
-    /**
-     * Get collection of data nodes via xpaths.
-     *
-     * @param xpaths collection of xpaths
-     * @param fetchDescendantsOption fetch descendants option
-     * @return collection of data nodes
-     */
-    Collection<DataNode> getDataNodes(Collection<String> xpaths, FetchDescendantsOption fetchDescendantsOption);
-
     /**
      * Get data node of given cm handle.
      *
@@ -178,26 +123,4 @@ public interface InventoryPersistence {
      * @return Collection of CM handle Ids
      */
     Collection<String> getCmHandleIdsWithGivenModules(Collection<String> moduleNamesForQuery);
-
-    /**
-     * Replaces list content by removing all existing elements and inserting the given new elements as data nodes.
-     *
-     * @param parentNodeXpath parent node xpath
-     * @param dataNodes       datanodes representing the updated data
-     */
-    void replaceListContent(String parentNodeXpath, Collection<DataNode> dataNodes);
-
-    /**
-     * Deletes data node.
-     *
-     * @param dataNodeXpath data node xpath
-     */
-    void deleteDataNode(String dataNodeXpath);
-
-    /**
-     * Deletes multiple data nodes.
-     *
-     * @param dataNodeXpaths data node xpaths
-     */
-    void deleteDataNodes(Collection<String> dataNodeXpaths);
 }
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP;
-import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
-
-import io.micrometer.core.annotation.Timed;
 import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
 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.CpsAdminService;
 import org.onap.cps.api.CpsDataService;
@@ -43,7 +36,6 @@ import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.exceptions.DataValidationException;
-import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
 import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.ModuleDefinition;
 import org.onap.cps.spi.model.ModuleReference;
@@ -52,31 +44,37 @@ import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.stereotype.Component;
 
 @Slf4j
-@RequiredArgsConstructor
 @Component
-public class InventoryPersistenceImpl implements InventoryPersistence {
-
-    private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
-
-    private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
-
-    private static final String NCMP_DMI_REGISTRY_PARENT = "/dmi-registry";
-
-    private final JsonObjectMapper jsonObjectMapper;
-
-    private final CpsDataService cpsDataService;
+public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements InventoryPersistence {
 
     private final CpsModuleService cpsModuleService;
-
     private final CpsAdminService cpsAdminService;
-
     private final CpsValidator cpsValidator;
 
+    /**
+     * initialize an inventory persistence object.
+     *
+     * @param jsonObjectMapper json mapper object
+     * @param cpsDataService   cps data service instance
+     * @param cpsModuleService cps module service instance
+     * @param cpsValidator     cps validation service instance
+     * @param cpsAdminService  cps admin service instance
+     */
+    public InventoryPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService,
+                                    final CpsModuleService cpsModuleService, final CpsValidator cpsValidator,
+                                    final CpsAdminService cpsAdminService) {
+        super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator);
+        this.cpsModuleService = cpsModuleService;
+        this.cpsAdminService = cpsAdminService;
+        this.cpsValidator = cpsValidator;
+    }
+
+
     @Override
     public CompositeState getCmHandleState(final String cmHandleId) {
         final DataNode stateAsDataNode = cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                createCmHandleXPath(cmHandleId) + "/state",
-                FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS).iterator().next();
+                        createCmHandleXPath(cmHandleId) + "/state", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+                .iterator().next();
         cpsValidator.validateNameCharacters(cmHandleId);
         return new CompositeStateBuilder().fromDataNode(stateAsDataNode).build();
     }
@@ -85,8 +83,7 @@ public class InventoryPersistenceImpl implements InventoryPersistence {
     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,
-                createCmHandleXPath(cmHandleId),
-                cmHandleJsonData, OffsetDateTime.now());
+                createCmHandleXPath(cmHandleId), cmHandleJsonData, OffsetDateTime.now());
     }
 
     @Override
@@ -149,60 +146,6 @@ public class InventoryPersistenceImpl implements InventoryPersistence {
                 NCMP_DMI_REGISTRY_PARENT, cmHandlesJsonData, NO_TIMESTAMP);
     }
 
-    @Override
-    public void deleteListOrListElement(final String listElementXpath) {
-        cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                listElementXpath, NO_TIMESTAMP);
-    }
-
-    @Override
-    @Timed(value = "cps.ncmp.inventory.persistence.schemaset.delete",
-            description = "Time taken to delete a schemaset")
-    public void deleteSchemaSetWithCascade(final String schemaSetName) {
-        try {
-            cpsValidator.validateNameCharacters(schemaSetName);
-            cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
-                    CASCADE_DELETE_ALLOWED);
-        } catch (final SchemaSetNotFoundException schemaSetNotFoundException) {
-            log.warn("Schema set {} does not exist or already deleted", schemaSetName);
-        }
-    }
-
-    @Override
-    @Timed(value = "cps.ncmp.inventory.persistence.schemaset.delete.batch",
-        description = "Time taken to delete multiple schemaset")
-    public void deleteSchemaSetsWithCascade(final Collection<String> schemaSetNames) {
-        cpsValidator.validateNameCharacters(schemaSetNames);
-        cpsModuleService.deleteSchemaSetsWithCascade(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetNames);
-    }
-
-    @Override
-    @Timed(value = "cps.ncmp.inventory.persistence.datanode.get",
-            description = "Time taken to get a data node (from ncmp dmi registry)")
-    public Collection<DataNode> getDataNode(final String xpath) {
-        return getDataNode(xpath, INCLUDE_ALL_DESCENDANTS);
-    }
-
-    @Override
-    @Timed(value = "cps.ncmp.inventory.persistence.datanode.get",
-            description = "Time taken to get a data node (from ncmp dmi registry)")
-    public Collection<DataNode> getDataNode(final String xpath, final FetchDescendantsOption fetchDescendantsOption) {
-        return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                xpath, fetchDescendantsOption);
-    }
-
-    @Override
-    public Collection<DataNode> getDataNodes(final Collection<String> xpaths) {
-        return getDataNodes(xpaths, INCLUDE_ALL_DESCENDANTS);
-    }
-
-    @Override
-    public Collection<DataNode> getDataNodes(final Collection<String> xpaths,
-                                             final FetchDescendantsOption fetchDescendantsOption) {
-        return cpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                xpaths, fetchDescendantsOption);
-    }
-
     @Override
     public Collection<DataNode> getCmHandleDataNode(final String cmHandleId) {
         return this.getDataNode(createCmHandleXPath(cmHandleId));
@@ -220,24 +163,8 @@ public class InventoryPersistenceImpl implements InventoryPersistence {
         return cpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery);
     }
 
-    @Override
-    public void replaceListContent(final String parentNodeXpath, final Collection<DataNode> dataNodes) {
-        cpsDataService.replaceListContent(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
-                parentNodeXpath, dataNodes, NO_TIMESTAMP);
-    }
-
-    @Override
-    public void deleteDataNode(final String dataNodeXpath) {
-        cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, dataNodeXpath, NO_TIMESTAMP);
-    }
-
-    @Override
-    public void deleteDataNodes(final Collection<String> dataNodeXpaths) {
-        cpsDataService.deleteDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, dataNodeXpaths, NO_TIMESTAMP);
-    }
-
     private static String createCmHandleXPath(final String cmHandleId) {
-        return "/dmi-registry/cm-handles[@id='" + cmHandleId + "']";
+        return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']";
     }
 
     private static String createStateJsonData(final String state) {
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 public enum LockReasonCategory {
-    LOCKED_MODULE_SYNC_FAILED
+    MODULE_SYNC_FAILED,
+    MODULE_UPGRADE,
+    MODULE_UPGRADE_FAILED,
+    LOCKED_MISBEHAVING
 }
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory;
+package org.onap.cps.ncmp.api.impl.inventory;
 
 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/NcmpPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/NcmpPersistenceImpl.java
new file mode 100644 (file)
index 0000000..6a2d6d8
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  ============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.inventory;
+
+import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
+
+import io.micrometer.core.annotation.Timed;
+import java.util.Collection;
+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.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;
+
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class NcmpPersistenceImpl implements NcmpPersistence {
+
+    protected final JsonObjectMapper jsonObjectMapper;
+    protected final CpsDataService cpsDataService;
+    private final CpsModuleService cpsModuleService;
+    private final CpsValidator cpsValidator;
+
+    @Override
+    public void deleteListOrListElement(final String listElementXpath) {
+        cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, listElementXpath,
+                NO_TIMESTAMP);
+    }
+
+    @Override
+    @Timed(value = "cps.ncmp.inventory.persistence.schemaset.delete",
+            description = "Time taken to delete a schemaset")
+    public void deleteSchemaSetWithCascade(final String schemaSetName) {
+        try {
+            cpsValidator.validateNameCharacters(schemaSetName);
+            cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
+                    CASCADE_DELETE_ALLOWED);
+        } catch (final SchemaSetNotFoundException schemaSetNotFoundException) {
+            log.warn("Schema set {} does not exist or already deleted", schemaSetName);
+        }
+    }
+
+    @Override
+    @Timed(value = "cps.ncmp.inventory.persistence.schemaset.delete.batch",
+        description = "Time taken to delete multiple schemaset")
+    public void deleteSchemaSetsWithCascade(final Collection<String> schemaSetNames) {
+        cpsValidator.validateNameCharacters(schemaSetNames);
+        cpsModuleService.deleteSchemaSetsWithCascade(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetNames);
+    }
+
+    @Override
+    @Timed(value = "cps.ncmp.inventory.persistence.datanode.get",
+            description = "Time taken to get a data node (from ncmp dmi registry)")
+    public Collection<DataNode> getDataNode(final String xpath) {
+        return getDataNode(xpath, INCLUDE_ALL_DESCENDANTS);
+    }
+
+    @Override
+    @Timed(value = "cps.ncmp.inventory.persistence.datanode.get",
+            description = "Time taken to get a data node (from ncmp dmi registry)")
+    public Collection<DataNode> getDataNode(final String xpath, final FetchDescendantsOption fetchDescendantsOption) {
+        return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath,
+                fetchDescendantsOption);
+    }
+
+    @Override
+    public Collection<DataNode> getDataNodes(final Collection<String> xpaths) {
+        return getDataNodes(xpaths, INCLUDE_ALL_DESCENDANTS);
+    }
+
+    @Override
+    public Collection<DataNode> getDataNodes(final Collection<String> xpaths,
+                                             final FetchDescendantsOption fetchDescendantsOption) {
+        return cpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpaths,
+                fetchDescendantsOption);
+    }
+
+    @Override
+    public void replaceListContent(final String parentNodeXpath, final Collection<DataNode> dataNodes) {
+        cpsDataService.replaceListContent(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, parentNodeXpath, dataNodes,
+                NO_TIMESTAMP);
+    }
+
+    @Override
+    public void deleteDataNode(final String dataNodeXpath) {
+        cpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, dataNodeXpath, NO_TIMESTAMP);
+    }
+
+    @Override
+    public void deleteDataNodes(final Collection<String> dataNodeXpaths) {
+        cpsDataService.deleteDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, dataNodeXpaths, NO_TIMESTAMP);
+    }
+
+}
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory.enums;
+package org.onap.cps.ncmp.api.impl.inventory.enums;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -18,7 +18,9 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory.sync;
+package org.onap.cps.ncmp.api.impl.inventory.sync;
+
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
 
 import com.hazelcast.map.IMap;
 import java.time.OffsetDateTime;
@@ -28,9 +30,9 @@ 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.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
+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.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
@@ -66,7 +68,7 @@ public class DataSyncWatchdog {
                 if (resourceData == null) {
                     log.debug("Error retrieving resource data for Cm-Handle: {}", cmHandleId);
                 } else {
-                    cpsDataService.saveData("NFP-Operational", cmHandleId,
+                    cpsDataService.saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId,
                             resourceData, OffsetDateTime.now());
                     setSyncStateToSynchronized().accept(compositeState);
                     inventoryPersistence.saveCmHandleState(cmHandleId, compositeState);
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/api/impl/inventory/sync/ModuleSyncService.java
new file mode 100644 (file)
index 0000000..8e17ab9
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *  ============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.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 java.time.OffsetDateTime;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.api.CpsAdminService;
+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.inventory.CompositeState;
+import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory;
+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.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.JsonObjectMapper;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ModuleSyncService {
+
+    private final DmiModelOperations dmiModelOperations;
+    private final CpsModuleService cpsModuleService;
+    private final CpsAdminService cpsAdminService;
+    private final CmHandleQueries cmHandleQueries;
+    private final CpsDataService cpsDataService;
+    private final JsonObjectMapper jsonObjectMapper;
+
+    /**
+     * This method registers a cm handle and initiates modules sync.
+     *
+     * @param upgradedCmHandle the yang model of cm handle.
+     */
+    public void syncAndCreateOrUpgradeSchemaSetAndAnchor(final YangModelCmHandle upgradedCmHandle) {
+
+        final String moduleSetTag = extractModuleSetTag(upgradedCmHandle.getCompositeState());
+        final Optional<DataNode> existingCmHandleWithSameModuleSetTag
+                = getFirstReadyDataNodeWithModuleSetTag(moduleSetTag);
+
+        if (existingCmHandleWithSameModuleSetTag.isPresent()) {
+            upgradeUsingModuleSetTag(upgradedCmHandle, moduleSetTag);
+        } else {
+            syncAndCreateSchemaSetAndAnchor(upgradedCmHandle);
+        }
+        setCmHandleModuleSetTag(upgradedCmHandle, moduleSetTag);
+    }
+
+    private void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) {
+        final Collection<ModuleReference> allModuleReferencesFromCmHandle =
+                dmiModelOperations.getModuleReferences(yangModelCmHandle);
+
+        final Collection<ModuleReference> identifiedNewModuleReferencesFromCmHandle = cpsModuleService
+                .identifyNewModuleReferences(allModuleReferencesFromCmHandle);
+
+        final Map<String, String> newModuleNameToContentMap;
+        if (identifiedNewModuleReferencesFromCmHandle.isEmpty()) {
+            newModuleNameToContentMap = Collections.emptyMap();
+        } else {
+            newModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
+                    identifiedNewModuleReferencesFromCmHandle);
+        }
+        createSchemaSetAndAnchor(yangModelCmHandle, newModuleNameToContentMap, allModuleReferencesFromCmHandle);
+    }
+
+    private void createSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle,
+                                          final Map<String, String> newModuleNameToContentMap,
+                                          final Collection<ModuleReference> allModuleReferencesFromCmHandle) {
+        final String schemaSetAndAnchorName = yangModelCmHandle.getId();
+        cpsModuleService.createOrUpgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+                schemaSetAndAnchorName, newModuleNameToContentMap, allModuleReferencesFromCmHandle);
+        cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName,
+            schemaSetAndAnchorName);
+    }
+
+    /**
+     * Deletes the SchemaSet for schema set id if the SchemaSet Exists.
+     *
+     * @param schemaSetId the schema set id to be deleted
+     */
+    public void deleteSchemaSetIfExists(final String schemaSetId) {
+        try {
+            cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetId,
+                CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED);
+            log.debug("SchemaSet for {} has been deleted. Ready to be recreated.", schemaSetId);
+        } catch (final SchemaSetNotFoundException e) {
+            log.debug("No SchemaSet for {}. Assuming CmHandle has not been previously Module Synced.", schemaSetId);
+        }
+    }
+
+    private Optional<DataNode> getFirstReadyDataNodeWithModuleSetTag(final String moduleSetTag) {
+        final List<DataNode> dataNodes = StringUtils.isNotBlank(moduleSetTag) ? cmHandleQueries
+                .queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='" + moduleSetTag + "']",
+                        FetchDescendantsOption.OMIT_DESCENDANTS) : Collections.emptyList();
+        return dataNodes.stream().filter(dataNode -> {
+            final String cmHandleId = YangDataConverter.extractCmHandleIdFromXpath(dataNode.getXpath());
+            return cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY);
+        }).findFirst();
+    }
+
+    private void setCmHandleModuleSetTag(final YangModelCmHandle upgradedCmHandle, final String moduleSetTag) {
+        final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1);
+        final Map<String, String> cmHandleProperties = new HashMap<>(2);
+        cmHandleProperties.put("id", upgradedCmHandle.getId());
+        cmHandleProperties.put("module-set-tag", moduleSetTag);
+        dmiRegistryProperties.put("cm-handles", cmHandleProperties);
+        cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
+                jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now());
+    }
+
+    private void upgradeUsingModuleSetTag(final YangModelCmHandle upgradedCmHandle, final String moduleSetTag) {
+        log.info("Found cm handle having module set tag: {}", moduleSetTag);
+        final Collection<ModuleReference> moduleReferencesFromExistingCmHandle =
+                cpsModuleService.getYangResourcesModuleReferences(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR);
+        final String upgradedSchemaSetAndAnchorName = upgradedCmHandle.getId();
+        final Map<String, String> noNewModules = Collections.emptyMap();
+        cpsModuleService.createOrUpgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+                upgradedSchemaSetAndAnchorName, noNewModules, moduleReferencesFromExistingCmHandle);
+    }
+
+    private static String extractModuleSetTag(final CompositeState compositeState) {
+        return compositeState.getLockReason() != null && compositeState.getLockReason().getLockReasonCategory()
+                == LockReasonCategory.MODULE_UPGRADE
+                ? Arrays.stream(compositeState.getLockReason().getDetails().split(":")).toList().get(1).trim()
+                : StringUtils.EMPTY;
+    }
+
+}
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory.sync;
+package org.onap.cps.ncmp.api.impl.inventory.sync;
 
 import com.hazelcast.map.IMap;
 import java.util.Collection;
@@ -30,12 +30,12 @@ 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.CmHandleState;
-import org.onap.cps.ncmp.api.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory;
 import org.onap.cps.spi.model.DataNode;
 import org.springframework.stereotype.Component;
 
@@ -60,7 +60,8 @@ public class ModuleSyncTasks {
     public CompletableFuture<Void> performModuleSync(final Collection<DataNode> cmHandlesAsDataNodes,
                                                      final AtomicInteger batchCounter) {
         try {
-            final Map<YangModelCmHandle, CmHandleState> cmHandelStatePerCmHandle = new HashMap<>();
+            final Map<YangModelCmHandle, CmHandleState> cmHandelStatePerCmHandle
+                    = new HashMap<>(cmHandlesAsDataNodes.size());
             for (final DataNode cmHandleAsDataNode : cmHandlesAsDataNodes) {
                 final String cmHandleId = String.valueOf(cmHandleAsDataNode.getLeaves().get("id"));
                 final YangModelCmHandle yangModelCmHandle =
@@ -68,16 +69,18 @@ public class ModuleSyncTasks {
                 final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId);
                 try {
                     moduleSyncService.deleteSchemaSetIfExists(cmHandleId);
-                    moduleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle);
+                    moduleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(yangModelCmHandle);
+                    yangModelCmHandle.getCompositeState().setLockReason(null);
                     cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.READY);
                 } catch (final Exception e) {
-                    log.warn("Processing of {} module sync failed due to reason {}.", cmHandleId, e.getMessage());
+                    log.warn("Processing of {} module sync failed due to reason {}.",
+                            cmHandleId, e.getMessage());
                     syncUtils.updateLockReasonDetailsAndAttempts(compositeState,
-                            LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, e.getMessage());
+                            LockReasonCategory.MODULE_SYNC_FAILED, e.getMessage());
                     setCmHandleStateLocked(yangModelCmHandle, compositeState.getLockReason());
                     cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED);
                 }
-                log.info("{} is now in {} state", cmHandleId, compositeState.getCmHandleState().name());
+                log.info("{} is now in {} state", cmHandleId, cmHandelStatePerCmHandle.get(yangModelCmHandle).name());
             }
             lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandelStatePerCmHandle);
         } finally {
@@ -96,7 +99,7 @@ public class ModuleSyncTasks {
         final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle = new HashMap<>(failedCmHandles.size());
         for (final YangModelCmHandle failedCmHandle : failedCmHandles) {
             final CompositeState compositeState = failedCmHandle.getCompositeState();
-            final boolean isReadyForRetry = syncUtils.isReadyForRetry(compositeState);
+            final boolean isReadyForRetry = syncUtils.needsModuleSyncRetryOrUpgrade(compositeState);
             log.info("Retry for cmHandleId : {} is {}", failedCmHandle.getId(), isReadyForRetry);
             if (isReadyForRetry) {
                 final String resetCmHandleId = failedCmHandle.getId();
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory.sync;
+package org.onap.cps.ncmp.api.impl.inventory.sync;
 
 import com.hazelcast.map.IMap;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -32,8 +33,8 @@ 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.api.inventory.sync.executor.AsyncTaskExecutor;
 import org.onap.cps.spi.model.DataNode;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
@@ -48,6 +49,7 @@ public class ModuleSyncWatchdog {
     private final IMap<String, Object> moduleSyncStartedOnCmHandles;
     private final ModuleSyncTasks moduleSyncTasks;
     private final AsyncTaskExecutor asyncTaskExecutor;
+    private final IMap<String, Set<String>> moduleSetTagCache;
     private static final int MODULE_SYNC_BATCH_SIZE = 100;
     private static final long PREVENT_CPU_BURN_WAIT_TIME_MILLIS = 10;
     private static final String VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP = "Started";
@@ -88,7 +90,7 @@ public class ModuleSyncWatchdog {
     @Scheduled(fixedDelayString = "${ncmp.timers.locked-modules-sync.sleep-time-ms:300000}")
     public void resetPreviouslyFailedCmHandles() {
         log.info("Processing module sync retry-watchdog waking up.");
-        final List<YangModelCmHandle> failedCmHandles = syncUtils.getModuleSyncFailedCmHandles();
+        final List<YangModelCmHandle> failedCmHandles = syncUtils.getCmHandlesThatFailedModelSyncOrUpgrade();
         log.info("Retrying {} cmHandles", failedCmHandles.size());
         moduleSyncTasks.resetFailedCmHandles(failedCmHandles);
     }
@@ -19,7 +19,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory.sync;
+package org.onap.cps.ncmp.api.impl.inventory.sync;
 
 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL;
 
@@ -35,17 +35,16 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 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.CmHandleQueries;
-import org.onap.cps.ncmp.api.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState;
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.utils.JsonObjectMapper;
@@ -56,12 +55,10 @@ import org.springframework.stereotype.Service;
 @Service
 @RequiredArgsConstructor
 public class SyncUtils {
-    private final CmHandleQueries cmHandleQueries;
 
+    private final CmHandleQueries cmHandleQueries;
     private final DmiDataOperations dmiDataOperations;
-
     private final JsonObjectMapper jsonObjectMapper;
-
     private static final Pattern retryAttemptPattern = Pattern.compile("^Attempt #(\\d+) failed:");
 
     /**
@@ -102,13 +99,14 @@ public class SyncUtils {
     }
 
     /**
-     * Query data nodes for cm handles with an "LOCKED" cm handle state with reason LOCKED_MODULE_SYNC_FAILED".
+     * Query data nodes for cm handles with an "LOCKED" cm handle state with reason.
      *
      * @return a random LOCKED yang model cm handle, return null if not found
      */
-    public List<YangModelCmHandle> getModuleSyncFailedCmHandles() {
-        final List<DataNode> lockedCmHandlesAsDataNodeList = cmHandleQueries.queryCmHandleDataNodesByCpsPath(
-                "//lock-reason[@reason=\"LOCKED_MODULE_SYNC_FAILED\"]",
+    public List<YangModelCmHandle> getCmHandlesThatFailedModelSyncOrUpgrade() {
+        final List<DataNode> lockedCmHandlesAsDataNodeList
+                = cmHandleQueries.queryCmHandleAncestorsByCpsPath(
+                "//lock-reason[@reason=\"MODULE_SYNC_FAILED\" or @reason=\"MODULE_UPGRADE\"]",
                 FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
         return convertCmHandlesDataNodesToYangModelCmHandles(lockedCmHandlesAsDataNodeList);
     }
@@ -136,28 +134,44 @@ public class SyncUtils {
 
 
     /**
-     * Check if the retry mechanism should attempt to unlock the cm handle based on the last update time.
+     * 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 isReadyForRetry(final CompositeState compositeState) {
-        int timeInMinutesUntilNextAttempt = 1;
-        final OffsetDateTime time =
-                OffsetDateTime.parse(compositeState.getLastUpdateTime(),
-                        DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
-        final Matcher matcher = retryAttemptPattern.matcher(compositeState.getLockReason().getDetails());
-        if (matcher.find()) {
-            timeInMinutesUntilNextAttempt = (int) Math.pow(2, Integer.parseInt(matcher.group(1)));
-        } else {
-            log.debug("First Attempt: no current attempts found.");
-        }
-        final int timeSinceLastAttempt = (int) Duration.between(time, OffsetDateTime.now()).toMinutes();
-        if (timeInMinutesUntilNextAttempt >= timeSinceLastAttempt) {
-            log.info("Time until next attempt is {} minutes: ",
-                    timeInMinutesUntilNextAttempt - timeSinceLastAttempt);
+    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 failedDuringModuleSync = LockReasonCategory.MODULE_SYNC_FAILED
+                == lockReason.getLockReasonCategory();
+        final boolean moduleUpgrade = LockReasonCategory.MODULE_UPGRADE
+                == lockReason.getLockReasonCategory();
+
+        if (failedDuringModuleSync) {
+            final int timeInMinutesUntilNextAttempt;
+            final Matcher matcher = retryAttemptPattern.matcher(lockReason.getDetails());
+            if (matcher.find()) {
+                timeInMinutesUntilNextAttempt = (int) Math.pow(2, Integer.parseInt(matcher.group(1)));
+            } else {
+                timeInMinutesUntilNextAttempt = 1;
+                log.info("First Attempt: no current attempts found.");
+            }
+            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;
+            }
+            log.info("Retry due now");
+            return true;
+        } else if (moduleUpgrade) {
+            log.info("Locked for module upgrade.");
+            return true;
         }
-        return timeSinceLastAttempt > timeInMinutesUntilNextAttempt;
+        log.info("Locked for other reason");
+        return false;
     }
 
     /**
@@ -189,6 +203,6 @@ public class SyncUtils {
             final List<DataNode> cmHandlesAsDataNodeList) {
         return cmHandlesAsDataNodeList.stream()
                 .map(cmHandle -> YangDataConverter.convertCmHandleToYangModel(cmHandle,
-                        cmHandle.getLeaves().get("id").toString())).collect(Collectors.toList());
+                        cmHandle.getLeaves().get("id").toString())).toList();
     }
 }
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory.sync.config;
+package org.onap.cps.ncmp.api.impl.inventory.sync.config;
 
 import java.util.concurrent.ThreadPoolExecutor;
 import org.springframework.context.annotation.Bean;
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -18,7 +18,7 @@
  *  ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.ncmp.api.inventory.sync.executor;
+package org.onap.cps.ncmp.api.impl.inventory.sync.executor;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
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/api/impl/ncmppersistence/NcmpPersistence.java
new file mode 100644 (file)
index 0000000..d72b5d5
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * ============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.ncmppersistence;
+
+import java.time.OffsetDateTime;
+import java.util.Collection;
+import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.model.DataNode;
+
+/**
+ * DmiRegistryConstants class to be strictly used for DMI Related constants only.
+ */
+public interface NcmpPersistence {
+
+    String NCMP_DATASPACE_NAME = "NCMP-Admin";
+    String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
+    String NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME = "NFP-Operational";
+    String NCMP_DMI_REGISTRY_PARENT = "/dmi-registry";
+    OffsetDateTime NO_TIMESTAMP = null;
+
+    /**
+     * Method to delete a list or a list element.
+     *
+     * @param listElementXpath list element xPath
+     */
+    void deleteListOrListElement(String listElementXpath);
+
+    /**
+     * Method to delete a schema set.
+     *
+     * @param schemaSetName schema set name
+     */
+    void deleteSchemaSetWithCascade(String schemaSetName);
+
+    /**
+     * Method to delete multiple schema sets.
+     *
+     * @param schemaSetNames schema set names
+     */
+    void deleteSchemaSetsWithCascade(Collection<String> schemaSetNames);
+
+    /**
+     * Get data node via xpath.
+     *
+     * @param xpath xpath
+     * @return data node
+     */
+    Collection<DataNode> getDataNode(String xpath);
+
+    /**
+     * Get data node via xpath.
+     *
+     * @param xpath                  xpath
+     * @param fetchDescendantsOption fetch descendants option
+     * @return data node
+     */
+    Collection<DataNode> getDataNode(String xpath, FetchDescendantsOption fetchDescendantsOption);
+
+    /**
+     * Get collection of data nodes via xpaths.
+     *
+     * @param xpaths collection of xpaths
+     * @return collection of data nodes
+     */
+    Collection<DataNode> getDataNodes(Collection<String> xpaths);
+
+    /**
+     * Get collection of data nodes via xpaths.
+     *
+     * @param xpaths                 collection of xpaths
+     * @param fetchDescendantsOption fetch descendants option
+     * @return collection of data nodes
+     */
+    Collection<DataNode> getDataNodes(Collection<String> xpaths,
+                                              FetchDescendantsOption fetchDescendantsOption);
+
+    /**
+     * Replaces list content by removing all existing elements and inserting the given new elements as data nodes.
+     *
+     * @param parentNodeXpath parent node xpath
+     * @param dataNodes       datanodes representing the updated data
+     */
+    void replaceListContent(String parentNodeXpath, Collection<DataNode> dataNodes);
+
+    /**
+     * Deletes data node.
+     *
+     * @param dataNodeXpath data node xpath
+     */
+    void deleteDataNode(String dataNodeXpath);
+
+    /**
+     * Deletes multiple data nodes.
+     *
+     * @param dataNodeXpaths data node xpaths
+     */
+    void deleteDataNodes(Collection<String> dataNodeXpaths);
+}
index ba6f891..b8edecc 100644 (file)
@@ -21,6 +21,8 @@
 
 package org.onap.cps.ncmp.api.impl.operations;
 
+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.impl.operations.DatastoreType.PASSTHROUGH_RUNNING;
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ;
 
@@ -30,16 +32,16 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.NcmpEventResponseCode;
+import org.onap.cps.ncmp.api.NcmpResponseStatus;
 import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException;
 import org.onap.cps.ncmp.api.impl.executor.TaskExecutor;
+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.inventory.CmHandleState;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.DataOperationRequest;
 import org.onap.cps.spi.exceptions.CpsException;
 import org.onap.cps.utils.JsonObjectMapper;
@@ -230,9 +232,7 @@ public class DmiDataOperations extends DmiOperations {
                                                                  final Map<String, List<DmiDataOperation>>
                                                                 groupsOutPerDmiServiceName) {
 
-        groupsOutPerDmiServiceName.entrySet().forEach(groupsOutPerDmiServiceNameEntry -> {
-            final String dmiServiceName = groupsOutPerDmiServiceNameEntry.getKey();
-            final List<DmiDataOperation> dmiDataOperationRequestBodies = groupsOutPerDmiServiceNameEntry.getValue();
+        groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> {
             final String dmiDataOperationResourceUrl =
                     getDmiServiceDataOperationRequestUrl(dmiServiceName, topicParamInQuery, requestId);
             sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies);
@@ -261,18 +261,18 @@ public class DmiDataOperations extends DmiOperations {
             final String topicName = dataOperationResourceUrlParameters.get("topic").get(0);
             final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0);
 
-            final MultiValueMap<DmiDataOperation, Map<NcmpEventResponseCode, List<String>>>
+            final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>>
                     cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
 
             dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> {
                 final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream()
-                        .map(CmHandle::getId).collect(Collectors.toList());
+                        .map(CmHandle::getId).toList();
                 if (throwable.getCause() instanceof HttpClientRequestException) {
                     cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody,
-                            Map.of(NcmpEventResponseCode.UNABLE_TO_READ_RESOURCE_DATA, cmHandleIds));
+                            Map.of(UNABLE_TO_READ_RESOURCE_DATA, cmHandleIds));
                 } else {
                     cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody,
-                            Map.of(NcmpEventResponseCode.DMI_SERVICE_NOT_RESPONDING, cmHandleIds));
+                            Map.of(DMI_SERVICE_NOT_RESPONDING, cmHandleIds));
                 }
             });
             ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId,
index 1bbd725..32b5cb7 100644 (file)
@@ -32,9 +32,9 @@ 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.NcmpConfiguration;
+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.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.models.YangResource;
 import org.onap.cps.spi.model.ModuleReference;
 import org.onap.cps.utils.JsonObjectMapper;
index 7e9079e..c8d73ea 100644 (file)
@@ -24,8 +24,8 @@ 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.NcmpConfiguration;
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence;
 import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.stereotype.Service;
 
index 27d4266..8092e39 100644 (file)
 package org.onap.cps.ncmp.api.impl.subscriptions;
 
 import java.util.Collection;
+import org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent;
 import org.onap.cps.spi.model.DataNode;
 
-public interface SubscriptionPersistence {
+public interface SubscriptionPersistence extends NcmpPersistence {
 
     /**
      * Save subscription Event.
index 83a375b..dd0c20d 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.subscriptions;
 
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP;
-
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
-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.inventory.NcmpPersistenceImpl;
 import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent;
 import org.onap.cps.spi.FetchDescendantsOption;
 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;
 
 @Slf4j
-@RequiredArgsConstructor
 @Component
-public class SubscriptionPersistenceImpl implements SubscriptionPersistence {
+public class SubscriptionPersistenceImpl extends NcmpPersistenceImpl implements SubscriptionPersistence {
 
-    private static final String SUBSCRIPTION_DATASPACE_NAME = "NCMP-Admin";
     private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions";
     private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry";
-    private final JsonObjectMapper jsonObjectMapper;
-    private final CpsDataService cpsDataService;
+
+    public SubscriptionPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService,
+                                       final CpsModuleService cpsModuleService, final CpsValidator cpsValidator) {
+        super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator);
+    }
+
 
     @Override
     public void saveSubscriptionEvent(final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
         final String clientId = yangModelSubscriptionEvent.getClientId();
         final String subscriptionName = yangModelSubscriptionEvent.getSubscriptionName();
 
-        final Collection<DataNode> dataNodes = cpsDataService.getDataNodes(SUBSCRIPTION_DATASPACE_NAME,
+        final Collection<DataNode> dataNodes = cpsDataService.getDataNodes(NCMP_DATASPACE_NAME,
                 SUBSCRIPTION_ANCHOR_NAME, SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
 
         if (isSubscriptionRegistryEmptyOrNonExist(dataNodes, clientId, subscriptionName)) {
@@ -74,8 +75,7 @@ public class SubscriptionPersistenceImpl implements SubscriptionPersistence {
         final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMapOriginal =
                 DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode(dataNodes);
 
-        final Map<String, Map<String, String>> newTargetCmHandles =
-                mapDifference(cmHandleIdToStatusAndDetailsAsMapNew,
+        final Map<String, Map<String, String>> newTargetCmHandles = mapDifference(cmHandleIdToStatusAndDetailsAsMapNew,
                         cmHandleIdToStatusAndDetailsAsMapOriginal);
         traverseCmHandleList(newTargetCmHandles, clientId, subscriptionName, true);
 
@@ -88,7 +88,7 @@ public class SubscriptionPersistenceImpl implements SubscriptionPersistence {
             final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
         return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles()
                 .stream().collect(
-                        HashMap<String, Map<String, String>>::new,
+                        HashMap::new,
                         (result, cmHandle) -> {
                             final String cmHandleId = cmHandle.getCmHandleId();
                             final SubscriptionStatus status = cmHandle.getStatus();
@@ -130,34 +130,31 @@ public class SubscriptionPersistenceImpl implements SubscriptionPersistence {
                                                           final boolean isAddListElementOperation) {
         if (isAddListElementOperation) {
             log.info("targetCmHandleAsJson to be added into DB {}", targetCmHandleAsJson);
-            cpsDataService.saveListElements(SUBSCRIPTION_DATASPACE_NAME,
-                    SUBSCRIPTION_ANCHOR_NAME, createCmHandleXpathPredicates(clientId, subscriptionName),
-                    targetCmHandleAsJson, NO_TIMESTAMP);
+            cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+                    createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP);
         } else {
             log.info("targetCmHandleAsJson to be updated into DB {}", targetCmHandleAsJson);
-            cpsDataService.updateNodeLeaves(SUBSCRIPTION_DATASPACE_NAME,
-                    SUBSCRIPTION_ANCHOR_NAME, createCmHandleXpathPredicates(clientId, subscriptionName),
-                    targetCmHandleAsJson, NO_TIMESTAMP);
+            cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+                    createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP);
         }
     }
 
     private void saveSubscriptionEventYangModel(final String subscriptionEventJsonData) {
         log.info("SubscriptionEventJsonData to be saved into DB {}", subscriptionEventJsonData);
-        cpsDataService.saveListElements(SUBSCRIPTION_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+        cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
                 SUBSCRIPTION_REGISTRY_PARENT, subscriptionEventJsonData, NO_TIMESTAMP);
     }
 
     @Override
     public Collection<DataNode> getDataNodesForSubscriptionEvent() {
-        return cpsDataService.getDataNodes(SUBSCRIPTION_DATASPACE_NAME,
-                SUBSCRIPTION_ANCHOR_NAME, SUBSCRIPTION_REGISTRY_PARENT,
-                FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
+        return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+                SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
     }
 
     @Override
     public Collection<DataNode> getCmHandlesForSubscriptionEvent(final String clientId, final String subscriptionName) {
-        return cpsDataService.getDataNodesForMultipleXpaths(SUBSCRIPTION_DATASPACE_NAME,
-                SUBSCRIPTION_ANCHOR_NAME, Arrays.asList(createCmHandleXpath(clientId, subscriptionName)),
+        return cpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+                List.of(createCmHandleXpath(clientId, subscriptionName)),
                 FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
     }
 
@@ -168,8 +165,8 @@ public class SubscriptionPersistenceImpl implements SubscriptionPersistence {
             final Map<String, String> statusAndDetailsMap = entry.getValue();
             final String status = statusAndDetailsMap.get("status");
             final String details = statusAndDetailsMap.get("details");
-            return new YangModelSubscriptionEvent.TargetCmHandle(cmHandleId,
-                    SubscriptionStatus.fromString(status), details);
+            return new YangModelSubscriptionEvent.TargetCmHandle(cmHandleId, SubscriptionStatus.fromString(status),
+                    details);
         }).collect(Collectors.toList());
     }
 
index dac32aa..d3b95ea 100644 (file)
@@ -46,7 +46,7 @@ public class DMiPluginWatchDog {
      */
     @Scheduled(fixedDelayString = "${ncmp.timers.trust-evel.dmi-availability-watchdog-ms:30000}")
     public void watchDmiPluginAliveness() {
-        trustLevelPerDmiPlugin.keySet().forEach((dmiPluginName) -> {
+        trustLevelPerDmiPlugin.keySet().forEach(dmiPluginName -> {
             final DmiPluginStatus dmiPluginStatus = dmiRestClient.getDmiPluginStatus(dmiPluginName);
             log.debug("Trust level for dmi-plugin: {} is {}", dmiPluginName, dmiPluginStatus.toString());
             if (DmiPluginStatus.UP.equals(dmiPluginStatus)) {
index 7466308..b6a04d3 100644 (file)
@@ -30,9 +30,9 @@ import java.util.regex.Pattern;
 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.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.spi.model.DataNode;
 
@@ -86,7 +86,8 @@ public class YangDataConverter {
                 (String) cmHandleDataNode.getLeaves().get("dmi-service-name"),
                 (String) cmHandleDataNode.getLeaves().get("dmi-data-service-name"),
                 (String) cmHandleDataNode.getLeaves().get("dmi-model-service-name"),
-                ncmpServiceCmHandle
+                ncmpServiceCmHandle,
+                (String) cmHandleDataNode.getLeaves().get("module-set-tag")
         );
     }
 
@@ -105,7 +106,12 @@ public class YangDataConverter {
         return yangModelCmHandles;
     }
 
-    private static String extractCmHandleIdFromXpath(final String xpath) {
+    /**
+     * This method extract cm handle id from xpath of data node.
+     * @param xpath for data node of the cm handle
+     * @return cm handle Id
+     */
+    public static String extractCmHandleIdFromXpath(final String xpath) {
         final Matcher matcher = cmHandleIdInXpathPattern.matcher(xpath);
         matcher.find();
         return matcher.group(1);
index 65cda94..61da706 100644 (file)
@@ -28,7 +28,7 @@ import java.util.Map;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.NcmpEventResponseCode;
+import org.onap.cps.ncmp.api.NcmpResponseStatus;
 import org.onap.cps.ncmp.api.impl.events.NcmpCloudEventBuilder;
 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation;
 import org.onap.cps.ncmp.events.async1_0_0.Data;
@@ -51,7 +51,7 @@ public class DataOperationEventCreator {
     public static CloudEvent createDataOperationEvent(final String clientTopic,
                                                       final String requestId,
                                                       final MultiValueMap<DmiDataOperation,
-                                                              Map<NcmpEventResponseCode, List<String>>>
+                                                              Map<NcmpResponseStatus, List<String>>>
                                                               cmHandleIdsPerResponseCodesPerOperation) {
         final DataOperationEvent dataOperationEvent = new DataOperationEvent();
         final Data data = createPayloadFromDataOperationResponses(cmHandleIdsPerResponseCodesPerOperation);
@@ -62,7 +62,7 @@ public class DataOperationEventCreator {
     }
 
     private static Data createPayloadFromDataOperationResponses(final MultiValueMap<DmiDataOperation,
-            Map<NcmpEventResponseCode, List<String>>> cmHandleIdsPerResponseCodesPerOperation) {
+            Map<NcmpResponseStatus, List<String>>> cmHandleIdsPerResponseCodesPerOperation) {
         final Data data = new Data();
         final List<org.onap.cps.ncmp.events.async1_0_0.Response> responses = new ArrayList<>();
         cmHandleIdsPerResponseCodesPerOperation.forEach((dmiDataOperation, cmHandleIdsPerResponseCodes) ->
@@ -75,13 +75,13 @@ public class DataOperationEventCreator {
 
     private static List<Response> createResponseFromDataOperationResponses(
             final DmiDataOperation dmiDataOperation,
-            final Map<NcmpEventResponseCode, List<String>> cmHandleIdsPerResponseCodeEntries) {
+            final Map<NcmpResponseStatus, List<String>> cmHandleIdsPerResponseCodeEntries) {
         final List<org.onap.cps.ncmp.events.async1_0_0.Response> responses = new ArrayList<>();
         cmHandleIdsPerResponseCodeEntries.forEach((ncmpEventResponseCode, cmHandleIds) -> {
             final Response response = new Response();
             response.setOperationId(dmiDataOperation.getOperationId());
-            response.setStatusCode(ncmpEventResponseCode.getStatusCode());
-            response.setStatusMessage(ncmpEventResponseCode.getStatusMessage());
+            response.setStatusCode(ncmpEventResponseCode.getCode());
+            response.setStatusMessage(ncmpEventResponseCode.getMessage());
             response.setIds(cmHandleIds);
             response.setResourceIdentifier(dmiDataOperation.getResourceIdentifier());
             response.setOptions(dmiDataOperation.getOptions());
index c455337..e78f090 100644 (file)
@@ -20,6 +20,9 @@
 
 package org.onap.cps.ncmp.api.impl.utils.data.operation;
 
+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 io.cloudevents.CloudEvent;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -32,14 +35,14 @@ import java.util.stream.Collectors;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.ncmp.api.NcmpEventResponseCode;
+import org.onap.cps.ncmp.api.NcmpResponseStatus;
 import org.onap.cps.ncmp.api.impl.events.EventsPublisher;
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState;
 import org.onap.cps.ncmp.api.impl.operations.CmHandle;
 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation;
 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.inventory.CmHandleState;
 import org.onap.cps.ncmp.api.models.DataOperationDefinition;
 import org.onap.cps.ncmp.api.models.DataOperationRequest;
 import org.springframework.scheduling.annotation.Async;
@@ -68,7 +71,7 @@ public class ResourceDataOperationRequestUtils {
             final Collection<YangModelCmHandle> yangModelCmHandles) {
 
         final Map<String, List<DmiDataOperation>> dmiDataOperationsOutPerDmiServiceName = new HashMap<>();
-        final MultiValueMap<DmiDataOperation, Map<NcmpEventResponseCode,
+        final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus,
                 List<String>>> cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
         final Set<String> nonReadyCmHandleIdsLookup = filterAndGetNonReadyCmHandleIds(yangModelCmHandles);
 
@@ -102,10 +105,10 @@ public class ResourceDataOperationRequestUtils {
             }
             populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperation,
                     DmiDataOperation.buildDmiDataOperationRequestBodyWithoutCmHandles(dataOperationDefinitionIn),
-                    NcmpEventResponseCode.CM_HANDLES_NOT_FOUND, nonExistingCmHandleIds);
+                    CM_HANDLES_NOT_FOUND, nonExistingCmHandleIds);
             populateCmHandleIdsPerOperationIdPerResponseCode(cmHandleIdsPerResponseCodesPerOperation,
                     DmiDataOperation.buildDmiDataOperationRequestBodyWithoutCmHandles(dataOperationDefinitionIn),
-                    NcmpEventResponseCode.CM_HANDLES_NOT_READY, nonReadyCmHandleIds);
+                    CM_HANDLES_NOT_READY, nonReadyCmHandleIds);
         }
         if (!cmHandleIdsPerResponseCodesPerOperation.isEmpty()) {
             publishErrorMessageToClientTopic(topicParamInQuery, requestId, cmHandleIdsPerResponseCodesPerOperation);
@@ -124,7 +127,7 @@ public class ResourceDataOperationRequestUtils {
     public static void publishErrorMessageToClientTopic(final String clientTopic,
                                                          final String requestId,
                                                          final MultiValueMap<DmiDataOperation,
-                                                                 Map<NcmpEventResponseCode, List<String>>>
+                                                                 Map<NcmpResponseStatus, List<String>>>
                                                                     cmHandleIdsPerResponseCodesPerOperation) {
         final CloudEvent dataOperationCloudEvent = DataOperationEventCreator.createDataOperationEvent(clientTopic,
                 requestId, cmHandleIdsPerResponseCodesPerOperation);
@@ -175,13 +178,13 @@ public class ResourceDataOperationRequestUtils {
     }
 
     private static void populateCmHandleIdsPerOperationIdPerResponseCode(final MultiValueMap<DmiDataOperation,
-            Map<NcmpEventResponseCode, List<String>>> cmHandleIdsPerResponseCodesPerOperation,
+            Map<NcmpResponseStatus, List<String>>> cmHandleIdsPerResponseCodesPerOperation,
                                                                         final DmiDataOperation dmiDataOperation,
-                                                                        final NcmpEventResponseCode
-                                                                                ncmpEventResponseCode,
+                                                                        final NcmpResponseStatus
+                                                                                 ncmpResponseStatus,
                                                                         final List<String> cmHandleIds) {
         if (!cmHandleIds.isEmpty()) {
-            cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperation, Map.of(ncmpEventResponseCode, cmHandleIds));
+            cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperation, Map.of(ncmpResponseStatus, cmHandleIds));
         }
     }
 }
index a6f953a..d148f37 100644 (file)
@@ -34,8 +34,8 @@ import lombok.EqualsAndHashCode;
 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.operations.RequiredDmiService;
-import org.onap.cps.ncmp.api.inventory.CompositeState;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 
 /**
@@ -64,6 +64,9 @@ public class YangModelCmHandle {
     @JsonProperty("dmi-model-service-name")
     private String dmiModelServiceName;
 
+    @JsonProperty("module-set-tag")
+    private String moduleSetTag;
+
     @JsonProperty("additional-properties")
     private List<Property> dmiProperties;
 
@@ -102,12 +105,14 @@ public class YangModelCmHandle {
     public static YangModelCmHandle toYangModelCmHandle(final String dmiServiceName,
                                                         final String dmiDataServiceName,
                                                         final String dmiModelServiceName,
-                                                        final NcmpServiceCmHandle ncmpServiceCmHandle) {
+                                                        final NcmpServiceCmHandle ncmpServiceCmHandle,
+                                                        final String moduleSetTag) {
         final YangModelCmHandle yangModelCmHandle = new YangModelCmHandle();
         yangModelCmHandle.setId(ncmpServiceCmHandle.getCmHandleId());
         yangModelCmHandle.setDmiServiceName(dmiServiceName);
         yangModelCmHandle.setDmiDataServiceName(dmiDataServiceName);
         yangModelCmHandle.setDmiModelServiceName(dmiModelServiceName);
+        yangModelCmHandle.setModuleSetTag(moduleSetTag);
         yangModelCmHandle.setDmiProperties(asYangModelCmHandleProperties(ncmpServiceCmHandle.getDmiProperties()));
         yangModelCmHandle.setPublicProperties(asYangModelCmHandleProperties(
                 ncmpServiceCmHandle.getPublicProperties()));
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncService.java
deleted file mode 100644 (file)
index 7efce1a..0000000
+++ /dev/null
@@ -1,97 +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.ncmp.api.inventory.sync;
-
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.api.CpsAdminService;
-import org.onap.cps.api.CpsModuleService;
-import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.spi.CascadeDeleteAllowed;
-import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
-import org.onap.cps.spi.model.ModuleReference;
-import org.springframework.stereotype.Service;
-
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class ModuleSyncService {
-
-    private final DmiModelOperations dmiModelOperations;
-    private final CpsModuleService cpsModuleService;
-
-    private final CpsAdminService cpsAdminService;
-
-    /**
-     * This method registers a cm handle and initiates modules sync.
-     *
-     * @param yangModelCmHandle the yang model of cm handle.
-     */
-    public void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) {
-
-        final Collection<ModuleReference> allModuleReferencesFromCmHandle =
-                dmiModelOperations.getModuleReferences(yangModelCmHandle);
-
-        final Collection<ModuleReference> identifiedNewModuleReferencesFromCmHandle = cpsModuleService
-                .identifyNewModuleReferences(allModuleReferencesFromCmHandle);
-
-        final Map<String, String> newModuleNameToContentMap;
-        if (identifiedNewModuleReferencesFromCmHandle.isEmpty()) {
-            newModuleNameToContentMap = Collections.emptyMap();
-        } else {
-            newModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
-                    identifiedNewModuleReferencesFromCmHandle);
-        }
-        createSchemaSetAndAnchor(yangModelCmHandle, newModuleNameToContentMap, allModuleReferencesFromCmHandle);
-    }
-
-    private void createSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle,
-                                          final Map<String, String> newModuleNameToContentMap,
-                                          final Collection<ModuleReference> allModuleReferencesFromCmHandle) {
-        final String schemaSetAndAnchorName = yangModelCmHandle.getId();
-        cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName,
-                        newModuleNameToContentMap, allModuleReferencesFromCmHandle);
-        cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName,
-            schemaSetAndAnchorName);
-    }
-
-    /**
-     * Deletes the SchemaSet for schema set id if the SchemaSet Exists.
-     *
-     * @param schemaSetId the schema set id to be deleted
-     */
-    public void deleteSchemaSetIfExists(final String schemaSetId) {
-        try {
-            cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetId,
-                CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED);
-            log.debug("SchemaSet for {} has been deleted. Ready to be recreated.", schemaSetId);
-        } catch (final SchemaSetNotFoundException e) {
-            log.debug("No SchemaSet for {}. Assuming CmHandle has not been previously Module Synced.", schemaSetId);
-        }
-    }
-
-}
index d5b27b6..e007491 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Bell Canada
- *  Modifications Copyright (C) 2022 Nordix Foundation
+ *  Modifications 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.
 
 package org.onap.cps.ncmp.api.models;
 
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 import lombok.Builder;
 import lombok.Data;
-import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.api.NcmpResponseStatus;
+import org.onap.cps.ncmp.api.impl.utils.YangDataConverter;
 
 @Data
 @Builder
@@ -39,11 +39,9 @@ public class CmHandleRegistrationResponse {
 
     private final String cmHandle;
     private final Status status;
-    private RegistrationError registrationError;
+    private NcmpResponseStatus ncmpResponseStatus;
     private String errorText;
 
-    private static final Pattern cmHandleIdInXpathPattern = Pattern.compile("\\[@id='(.*?)']");
-
     /**
      * Creates a failure response based on exception.
      *
@@ -56,7 +54,7 @@ public class CmHandleRegistrationResponse {
         return CmHandleRegistrationResponse.builder()
             .cmHandle(cmHandleId)
             .status(Status.FAILURE)
-            .registrationError(RegistrationError.UNKNOWN_ERROR)
+            .ncmpResponseStatus(UNKNOWN_ERROR)
             .errorText(exception.getMessage()).build();
     }
 
@@ -64,15 +62,15 @@ public class CmHandleRegistrationResponse {
      * Creates a failure response based on registration error.
      *
      * @param cmHandleId          cmHandleId
-     * @param registrationError registrationError
+     * @param ncmpResponseStatus registration error code and status
      * @return CmHandleRegistrationResponse
      */
     public static CmHandleRegistrationResponse createFailureResponse(final String cmHandleId,
-        final RegistrationError registrationError) {
+        final NcmpResponseStatus ncmpResponseStatus) {
         return CmHandleRegistrationResponse.builder().cmHandle(cmHandleId)
             .status(Status.FAILURE)
-            .registrationError(registrationError)
-            .errorText(registrationError.errorText)
+            .ncmpResponseStatus(ncmpResponseStatus)
+            .errorText(ncmpResponseStatus.getMessage())
             .build();
     }
 
@@ -80,18 +78,18 @@ public class CmHandleRegistrationResponse {
      * Creates a failure response based on registration error.
      *
      * @param failedXpaths       list of failed Xpaths
-     * @param registrationError enum describing the type of registration error
+     * @param ncmpResponseStatus enum describing the type of registration error
      * @return CmHandleRegistrationResponse
      */
     public static List<CmHandleRegistrationResponse> createFailureResponses(final Collection<String> failedXpaths,
-            final RegistrationError registrationError) {
+            final NcmpResponseStatus ncmpResponseStatus) {
         final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failedXpaths.size());
         for (final String xpath : failedXpaths) {
-            final Matcher matcher = cmHandleIdInXpathPattern.matcher(xpath);
-            if (matcher.find()) {
+            try {
+                final String cmHandleId = YangDataConverter.extractCmHandleIdFromXpath(xpath);
                 cmHandleRegistrationResponses.add(
-                    CmHandleRegistrationResponse.createFailureResponse(matcher.group(1), registrationError));
-            } else {
+                        CmHandleRegistrationResponse.createFailureResponse(cmHandleId, ncmpResponseStatus));
+            } catch (IllegalArgumentException | IllegalStateException e) {
                 log.warn("Unexpected xpath {}", xpath);
             }
         }
@@ -109,7 +107,7 @@ public class CmHandleRegistrationResponse {
             final Exception exception) {
         return cmHandleIds.stream()
                 .map(cmHandleId -> CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception))
-                .collect(Collectors.toList());
+                .toList();
     }
 
     public static CmHandleRegistrationResponse createSuccessResponse(final String cmHandle) {
@@ -118,23 +116,10 @@ public class CmHandleRegistrationResponse {
     }
 
     public static List<CmHandleRegistrationResponse> createSuccessResponses(final List<String> cmHandleIds) {
-        return cmHandleIds.stream().map(CmHandleRegistrationResponse::createSuccessResponse)
-                .collect(Collectors.toList());
+        return cmHandleIds.stream().map(CmHandleRegistrationResponse::createSuccessResponse).toList();
     }
 
     public enum Status {
         SUCCESS, FAILURE;
     }
-
-    @RequiredArgsConstructor
-    public enum RegistrationError {
-        UNKNOWN_ERROR("00", "Unknown error"),
-        CM_HANDLE_ALREADY_EXIST("01", "cm-handle already exists"),
-        CM_HANDLE_DOES_NOT_EXIST("02", "cm-handle does not exist"),
-        CM_HANDLE_INVALID_ID("03", "cm-handle has an invalid character(s) in id");
-
-        public final String errorCode;
-        public final String errorText;
-
-    }
 }
index d1360c3..4615af6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2023 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -50,6 +50,8 @@ public class DmiPluginRegistration {
 
     private List<String> removedCmHandles = Collections.emptyList();
 
+    private UpgradedCmHandles upgradedCmHandles;
+
     /**
      * Validates plugin service names.
      * @throws NcmpException if validation fails.
@@ -80,7 +82,7 @@ public class DmiPluginRegistration {
         }
     }
 
-    private static boolean isNullEmptyOrBlank(final String serviceName) {
+    public static boolean isNullEmptyOrBlank(final String serviceName) {
         return Strings.isNullOrEmpty(serviceName) || serviceName.isBlank();
     }
 
index 8a3d264..ee03417 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Bell Canada
+ *  Modifications 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.
@@ -31,4 +32,5 @@ public class DmiPluginRegistrationResponse {
     private List<CmHandleRegistrationResponse> createdCmHandles = Collections.emptyList();
     private List<CmHandleRegistrationResponse> updatedCmHandles = Collections.emptyList();
     private List<CmHandleRegistrationResponse> removedCmHandles = Collections.emptyList();
+    private List<CmHandleRegistrationResponse> upgradedCmHandles = Collections.emptyList();
 }
\ No newline at end of file
index ae40d33..0b50346 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2023 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import java.util.Map;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-import org.onap.cps.ncmp.api.inventory.CompositeState;
+import org.onap.cps.ncmp.api.impl.inventory.CompositeState;
 import org.springframework.validation.annotation.Validated;
 
 /**
@@ -52,6 +52,9 @@ public class NcmpServiceCmHandle {
     @JsonSetter(nulls = Nulls.AS_EMPTY)
     private CompositeState compositeState;
 
+    @JsonSetter(nulls = Nulls.AS_EMPTY)
+    private String moduleSetTag;
+
     /**
      * NcmpServiceCmHandle copy constructor.
      *
@@ -63,5 +66,6 @@ public class NcmpServiceCmHandle {
         this.publicProperties = new LinkedHashMap<>(ncmpServiceCmHandle.getPublicProperties());
         this.compositeState = ncmpServiceCmHandle.getCompositeState() != null ? new CompositeState(
                 ncmpServiceCmHandle.getCompositeState()) : null;
+        this.moduleSetTag = ncmpServiceCmHandle.getModuleSetTag();
     }
 }
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/models/UpgradedCmHandles.java
new file mode 100644 (file)
index 0000000..61cd99a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 Nordix Foundation
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.models;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Collections;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class UpgradedCmHandles {
+    private List<String> cmHandles = Collections.emptyList();
+    private String moduleSetTag;
+}
+
index 5316d66..b805cdc 100644 (file)
@@ -20,6 +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 lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsAdminService;
 import org.onap.cps.api.CpsDataService;
@@ -32,8 +35,6 @@ public class InventoryModelLoader extends AbstractModelLoader {
 
     private static final String NEW_MODEL_FILE_NAME = "dmi-registry@2023-08-23.yang";
     private static final String NEW_SCHEMA_SET_NAME = "dmi-registry-2023-08-23";
-    private static final String DATASPACE_NAME = "NCMP-Admin";
-    private static final String ANCHOR_NAME = "ncmp-dmi-registry";
 
     public InventoryModelLoader(final CpsAdminService cpsAdminService,
                                 final CpsModuleService cpsModuleService,
@@ -43,20 +44,20 @@ public class InventoryModelLoader extends AbstractModelLoader {
 
     @Override
     public void onboardOrUpgradeModel() {
-        waitUntilDataspaceIsAvailable(DATASPACE_NAME);
+        waitUntilDataspaceIsAvailable(NCMP_DATASPACE_NAME);
         updateInventoryModel();
         log.info("Inventory Model updated successfully");
     }
 
     private void updateInventoryModel() {
-        createSchemaSet(DATASPACE_NAME, NEW_SCHEMA_SET_NAME, NEW_MODEL_FILE_NAME);
-        updateAnchorSchemaSet(DATASPACE_NAME, ANCHOR_NAME, NEW_SCHEMA_SET_NAME);
+        createSchemaSet(NCMP_DATASPACE_NAME, NEW_SCHEMA_SET_NAME, NEW_MODEL_FILE_NAME);
+        updateAnchorSchemaSet(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NEW_SCHEMA_SET_NAME);
         deleteOldButNotThePreviousSchemaSets();
     }
 
     private void deleteOldButNotThePreviousSchemaSets() {
         //No schema sets passed in yet, but wil be required for future updates
-        deleteUnusedSchemaSets(DATASPACE_NAME);
+        deleteUnusedSchemaSets(NCMP_DATASPACE_NAME);
     }
 
 }
index 891244c..4d1a91c 100644 (file)
@@ -20,6 +20,8 @@
 
 package org.onap.cps.ncmp.init;
 
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME;
+
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsAdminService;
 import org.onap.cps.api.CpsDataService;
@@ -32,7 +34,6 @@ import org.springframework.stereotype.Service;
 public class SubscriptionModelLoader extends AbstractModelLoader {
 
     private static final String MODEL_FILENAME = "subscription.yang";
-    private static final String DATASPACE_NAME = "NCMP-Admin";
     private static final String ANCHOR_NAME = "AVC-Subscriptions";
     private static final String SCHEMASET_NAME = "subscriptions";
     private static final String REGISTRY_DATANODE_NAME = "subscription-registry";
@@ -49,7 +50,7 @@ public class SubscriptionModelLoader extends AbstractModelLoader {
     @Override
     public void onboardOrUpgradeModel() {
         if (subscriptionModelLoaderEnabled) {
-            waitUntilDataspaceIsAvailable(DATASPACE_NAME);
+            waitUntilDataspaceIsAvailable(NCMP_DATASPACE_NAME);
             onboardSubscriptionModel();
             log.info("Subscription Model onboarded successfully");
         } else {
@@ -58,9 +59,9 @@ public class SubscriptionModelLoader extends AbstractModelLoader {
     }
 
     private void onboardSubscriptionModel() {
-        createSchemaSet(DATASPACE_NAME, SCHEMASET_NAME, MODEL_FILENAME);
-        createAnchor(DATASPACE_NAME, SCHEMASET_NAME, ANCHOR_NAME);
-        createTopLevelDataNode(DATASPACE_NAME, ANCHOR_NAME, REGISTRY_DATANODE_NAME);
+        createSchemaSet(NCMP_DATASPACE_NAME, SCHEMASET_NAME, MODEL_FILENAME);
+        createAnchor(NCMP_DATASPACE_NAME, SCHEMASET_NAME, ANCHOR_NAME);
+        createTopLevelDataNode(NCMP_DATASPACE_NAME, ANCHOR_NAME, REGISTRY_DATANODE_NAME);
     }
 
 }
index 93af7f4..ce6d856 100644 (file)
 
 package org.onap.cps.ncmp.api.impl
 
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+
 import org.onap.cps.cpspath.parser.PathParsingException
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.inventory.CmHandleQueriesImpl
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+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.spi.FetchDescendantsOption
@@ -40,7 +42,7 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
     def partiallyMockedCmHandleQueries = Spy(CmHandleQueriesImpl)
     def mockInventoryPersistence = Mock(InventoryPersistence)
 
-    def dmiRegistry = new DataNode(xpath: '/dmi-registry', childDataNodes: createDataNodeList(['PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4']))
+    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)
@@ -51,7 +53,7 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
             def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
             cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
         and: 'the query get the cm handle datanodes excluding all descendants returns a datanode'
-            cmHandleQueries.queryCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(leaves: ['id':'some-cmhandle-id'])]
+            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.queryCmHandleIds(cmHandleQueryParameters)
         then: 'the correct expected cm handles ids are returned'
@@ -64,7 +66,7 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
             def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
             cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
         and: 'cmHandleQueries throws a path parsing exception'
-            cmHandleQueries.queryCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> { throw thrownException }
+            cmHandleQueries.queryCmHandleAncestorsByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> { throw thrownException }
         when: 'the query is executed for cm handle ids'
             objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
         then: 'a data validation exception is thrown'
@@ -126,7 +128,7 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
         given: 'We use an empty query'
             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
         and: 'the inventory persistence returns the dmi registry datanode with just ids'
-            mockInventoryPersistence.getDataNode("/dmi-registry", FetchDescendantsOption.DIRECT_CHILDREN_ONLY) >> [dmiRegistry]
+            mockInventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT, FetchDescendantsOption.DIRECT_CHILDREN_ONLY) >> [dmiRegistry]
         when: 'the query is executed for both cm handle ids'
             def result = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
         then: 'the correct expected cm handles are returned'
@@ -137,7 +139,7 @@ class NetworkCmProxyCmHandleQueryServiceSpec extends Specification {
         given: 'We use an empty query'
             def cmHandleQueryParameters = new CmHandleQueryServiceParameters()
         and: 'the inventory persistence returns the dmi registry datanode with just ids'
-            mockInventoryPersistence.getDataNode("/dmi-registry") >> [dmiRegistry]
+            mockInventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT) >> [dmiRegistry]
         when: 'the query is executed for both cm handle details'
             def result = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
         then: 'the correct cm handles are returned'
index 8942c42..9e4737f 100644 (file)
 
 package org.onap.cps.ncmp.api.impl
 
+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.models.CmHandleRegistrationResponse.Status
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.hazelcast.map.IMap
 import org.onap.cps.api.CpsDataService
@@ -29,10 +35,11 @@ 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.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+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
@@ -44,12 +51,6 @@ import org.onap.cps.utils.JsonObjectMapper
 import spock.lang.Shared
 import spock.lang.Specification
 
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_DOES_NOT_EXIST
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_ALREADY_EXIST
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_INVALID_ID
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.UNKNOWN_ERROR
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
-
 class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
 
     @Shared
@@ -65,6 +66,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
     def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
     def mockCpsDataService = Mock(CpsDataService)
     def mockModuleSyncStartedOnCmHandles = Mock(IMap<String, Object>)
+    def mockTrustLevelPerDmiPlugin = Mock(IMap<String, TrustLevel>)
     def objectUnderTest = getObjectUnderTest()
 
     def 'DMI Registration: Create, Update & Delete operations are processed in the right order'() {
@@ -78,11 +80,11 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
         when: 'registration is processed'
             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
         then: 'cm-handles are removed first'
-            1 * objectUnderTest.parseAndRemoveCmHandlesInDmiRegistration(*_)
+            1 * objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_)
         and: 'de-registered cm handle entry is removed from in progress map'
             1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
         then: 'cm-handles are created'
-            1 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(*_)
+            1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_)
         then: 'cm-handles are updated'
             1 * mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_)
     }
@@ -98,10 +100,10 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
             mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) >> updateResponses
         and: 'create cm-handles can be processed successfully'
             def createdResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-1')]
-            objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(*_) >> createdResponses
+            objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_) >> createdResponses
         and: 'delete cm-handles can be processed successfully'
             def removeResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-3')]
-            objectUnderTest.parseAndRemoveCmHandlesInDmiRegistration(*_) >> removeResponses
+            objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_) >> removeResponses
         when: 'registration is processed'
             def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
         then: 'response has values from all operations'
@@ -118,12 +120,14 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
         when: 'update registration and sync module is called with correct DMI plugin information'
             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
         then: 'create cm handles registration and sync modules is called with the correct plugin information'
-            1 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+            1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)
+        and: 'dmi is added to the trustLevel map'
+            1 * mockTrustLevelPerDmiPlugin.put(dmiPluginRegisteredName, TrustLevel.COMPLETE)
         where:
-            scenario                          | dmiPlugin  | dmiModelPlugin | dmiDataPlugin
-            'combined DMI plugin'             | 'service1' | ''             | ''
-            'data & model DMI plugins'        | ''         | 'service1'     | 'service2'
-            'data & model using same service' | ''         | 'service1'     | 'service1'
+            scenario                          | dmiPlugin  | dmiModelPlugin | dmiDataPlugin | dmiPluginRegisteredName
+            'combined DMI plugin'             | 'service1' | ''             | ''            | 'service1'
+            'data & model DMI plugins'        | ''         | 'service1'     | 'service2'    | 'service2'
+            'data & model using same service' | ''         | 'service1'     | 'service1'    | 'service1'
     }
 
     def 'Create CM-handle Validation: Invalid DMI plugin service name with #scenario'() {
@@ -137,7 +141,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
             def exceptionThrown = thrown(DmiRequestException.class)
             assert exceptionThrown.getMessage().contains(expectedMessageDetails)
         and: 'registration is not called'
-            0 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+            0 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)
         where:
             scenario                         | dmiPlugin  | dmiModelPlugin | dmiDataPlugin || expectedMessageDetails
             'empty DMI plugins'              | ''         | ''             | ''            || 'No DMI plugin service names'
@@ -199,7 +203,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
             response.createdCmHandles.each {
                 assert it.cmHandle == 'cmhandle2'
                 assert it.status == Status.FAILURE
-                assert it.registrationError == CM_HANDLE_ALREADY_EXIST
+                assert it.ncmpResponseStatus == CM_HANDLE_ALREADY_EXIST
                 assert it.errorText == 'cm-handle already exists'
             }
     }
@@ -217,7 +221,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
             with(response.createdCmHandles[0]) {
                 assert it.status == Status.FAILURE
                 assert it.cmHandle ==  'cmhandle'
-                assert it.registrationError == expectedError
+                assert it.ncmpResponseStatus == expectedError
                 assert it.errorText == expectedErrorText
             }
         where:
@@ -232,7 +236,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
         and: 'cm-handle updates can be processed successfully'
             def updateOperationResponse = [CmHandleRegistrationResponse.createSuccessResponse('cm-handle-1'),
                                            CmHandleRegistrationResponse.createFailureResponse('cm-handle-2', new Exception("Failed")),
-                                           CmHandleRegistrationResponse.createFailureResponse('cm-handle-3', CM_HANDLE_DOES_NOT_EXIST),
+                                           CmHandleRegistrationResponse.createFailureResponse('cm-handle-3', CM_HANDLES_NOT_FOUND),
                                            CmHandleRegistrationResponse.createFailureResponse('cm handle 4', CM_HANDLE_INVALID_ID)]
             mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(_) >> updateOperationResponse
         when: 'registration is updated'
@@ -306,7 +310,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
         and: '2nd cm-handle deletion fails'
             with(response.removedCmHandles[1]) {
                 assert it.status == Status.FAILURE
-                assert it.registrationError == UNKNOWN_ERROR
+                assert it.ncmpResponseStatus == UNKNOWN_ERROR
                 assert it.errorText == 'Failed'
                 assert it.cmHandle == 'cmhandle2'
             }
@@ -340,7 +344,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
                 assert it.status == Status.FAILURE
                 assert it.cmHandle == 'cmhandle'
                 assert it.errorText == 'Failed'
-                assert it.registrationError == UNKNOWN_ERROR
+                assert it.ncmpResponseStatus == UNKNOWN_ERROR
             }
     }
 
@@ -360,23 +364,23 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
             with(response.removedCmHandles[0]) {
                 assert it.status == Status.FAILURE
                 assert it.cmHandle == 'cmhandle'
-                assert it.registrationError == expectedError
+                assert it.ncmpResponseStatus == expectedError
                 assert it.errorText == expectedErrorText
             }
         and: 'the cm handle state is not updated to "DELETED"'
             0 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_, CmHandleState.DELETED)
         where:
-            scenario                     | cmHandleId             | deleteListElementException                ||  expectedError           | expectedErrorText
-            'cm-handle does not exist'   | 'cmhandle'             | new DataNodeNotFoundException('', '', '') || CM_HANDLE_DOES_NOT_EXIST | 'cm-handle does not exist'
-            'cm-handle has invalid name' | 'cm handle with space' | new DataValidationException('', '')       || CM_HANDLE_INVALID_ID     | 'cm-handle has an invalid character(s) in id'
-            'an unexpected exception'    | 'cmhandle'             | new RuntimeException('Failed')            || UNKNOWN_ERROR            | 'Failed'
+        scenario                     | cmHandleId             | deleteListElementException                || expectedError        | expectedErrorText
+        'cm-handle does not exist'   | 'cmhandle'             | new DataNodeNotFoundException('', '', '') || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found'
+        'cm-handle has invalid name' | 'cm handle with space' | new DataValidationException('', '')       || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id'
+        'an unexpected exception'    | 'cmhandle'             | new RuntimeException('Failed')            || UNKNOWN_ERROR        | 'Failed'
     }
 
     def getObjectUnderTest() {
         return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations,
                 mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmhandleQueries,
                 stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService,
-                mockModuleSyncStartedOnCmHandles))
+                mockModuleSyncStartedOnCmHandles, mockTrustLevelPerDmiPlugin))
     }
 
     def addPersistedYangModelCmHandles(ids) {
index 75af043..0d9aa61 100644 (file)
 
 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 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.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
+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
@@ -54,12 +64,6 @@ import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
 import spock.lang.Specification
 
-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
-
 class NetworkCmProxyDataServiceImplSpec extends Specification {
 
     def mockCpsDataService = Mock(CpsDataService)
@@ -72,6 +76,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     def mockCpsCmHandlerQueryService = Mock(NetworkCmProxyCmHandleQueryService)
     def mockLcmEventsCmHandleStateHandler = Mock(LcmEventsCmHandleStateHandler)
     def stubModuleSyncStartedOnCmHandles = Stub(IMap<String, Object>)
+    def stubTrustLevelPerDmiPlugin = Stub(IMap<String, TrustLevel>)
 
     def NO_TOPIC = null
     def NO_REQUEST_ID = null
@@ -89,7 +94,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             mockCpsCmHandlerQueryService,
             mockLcmEventsCmHandleStateHandler,
             mockCpsDataService,
-            stubModuleSyncStartedOnCmHandles)
+            stubModuleSyncStartedOnCmHandles,
+            stubTrustLevelPerDmiPlugin)
 
     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
 
@@ -163,7 +169,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
         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.LOCKED_MODULE_SYNC_FAILED).details("lock details").build(),
+                lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
                 lastUpdateTime: 'some-timestamp',
                 dataSyncEnabled: false,
                 dataStores: dataStores())
@@ -220,7 +226,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     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.LOCKED_MODULE_SYNC_FAILED).details("lock details").build(),
+                lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
                 lastUpdateTime: 'some-timestamp',
                 dataSyncEnabled: false,
                 dataStores: dataStores())
@@ -237,8 +243,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
 
     def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() {
         given: 'cpsDataService returns valid datanode'
-            mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
-                cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> 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,
@@ -256,7 +261,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
             mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle]
         when: 'parse and create cm handle in dmi registration then sync module'
-            objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(mockDmiPluginRegistration)
+            objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration)
         then: 'system persists the cm handle state'
             1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> {
                 args -> {
@@ -325,7 +330,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
         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', 'some-cm-handle-id', '/netconf-state', _)
+            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'
@@ -368,8 +373,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
     }
 
     def mockDataNode() {
-        mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
-                cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+        mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
     }
 
     def getDataOperationRequest(datastore) {
index 0df61f4..6439f0b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * Copyright (C) 2022-2023 Nordix Foundation
  * Modifications Copyright (C) 2022 Bell Canada
  * Modifications Copyright (C) 2023 TechMahindra Ltd.
  * ================================================================================
 
 package org.onap.cps.ncmp.api.impl
 
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
-import org.onap.cps.spi.exceptions.DataValidationException
-
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_DOES_NOT_EXIST
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.CM_HANDLE_INVALID_ID
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError.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.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.models.CmHandleRegistrationResponse.Status
 
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
+import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException
 import org.onap.cps.spi.model.DataNode
@@ -130,14 +131,14 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
             with(response.get(0)) {
                 assert it.status == Status.FAILURE
                 assert it.cmHandle == cmHandleId
-                assert it.registrationError == expectedError
+                assert it.ncmpResponseStatus == expectedError
                 assert it.errorText == expectedErrorText
             }
         where:
-            scenario                   | cmHandleId               | exception                                                                                           || expectedError            | expectedErrorText
-            'Cm Handle does not exist' | 'cmHandleId'             | new DataNodeNotFoundException('NCMP-Admin', 'ncmp-dmi-registry')                                    || CM_HANDLE_DOES_NOT_EXIST | 'cm-handle does not exist'
-            'Unknown'                  | 'cmHandleId'             | new RuntimeException('Failed')                                                                      || UNKNOWN_ERROR            | 'Failed'
-            'Invalid cm handle id'     | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID     | 'cm-handle has an invalid character(s) in id'
+        scenario                   | cmHandleId               | exception                                                                                           || expectedError        | expectedErrorText
+        'Cm Handle does not exist' | 'cmHandleId'             | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR)                        || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found'
+        'Unknown'                  | 'cmHandleId'             | new RuntimeException('Failed')                                                                      || UNKNOWN_ERROR        | 'Failed'
+        'Invalid cm handle id'     | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id'
     }
 
     def 'Multiple update operations in a single request'() {
@@ -147,7 +148,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
                                          new NcmpServiceCmHandle(cmHandleId: cmHandleId, publicProperties: ['publicProp1': "value"], dmiProperties: [:])]
         and: 'data node can be found for 1st and 3rd cm-handle but not for 2nd cm-handle'
             mockInventoryPersistence.getCmHandleDataNode(*_) >> cmHandleDataNodeAsCollection >> {
-                throw new DataNodeNotFoundException('NCMP-Admin', 'ncmp-dmi-registry') } >> cmHandleDataNodeAsCollection
+                throw new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) } >> cmHandleDataNodeAsCollection
         when: 'update data node leaves is called using correct parameters'
             def cmHandleResponseList = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest)
         then: 'response has 3 values'
@@ -165,8 +166,8 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification {
             with(cmHandleResponseList.get(1)) {
                 assert it.status == Status.FAILURE
                 assert it.cmHandle == cmHandleId
-                assert it.registrationError == CM_HANDLE_DOES_NOT_EXIST
-                assert it.errorText == "cm-handle does not exist"
+                assert it.ncmpResponseStatus == CM_HANDLES_NOT_FOUND
+                assert it.errorText == 'cm handle id(s) not found'
             }
         then: 'the replace list method is called twice'
             2 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_)
index 1e86a0b..5f4f248 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -20,6 +20,9 @@
 
 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
+
 import org.onap.cps.api.CpsQueryService
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.model.DataNode
@@ -35,10 +38,10 @@ class NetworkCmProxyQueryServiceImplSpec extends Specification {
         given: 'a list of datanodes'
             def dataNodes = [new DataNode(xpath: '/cps/path'), new DataNode(xpath: '/cps/path/child')]
         and: 'the list of datanodes is returned for query data node'
-            1 * mockCpsQueryService.queryDataNodes('NFP-Operational', 'ncmp-dmi-registry',
+            1 * mockCpsQueryService.queryDataNodes(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                 '//cps/path', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNodes
         when: 'query resource data operational for cm-handle is called'
-            def response = objectUnderTest.queryResourceDataOperational('ncmp-dmi-registry',
+            def response = objectUnderTest.queryResourceDataOperational(NCMP_DMI_REGISTRY_ANCHOR,
                 '//cps/path', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
         then: 'the expected datanodes are returned from the DMI'
             response == dataNodes
index c0fc18a..2fa9606 100644 (file)
@@ -44,6 +44,9 @@ class SynchronizationCacheConfigSpec extends Specification {
     @Autowired
     private IMap<String, Boolean> dataSyncSemaphores
 
+    @Autowired
+    private IMap<String, Set<String>> moduleSetTagCache
+
     def 'Embedded (hazelcast) Caches for Module and Data Sync.'() {
         expect: 'system is able to create an instance of the Module Sync Work Queue'
             assert null != moduleSyncWorkQueue
@@ -51,10 +54,12 @@ class SynchronizationCacheConfigSpec extends Specification {
             assert null != moduleSyncStartedOnCmHandles
         and: 'system is able to create an instance of a map to hold data sync semaphores'
             assert null != dataSyncSemaphores
-        and: 'there are at least 3 instances'
-            assert Hazelcast.allHazelcastInstances.size() > 2
+        and: 'system is able to create an instance of a map to hold module set tags'
+            assert null != moduleSetTagCache
+            and: 'there are at least 4 instances'
+        assert Hazelcast.allHazelcastInstances.size() > 3
         and: 'they have the correct names (in any order)'
-            assert Hazelcast.allHazelcastInstances.name.containsAll('moduleSyncWorkQueue', 'moduleSyncStartedOnCmHandles', 'dataSyncSemaphores' )
+            assert Hazelcast.allHazelcastInstances.name.containsAll('moduleSyncWorkQueue', 'moduleSyncStartedOnCmHandles', 'dataSyncSemaphores', 'moduleSetTags')
     }
 
     def 'Verify configs for Distributed objects'(){
@@ -67,6 +72,9 @@ class SynchronizationCacheConfigSpec extends Specification {
         and: 'the Data Sync Semaphores Map config'
             def dataSyncSemaphoresConfig =  Hazelcast.getHazelcastInstanceByName('dataSyncSemaphores').config
             def dataSyncSemaphoresMapConfig =  dataSyncSemaphoresConfig.mapConfigs.get('dataSyncSemaphoresConfig')
+        and: 'the Module Set Tag Map config'
+            def moduleSetTagCacheConfig =  Hazelcast.getHazelcastInstanceByName('moduleSetTags').config
+            def moduleSetTagMapConfig =  moduleSetTagCacheConfig.mapConfigs.get('moduleSetTagCacheMapConfig')
         expect: 'system created instance with correct config of Module Sync Work Queue'
             assert moduleSyncDefaultWorkQueueConfig.backupCount == 3
             assert moduleSyncDefaultWorkQueueConfig.asyncBackupCount == 3
@@ -76,11 +84,15 @@ class SynchronizationCacheConfigSpec extends Specification {
         and: 'Data Sync Semaphore Map has the correct settings'
             assert dataSyncSemaphoresMapConfig.backupCount == 3
             assert dataSyncSemaphoresMapConfig.asyncBackupCount == 3
+        and: 'Module Set Tag Map has the correct settings'
+            assert moduleSetTagMapConfig.backupCount == 3
+            assert moduleSetTagMapConfig.asyncBackupCount == 3
         and: 'all instances are part of same cluster'
             def testClusterName = 'cps-and-ncmp-test-caches'
             assert moduleSyncWorkQueueConfig.clusterName == testClusterName
             assert moduleSyncStartedOnCmHandlesConfig.clusterName == testClusterName
             assert dataSyncSemaphoresConfig.clusterName == testClusterName
+            assert moduleSetTagCacheConfig.clusterName == testClusterName
     }
 
     def 'Verify deployment network configs for Distributed objects'() {
@@ -90,6 +102,8 @@ class SynchronizationCacheConfigSpec extends Specification {
             def moduleSyncStartedOnCmHandlesNetworkConfig = Hazelcast.getHazelcastInstanceByName('moduleSyncStartedOnCmHandles').config.networkConfig
         and: 'the Data Sync Semaphores Map config'
             def dataSyncSemaphoresNetworkConfig = Hazelcast.getHazelcastInstanceByName('dataSyncSemaphores').config.networkConfig
+        and: 'the Module Set Tag Map config'
+            def moduleSetTagNetworkConfig = Hazelcast.getHazelcastInstanceByName('moduleSetTags').config.networkConfig
         expect: 'system created instance with correct config of Module Sync Work Queue'
             assert queueNetworkConfig.join.autoDetectionConfig.enabled
             assert !queueNetworkConfig.join.kubernetesConfig.enabled
@@ -99,7 +113,9 @@ class SynchronizationCacheConfigSpec extends Specification {
         and: 'Data Sync Semaphore Map has the correct settings'
             assert dataSyncSemaphoresNetworkConfig.join.autoDetectionConfig.enabled
             assert !dataSyncSemaphoresNetworkConfig.join.kubernetesConfig.enabled
-
+        and: 'Module Set Tag Map has the correct settings'
+            assert moduleSetTagNetworkConfig.join.autoDetectionConfig.enabled
+            assert !moduleSetTagNetworkConfig.join.kubernetesConfig.enabled
     }
 
     def 'Verify network config'() {
@@ -135,6 +151,15 @@ class SynchronizationCacheConfigSpec extends Specification {
             waitMax2SecondsForKeyExpiration(dataSyncSemaphores, 'testKeyDataSync')
     }
 
+    def 'Time to Live Verify for Module Set Tag'() {
+        when: 'the key is inserted with a TTL of 1 second'
+            moduleSetTagCache.put('testKeyModuleSetTag', ['module-set-tag'] as Set, 1, TimeUnit.SECONDS)
+        then: 'the entry is present in the map'
+            assert moduleSetTagCache.get('testKeyModuleSetTag') != null
+        and: 'the entry expires in less then 2 seconds'
+            waitMax2SecondsForKeyExpiration(moduleSetTagCache, 'testKeyModuleSetTag')
+    }
+
     def waitMax2SecondsForKeyExpiration(map, key) {
         def count = 0
         while ( map.get(key)!=null && ++count <= 20 ) {
index 175ead8..95dee77 100644 (file)
@@ -20,6 +20,8 @@
 
 package org.onap.cps.ncmp.api.impl.events.cmsubscription
 
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.hazelcast.map.IMap
 import io.cloudevents.CloudEvent
@@ -131,7 +133,7 @@ class CmSubscriptionDmiOutEventConsumerSpec extends MessagingBaseSpec {
 
     def getDataNode() {
         def leaves = [status:'ACCEPTED', cmHandleId:'cmhandle1'] as Map
-        return new DataNodeBuilder().withDataspace('NCMP-Admin')
+        return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
             .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
             .withLeaves(leaves).build()
     }
index fd1a83e..1edfa58 100644 (file)
@@ -20,6 +20,8 @@
 
 package org.onap.cps.ncmp.api.impl.events.cmsubscription
 
+import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.hazelcast.map.IMap
 import io.cloudevents.CloudEvent
@@ -30,12 +32,9 @@ import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionStatus
 import org.onap.cps.ncmp.api.impl.utils.CmSubscriptionEventCloudMapper
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent.TargetCmHandle
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence
 import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
-import org.onap.cps.ncmp.api.models.CmSubscriptionEvent
 import org.onap.cps.ncmp.events.cmsubscription1_0_0.client_to_ncmp.CmSubscriptionNcmpInEvent
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.CmSubscriptionDmiOutEvent
-import org.onap.cps.ncmp.events.cmsubscription1_0_0.dmi_to_ncmp.Data
 import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmHandle
 import org.onap.cps.ncmp.events.cmsubscription1_0_0.ncmp_to_dmi.CmSubscriptionDmiInEvent
 import org.onap.cps.ncmp.utils.TestUtils
@@ -46,8 +45,6 @@ import org.springframework.boot.test.context.SpringBootTest
 import spock.util.concurrent.BlockingVariable
 import java.util.concurrent.TimeUnit
 
-import static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
-
 @SpringBootTest(classes = [ObjectMapper, JsonObjectMapper, CmSubscriptionNcmpInEventForwarder])
 class CmSubscriptionNcmpInEventForwarderSpec extends MessagingBaseSpec {
 
index cc14195..a0567cb 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.events.cmsubscription
 
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESSFULLY_APPLIED_SUBSCRIPTION
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_PENDING
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUBSCRIPTION_NOT_APPLICABLE
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.PARTIALLY_APPLIED_SUBSCRIPTION
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import io.cloudevents.CloudEvent
 import io.cloudevents.core.builder.CloudEventBuilder
 import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.api.NcmpEventResponseCode
 import org.onap.cps.ncmp.api.impl.events.EventsPublisher
 import org.onap.cps.ncmp.api.impl.subscriptions.SubscriptionPersistence
 import org.onap.cps.ncmp.api.impl.utils.DataNodeBaseSpec
@@ -98,9 +102,9 @@ class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec {
         then: 'the result will be equal to ncmp out event'
             expectedResult == ncmpOutEvent
         where: 'the following values are used'
-            scenario             | ncmpEventResponseCode                                        || statusMessage                          ||  statusCode
-            'is full outcome'    | NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION      || 'successfully applied subscription'    ||  1
-            'is partial outcome' | NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION         || 'partially applied subscription'       ||  104
+        scenario             | ncmpEventResponseCode             || statusMessage                       || statusCode
+        'is full outcome'    | SUCCESSFULLY_APPLIED_SUBSCRIPTION || 'successfully applied subscription' || 1
+        'is partial outcome' | PARTIALLY_APPLIED_SUBSCRIPTION    || 'partially applied subscription'    || 104
     }
 
     def 'Check cm handle id to status map to see if it is a full outcome response'() {
@@ -109,16 +113,16 @@ class CmSubscriptionNcmpOutEventPublisherSpec extends DataNodeBaseSpec {
         then: 'the result will be as expected'
             response == expectedOutcomeResponseDecision
         where: 'the following values are used'
-            scenario                                          | cmHandleIdToStatusAndDetailsAsMap                                                                                                                                                   || expectedOutcomeResponseDecision
-            'The map contains PENDING status'                 | [CMHandle1: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map] as Map                                                                                        || NcmpEventResponseCode.SUBSCRIPTION_PENDING
-            'The map contains ACCEPTED status'                | [CMHandle1: [details:'',status:'ACCEPTED'] as Map] as Map                                                                                                                           || NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION
-            'The map contains REJECTED status'                | [CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map] as Map                                                                                                   || NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE
-            'The map contains PENDING and PENDING statuses'   | [CMHandle1: [details:'Some details',status:'PENDING'] as Map, CMHandle2: [details:'Some details',status:'PENDING'] as Map as Map] as Map                                            || NcmpEventResponseCode.SUBSCRIPTION_PENDING
-            'The map contains ACCEPTED and ACCEPTED statuses' | [CMHandle1: [details:'',status:'ACCEPTED'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map                                                                  || NcmpEventResponseCode.SUCCESSFULLY_APPLIED_SUBSCRIPTION
-            'The map contains REJECTED and REJECTED statuses' | [CMHandle1: [details:'Reject details',status:'REJECTED'] as Map, CMHandle2: [details:'Reject details',status:'REJECTED'] as Map as Map] as Map                                      || NcmpEventResponseCode.SUBSCRIPTION_NOT_APPLICABLE
-            'The map contains PENDING and ACCEPTED statuses'  | [CMHandle1: [details:'Some details',status:'PENDING'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map                                                       || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION
-            'The map contains REJECTED and ACCEPTED statuses' | [CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map, CMHandle2: [details:'',status:'ACCEPTED'] as Map as Map] as Map                                          || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION
-            'The map contains PENDING and REJECTED statuses'  | [CMHandle1: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map, CMHandle2: [details:'Cm handle does not exist',status:'REJECTED'] as Map as Map] as Map       || NcmpEventResponseCode.PARTIALLY_APPLIED_SUBSCRIPTION
+        scenario                                          | cmHandleIdToStatusAndDetailsAsMap                                                                                                                                                   || expectedOutcomeResponseDecision
+        'The map contains PENDING status'                 | [CMHandle1: [details: 'Subscription forwarded to dmi plugin', status: 'PENDING'] as Map] as Map                                                                                     || SUBSCRIPTION_PENDING
+        'The map contains ACCEPTED status'                | [CMHandle1: [details: '', status: 'ACCEPTED'] as Map] as Map                                                                                                                        || SUCCESSFULLY_APPLIED_SUBSCRIPTION
+        'The map contains REJECTED status'                | [CMHandle1: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map] as Map                                                                                                || SUBSCRIPTION_NOT_APPLICABLE
+        'The map contains PENDING and PENDING statuses'   | [CMHandle1: [details: 'Some details', status: 'PENDING'] as Map, CMHandle2: [details: 'Some details', status: 'PENDING'] as Map as Map] as Map                                      || SUBSCRIPTION_PENDING
+        'The map contains ACCEPTED and ACCEPTED statuses' | [CMHandle1: [details: '', status: 'ACCEPTED'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map                                                            || SUCCESSFULLY_APPLIED_SUBSCRIPTION
+        'The map contains REJECTED and REJECTED statuses' | [CMHandle1: [details: 'Reject details', status: 'REJECTED'] as Map, CMHandle2: [details: 'Reject details', status: 'REJECTED'] as Map as Map] as Map                                || SUBSCRIPTION_NOT_APPLICABLE
+        'The map contains PENDING and ACCEPTED statuses'  | [CMHandle1: [details: 'Some details', status: 'PENDING'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map                                                 || PARTIALLY_APPLIED_SUBSCRIPTION
+        'The map contains REJECTED and ACCEPTED statuses' | [CMHandle1: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map, CMHandle2: [details: '', status: 'ACCEPTED'] as Map as Map] as Map                                    || PARTIALLY_APPLIED_SUBSCRIPTION
+        'The map contains PENDING and REJECTED statuses'  | [CMHandle1: [details: 'Subscription forwarded to dmi plugin', status: 'PENDING'] as Map, CMHandle2: [details: 'Cm handle does not exist', status: 'REJECTED'] as Map as Map] as Map || PARTIALLY_APPLIED_SUBSCRIPTION
     }
 
 }
index 261b6e0..0ec73a2 100644 (file)
 
 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.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+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 spock.lang.Specification
 
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETED
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETING
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.LOCKED
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY
-import static org.onap.cps.ncmp.api.inventory.LockReasonCategory.LOCKED_MODULE_SYNC_FAILED
-
 class LcmEventsCmHandleStateHandlerImplSpec extends Specification {
 
     def mockInventoryPersistence = Mock(InventoryPersistence)
@@ -80,7 +80,7 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification {
     def 'Update and Publish Events on State Change from LOCKED to ADVISED'() {
         given: 'Cm Handle represented as YangModelCmHandle in LOCKED state'
             compositeState = new CompositeState(cmHandleState: LOCKED,
-                lockReason: CompositeState.LockReason.builder().lockReasonCategory(LOCKED_MODULE_SYNC_FAILED).details('some lock details').build())
+                lockReason: CompositeState.LockReason.builder().lockReasonCategory(MODULE_SYNC_FAILED).details('some lock details').build())
             yangModelCmHandle = new YangModelCmHandle(id: cmHandleId, dmiProperties: [], publicProperties: [], compositeState: compositeState)
         when: 'update state is invoked'
             objectUnderTest.updateCmHandleState(yangModelCmHandle, ADVISED)
index 6d7d625..0917953 100644 (file)
 
 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
+
 import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
+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.events.lcm.v1.Values
 import spock.lang.Specification
 
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.ADVISED
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.DELETING
-import static org.onap.cps.ncmp.api.inventory.CmHandleState.READY
-
 class LcmEventsCreatorSpec extends Specification {
 
     LcmEventHeaderMapper lcmEventsHeaderMapper = Mappers.getMapper(LcmEventHeaderMapper)
index 76ef23f..39c4fe6 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.operations
 
+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 static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING
+
 import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.NcmpEventResponseCode
 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
 import org.onap.cps.ncmp.api.impl.events.EventsPublisher
 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
@@ -41,13 +49,6 @@ import org.springframework.http.HttpStatus
 import spock.lang.Shared
 import java.util.concurrent.TimeoutException
 
-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 static org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper.toTargetEvent
-
 @SpringBootTest
 @ContextConfiguration(classes = [EventsPublisher, CpsApplicationContext, NcmpConfiguration.DmiProperties, DmiDataOperations])
 class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
@@ -128,12 +129,12 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec {
             def eventDataValue = extractDataValue(actualDataOperationCloudEvent)
             assert eventDataValue.operationId == dmiDataOperation.operationId
             assert eventDataValue.ids == dmiDataOperation.cmHandles.id
-            assert eventDataValue.statusCode == responseCode.statusCode
-            assert eventDataValue.statusMessage == responseCode.statusMessage
+            assert eventDataValue.statusCode == responseCode.code
+            assert eventDataValue.statusMessage == responseCode.message
         where: 'the following exceptions are occurred'
             scenario                        | exception                                                                                                || responseCode
-            'http client request exception' | new HttpClientRequestException('error-message', 'error-details', HttpStatus.SERVICE_UNAVAILABLE.value()) || NcmpEventResponseCode.UNABLE_TO_READ_RESOURCE_DATA
-            'timeout exception'             | new TimeoutException()                                                                                   || NcmpEventResponseCode.DMI_SERVICE_NOT_RESPONDING
+            'http client request exception' | new HttpClientRequestException('error-message', 'error-details', HttpStatus.SERVICE_UNAVAILABLE.value()) || UNABLE_TO_READ_RESOURCE_DATA
+            'timeout exception'             | new TimeoutException()                                                                                   || DMI_SERVICE_NOT_RESPONDING
     }
 
     def 'call get all resource data.'() {
index 1b2c50a..cc64255 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2023 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,9 +25,9 @@ import org.onap.cps.ncmp.api.impl.client.DmiRestClient
 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+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.spockframework.spring.SpringBean
 import spock.lang.Shared
index 7116a17..541a4f7 100644 (file)
 
 package org.onap.cps.ncmp.api.impl.subscriptions
 
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent
 import org.onap.cps.spi.model.DataNodeBuilder
 import org.onap.cps.utils.JsonObjectMapper
+import org.onap.cps.api.CpsModuleService
+import org.onap.cps.spi.utils.CpsValidator
 import spock.lang.Specification
 
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP
-
 class SubscriptionPersistenceSpec extends Specification {
 
-    private static final String SUBSCRIPTION_DATASPACE_NAME = "NCMP-Admin";
     private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions";
     private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry";
     private static final String SUBSCRIPTION_REGISTRY_PREDICATES_XPATH = "/subscription-registry/subscription[@clientID='some-client-id' and @subscriptionName='some-subscription-name']/predicates";
 
-    def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
+    def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
     def mockCpsDataService = Mock(CpsDataService)
-    def objectUnderTest = new SubscriptionPersistenceImpl(jsonObjectMapper, mockCpsDataService)
+    def mockCpsModuleService = Mock(CpsModuleService)
+    def mockCpsValidator = Mock(CpsValidator)
+
+    def objectUnderTest = new SubscriptionPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService,
+            mockCpsModuleService, mockCpsValidator)
 
     def predicates = new YangModelSubscriptionEvent.Predicates(datastore: 'some-datastore',
         targetCmHandles: [new YangModelSubscriptionEvent.TargetCmHandle('cmhandle1'),
@@ -48,14 +54,14 @@ class SubscriptionPersistenceSpec extends Specification {
 
    def 'save a subscription event as yang model into db for the #scenarios' () {
        given: 'a blank data node that exist in db'
-           def blankDataNode = new DataNodeBuilder().withDataspace('NCMP-Admin')
+           def blankDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
                 .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry').build()
        and: 'cps data service return an empty data node'
             mockCpsDataService.getDataNodes(*_) >> [blankDataNode]
        when: 'the yangModelSubscriptionEvent is saved into db'
             objectUnderTest.saveSubscriptionEvent(yangModelSubscriptionEvent)
        then: 'the cpsDataService save operation is called with the correct data'
-            1 * mockCpsDataService.saveListElements(SUBSCRIPTION_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+            1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
                 SUBSCRIPTION_REGISTRY_PARENT,
                 '{"subscription":[{' +
                     '"topic":"some-topic",' +
@@ -68,10 +74,10 @@ class SubscriptionPersistenceSpec extends Specification {
     def 'add or replace cm handle list element into db' () {
         given: 'a data node with child node exist in db'
             def leaves1 = [status:'REJECTED', cmHandleId:'cmhandle1', details:'Cm handle does not exist'] as Map
-            def childDataNode = new DataNodeBuilder().withDataspace('NCMP-Admin')
+            def childDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
                 .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
                 .withLeaves(leaves1).build()
-            def engagedDataNode = new DataNodeBuilder().withDataspace('NCMP-Admin')
+            def engagedDataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
                 .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry')
                 .withChildDataNodes([childDataNode]).build()
         and: 'cps data service return data node including a child data node'
@@ -81,11 +87,11 @@ class SubscriptionPersistenceSpec extends Specification {
         when: 'the yang model subscription event is saved into db'
             objectUnderTest.saveSubscriptionEvent(yangModelSubscriptionEvent)
         then: 'the cpsDataService save non-existing cm handle with the correct data'
-            1 * mockCpsDataService.saveListElements(SUBSCRIPTION_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+            1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
                 SUBSCRIPTION_REGISTRY_PREDICATES_XPATH, '{"targetCmHandles":[{"cmHandleId":"cmhandle2","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]}',
                 NO_TIMESTAMP)
         and: 'the cpsDataService update existing cm handle with the correct data'
-            1 * mockCpsDataService.updateNodeLeaves(SUBSCRIPTION_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+            1 * mockCpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
                 SUBSCRIPTION_REGISTRY_PREDICATES_XPATH, '{"targetCmHandles":[{"cmHandleId":"cmhandle1","status":"PENDING","details":"Subscription forwarded to dmi plugin"}]}',
                 NO_TIMESTAMP)
     }
index e28a102..9f84fb0 100644 (file)
@@ -20,6 +20,8 @@
 
 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
 
@@ -38,13 +40,13 @@ class DataNodeBaseSpec extends Specification {
     def dataNode4 = createDataNodeWithLeavesAndChildDataNodes(leaves4, [dataNode1, dataNode2, dataNode3])
 
     static def createDataNodeWithLeaves(leaves) {
-        return new DataNodeBuilder().withDataspace('NCMP-Admin')
+        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-Admin')
+        return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME)
             .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription')
             .withLeaves(leaves).withChildDataNodes(dataNodes)
             .build()
index 28db7ba..05e5f58 100644 (file)
 
 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-Admin')
+            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()
@@ -44,7 +46,7 @@ class DataNodeHelperSpec extends DataNodeBaseSpec {
 
     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-Admin')
+            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()
@@ -65,7 +67,7 @@ class DataNodeHelperSpec extends DataNodeBaseSpec {
 
     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-Admin')
+            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()
index 6c45755..2b17e5d 100644 (file)
@@ -32,7 +32,7 @@ import spock.lang.Specification
 class DmiServiceUrlBuilderSpec extends Specification {
 
     static YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName',
-        'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'))
+        'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'),'')
 
     NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties()
 
index 38b2056..f57988b 100644 (file)
@@ -28,8 +28,8 @@ import org.apache.kafka.clients.consumer.KafkaConsumer
 import org.onap.cps.ncmp.api.impl.events.EventsPublisher
 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.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
+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.events.async1_0_0.DataOperationEvent
index 5fe2660..ca0015e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2023 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 
 package org.onap.cps.ncmp.api.impl.yangmodels
 
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
+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 spock.lang.Specification
 
@@ -43,11 +43,11 @@ class YangModelCmHandleSpec extends Specification {
             def compositeState = new CompositeStateBuilder()
                 .withCmHandleState(CmHandleState.LOCKED)
                 .withLastUpdatedTime('some-update-time')
-                .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, 'locked details')
+                .withLockReason(LockReasonCategory.MODULE_SYNC_FAILED, 'locked details')
                 .withOperationalDataStores(DataStoreSyncState.SYNCHRONIZED, 'some-sync-time').build()
             ncmpServiceCmHandle.setCompositeState(compositeState)
         when: 'it is converted to a yang model cm handle'
-            def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('', '', '', ncmpServiceCmHandle)
+            def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('', '', '', ncmpServiceCmHandle,'')
         then: 'the result has the right size'
             assert objectUnderTest.dmiProperties.size() == 1
         and: 'the DMI property in the result has the correct name and value'
@@ -63,7 +63,8 @@ class YangModelCmHandleSpec extends Specification {
 
     def 'Resolve DMI service name: #scenario and #requiredService service require.'() {
         given: 'a yang model cm handle'
-            def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1'))
+            def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName,
+                    dmiModelServiceName, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1'),'')
         expect:
             assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService
         where:
index fd01a05..e7c337c 100644 (file)
 
 package org.onap.cps.ncmp.api.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.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueriesImpl
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.model.DataNode
 import spock.lang.Shared
 import spock.lang.Specification
 
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-
 class CmHandleQueriesImplSpec extends Specification {
     def cpsDataPersistenceService = Mock(CpsDataPersistenceService)
 
@@ -88,7 +94,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'
-            cpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
+            cpsDataPersistenceService.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)
@@ -100,8 +106,9 @@ class CmHandleQueriesImplSpec extends Specification {
         given: 'a cm handle state to compare'
             def cmHandleState = state
         and: 'the persistence service returns a list of data nodes'
-            cpsDataPersistenceService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
-                    '/dmi-registry/cm-handles[@id=\'some-cm-handle\']/state', OMIT_DESCENDANTS) >> [new DataNode(leaves: ['cm-handle-state': 'READY'])]
+            cpsDataPersistenceService.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'
             def result = objectUnderTest.cmHandleHasState('some-cm-handle', cmHandleState)
         then: 'the returned result matches the expected result from the persistence service'
@@ -116,8 +123,9 @@ 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'
-            cpsDataPersistenceService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
-                '/dmi-registry/cm-handles[@id=\'some-cm-handle\']/state', OMIT_DESCENDANTS) >> [new DataNode(leaves: ['cm-handle-state': 'READY'])]
+            cpsDataPersistenceService.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'
             def result = objectUnderTest.getCmHandleState('some-cm-handle')
         then: 'the returned result is a list of data nodes returned by cps data service'
@@ -128,7 +136,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'
-            cpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
+            cpsDataPersistenceService.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)
@@ -141,11 +149,11 @@ class CmHandleQueriesImplSpec extends Specification {
             def cmHandleDataNode = new DataNode(xpath: 'xpath', leaves: ['cm-handle-state': 'LOCKED'])
             def cpsPath = '//cps-path'
         and: 'cps data service returns a valid data node'
-            cpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
+            cpsDataPersistenceService.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'
-            def result = objectUnderTest.queryCmHandleDataNodesByCpsPath(cpsPath, INCLUDE_ALL_DESCENDANTS)
+            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)
     }
@@ -168,9 +176,9 @@ class CmHandleQueriesImplSpec extends Specification {
         cpsDataPersistenceService.queryDataNodes(_, _, '//public-properties[@name=\"Contact2\" and @value=\"\"]/ancestor::cm-handles', _) >> []
         cpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"READY\"]/ancestor::cm-handles', _) >> [pnfDemo, pnfDemo3]
         cpsDataPersistenceService.queryDataNodes(_, _, '//state[@cm-handle-state=\"LOCKED\"]/ancestor::cm-handles', _) >> [pnfDemo2, pnfDemo4]
-        cpsDataPersistenceService.queryDataNodes('NCMP-Admin','ncmp-dmi-registry','/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']',OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo2]
-        cpsDataPersistenceService.queryDataNodes('NCMP-Admin','ncmp-dmi-registry','/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']',OMIT_DESCENDANTS) >> [pnfDemo,pnfDemo4]
-        cpsDataPersistenceService.queryDataNodes('NCMP-Admin','ncmp-dmi-registry','/dmi-registry/cm-handles[@dmi-model-service-name=\'my-dmi-plugin-identifier\']',OMIT_DESCENDANTS) >> [pnfDemo2,pnfDemo4]
+        cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo2]
+        cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, '/dmi-registry/cm-handles[@dmi-data-service-name=\'my-dmi-plugin-identifier\']', OMIT_DESCENDANTS) >> [pnfDemo, pnfDemo4]
+        cpsDataPersistenceService.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) {
index fa43798..c2cdd9b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  * Copyright (C) 2022 Bell Canada
- * Modifications Copyright (C) 2022 Nordix Foundation.
+ * Modifications 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.
 
 package org.onap.cps.ncmp.api.inventory
 
+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.spi.model.DataNode
 import org.onap.cps.spi.model.DataNodeBuilder
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
 import spock.lang.Specification
 
 import java.time.OffsetDateTime
@@ -38,7 +42,7 @@ class CompositeStateBuilderSpec extends Specification {
     def static cmHandleId = 'myHandle1'
     def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}/state']"
     def static stateDataNodes = [new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/state/lock-reason")
-                                         .withLeaves(['reason': 'LOCKED_MODULE_SYNC_FAILED', 'details': 'lock details']).build(),
+                                         .withLeaves(['reason': 'MODULE_SYNC_FAILED', 'details': 'lock details']).build(),
                                  new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/state/datastores")
                                             .withChildDataNodes(Arrays.asList(new DataNodeBuilder()
                                                     .withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/state/datastores/operational")
@@ -48,7 +52,7 @@ class CompositeStateBuilderSpec extends Specification {
     def "Composite State Specification"() {
         when: 'using composite state builder '
             def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.ADVISED)
-                    .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED,"").withOperationalDataStores(DataStoreSyncState.UNSYNCHRONIZED,
+                    .withLockReason(LockReasonCategory.MODULE_SYNC_FAILED,"").withOperationalDataStores(DataStoreSyncState.UNSYNCHRONIZED,
                     formattedDateAndTime.toString()).withLastUpdatedTime(formattedDateAndTime).build()
         then: 'it matches expected cm handle state and data store sync state'
             assert compositeState.cmHandleState == CmHandleState.ADVISED
@@ -69,7 +73,7 @@ class CompositeStateBuilderSpec extends Specification {
             def finalCompositeStateBuilder = new CompositeStateBuilder()
                 .withCmHandleState(CmHandleState.ADVISED)
                 .withLastUpdatedTime(formattedDateAndTime.toString())
-                .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, 'locked details')
+                .withLockReason(LockReasonCategory.MODULE_SYNC_FAILED, 'locked details')
                 .withOperationalDataStores(DataStoreSyncState.SYNCHRONIZED, formattedDateAndTime)
         when: 'build is called'
             def result = finalCompositeStateBuilder.build()
@@ -78,7 +82,7 @@ class CompositeStateBuilderSpec extends Specification {
         and: 'built result should have correct values'
             assert !result.getDataSyncEnabled()
             assert result.getLastUpdateTime() == formattedDateAndTime
-            assert result.getLockReason().getLockReasonCategory() == LockReasonCategory.LOCKED_MODULE_SYNC_FAILED
+            assert result.getLockReason().getLockReasonCategory() == LockReasonCategory.MODULE_SYNC_FAILED
             assert result.getLockReason().getDetails() == 'locked details'
             assert result.getCmHandleState() == CmHandleState.ADVISED
             assert result.getDataStores().getOperationalDataStore().getDataStoreSyncState() == DataStoreSyncState.SYNCHRONIZED
index 7bdf335..985bdc5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * 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.
 package org.onap.cps.ncmp.api.inventory
 
 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 spock.lang.Specification
 import java.time.OffsetDateTime
 import java.time.ZoneOffset
 import java.time.format.DateTimeFormatter
 
-import static org.onap.cps.ncmp.api.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.inventory.CompositeState.Operational
+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.utils.TestUtils.getResourceFileContent
 import static org.springframework.util.StringUtils.trimAllWhitespace
 
@@ -40,7 +44,7 @@ class CompositeStateSpec extends Specification {
     def "Composite State Specification"() {
         given: "a Composite State"
             def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
-                lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED).details("lock details").build(),
+                lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(),
                 lastUpdateTime: formattedDateAndTime.toString(),
                 dataSyncEnabled: false,
                 dataStores: dataStores())
index efe6f00..724f05b 100644 (file)
 
 package org.onap.cps.ncmp.api.inventory
 
+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.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NO_TIMESTAMP
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.api.CpsAdminService
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.api.CpsModuleService
+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.InventoryPersistenceImpl
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 import org.onap.cps.spi.CascadeDeleteAllowed
 import org.onap.cps.spi.FetchDescendantsOption
-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
@@ -41,9 +50,6 @@ import java.time.OffsetDateTime
 import java.time.ZoneOffset
 import java.time.format.DateTimeFormatter
 
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-
 class InventoryPersistenceImplSpec extends Specification {
 
     def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
@@ -57,7 +63,7 @@ class InventoryPersistenceImplSpec extends Specification {
     def mockCpsValidator = Mock(CpsValidator)
 
     def objectUnderTest = new InventoryPersistenceImpl(spiedJsonObjectMapper, mockCpsDataService, mockCpsModuleService,
-            mockCpsAdminService, mockCpsValidator)
+            mockCpsValidator, mockCpsAdminService)
 
     def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
             .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC))
@@ -85,7 +91,7 @@ class InventoryPersistenceImplSpec extends Specification {
     def "Retrieve CmHandle using datanode with #scenario."() {
         given: 'the cps data service returns a data node from the DMI registry'
             def dataNode = new DataNode(childDataNodes:childDataNodes, leaves: leaves)
-            mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
+            mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
         when: 'retrieving the yang modelled cm handle'
             def result = objectUnderTest.getYangModelCmHandle(cmHandleId)
         then: 'the result has the correct id and service names'
@@ -112,7 +118,7 @@ class InventoryPersistenceImplSpec extends Specification {
     def "Handling missing service names as null."() {
         given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes'
             def dataNode = new DataNode(childDataNodes:[], leaves: [:])
-            mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
+            mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
         when: 'retrieving the yang modelled cm handle'
             def result = objectUnderTest.getYangModelCmHandle(cmHandleId)
         then: 'the service names are returned as null'
@@ -126,7 +132,7 @@ class InventoryPersistenceImplSpec extends Specification {
     def "Retrieve multiple YangModelCmHandles"() {
         given: 'the cps data service returns 2 data nodes from the DMI registry'
             def dataNodes = [new DataNode(xpath: xpath), new DataNode(xpath: xpath2)]
-            mockCpsDataService.getDataNodesForMultipleXpaths('NCMP-Admin', 'ncmp-dmi-registry', [xpath, xpath2] , INCLUDE_ALL_DESCENDANTS) >> dataNodes
+            mockCpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, [xpath, xpath2] , INCLUDE_ALL_DESCENDANTS) >> dataNodes
         when: 'retrieving the yang modelled cm handle'
             def results = objectUnderTest.getYangModelCmHandles([cmHandleId, cmHandleId2])
         then: 'verify both have returned and cmhandleIds are correct'
@@ -139,7 +145,7 @@ class InventoryPersistenceImplSpec extends Specification {
             def cmHandleId = 'Some-Cm-Handle'
             def dataNode = new DataNode(leaves: ['cm-handle-state': 'ADVISED'])
         and: 'cps data service returns a valid data node'
-            mockCpsDataService.getDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
+            mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
                     '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']/state', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode]
         when: 'get cm handle state is invoked'
             def result = objectUnderTest.getCmHandleState(cmHandleId)
@@ -156,7 +162,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-Admin', 'ncmp-dmi-registry', '/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)
         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"}}'
@@ -172,7 +178,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-Admin', 'ncmp-dmi-registry', cmHandlesJsonDataMap, _ as OffsetDateTime)
+            1 * mockCpsDataService.updateDataNodesAndDescendants(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, cmHandlesJsonDataMap, _ as OffsetDateTime)
         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"}}']
@@ -183,7 +189,7 @@ class InventoryPersistenceImplSpec extends Specification {
     def 'Get module definitions'() {
         given: 'cps module service returns a collection of module definitions'
             def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
-            mockCpsModuleService.getModuleDefinitionsByAnchorName('NFP-Operational','some-cmHandle-Id') >> moduleDefinitions
+            mockCpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id') >> moduleDefinitions
         when: 'get module definitions by cmHandle is invoked'
             def result = objectUnderTest.getModuleDefinitionsByCmHandleId('some-cmHandle-Id')
         then: 'the returned result are the same module definitions as returned from the module service'
@@ -193,7 +199,7 @@ class InventoryPersistenceImplSpec extends Specification {
     def 'Get module references'() {
         given: 'cps module service returns a collection of module references'
             def moduleReferences = [new ModuleReference('moduleName','revision','namespace')]
-            mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some-cmHandle-Id') >> moduleReferences
+            mockCpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id') >> moduleReferences
         when: 'get yang resources module references by cmHandle is invoked'
             def result = objectUnderTest.getYangResourcesModuleReferences('some-cmHandle-Id')
         then: 'the returned result is a collection of module definitions'
@@ -208,7 +214,8 @@ class InventoryPersistenceImplSpec extends Specification {
         when: 'the method to save cmhandle is called'
             objectUnderTest.saveCmHandle(yangModelCmHandle)
         then: 'the data service method to save list elements is called once'
-            1 * mockCpsDataService.saveListElements('NCMP-Admin','ncmp-dmi-registry','/dmi-registry',_,null) >> {
+            1 * mockCpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
+                    _,null) >> {
                 args -> {
                     assert args[3].startsWith('{"cm-handles":[{"id":"cmhandle","additional-properties":[],"public-properties":[]}]}')
                 }
@@ -222,7 +229,8 @@ class InventoryPersistenceImplSpec extends Specification {
         when: 'the cm handles are saved'
             objectUnderTest.saveCmHandleBatch([yangModelCmHandle1, yangModelCmHandle2])
         then: 'CPS Data Service persists both cm handles as a batch'
-            1 * mockCpsDataService.saveListElementsBatch('NCMP-Admin','ncmp-dmi-registry','/dmi-registry',_,null) >> {
+            1 * mockCpsDataService.saveListElementsBatch(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+                    NCMP_DMI_REGISTRY_PARENT, _,null) >> {
                 args -> {
                     def jsonDataList = (args[3] as List)
                     (jsonDataList[0] as String).contains('cmhandle1')
@@ -235,14 +243,14 @@ class InventoryPersistenceImplSpec extends Specification {
         when: 'the method to delete list or list elements is called'
             objectUnderTest.deleteListOrListElement('sample xPath')
         then: 'the data service method to save list elements is called once'
-            1 * mockCpsDataService.deleteListOrListElement('NCMP-Admin','ncmp-dmi-registry','sample xPath',null)
+            1 * mockCpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'sample xPath',null)
     }
 
     def 'Delete schema set with a valid schema set name'() {
         when: 'the method to delete schema set is called with valid schema set name'
             objectUnderTest.deleteSchemaSetWithCascade('validSchemaSetName')
         then: 'the module service to delete schemaSet is invoked once'
-            1 * mockCpsModuleService.deleteSchemaSet('NFP-Operational', 'validSchemaSetName', CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED)
+            1 * mockCpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'validSchemaSetName', CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED)
         and: 'the schema set name is validated'
             1 * mockCpsValidator.validateNameCharacters('validSchemaSetName')
     }
@@ -251,7 +259,7 @@ class InventoryPersistenceImplSpec extends Specification {
         when: 'the method to delete schema sets is called with valid schema set names'
             objectUnderTest.deleteSchemaSetsWithCascade(['validSchemaSetName1', 'validSchemaSetName2'])
         then: 'the module service to delete schema sets is invoked once'
-            1 * mockCpsModuleService.deleteSchemaSetsWithCascade('NFP-Operational', ['validSchemaSetName1', 'validSchemaSetName2'])
+            1 * mockCpsModuleService.deleteSchemaSetsWithCascade(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, ['validSchemaSetName1', 'validSchemaSetName2'])
         and: 'the schema set names are validated'
             1 * mockCpsValidator.validateNameCharacters(['validSchemaSetName1', 'validSchemaSetName2'])
     }
@@ -260,7 +268,7 @@ class InventoryPersistenceImplSpec extends Specification {
         when: 'the method to get data nodes is called'
             objectUnderTest.getDataNode('sample xPath')
         then: 'the data persistence service method to get data node is invoked once'
-            1 * mockCpsDataService.getDataNodes('NCMP-Admin','ncmp-dmi-registry','sample xPath', INCLUDE_ALL_DESCENDANTS)
+            1 * mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'sample xPath', INCLUDE_ALL_DESCENDANTS)
     }
 
     def 'Get cmHandle data node'() {
@@ -269,38 +277,35 @@ class InventoryPersistenceImplSpec extends Specification {
         when: 'the method to get data nodes is called'
             objectUnderTest.getCmHandleDataNode('sample cmHandleId')
         then: 'the data persistence service method to get cmHandle data node is invoked once with expected xPath'
-            1 * mockCpsDataService.getDataNodes('NCMP-Admin','ncmp-dmi-registry',expectedXPath, INCLUDE_ALL_DESCENDANTS)
+            1 * mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, expectedXPath, INCLUDE_ALL_DESCENDANTS)
     }
 
     def 'Get CM handles that has given module names'() {
         when: 'the method to get cm handles is called'
             objectUnderTest.getCmHandleIdsWithGivenModules(['sample-module-name'])
         then: 'the admin persistence service method to query anchors is invoked once with the same parameter'
-            1 * mockCpsAdminService.queryAnchorNames('NFP-Operational',['sample-module-name'])
+            1 * mockCpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, ['sample-module-name'])
     }
 
     def 'Replace list content'() {
         when: 'replace list content method is called with xpath and data nodes collection'
             objectUnderTest.replaceListContent('sample xpath', [new DataNode()])
         then: 'the cps data service method to replace list content is invoked once with same parameters'
-            1 * mockCpsDataService.replaceListContent('NCMP-Admin', 'ncmp-dmi-registry',
-                    'sample xpath', [new DataNode()], NO_TIMESTAMP);
+            1 * mockCpsDataService.replaceListContent(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,'sample xpath', [new DataNode()], NO_TIMESTAMP);
     }
 
     def 'Delete data node via xPath'() {
         when: 'Delete data node method is called with xpath as parameter'
             objectUnderTest.deleteDataNode('sample dataNode xpath')
         then: 'the cps data service method to delete data node is invoked once with the same xPath'
-            1 * mockCpsDataService.deleteDataNode('NCMP-Admin', 'ncmp-dmi-registry',
-                    'sample dataNode xpath', NO_TIMESTAMP);
+            1 * mockCpsDataService.deleteDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, 'sample dataNode xpath', NO_TIMESTAMP);
     }
 
     def 'Delete multiple data nodes via xPath'() {
         when: 'Delete data nodes method is called with multiple xpaths as parameters'
             objectUnderTest.deleteDataNodes(['xpath1', 'xpath2'])
         then: 'the cps data service method to delete data nodes is invoked once with the same xPaths'
-            1 * mockCpsDataService.deleteDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
-                    ['xpath1', 'xpath2'], NO_TIMESTAMP);
+            1 * mockCpsDataService.deleteDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, ['xpath1', 'xpath2'], NO_TIMESTAMP);
     }
 
 }
index 0d09bef..ed313a0 100644 (file)
 
 package org.onap.cps.ncmp.api.inventory.sync
 
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+
 import com.hazelcast.map.IMap
 import org.onap.cps.api.CpsDataService
+import org.onap.cps.ncmp.api.impl.inventory.sync.DataSyncWatchdog
+import org.onap.cps.ncmp.api.impl.inventory.sync.SyncUtils
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
+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 spock.lang.Specification
 
 class DataSyncWatchdogSpec extends Specification {
@@ -61,7 +65,7 @@ class DataSyncWatchdogSpec extends Specification {
         and: 'the sync util returns first resource data'
             1 * mockSyncUtils.getResourceData('cm-handle-1') >> resourceData
         and: 'the cm-handle data is saved'
-            1 * mockCpsDataService.saveData('NFP-Operational', 'cm-handle-1', jsonString, _)
+            1 * mockCpsDataService.saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'cm-handle-1', jsonString, _)
         and: 'the first cm handle operational sync state is updated'
             1 * mockInventoryPersistence.saveCmHandleState('cm-handle-1', compositeState)
         then: 'the inventory persistence cm handle returns a composite state for the second cm handle'
@@ -69,7 +73,7 @@ class DataSyncWatchdogSpec extends Specification {
         and: 'the sync util returns first resource data'
             1 * mockSyncUtils.getResourceData('cm-handle-2') >> resourceData
         and: 'the cm-handle data is saved'
-            1 * mockCpsDataService.saveData('NFP-Operational', 'cm-handle-2', jsonString, _)
+            1 * mockCpsDataService.saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'cm-handle-2', jsonString, _)
         and: 'the second cm handle operational sync state is updated from "UNSYNCHRONIZED" to "SYNCHRONIZED"'
             1 * mockInventoryPersistence.saveCmHandleState('cm-handle-2', compositeState)
     }
index 3c4c6f5..b547da7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
 
 package org.onap.cps.ncmp.api.inventory.sync
 
+import org.onap.cps.spi.FetchDescendantsOption
+
+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.api.CpsAdminService
+import org.onap.cps.api.CpsDataService
 import org.onap.cps.api.CpsModuleService
+import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncService
 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.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
 
 class ModuleSyncServiceSpec extends Specification {
@@ -35,17 +45,23 @@ class ModuleSyncServiceSpec extends Specification {
     def mockCpsModuleService = Mock(CpsModuleService)
     def mockDmiModelOperations = Mock(DmiModelOperations)
     def mockCpsAdminService = Mock(CpsAdminService)
+    def mockCmHandleQueries = Mock(CmHandleQueries)
+    def mockCpsDataService = Mock(CpsDataService)
+    def mockJsonObjectMapper = Mock(JsonObjectMapper)
 
-    def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService, mockCpsAdminService)
+    def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService, mockCpsAdminService,
+            mockCmHandleQueries, mockCpsDataService, mockJsonObjectMapper)
 
-    def expectedDataspaceName = 'NFP-Operational'
+    def expectedDataspaceName = NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
 
     def 'Sync model for a (new) cm handle with #scenario'() {
-        given: 'a cm handle'
+        given: 'a cm handle having lock reason : MODULE_UPGRADE'
             def ncmpServiceCmHandle = new NcmpServiceCmHandle()
+            ncmpServiceCmHandle.setCompositeState(new CompositeStateBuilder()
+                .withLockReason(MODULE_UPGRADE, 'new moduleSetTag: someModuleSetTag').build())
             def dmiServiceName = 'some service name'
             ncmpServiceCmHandle.cmHandleId = 'cmHandleId-1'
-            def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '', '', ncmpServiceCmHandle)
+            def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '', '', ncmpServiceCmHandle,'someModuleSetTag')
         and: 'DMI operations returns some module references'
             def moduleReferences =  [ new ModuleReference('module1','1'), new ModuleReference('module2','2') ]
             mockDmiModelOperations.getModuleReferences(yangModelCmHandle) >> moduleReferences
@@ -53,13 +69,16 @@ class ModuleSyncServiceSpec extends Specification {
             mockCpsModuleService.getYangResourceModuleReferences(expectedDataspaceName) >> toModuleReference(existingModuleResourcesInCps)
         and: 'DMI-Plugin returns resource(s) for "new" module(s)'
             mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('module1', '1')]) >> newModuleNameContentToMap
+        and: 'empty data node list is returned by cps path a query'
+        mockCmHandleQueries.queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='someModuleSetTag']",
+                FetchDescendantsOption.OMIT_DESCENDANTS) >> Collections.emptyList()
         when: 'module sync is triggered'
             mockCpsModuleService.identifyNewModuleReferences(moduleReferences) >> toModuleReference(identifiedNewModuleReferences)
-            objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle)
+            objectUnderTest.syncAndCreateOrUpgradeSchemaSetAndAnchor(yangModelCmHandle)
         then: 'create schema set from module is invoked with correct parameters'
-            1 * mockCpsModuleService.createSchemaSetFromModules('NFP-Operational', 'cmHandleId-1', newModuleNameContentToMap, moduleReferences)
+            1 * mockCpsModuleService.createOrUpgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'cmHandleId-1', newModuleNameContentToMap, moduleReferences)
         and: 'anchor is created with the correct parameters'
-            1 * mockCpsAdminService.createAnchor('NFP-Operational', 'cmHandleId-1', 'cmHandleId-1')
+            1 * mockCpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'cmHandleId-1', 'cmHandleId-1')
         where: 'the following parameters are used'
             scenario             | existingModuleResourcesInCps           | identifiedNewModuleReferences | newModuleNameContentToMap
             'one new module'     | [['module2' : '2'], ['module3' : '3']] | [['module1' : '1']]           | [module1: 'some yang source']
index 382d5da..a11f148 100644 (file)
@@ -25,12 +25,15 @@ 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.inventory.sync.ModuleSyncService
+import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncTasks
+import org.onap.cps.ncmp.api.impl.inventory.sync.SyncUtils
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.inventory.InventoryPersistence
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory
+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.spi.model.DataNode
 import spock.lang.Specification
 import java.util.concurrent.atomic.AtomicInteger
@@ -66,8 +69,8 @@ class ModuleSyncTasksSpec extends Specification {
             1 * mockModuleSyncService.deleteSchemaSetIfExists('cm-handle-1')
             1 * mockModuleSyncService.deleteSchemaSetIfExists('cm-handle-2')
         and: 'module sync service is invoked for each cm handle'
-            1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
-            1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-2') }
+            1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
+            1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-2') }
         and: 'the state handler is called for the both cm handles'
             1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> { args ->
                 assertBatch(args, ['cm-handle-1', 'cm-handle-2'], CmHandleState.READY)
@@ -83,11 +86,11 @@ class ModuleSyncTasksSpec extends Specification {
             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') }
+            1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(*_) >> { 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, LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, 'some exception')
+            1 * mockSyncUtils.updateLockReasonDetailsAndAttempts(cmHandleState, LockReasonCategory.MODULE_SYNC_FAILED, 'some exception')
         and: 'the state handler is called to update the state to LOCKED'
             1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> { args ->
                 assertBatch(args, ['cm-handle'], CmHandleState.LOCKED)
@@ -99,7 +102,7 @@ class ModuleSyncTasksSpec extends Specification {
     def 'Reset failed CM Handles #scenario.'() {
         given: 'cm handles in an locked state'
             def lockedState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED)
-                    .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, '').withLastUpdatedTimeNow().build()
+                    .withLockReason(LockReasonCategory.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]
@@ -109,7 +112,7 @@ class ModuleSyncTasksSpec extends Specification {
             moduleSyncStartedOnCmHandles.put('cm-handle-1', 'started')
             moduleSyncStartedOnCmHandles.put('cm-handle-2', 'started')
         and: 'sync utils retry locked cm handle returns #isReadyForRetry'
-            mockSyncUtils.isReadyForRetry(lockedState) >>> 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'
@@ -132,7 +135,7 @@ class ModuleSyncTasksSpec extends Specification {
         when: 'module sync poll is executed'
             objectUnderTest.performModuleSync([cmHandle1], batchCount)
         then: 'module sync service is invoked for cm handle'
-            1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
+            1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
         and: 'the entry for other cm handle is still in the progress map'
             assert moduleSyncStartedOnCmHandles.get('other-cm-handle') != null
     }
index bb730fc..390e88b 100644 (file)
 package org.onap.cps.ncmp.api.inventory.sync
 
 import com.hazelcast.map.IMap
+import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncTasks
+import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
+import org.onap.cps.ncmp.api.impl.inventory.sync.SyncUtils
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.inventory.sync.executor.AsyncTaskExecutor
+import org.onap.cps.ncmp.api.impl.inventory.sync.executor.AsyncTaskExecutor
 import java.util.concurrent.ArrayBlockingQueue
 import org.onap.cps.spi.model.DataNode
 import spock.lang.Specification
@@ -42,7 +45,9 @@ class ModuleSyncWatchdogSpec extends Specification {
 
     def spiedAsyncTaskExecutor = Spy(AsyncTaskExecutor)
 
-    def objectUnderTest = new ModuleSyncWatchdog(mockSyncUtils, moduleSyncWorkQueue , mockModuleSyncStartedOnCmHandles, mockModuleSyncTasks, spiedAsyncTaskExecutor)
+    def moduleSetTagCache = Mock(IMap<String, Set<String>>)
+
+    def objectUnderTest = new ModuleSyncWatchdog(mockSyncUtils, moduleSyncWorkQueue , mockModuleSyncStartedOnCmHandles, mockModuleSyncTasks, spiedAsyncTaskExecutor, moduleSetTagCache)
 
     void setup() {
         spiedAsyncTaskExecutor.setupThreadPool()
@@ -106,7 +111,7 @@ class ModuleSyncWatchdogSpec extends Specification {
     def 'Reset failed cm handles.'() {
         given: 'sync utilities returns failed cm handles'
             def failedCmHandles = [new YangModelCmHandle()]
-            mockSyncUtils.getModuleSyncFailedCmHandles() >> failedCmHandles
+            mockSyncUtils.getCmHandlesThatFailedModelSyncOrUpgrade() >> failedCmHandles
         when: 'reset failed cm handles is started'
             objectUnderTest.resetPreviouslyFailedCmHandles()
         then: 'it is delegated to the module sync task (service)'
index c6ce1a5..00d14cd 100644 (file)
 package org.onap.cps.ncmp.api.inventory.sync
 
 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
+import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE_FAILED
+
+import ch.qos.logback.classic.Level
+import ch.qos.logback.classic.Logger
+import ch.qos.logback.core.read.ListAppender
+import org.onap.cps.ncmp.api.impl.inventory.sync.SyncUtils
+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.inventory.CmHandleQueries
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
-import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
-import org.onap.cps.ncmp.api.inventory.LockReasonCategory
+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.spi.FetchDescendantsOption
 import org.onap.cps.spi.model.DataNode
 import org.onap.cps.utils.JsonObjectMapper
 import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
-import spock.lang.Shared
 import spock.lang.Specification
 import java.time.OffsetDateTime
 import java.time.format.DateTimeFormatter
@@ -53,12 +60,31 @@ class SyncUtilsSpec extends Specification{
 
     def objectUnderTest = new SyncUtils(mockCmHandleQueries, mockDmiDataOperations, jsonObjectMapper)
 
-    @Shared
-    def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(OffsetDateTime.now())
+    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()
 
-    @Shared
-    def dataNode = new DataNode(leaves: ['id': 'cm-handle-123'])
+    def logger = (Logger) LoggerFactory.getLogger(SyncUtils)
+    def loggingListAppender
 
+    void setup() {
+        logger.setLevel(Level.DEBUG)
+        loggingListAppender = new ListAppender()
+        logger.addAppender(loggingListAppender)
+        loggingListAppender.start()
+        applicationContext.refresh()
+    }
+
+    void cleanup() {
+        ((Logger) LoggerFactory.getLogger(SyncUtils.class)).detachAndStopAllAppenders()
+        applicationContext.close()
+    }
 
     def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() {
         given: 'the inventory persistence service returns a collection of data nodes'
@@ -77,9 +103,9 @@ class SyncUtilsSpec extends Specification{
         given: 'A locked state'
             def compositeState = new CompositeState(lockReason: lockReason)
         when: 'update cm handle details and attempts is called'
-            objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, 'new error message')
+            objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, MODULE_SYNC_FAILED, 'new error message')
         then: 'the composite state lock reason and details are updated'
-            assert compositeState.lockReason.lockReasonCategory == LockReasonCategory.LOCKED_MODULE_SYNC_FAILED
+            assert compositeState.lockReason.lockReasonCategory == MODULE_SYNC_FAILED
             assert compositeState.lockReason.details == expectedDetails
         where:
             scenario         | lockReason                                                                                   || expectedDetails
@@ -87,13 +113,13 @@ class SyncUtilsSpec extends Specification{
             'exists'         | CompositeState.LockReason.builder().details("Attempt #2 failed: some error message").build() || 'Attempt #3 failed: new error message'
     }
 
-    def 'Get all locked Cm-Handle where Lock Reason is LOCKED_MODULE_SYNC_FAILED cm handle #scenario'() {
+    def 'Get all locked Cm-Handle where Lock Reason is MODULE_SYNC_FAILED cm handle #scenario'() {
         given: 'the cps (persistence service) returns a collection of data nodes'
-            mockCmHandleQueries.queryCmHandleDataNodesByCpsPath(
-                '//lock-reason[@reason="LOCKED_MODULE_SYNC_FAILED"]',
+            mockCmHandleQueries.queryCmHandleAncestorsByCpsPath(
+                    '//lock-reason[@reason="MODULE_SYNC_FAILED" or @reason="MODULE_UPGRADE"]',
                 FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode]
         when: 'get locked Misbehaving cm handle is called'
-            def result = objectUnderTest.getModuleSyncFailedCmHandles()
+            def result = objectUnderTest.getCmHandlesThatFailedModelSyncOrUpgrade()
         then: 'the returned cm handle collection is the correct size'
             result.size() == 1
         and: 'the correct cm handle is returned'
@@ -101,19 +127,43 @@ class SyncUtilsSpec extends Specification{
     }
 
     def 'Retry Locked Cm-Handle where the last update time is #scenario'() {
-        when: 'retry locked cm handle is invoked'
-            def result = objectUnderTest.isReadyForRetry(new CompositeStateBuilder()
-                .withLockReason(LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, details)
-                .withLastUpdatedTime(lastUpdateTime).build())
-        then: 'result returns #expectedResult'
-            result == expectedResult
-        where:
-            scenario                     | lastUpdateTime                     | details                 || expectedResult
-            'the first attempt'          | '1900-01-01T00:00:00.000+0100'     | 'First Attempt'         || true
-            'greater than one minute'    | '1900-01-01T00:00:00.000+0100'     | 'Attempt #1 failed:'    || true
-            'less than eight minutes'    | formattedDateAndTime               | 'Attempt #3 failed:'    || false
+        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:' | 'Retry due now'                         || true
+            '2nd attempt, last attempt < 4 minutes ago' | 1                    | 'Attempt #2 failed:' | 'Time until next attempt is 3 minutes:' || false
+            '2nd attempt, last attempt > 4 minutes ago' | 5                    | 'Attempt #2 failed:' | 'Retry due now'                         || true
     }
 
+    def 'Retry Locked Cm-Handle with other 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 == retryAttempt
+        and: 'logs contain related information'
+        def logs = loggingListAppender.list.toString()
+        assert logs.contains(logReason)
+        where: 'the following lock reasons occurred'
+        scenario             | lockReasonCategory || logReason                    | retryAttempt
+        'module upgrade'     | MODULE_UPGRADE     || 'Locked for module upgrade.' | true
+        'module sync failed' | MODULE_SYNC_FAILED || 'First Attempt:'             | false
+    }
 
     def 'Get a Cm-Handle where #scenario'() {
         given: 'the inventory persistence service returns a collection of data nodes'
index d4010aa..7361948 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * 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.
@@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.inventory.sync.config
 
 import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
+import org.onap.cps.ncmp.api.impl.inventory.sync.config.WatchdogSchedulingConfigurer
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.context.ConfigurableApplicationContext
index ba1820e..b3ed945 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -20,6 +20,7 @@
 
 package org.onap.cps.ncmp.api.inventory.sync.executor
 
+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
index dba2934..d76f912 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Bell Canada
+ *  Modifications 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.
 
 package org.onap.cps.ncmp.api.models
 
-import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError
+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 {
@@ -37,7 +39,7 @@ class CmHandleRegistrationResponseSpec extends Specification {
                 assert it.status == Status.SUCCESS
             }
         and: 'error details are null'
-            cmHandleRegistrationResponse.registrationError == null
+            cmHandleRegistrationResponse.ncmpResponseStatus == null
             cmHandleRegistrationResponse.errorText == null
     }
 
@@ -47,33 +49,29 @@ class CmHandleRegistrationResponseSpec extends Specification {
                 CmHandleRegistrationResponse.createFailureResponse('cmHandle', new Exception('unexpected error'))
         then: 'the response is created with expected value'
             with(cmHandleRegistrationResponse) {
-                assert it.registrationError == RegistrationError.UNKNOWN_ERROR
+                assert it.ncmpResponseStatus == UNKNOWN_ERROR
                 assert it.cmHandle == 'cmHandle'
                 assert errorText == 'unexpected error'
             }
     }
 
-    def 'Failed cm-handle Registration Response: for #scenario'() {
-        when: 'cm-handle failure response is created for #scenario'
-            def cmHandleRegistrationResponse =
-                CmHandleRegistrationResponse.createFailureResponse(cmHandleId, registrationError)
+    def 'Failed cm-handle Registration Response'() {
+        when: 'cm-handle failure response is created'
+        def cmHandleRegistrationResponse =
+                CmHandleRegistrationResponse.createFailureResponse('cmHandle', CM_HANDLE_ALREADY_EXIST)
         then: 'the response is created with expected value'
-            with(cmHandleRegistrationResponse) {
-                assert it.registrationError == registrationError
-                assert it.cmHandle == cmHandleId
-                assert it.status == Status.FAILURE
-                assert errorText == registrationError.errorText
-            }
-        where:
-            scenario                   | cmHandleId  | registrationError
-            'cm-handle already exists' | 'cmHandle'  | RegistrationError.CM_HANDLE_ALREADY_EXIST
-            'cm-handle id is invalid'  | 'cm handle' | RegistrationError.CM_HANDLE_INVALID_ID
+        with(cmHandleRegistrationResponse) {
+            assert it.ncmpResponseStatus == CM_HANDLE_ALREADY_EXIST
+            assert it.cmHandle == 'cmHandle'
+            assert it.status == Status.FAILURE
+            assert errorText == CM_HANDLE_ALREADY_EXIST.message
+        }
     }
 
     def 'Failed cm-handle Registration with multiple responses.'() {
         when: 'cm-handle failure response is created for 2 xpaths'
             def cmHandleRegistrationResponses =
-                CmHandleRegistrationResponse.createFailureResponses(["somePathWithId[@id='123']","somePathWithId[@id='456']"], RegistrationError.CM_HANDLE_ALREADY_EXIST)
+                CmHandleRegistrationResponse.createFailureResponses(["somePathWithId[@id='123']","somePathWithId[@id='456']"], CM_HANDLE_ALREADY_EXIST)
         then: 'the response has the correct cm handle ids'
             assert cmHandleRegistrationResponses.size() == 2
             assert cmHandleRegistrationResponses.stream().map(it -> it.cmHandle).collect(Collectors.toList())
@@ -83,12 +81,9 @@ class CmHandleRegistrationResponseSpec extends Specification {
     def 'Failed cm-handle Registration with multiple responses with an unexpected xpath.'() {
         when: 'cm-handle failure response is created for one valid and one unexpected xpath'
             def cmHandleRegistrationResponses =
-                CmHandleRegistrationResponse.createFailureResponses(["somePathWithId[@id='123']","valid/xpath/without-id[@key='123']"], RegistrationError.CM_HANDLE_ALREADY_EXIST)
+                CmHandleRegistrationResponse.createFailureResponses(["somePathWithId[@id='123']","valid/xpath/without-id[@key='123']"], CM_HANDLE_ALREADY_EXIST)
         then: 'the response has only one entry'
             assert cmHandleRegistrationResponses.size() == 1
     }
 
-
-
-
 }
index 3569887..e42b914 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation
+ *  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.
@@ -20,8 +20,8 @@
 
 package org.onap.cps.ncmp.api.models
 
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.inventory.CompositeState
 import spock.lang.Specification
 
 class NcmpServiceCmHandleSpec extends Specification {
index 9195bc7..16ab0b8 100644 (file)
@@ -20,6 +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 ch.qos.logback.classic.Level
 import ch.qos.logback.classic.Logger
 import ch.qos.logback.core.read.ListAppender
@@ -61,15 +64,15 @@ class InventoryModelLoaderSpec extends Specification {
 
     def 'Onboard subscription model via application ready event.'() {
         given: 'dataspace is ready for use'
-            mockCpsAdminService.getDataspace('NCMP-Admin') >> new Dataspace('')
+            mockCpsAdminService.getDataspace(NCMP_DATASPACE_NAME) >> new Dataspace('')
         when: 'the application is ready'
             objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent))
         then: 'the module service is used to create the new schema set from the correct resource'
-            1 * mockCpsModuleService.createSchemaSet('NCMP-Admin', 'dmi-registry-2023-08-23', expectedYangResourceToContentMap)
+            1 * mockCpsModuleService.createSchemaSet(NCMP_DATASPACE_NAME, 'dmi-registry-2023-08-23', expectedYangResourceToContentMap)
         and: 'the admin service is used to update the anchor'
-            1 * mockCpsAdminService.updateAnchorSchemaSet('NCMP-Admin', 'ncmp-dmi-registry', 'dmi-registry-2023-08-23')
+            1 * mockCpsAdminService.updateAnchorSchemaSet(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, 'dmi-registry-2023-08-23')
         and: 'No schema sets are being removed by the module service (yet)'
-            0 * mockCpsModuleService.deleteSchemaSet('NCMP-Admin', _, _)
+            0 * mockCpsModuleService.deleteSchemaSet(NCMP_DATASPACE_NAME, _, _)
     }
 
 }
index d99874a..3486316 100644 (file)
@@ -20,6 +20,8 @@
 
 package org.onap.cps.ncmp.init
 
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+
 import ch.qos.logback.classic.Level
 import ch.qos.logback.classic.Logger
 import ch.qos.logback.core.read.ListAppender
@@ -63,15 +65,15 @@ class SubscriptionModelLoaderSpec extends Specification {
         given:'model loader is enabled'
             objectUnderTest.subscriptionModelLoaderEnabled = true
         and: 'dataspace is ready for use'
-            mockCpsAdminService.getDataspace('NCMP-Admin') >> new Dataspace('')
+            mockCpsAdminService.getDataspace(NCMP_DATASPACE_NAME) >> new Dataspace('')
         when: 'the application is ready'
             objectUnderTest.onApplicationEvent(Mock(ApplicationReadyEvent))
         then: 'the module service to create schema set is called once'
-            1 * mockCpsModuleService.createSchemaSet('NCMP-Admin', 'subscriptions', expectedYangResourceToContentMap)
+            1 * mockCpsModuleService.createSchemaSet(NCMP_DATASPACE_NAME, 'subscriptions', expectedYangResourceToContentMap)
         and: 'the admin service to create an anchor set is called once'
-            1 * mockCpsAdminService.createAnchor('NCMP-Admin', 'subscriptions', 'AVC-Subscriptions')
+            1 * mockCpsAdminService.createAnchor(NCMP_DATASPACE_NAME, 'subscriptions', 'AVC-Subscriptions')
         and: 'the data service to create a top level datanode is called once'
-            1 * mockCpsDataService.saveData('NCMP-Admin', 'AVC-Subscriptions', '{"subscription-registry":{}}', _)
+            1 * mockCpsDataService.saveData(NCMP_DATASPACE_NAME, 'AVC-Subscriptions', '{"subscription-registry":{}}', _)
     }
 
     def 'Subscription model loader disabled.' () {
index 07275e0..79ce228 100644 (file)
@@ -1,7 +1,7 @@
 {
   "cm-handle-state" : "ADVISED",
   "lock-reason" : {
-    "reason" : "LOCKED_MODULE_SYNC_FAILED",
+    "reason" : "MODULE_SYNC_FAILED",
     "details" : "lock details"
   },
   "last-update-time" : "2022-12-31T20:30:40.000+0000",
index efee388..37c9ad3 100755 (executable)
@@ -32,7 +32,7 @@
 
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-parent</artifactId>
-    <version>3.3.7-SNAPSHOT</version>
+    <version>3.3.9-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
                 <plugin>
                     <groupId>org.springframework.boot</groupId>
                     <artifactId>spring-boot-maven-plugin</artifactId>
-                    <version>3.0.0</version>
+                    <version>3.1.2</version>
                     <executions>
                         <execution>
                             <goals>
index 325c303..4fc7d40 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 5330b86..4a5fbe4 100755 (executable)
@@ -28,7 +28,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 0a32a3a..63a6ab2 100644 (file)
@@ -26,7 +26,7 @@
     <parent>\r
         <groupId>org.onap.cps</groupId>\r
         <artifactId>cps-parent</artifactId>\r
-        <version>3.3.7-SNAPSHOT</version>\r
+        <version>3.3.9-SNAPSHOT</version>\r
         <relativePath>../cps-parent/pom.xml</relativePath>\r
     </parent>\r
 \r
index f0927ca..ac06b0b 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.cps.spi.entities;
 
+
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.FetchType;
index ca88a4d..0d77530 100755 (executable)
@@ -46,7 +46,6 @@ 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.spi.CpsAdminPersistenceService;
 import org.onap.cps.spi.CpsModulePersistenceService;
 import org.onap.cps.spi.entities.DataspaceEntity;
 import org.onap.cps.spi.entities.SchemaSetEntity;
@@ -89,8 +88,6 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ
 
     private final DataspaceRepository dataspaceRepository;
 
-    private final CpsAdminPersistenceService cpsAdminPersistenceService;
-
     private final ModuleReferenceRepository moduleReferenceRepository;
 
     @Override
index b8503a7..19646c5 100755 (executable)
@@ -70,13 +70,25 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Long> {
 
     Integer countByDataspace(DataspaceEntity dataspaceEntity);
 
-    @Query(value = "SELECT anchor.* FROM yang_resource\n"
-        + "JOIN schema_set_yang_resources ON schema_set_yang_resources.yang_resource_id = yang_resource.id\n"
-        + "JOIN schema_set ON schema_set.id = schema_set_yang_resources.schema_set_id\n"
-        + "JOIN anchor ON anchor.schema_set_id = schema_set.id\n"
-        + "WHERE schema_set.dataspace_id = :dataspaceId AND module_name = ANY (:moduleNames)\n"
-        + "GROUP BY anchor.id, anchor.name, anchor.dataspace_id, anchor.schema_set_id\n"
-        + "HAVING COUNT(DISTINCT module_name) = :sizeOfModuleNames", nativeQuery = true)
+    @Query(value = """
+            SELECT
+                anchor.*
+            FROM
+                     yang_resource
+                JOIN schema_set_yang_resources ON schema_set_yang_resources.yang_resource_id = yang_resource.id
+                JOIN schema_set ON schema_set.id = schema_set_yang_resources.schema_set_id
+                JOIN anchor ON anchor.schema_set_id = schema_set.id
+            WHERE
+                    schema_set.dataspace_id = :dataspaceId
+                AND module_name = ANY ( :moduleNames )
+            GROUP BY
+                anchor.id,
+                anchor.name,
+                anchor.dataspace_id,
+                anchor.schema_set_id
+            HAVING
+                COUNT(DISTINCT module_name) = :sizeOfModuleNames
+            """, nativeQuery = true)
     Collection<AnchorEntity> getAnchorsByDataspaceIdAndModuleNames(@Param("dataspaceId") int dataspaceId,
                                                                    @Param("moduleNames") String[] moduleNames,
                                                                    @Param("sizeOfModuleNames") int sizeOfModuleNames);
index df21ccc..e833796 100644 (file)
@@ -41,56 +41,65 @@ public interface YangResourceRepository extends JpaRepository<YangResourceEntity
         return findAllByChecksumIn(checksums.toArray(new String[0]));
     }
 
-    @Query(value = "SELECT DISTINCT\n"
-        + "yang_resource.module_name AS module_name,\n"
-        + "yang_resource.revision AS revision\n"
-        + "FROM\n"
-        + "dataspace\n"
-        + "JOIN schema_set ON schema_set.dataspace_id = dataspace.id\n"
-        + "JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = "
-        + "schema_set.id\n"
-        + "JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id\n"
-        + "WHERE\n"
-        + "dataspace.name = :dataspaceName", nativeQuery = true)
+    @Query(value = """
+            SELECT DISTINCT
+                yang_resource.module_name AS module_name,
+                yang_resource.revision    AS revision
+            FROM
+                     dataspace
+                JOIN schema_set ON schema_set.dataspace_id = dataspace.id
+                JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = schema_set.id
+                JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id
+            WHERE
+                dataspace.name = :dataspaceName
+            """, nativeQuery = true)
     Set<YangResourceModuleReference> findAllModuleReferencesByDataspace(@Param("dataspaceName") String dataspaceName);
 
-    @Query(value = "SELECT DISTINCT\n"
-        + "yang_resource.module_Name AS module_name,\n"
-        + "yang_resource.revision AS revision\n"
-        + "FROM\n"
-        + "dataspace\n"
-        + "JOIN anchor ON anchor.dataspace_id = dataspace.id\n"
-        + "JOIN schema_set ON schema_set.id = anchor.schema_set_id\n"
-        + "JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = "
-        + "schema_set.id\n"
-        + "JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id\n"
-        + "WHERE\n"
-        + "dataspace.name = :dataspaceName AND\n"
-        + "anchor.name =:anchorName", nativeQuery = true)
+    @Query(value = """
+            SELECT DISTINCT
+                yang_resource.module_name AS module_name,
+                yang_resource.revision    AS revision
+            FROM
+                     dataspace
+                JOIN anchor ON anchor.dataspace_id = dataspace.id
+                JOIN schema_set ON schema_set.id = anchor.schema_set_id
+                JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = schema_set.id
+                JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id
+            WHERE
+                    dataspace.name = :dataspaceName
+                AND anchor.name = :anchorName
+            """, nativeQuery = true)
     Set<YangResourceModuleReference> findAllModuleReferencesByDataspaceAndAnchor(
         @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName);
 
-    @Query(value = "SELECT DISTINCT yang_resource.*\n"
-            + "FROM dataspace\n"
-            + "JOIN anchor ON anchor.dataspace_id = dataspace.id\n"
-            + "JOIN schema_set ON schema_set.id = anchor.schema_set_id\n"
-            + "JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = schema_set.id\n"
-            + "JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id\n"
-            + "WHERE dataspace.name = :dataspaceName "
-            + "AND anchor.name =:anchorName", nativeQuery = true)
+    @Query(value = """
+            SELECT DISTINCT
+                yang_resource.*
+            FROM
+                     dataspace
+                JOIN anchor ON anchor.dataspace_id = dataspace.id
+                JOIN schema_set ON schema_set.id = anchor.schema_set_id
+                JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = schema_set.id
+                JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id
+            WHERE
+                    dataspace.name = :dataspaceName
+                AND anchor.name = :anchorName
+            """, nativeQuery = true)
     Set<YangResourceEntity> findAllModuleDefinitionsByDataspaceAndAnchor(
             @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName);
 
-    @Query(value = "SELECT DISTINCT\n"
-        + "yang_resource.*\n"
-        + "FROM\n"
-        + "dataspace\n"
-        + "JOIN schema_set ON schema_set.dataspace_id = dataspace.id\n"
-        + "JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = "
-        + "schema_set.id\n"
-        + "JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id\n"
-        + "WHERE\n"
-        + "dataspace.name = :dataspaceName and yang_resource.module_Name = ANY (:moduleNames)", nativeQuery = true)
+    @Query(value = """
+            SELECT DISTINCT
+                yang_resource.*
+            FROM
+                     dataspace
+                JOIN schema_set ON schema_set.dataspace_id = dataspace.id
+                JOIN schema_set_yang_resources ON schema_set_yang_resources.schema_set_id = schema_set.id
+                JOIN yang_resource ON yang_resource.id = schema_set_yang_resources.yang_resource_id
+            WHERE
+                    dataspace.name = :dataspaceName
+                AND yang_resource.module_name = ANY ( :moduleNames )
+            """, nativeQuery = true)
     Set<YangResourceModuleReference> findAllModuleReferencesByDataspaceAndModuleNames(
             @Param("dataspaceName") String dataspaceName, @Param("moduleNames") String[] moduleNames);
 
index 98e6cfc..1b822b9 100644 (file)
@@ -9,7 +9,7 @@
         <property name="hibernate.connection.url">jdbc:postgresql://${DB_HOST}:${DB_PORT:5432}/cpsdb</property>
         <property name="hibernate.connection.username">${DB_USERNAME}</property>
         <property name="hibernate.connection.password">${DB_PASSWORD}</property>
-        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQL82Dialect</property>
+        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
         <property name="show_sql">true</property>
         <property name="hibernate.hbm2ddl.auto">update</property>
     </session-factory>
index 52651c6..9696b28 100644 (file)
@@ -69,7 +69,7 @@ class CpsModulePersistenceServiceSpec extends Specification {
 
     def setup() {
         objectUnderTest = new CpsModulePersistenceServiceImpl(yangResourceRepositoryMock, schemaSetRepositoryMock,
-            dataspaceRepositoryMock, cpsAdminPersistenceServiceMock, moduleReferenceRepositoryMock)
+            dataspaceRepositoryMock, moduleReferenceRepositoryMock)
     }
 
     def 'Store schema set error scenario: #scenario.'() {
index 3f5d639..eaa9fdc 100644 (file)
@@ -29,7 +29,7 @@
   <parent>
     <groupId>org.onap.cps</groupId>
     <artifactId>cps-parent</artifactId>
-    <version>3.3.7-SNAPSHOT</version>
+    <version>3.3.9-SNAPSHOT</version>
     <relativePath>../cps-parent/pom.xml</relativePath>
   </parent>
 
       <artifactId>spring-test</artifactId>
       <scope>test</scope>
     </dependency>
-
     <!-- T E S T   D E P E N D E N C I E S -->
     <dependency>
       <groupId>org.codehaus.groovy</groupId>
index 5ff08c9..e8c3e77 100644 (file)
@@ -47,13 +47,13 @@ public interface CpsModuleService {
                          Map<String, String> yangResourcesNameToContentMap);
 
     /**
-     * Create a schema set from new modules and existing modules.
+     * Create or upgrade a schema set from new modules and existing modules or only existing modules.
      * @param dataspaceName             Dataspace name
      * @param schemaSetName             schema set name
      * @param newModuleNameToContentMap YANG resources map where key is a module name and value is content
      * @param allModuleReferences       All YANG resource module references
      */
-    void createSchemaSetFromModules(String dataspaceName, String schemaSetName,
+    void createOrUpgradeSchemaSetFromModules(String dataspaceName, String schemaSetName,
                                     Map<String, String> newModuleNameToContentMap,
                                     Collection<ModuleReference> allModuleReferences);
 
index 7db87e8..1d68450 100755 (executable)
@@ -31,6 +31,7 @@ import static org.onap.cps.notification.Operation.UPDATE;
 import io.micrometer.core.annotation.Timed;
 import java.io.Serializable;
 import java.time.OffsetDateTime;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
@@ -321,28 +322,12 @@ public class CpsDataServiceImpl implements CpsDataService {
         processDataUpdatedEventAsync(anchor, listNodeXpath, DELETE, observedTimestamp);
     }
 
-    private DataNode buildDataNode(final Anchor anchor, final String parentNodeXpath, final String nodeData,
-                                   final ContentType contentType) {
-        final SchemaContext schemaContext = getSchemaContext(anchor);
-
-        if (ROOT_NODE_XPATH.equals(parentNodeXpath)) {
-            final ContainerNode containerNode = timedYangParser.parseData(contentType, nodeData, schemaContext);
-            return new DataNodeBuilder().withContainerNode(containerNode).build();
-        }
-
-        final ContainerNode containerNode =
-            timedYangParser.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
-
-        return new DataNodeBuilder()
-                .withParentNodeXpath(parentNodeXpath)
-                .withContainerNode(containerNode)
-                .build();
-    }
-
     private Collection<DataNode> buildDataNodes(final Anchor anchor, final Map<String, String> nodesJsonData) {
-        return nodesJsonData.entrySet().stream().map(nodeJsonData ->
-            buildDataNode(anchor, nodeJsonData.getKey(),
-                nodeJsonData.getValue(), ContentType.JSON)).collect(Collectors.toList());
+        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));
+        }
+        return dataNodes;
     }
 
     private Collection<DataNode> buildDataNodes(final Anchor anchor, final String parentNodeXpath,
index 7d9c472..444c895 100644 (file)
@@ -66,7 +66,7 @@ public class CpsModuleServiceImpl implements CpsModuleService {
     }
 
     @Override
-    public void createSchemaSetFromModules(final String dataspaceName, final String schemaSetName,
+    public void createOrUpgradeSchemaSetFromModules(final String dataspaceName, final String schemaSetName,
         final Map<String, String> newModuleNameToContentMap,
         final Collection<ModuleReference> allModuleReferences) {
         cpsValidator.validateNameCharacters(dataspaceName, schemaSetName);
index ca90714..0235b00 100644 (file)
@@ -43,10 +43,11 @@ import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.RFC7950Reactors;
-import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource;
-import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
-import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.api.YangParser;
+import org.opendaylight.yangtools.yang.parser.api.YangParserException;
+import org.opendaylight.yangtools.yang.parser.api.YangParserFactory;
+import org.opendaylight.yangtools.yang.parser.impl.DefaultYangParserFactory;
+import org.opendaylight.yangtools.yang.xpath.impl.di.DefaultXPathParserFactory;
 
 @NoArgsConstructor
 public final class YangTextSchemaSourceSetBuilder {
@@ -56,6 +57,9 @@ public final class YangTextSchemaSourceSetBuilder {
 
     private final ImmutableMap.Builder<String, String> yangModelMap = new ImmutableMap.Builder<>();
 
+    private static final YangParserFactory YANG_PARSER_FACTORY =
+            new DefaultYangParserFactory(new DefaultXPathParserFactory());
+
     /**
      * Add Yang resource context.
      *
@@ -136,11 +140,11 @@ public final class YangTextSchemaSourceSetBuilder {
      * @return the schema context
      */
     private static SchemaContext generateSchemaContext(final Map<String, String> yangResourceNameToContent) {
-        final CrossSourceStatementReactor.BuildAction reactor = RFC7950Reactors.defaultReactor().newBuild();
+        final YangParser yangParser = YANG_PARSER_FACTORY.createParser();
         for (final YangTextSchemaSource yangTextSchemaSource : forResources(yangResourceNameToContent)) {
             final String resourceName = yangTextSchemaSource.getIdentifier().getName();
             try {
-                reactor.addSource(YangStatementStreamSource.create(yangTextSchemaSource));
+                yangParser.addSource(yangTextSchemaSource);
             } catch (final Exception exception) {
                 throw new ModelValidationException("Yang resource processing exception.",
                     String.format("Could not process resource %s:%n%s", resourceName, exception.getMessage()),
@@ -148,13 +152,13 @@ public final class YangTextSchemaSourceSetBuilder {
             }
         }
         try {
-            return reactor.buildEffective();
-        } catch (final ReactorException reactorException) {
+            return yangParser.buildEffectiveModel();
+        } catch (final YangParserException yangParserException) {
             final List<String> resourceNames = yangResourceNameToContent.keySet().stream().collect(Collectors.toList());
             Collections.sort(resourceNames);
             throw new ModelValidationException("Invalid schema set.",
                 String.format("Effective schema context build failed for resources %s.", resourceNames),
-                reactorException);
+                yangParserException);
         }
     }
 
index b4ac7a6..e1d15d6 100644 (file)
@@ -307,15 +307,16 @@ class CpsDataServiceImplSpec extends Specification {
             objectUnderTest.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath, jsonData, observedTimestamp)
         then: 'the persistence service method is invoked with correct parameters'
             1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
-                { dataNode -> dataNode.xpath[0] == expectedNodeXpath })
+                    { dataNode -> dataNode.xpath == expectedNodeXpath})
         and: 'data updated event is sent to notification service'
             1 * mockNotificationService.processDataUpdatedEvent(anchor, parentNodeXpath, Operation.UPDATE, observedTimestamp)
         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 | jsonData                                           || expectedNodeXpath
+            'top level node' | '/'             | '{"test-tree": {"branch": []}}'                    || ['/test-tree']
+            'level 2 node'   | '/test-tree'    | '{"branch": [{"name":"Name"}]}'                    || ['/test-tree/branch[@name=\'Name\']']
+            '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.'() {
@@ -327,14 +328,16 @@ class CpsDataServiceImplSpec extends Specification {
             1 * mockCpsDataPersistenceService.updateDataNodesAndDescendants(dataspaceName, anchorName,
                 { dataNode -> dataNode.xpath == expectedNodeXpath})
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(anchor, nodesJsonData.keySet()[0], Operation.UPDATE, observedTimestamp)
-            1 * mockNotificationService.processDataUpdatedEvent(anchor, nodesJsonData.keySet()[1], Operation.UPDATE, observedTimestamp)
+            nodesJsonData.keySet().each {
+                1 * mockNotificationService.processDataUpdatedEvent(anchor, it, Operation.UPDATE, observedTimestamp)
+            }
         and: 'the CpsValidator is called on the dataspaceName and AnchorName'
             1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
         where: 'following parameters were used'
             scenario         | nodesJsonData                                                                                                        || 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 with concurrency exception in persistence layer.'() {
index a794c58..61f6741 100644 (file)
@@ -65,7 +65,7 @@ class CpsModuleServiceImplSpec extends Specification {
             def moduleReferenceForExistingModule = new ModuleReference('test',  '2021-10-12','test.org')
             def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule]
         when: 'create schema set from modules method is invoked'
-            objectUnderTest.createSchemaSetFromModules('someDataspaceName', 'someSchemaSetName', [newModule: 'newContent'], listOfExistingModulesModuleReference)
+            objectUnderTest.createOrUpgradeSchemaSetFromModules('someDataspaceName', 'someSchemaSetName', [newModule: 'newContent'], listOfExistingModulesModuleReference)
         then: 'processing is delegated to persistence service'
             1 * mockCpsModulePersistenceService.storeSchemaSetFromModules('someDataspaceName', 'someSchemaSetName', [newModule: 'newContent'], listOfExistingModulesModuleReference)
         and: 'the CpsValidator is called on the dataspaceName and schemaSetName'
index c3ec937..9ede0f2 100644 (file)
@@ -62,7 +62,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}
 
index afc7f07..d18788d 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>dmi-plugin-demo-and-csit-stub</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
     </parent>
 
     <artifactId>dmi-plugin-demo-and-csit-stub-app</artifactId>
index 53f1985..3a46e43 100644 (file)
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>dmi-plugin-demo-and-csit-stub</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
     </parent>
     <artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId>
 
index 987436f..3f9731d 100644 (file)
@@ -20,6 +20,8 @@
 
 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;
@@ -28,12 +30,10 @@ import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
-import java.util.stream.Collectors;
 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.NcmpEventResponseCode;
 import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter;
 import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.CmHandle;
 import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.DataOperationRequest;
@@ -161,9 +161,9 @@ public class DmiRestStubController {
     private DataOperationEvent getDataOperationEvent(final DataOperationRequest dataOperationRequest) {
         final Response response = new Response();
         response.setOperationId(dataOperationRequest.getOperationId());
-        response.setStatusCode(NcmpEventResponseCode.SUCCESS.getStatusCode());
-        response.setStatusMessage(NcmpEventResponseCode.SUCCESS.getStatusMessage());
-        response.setIds(dataOperationRequest.getCmHandles().stream().map(CmHandle::getId).collect(Collectors.toList()));
+        response.setStatusCode(SUCCESS.getCode());
+        response.setStatusMessage(SUCCESS.getMessage());
+        response.setIds(dataOperationRequest.getCmHandles().stream().map(CmHandle::getId).toList());
         response.setResourceIdentifier(dataOperationRequest.getResourceIdentifier());
         response.setOptions(dataOperationRequest.getOptions());
         final String ietfNetworkTopologySample = ResourceFileReaderUtil
@@ -176,7 +176,7 @@ public class DmiRestStubController {
         } catch (final ParseException parseException) {
             log.error("Unable to parse event result as json object. cause : {}", parseException.getMessage());
         }
-        final List<Response> responseList = new ArrayList<>();
+        final List<Response> responseList = new ArrayList<>(1);
         responseList.add(response);
         final Data data = new Data();
         data.setResponses(responseList);
index f9f4197..88f11c7 100644 (file)
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index bb286fd..2607385 100644 (file)
@@ -38,6 +38,7 @@ services:
     ports:
       - ${CPS_CORE_PORT:-8883}:8080
       - ${CPS_CORE_MANAGEMENT_PORT:-8887}:8081
+      - ${CPS_CORE_DEBUG_PORT:-5005}:5005
     environment:
       CPS_USERNAME: ${CPS_CORE_USERNAME:-cpsuser}
       CPS_PASSWORD: ${CPS_CORE_PASSWORD:-cpsr0cks!}
@@ -52,6 +53,7 @@ services:
       NOTIFICATION_DATASPACE_FILTER_PATTERNS: '.*'
       NCMP_TIMERS_ADVISED-MODULES-SYNC_SLEEP-TIME-MS: ${ADVISED_MODULES_SYNC_SLEEP_TIME_MS:-30000}
       NCMP_TIMERS_CM-HANDLE-DATA-SYNC_SLEEP-TIME-MS: ${CMHANDLE_DATA_SYNC_SLEEP_TIME_MS:-30000}
+      JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
     restart: unless-stopped
     depends_on:
       - dbpostgresql
index 6203c85..af6b004 100644 (file)
@@ -265,22 +265,26 @@ components:
             key: my-property
           cmHandleProperties:
             key: my-property
+          moduleSetTag: my-module-set-tag
         - cmHandle: my-cm-handle
           publicCmHandleProperties:
             key: my-property
           cmHandleProperties:
             key: my-property
+          moduleSetTag: my-module-set-tag
         createdCmHandles:
         - cmHandle: my-cm-handle
           publicCmHandleProperties:
             key: my-property
           cmHandleProperties:
             key: my-property
+          moduleSetTag: my-module-set-tag
         - cmHandle: my-cm-handle
           publicCmHandleProperties:
             key: my-property
           cmHandleProperties:
             key: my-property
+          moduleSetTag: my-module-set-tag
         dmiPlugin: my-dmi-plugin
         dmiModelPlugin: my-dmi-model-plugin
         dmiDataPlugin: my-dmi-data-plugin
@@ -325,6 +329,7 @@ components:
           key: my-property
         cmHandleProperties:
           key: my-property
+        moduleSetTag: my-module-set-tag
       properties:
         cmHandle:
           example: my-cm-handle
@@ -339,6 +344,9 @@ components:
             example: my-property
             type: string
           type: object
+        moduleSetTag:
+          example: my-module-set-tag
+          type: string
       required:
       - cmHandle
       type: object
index 1b74153..20a5ae3 100644 (file)
@@ -10,15 +10,15 @@ CPS-NCMP Message Status Codes
 #############################
 
     +-----------------+------------------------------------------------------+-----------------------------------+
-    | Status Code     | Status Message                                       | Feature                           |
+    | Status Code     | Status Message                                       | Feature(s)                        |
     +=================+======================================================+===================================+
     | 0               | Successfully applied changes                         | Data Operation                    |
     +-----------------+------------------------------------------------------+-----------------------------------+
     | 1               | successfully applied subscription                    | CM Data Notification Subscription |
     +-----------------+------------------------------------------------------+-----------------------------------+
-    | 100             | cm handle id(s) is(are) not found                    | Data Operation                    |
+    | 100             | cm handle id(s) is(are) not found                    | Data Operation, Inventory         |
     +-----------------+------------------------------------------------------+-----------------------------------+
-    | 101             | cm handle id(s) is(are) in non ready state           | Data Operation                    |
+    | 101             | cm handle(s) not ready                               | Data Operation                    |
     +-----------------+------------------------------------------------------+-----------------------------------+
     | 102             | dmi plugin service is not responding                 | Data Operation                    |
     +-----------------+------------------------------------------------------+-----------------------------------+
@@ -32,6 +32,12 @@ CPS-NCMP Message Status Codes
     +-----------------+------------------------------------------------------+-----------------------------------+
     | 107             | southbound system is busy                            | Data Operation                    |
     +-----------------+------------------------------------------------------+-----------------------------------+
+    | 108             | Unknown error                                        | Inventory                         |
+    +-----------------+------------------------------------------------------+-----------------------------------+
+    | 109             | cm-handle already exists                             | Inventory                         |
+    +-----------------+------------------------------------------------------+-----------------------------------+
+    | 110             | cm-handle has an invalid character(s) in id          | Inventory                         |
+    +-----------------+------------------------------------------------------+-----------------------------------+
 
 .. note::
 
index acc32e3..0642e6a 100644 (file)
@@ -336,5 +336,7 @@ Below are the list of distributed datastructures that we have.
 +--------------+---------------------------------+----------------------------------------------------------+
 | cps-ncmp     | trustLevelPerDmiPlugin          | Stores the TrustLevel for the dmi-plugins.               |
 +--------------+---------------------------------+----------------------------------------------------------+
+| cps-ncmp     | moduleSetTagCacheMapConfig      | Stores the Module Set Tags for cmHandles.                |
++--------------+---------------------------------+----------------------------------------------------------+
 
-Total number of caches : 7
\ No newline at end of file
+Total number of caches : 8
\ No newline at end of file
index c6413c2..5ad86a3 100755 (executable)
@@ -83,3 +83,13 @@ NCMP Inventory CM Handle Querying
 
 The CM Handle searches ncmp inventory endpoints can be used to query for CM Handles or CM Handle IDs.
 This endpoint is described in detail in :doc:`ncmp-inventory-querying`.
+
+Common NCMP Response Codes
+==========================
+
+NCMP uses common responses codes in REST responses and events. Also the DMI plugin interface uses these codes which are defined here:
+
+.. toctree::
+   :maxdepth: 1
+
+   cps-ncmp-message-status-codes.rst
index 013617a..d891162 100755 (executable)
@@ -16,6 +16,61 @@ CPS Release Notes
 ..      * * *   MONTREAL   * * *
 ..      ========================
 
+Version: 3.3.9
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project**                      |                                                        |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images**                    | onap/cps-and-ncmp:3.3.9                                |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation**              | 3.3.9 Montreal                                         |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Release date**                     | Not yet released                                       |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.3.9
+
+Features
+--------
+
+Version: 3.3.8
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project**                      |                                                        |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images**                    | onap/cps-and-ncmp:3.3.8                                |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation**              | 3.3.8 Montreal                                         |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+| **Release date**                     | 2023 September 29                                      |
+|                                      |                                                        |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.3.8
+
+Features
+--------
+    - `CPS-1888 <https://jira.onap.org/browse/CPS-1888>`_ Uplift Spring Boot to 3.1.2.
+
 Version: 3.3.7
 ==============
 
@@ -32,16 +87,22 @@ Release Data
 | **Release designation**              | 3.3.7 Montreal                                         |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
-| **Release date**                     | Not yet released                                       |
+| **Release date**                     | 2023 September 20                                      |
 |                                      |                                                        |
 +--------------------------------------+--------------------------------------------------------+
 
 Bug Fixes
 ---------
 3.3.7
+    - `CPS-1866 <https://jira.onap.org/browse/CPS-1866>`_ Fix ClassDefNotFoundError in opendaylight Yang parser
 
 Features
 --------
+    - `CPS-1789 <https://jira.onap.org/browse/CPS-1789>`_ CPS Upgrade to Springboot 3.0.
+
+Note
+----
+Migrating to Spring Boot 3.0 requires the product be built with Java 17 and at least MVN version 3.8.7.
 
 Version: 3.3.6
 ==============
index 9ae7d0c..b2bdce7 100644 (file)
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
 
index 03ef9c2..40fe030 100644 (file)
@@ -79,6 +79,7 @@ class CpsIntegrationSpecBase extends Specification {
     def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
 
     def static initialized = false
+    def now = OffsetDateTime.now()
 
     def setup() {
         if (!initialized) {
@@ -120,4 +121,31 @@ class CpsIntegrationSpecBase extends Specification {
             cpsDataService.saveData(dataspaceName, anchorNamePrefix + it, data.replace("Easons", "Easons-"+it.toString()), OffsetDateTime.now())
         }
     }
+
+    def createJsonArray(name, numberOfElements, keyName, keyValuePrefix, dataPerKey) {
+        def json = '{"' + name + '":['
+        (1..numberOfElements).each {
+            json += '{"' + keyName + '":"' + keyValuePrefix + '-' + it + '"'
+            if (!dataPerKey.isEmpty()) {
+                json += ',' + dataPerKey
+            }
+            json += '}'
+            if (it < numberOfElements) {
+                json += ','
+            }
+        }
+        json += ']}'
+    }
+
+    def createLeafList(name, numberOfElements, valuePrefix) {
+        def json = '"' + name + '":['
+        (1..numberOfElements).each {
+            json += '"' + valuePrefix + '-' + it + '"'
+            if (it < numberOfElements) {
+                json += ','
+            }
+        }
+        json += ']'
+    }
+
 }
index e39e114..f4cc8b7 100644 (file)
@@ -90,7 +90,7 @@ class TestConfig extends Specification{
 
     @Bean
     CpsModulePersistenceService cpsModulePersistenceService() {
-        return (CpsModulePersistenceService) new CpsModulePersistenceServiceImpl(yangResourceRepository, schemaSetRepository, dataspaceRepository, cpsAdminPersistenceService(), moduleReferenceRepository)
+        return (CpsModulePersistenceService) new CpsModulePersistenceServiceImpl(yangResourceRepository, schemaSetRepository, dataspaceRepository, moduleReferenceRepository)
     }
 
     @Bean
index 2fe2753..12c97ed 100644 (file)
@@ -44,7 +44,6 @@ class CpsDataServiceIntegrationSpec extends FunctionalSpecBase {
     CpsDataService objectUnderTest
     def originalCountBookstoreChildNodes
     def originalCountBookstoreTopLevelListNodes
-    def now = OffsetDateTime.now()
 
     def setup() {
         objectUnderTest = cpsDataService
index cfc8ab7..d33a774 100644 (file)
@@ -94,7 +94,7 @@ class CpsModuleServiceIntegrationSpec extends FunctionalSpecBase {
             moduleReferences.addAll(existingModuleReferences)
         when: 'the new schema set is created'
             def schemaSetName = "NewSchemaWith${numberOfNewModules}Modules"
-            objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, newYangResourcesNameToContentMap, moduleReferences)
+            objectUnderTest.createOrUpgradeSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, newYangResourcesNameToContentMap, moduleReferences)
         and: 'associated with a new anchor'
             cpsAdminService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, 'newAnchor')
         then: 'the new anchor has the correct number of modules'
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
new file mode 100644 (file)
index 0000000..f5d7c5e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  ============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.integration.performance.base
+
+import java.time.OffsetDateTime
+
+class NcmpPerfTestBase extends PerfTestBase {
+
+    def static NCMP_PERFORMANCE_TEST_DATASPACE = 'ncmpPerformance'
+    def static REGISTRY_ANCHOR = 'ncmp-registry'
+    def static REGISTRY_SCHEMA_SET = 'registrySchemaSet'
+    def static CM_DATA_SUBSCRIPTIONS_ANCHOR = 'cm-data-subscriptions'
+    def static CM_DATA_SUBSCRIPTIONS_SCHEMA_SET = 'cmDataSubscriptionsSchemaSet'
+
+    def datastore1cmHandlePlaceHolder = '{"datastores":{"datastore":[{"name":"ds-1","cm-handles":{"cm-handle":[]}}]}}'
+    def xPathForDataStore1CmHandles = '/datastores/datastore[@name="ds-1"]/cm-handles'
+    def numberOfCmDataSubscribers = 200
+    def numberOfFiltersPerCmHandle = 10
+    def numberOfCmHandlesPerCmDataSubscription = 200
+
+// SHORT versions for easier debugging
+//    def subscriberIdPrefix = 'sub'
+//    def xpathPrefix = 'f'
+//    def cmHandlePrefix = 'ch'
+
+
+// LONG versions for performance testing
+    def subscriberIdPrefix = 'some really long subscriber id to see if this makes any difference to the performance'
+    def xpathPrefix = 'some really long xpath/with/loads/of/children/grandchildren/and/whatever/else/I/can/think/of to see if this makes any difference to the performance'
+    def cmHandlePrefix = 'some really long cm handle id to see if this makes any difference to the performance'
+
+    def printTitle() {
+        println('##      N C M P   P E R F O R M A N C E   T E S T   R E S U L T S          ##')
+    }
+
+    def isInitialised() {
+        return dataspaceExists(NCMP_PERFORMANCE_TEST_DATASPACE)
+    }
+
+    def setupPerformanceInfraStructure() {
+        cpsAdminService.createDataspace(NCMP_PERFORMANCE_TEST_DATASPACE)
+        createRegistrySchemaSet()
+        createCmDataSubscriptionsSchemaSet()
+        addCmSubscriptionData()
+    }
+
+    def createInitialData() {
+        cpsAdminService.createAnchor(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_SCHEMA_SET, REGISTRY_ANCHOR)
+        def data = readResourceDataFile('ncmp-registry/1000-cmhandles.json')
+        cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, data, OffsetDateTime.now())
+    }
+
+    def createRegistrySchemaSet() {
+        def modelAsString = readResourceDataFile('ncmp-registry/dmi-registry@2022-05-10.yang')
+        cpsModuleService.createSchemaSet(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_SCHEMA_SET, [registry: modelAsString])
+    }
+
+    def createCmDataSubscriptionsSchemaSet() {
+        def modelAsString = readResourceDataFile('cm-data-subscriptions/cm-data-subscriptions@2023-09-21.yang')
+        cpsModuleService.createSchemaSet(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_SCHEMA_SET, [registry: modelAsString])
+    }
+
+    def addCmSubscriptionData() {
+        cpsAdminService.createAnchor(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_SCHEMA_SET, CM_DATA_SUBSCRIPTIONS_ANCHOR)
+        cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, datastore1cmHandlePlaceHolder, now)
+        def subscribers = createLeafList('subscribers',numberOfCmDataSubscribers, subscriberIdPrefix)
+        def filters = '"filters":' + createJsonArray('filter',numberOfFiltersPerCmHandle,'xpath',xpathPrefix,subscribers)
+        def cmHandles = createJsonArray('cm-handle',numberOfCmHandlesPerCmDataSubscription,'id',cmHandlePrefix, filters)
+        cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, xPathForDataStore1CmHandles, cmHandles, now)
+    }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpRegistryPerfTestBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/base/NcmpRegistryPerfTestBase.groovy
deleted file mode 100644 (file)
index d169bd7..0000000
+++ /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.integration.performance.base
-
-import java.time.OffsetDateTime
-
-import org.onap.cps.integration.base.CpsIntegrationSpecBase
-
-class NcmpRegistryPerfTestBase extends PerfTestBase {
-
-    def static REGISTRY_ANCHOR = 'ncmp-registry'
-    def static REGISTRY_SCHEMA_SET = 'registrySchemaSet'
-    def static NCMP_PERFORMANCE_TEST_DATASPACE = 'ncmpPerformacne'
-
-    def printTitle() {
-        println('##      N C M P   P E R F O R M A N C E   T E S T   R E S U L T S          ##')
-    }
-
-    def isInitialised() {
-        return dataspaceExists(NCMP_PERFORMANCE_TEST_DATASPACE)
-    }
-
-    def setupPerformanceInfraStructure() {
-        cpsAdminService.createDataspace(NCMP_PERFORMANCE_TEST_DATASPACE)
-        def modelAsString = readResourceDataFile('ncmp-registry/dmi-registry@2022-05-10.yang')
-        cpsModuleService.createSchemaSet(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_SCHEMA_SET, [registry: modelAsString])
-    }
-
-    def createInitialData() {
-        def data = readResourceDataFile('ncmp-registry/1000-cmhandles.json')
-        cpsAdminService.createAnchor(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_SCHEMA_SET, REGISTRY_ANCHOR)
-        cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, REGISTRY_ANCHOR, data, OffsetDateTime.now())
-    }
-
-
-}
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
new file mode 100644 (file)
index 0000000..cf5c3f6
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  ============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.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 static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+
+class CmDataSubscriptionsPerfTest extends NcmpPerfTestBase {
+
+    def datastore1cmHandlePlaceHolder = '{"datastores":{"datastore":[{"name":"ds-1","cm-handles":{"cm-handle":[]}}]}}'
+    def xPathForDataStore1CmHandles = '/datastores/datastore[@name="ds-1"]/cm-handles'
+
+    CpsQueryService objectUnderTest
+
+    def setup() { objectUnderTest = cpsQueryService }
+
+    def totalNumberOfEntries = numberOfFiltersPerCmHandle * numberOfCmHandlesPerCmDataSubscription
+
+    def random = new Random()
+
+    def 'Find many subscribers in large dataset.'() {
+        when: 'all filters are queried'
+            stopWatch.start()
+            def cpsPath = '//filter'
+            def result = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
+        then: 'got all filter entries'
+            result.size() == totalNumberOfEntries
+        then: 'find a random subscriptions by iteration (worst case: whole subscription matches previous entries)'
+            def matches = querySubscriptionsByIteration(result, -1)
+            stopWatch.stop()
+            matches.size() == numberOfFiltersPerCmHandle * numberOfCmHandlesPerCmDataSubscription
+        and: 'query all subscribers within 1 second'
+            def durationInMillis = stopWatch.getTotalTimeMillis()
+            recordAndAssertPerformance("Query all subscribers", 1_000, durationInMillis)
+    }
+
+    def 'Worst case subscription update (200x10 matching entries).'() {
+        given: 'all filters are queried'
+            def cpsPath = '//filter'
+            def result = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
+        and: 'there are the expected number of subscribers per subscription'
+            assert result.collect {it.leaves.subscribers.size()}.sum() == totalNumberOfEntries * numberOfCmDataSubscribers
+        and: 'find all entries for an existing subscriptions'
+            def matches = querySubscriptionsByIteration(result, 1)
+        when: 'update all subscriptions found'
+            stopWatch.start()
+            HashMap<String, List<String>> filterEntriesPerPath = [:]
+            matches.each { dataNode, subscribersAsArray ->
+                def updatedSubscribers = createLeafList('subscribers', 1 + numberOfCmDataSubscribers, subscriberIdPrefix)
+                def filterEntry = '{"xpath":"' + dataNode.leaves.xpath + '", ' + updatedSubscribers + ' }'
+                def parentPath = dataNode.xpath.toString().substring(0, dataNode.xpath.toString().indexOf('/filter[@xpath='))
+                filterEntriesPerPath.putIfAbsent(parentPath, new ArrayList<String>())
+                filterEntriesPerPath.get(parentPath).add(filterEntry)
+            }
+            HashMap<String, String> jsonPerPath = [:]
+            filterEntriesPerPath.each { parentPath, filterEntries ->
+                jsonPerPath.put(parentPath, '{"filter": [' + filterEntries.join(',') + ']}')
+            }
+
+            // NOTE Below fails as updateDataNodesAndDescendants can't handle JSON lists!
+            // cpsDataService.updateDataNodesAndDescendants(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, jsonPerPath, now)
+
+            // So update for each CM-handle instead:
+            jsonPerPath.each { parentPath, json ->
+                // 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)
+            }
+
+            stopWatch.stop()
+            def durationInMillis = stopWatch.getTotalTimeMillis()
+        then: 'a subscriber has been added to each filter entry'
+            def resultAfter = objectUnderTest.queryDataNodes(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, cpsPath, INCLUDE_ALL_DESCENDANTS)
+            assert resultAfter.collect {it.leaves.subscribers.size()}.sum() == totalNumberOfEntries * (1 + numberOfCmDataSubscribers)
+        and: 'update matching subscription within 8 seconds'
+            recordAndAssertPerformance("Update matching subscription", 8_000, durationInMillis)
+    }
+
+    def 'Worst case new subscription (200x10 new entries).'() {
+        given: 'a new subscription with non-matching data'
+            def subscribers = createLeafList('subscribers',1, subscriberIdPrefix)
+            def filters = '"filters":' + createJsonArray('filter',numberOfFiltersPerCmHandle,'xpath','other_' + xpathPrefix,subscribers)
+            def cmHandles = createJsonArray('cm-handle',numberOfCmHandlesPerCmDataSubscription,'id','other' + cmHandlePrefix, filters)
+        when: 'Insert a new subscription'
+            stopWatch.start()
+            cpsDataService.saveData(NCMP_PERFORMANCE_TEST_DATASPACE, CM_DATA_SUBSCRIPTIONS_ANCHOR, xPathForDataStore1CmHandles, cmHandles, now)
+            stopWatch.stop()
+            def durationInMillis = stopWatch.getTotalTimeMillis()
+        then: 'insert new subscription with 1 second'
+            recordAndAssertPerformance("Insert new subscription", 1_000, durationInMillis)
+    }
+
+    def querySubscriptionsByIteration(Collection<DataNode> allSubscriptionsAsDataNodes, targetSubscriptionSequenceNumber) {
+        def matches = [:]
+        allSubscriptionsAsDataNodes.each {
+            String[] subscribersAsArray = it.leaves.get('subscribers')
+            Set<String> subscribersAsSet = new HashSet<>(Arrays.asList(subscribersAsArray))
+            def targetSubscriptionId = subscriberIdPrefix + '-' + ( targetSubscriptionSequenceNumber > 0 ? targetSubscriptionSequenceNumber
+                                                                                                     : 1 + random.nextInt(numberOfCmDataSubscribers) )
+            if (subscribersAsSet.contains(targetSubscriptionId)) {
+                matches.put(it, subscribersAsArray)
+            }
+        }
+        return matches
+    }
+
+}
index d01216e..54e56d8 100644 (file)
@@ -22,11 +22,11 @@ package org.onap.cps.integration.performance.ncmp
 
 import java.util.stream.Collectors
 import org.onap.cps.api.CpsQueryService
-import org.onap.cps.integration.performance.base.NcmpRegistryPerfTestBase
+import org.onap.cps.integration.performance.base.NcmpPerfTestBase
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 
-class CmHandleQueryPerfTest extends NcmpRegistryPerfTestBase {
+class CmHandleQueryPerfTest extends NcmpPerfTestBase {
 
     CpsQueryService objectUnderTest
 
diff --git a/integration-test/src/test/resources/data/cm-data-subscriptions/cm-data-subscriptions@2023-09-21.yang b/integration-test/src/test/resources/data/cm-data-subscriptions/cm-data-subscriptions@2023-09-21.yang
new file mode 100644 (file)
index 0000000..552f137
--- /dev/null
@@ -0,0 +1,49 @@
+module cm-data-subscriptions {
+    yang-version 1.1;
+    namespace "org:onap:cps:ncmp";
+
+    prefix cmds;
+
+    revision "2023-09-21" {
+        description
+        "First release, Proof of Concept & Performance";
+    }
+
+    container datastores {
+
+        list datastore {
+            key "name";
+
+            leaf name {
+                type string;
+            }
+
+            container cm-handles {
+
+                list cm-handle {
+                    key "id";
+
+                    leaf id {
+                        type string;
+                    }
+
+                    container filters {
+
+                        list filter {
+                            key "xpath";
+
+                            leaf xpath {
+                                type string;
+                            }
+
+                            leaf-list subscribers {
+                                type string;
+                            }
+
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
index 513c00a..8d5139b 100644 (file)
@@ -9,7 +9,7 @@
         <property name="hibernate.connection.url">${DB_URL}</property>
         <property name="hibernate.connection.username">${DB_USERNAME}</property>
         <property name="hibernate.connection.password">${DB_PASSWORD}</property>
-        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQL82Dialect</property>
+        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
         <property name="show_sql">true</property>
         <property name="hibernate.hbm2ddl.auto">none</property>
     </session-factory>
index c8a3be8..020cbc9 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.onap.cps</groupId>
         <artifactId>cps-parent</artifactId>
-        <version>3.3.7-SNAPSHOT</version>
+        <version>3.3.9-SNAPSHOT</version>
         <relativePath>../cps-parent/pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/pom.xml b/pom.xml
index 0834767..9efdef2 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
 \r
     <groupId>org.onap.cps</groupId>\r
     <artifactId>cps-aggregator</artifactId>\r
-    <version>3.3.7-SNAPSHOT</version>\r
+    <version>3.3.9-SNAPSHOT</version>\r
     <packaging>pom</packaging>\r
 \r
     <name>cps</name>\r
diff --git a/releases/3.3.7-container.yaml b/releases/3.3.7-container.yaml
new file mode 100644 (file)
index 0000000..04b6fa5
--- /dev/null
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.3.7
+project: cps
+log_dir: cps-maven-docker-stage-master/928/
+ref: c3e7b0e3ab0d3b3155d713f639080bdd036d7ba2
+containers:
+  - name: 'cps-and-ncmp'
+    version: '3.3.7-20230920T152321Z'
\ No newline at end of file
diff --git a/releases/3.3.7.yaml b/releases/3.3.7.yaml
new file mode 100644 (file)
index 0000000..b0a0563
--- /dev/null
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/936/
+project: cps
+version: 3.3.7
\ No newline at end of file
diff --git a/releases/3.3.8-container.yaml b/releases/3.3.8-container.yaml
new file mode 100644 (file)
index 0000000..810f328
--- /dev/null
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.3.8
+project: cps
+log_dir: cps-maven-docker-stage-master/929/
+ref: cb9d15022ca5e7696e474ffc8c1b10fa053d6b40
+containers:
+  - name: 'cps-and-ncmp'
+    version: '3.3.8-20230928T113343Z'
\ No newline at end of file
diff --git a/releases/3.3.8.yaml b/releases/3.3.8.yaml
new file mode 100644 (file)
index 0000000..e28b453
--- /dev/null
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/937/
+project: cps
+version: 3.3.8
\ No newline at end of file
index daa4756..743d3b7 100644 (file)
@@ -25,7 +25,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.onap.cps</groupId>
     <artifactId>spotbugs</artifactId>
-    <version>3.3.7-SNAPSHOT</version>
+    <version>3.3.9-SNAPSHOT</version>
 
     <properties>
         <nexusproxy>https://nexus.onap.org</nexusproxy>
index b583c9e..482fe36 100755 (executable)
@@ -22,7 +22,7 @@
 
 major=3
 minor=3
-patch=7
+patch=9
 
 base_version=${major}.${minor}.${patch}