Merge "Add CSIT Test for Registration of a cm-handle endpoint"
authorToine Siebelink <toine.siebelink@est.tech>
Thu, 20 Jan 2022 17:00:25 +0000 (17:00 +0000)
committerGerrit Code Review <gerrit@onap.org>
Thu, 20 Jan 2022 17:00:25 +0000 (17:00 +0000)
18 files changed:
cps-ncmp-rest/docs/openapi/ncmp.yml
cps-ncmp-rest/docs/openapi/openapi.yml
cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.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/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
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/NetworkCmProxyDataServiceImpl.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.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-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
cps-service/src/main/java/org/onap/cps/notification/CpsDataUpdatedEventFactory.java
cps-service/src/main/java/org/onap/cps/notification/NotificationService.java
cps-service/src/main/java/org/onap/cps/notification/Operation.java [new file with mode: 0644]
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/notification/CpsDataUpdateEventFactorySpec.groovy
cps-service/src/test/groovy/org/onap/cps/notification/NotificationServiceSpec.groovy
docs/api/swagger/ncmp/openapi.yaml

index 7845a34..71b4f1c 100755 (executable)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START=======================================================
-#  Copyright (C) 2021 Nordix Foundation
+#  Copyright (C) 2021-2022 Nordix Foundation
 #  Modifications Copyright (C) 2021 Pantheon.tech
 #  Modifications Copyright (C) 2021 Bell Canada
 #  ================================================================================
 #
 #  SPDX-License-Identifier: Apache-2.0
 #  ============LICENSE_END=========================================================
-
-nodeByCmHandleAndXpath:
-  get:
-    description: Get a node with an option to retrieve all the children for a given cm Handle
-    deprecated: true
-    tags:
-      - network-cm-proxy
-    summary: Get a node given a cm Handle and xpath
-    operationId: getNodeByCmHandleAndXpath
-    parameters:
-      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
-      - $ref: 'components.yaml#/components/parameters/xpathInQuery'
-      - $ref: 'components.yaml#/components/parameters/includeDescendantsOptionInQuery'
-    responses:
-      200:
-        $ref: 'components.yaml#/components/responses/Ok'
-      400:
-        $ref: 'components.yaml#/components/responses/BadRequest'
-      401:
-        $ref: 'components.yaml#/components/responses/Unauthorized'
-      403:
-        $ref: 'components.yaml#/components/responses/Forbidden'
-      404:
-        $ref: 'components.yaml#/components/responses/NotFound'
-
-nodesByCmHandleAndCpsPath:
-  get:
-    description: Query nodes for the given cps path and cm Handle
-    deprecated: true
-    tags:
-      - network-cm-proxy
-    summary: Query data nodes
-    operationId: queryNodesByCmHandleAndCpsPath
-    parameters:
-      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
-      - $ref: 'components.yaml#/components/parameters/cpsPathInQuery'
-      - $ref: 'components.yaml#/components/parameters/includeDescendantsOptionInQuery'
-    responses:
-      200:
-        $ref: 'components.yaml#/components/responses/Ok'
-      400:
-        $ref: 'components.yaml#/components/responses/BadRequest'
-      401:
-        $ref: 'components.yaml#/components/responses/Unauthorized'
-      403:
-        $ref: 'components.yaml#/components/responses/Forbidden'
-      404:
-        $ref: 'components.yaml#/components/responses/NotFound'
-
-nodesByCmHandleAndXpath:
-  post:
-    description: Create a node with descendants for the given CM Handle; top level or under existing node (requires xpath)
-    deprecated: true
-    tags:
-      - network-cm-proxy
-    summary: Create a node with descendants
-    operationId: createNode
-    parameters:
-      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
-      - $ref: 'components.yaml#/components/parameters/xpathInQuery'
-    requestBody:
-      required: true
-      content:
-        application/json:
-          schema:
-            type: object
-          examples:
-            dataSampleRequest:
-              $ref: 'components.yaml#/components/examples/dataSampleRequest'
-    responses:
-      201:
-        $ref: 'components.yaml#/components/responses/Created'
-      400:
-        $ref: 'components.yaml#/components/responses/BadRequest'
-      401:
-        $ref: 'components.yaml#/components/responses/Unauthorized'
-      403:
-        $ref: 'components.yaml#/components/responses/Forbidden'
-      404:
-        $ref: 'components.yaml#/components/responses/NotFound'
-
-  patch:
-    description: Update node leaves for the given cps path and cm Handle
-    deprecated: true
-    tags:
-      - network-cm-proxy
-    summary: Update node leaves
-    operationId: updateNodeLeaves
-    parameters:
-      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
-      - $ref: 'components.yaml#/components/parameters/xpathInQuery'
-    requestBody:
-      required: true
-      content:
-        application/json:
-          schema:
-            type: object
-          examples:
-            dataSampleRequest:
-              $ref: 'components.yaml#/components/examples/dataSampleRequest'
-    responses:
-      200:
-        $ref: 'components.yaml#/components/responses/Ok'
-      400:
-        $ref: 'components.yaml#/components/responses/BadRequest'
-      401:
-        $ref: 'components.yaml#/components/responses/Unauthorized'
-      403:
-        $ref: 'components.yaml#/components/responses/Forbidden'
-      404:
-        $ref: 'components.yaml#/components/responses/NotFound'
-
-  put:
-    description: Replace a node with descendants for the given cps path and cm Handle
-    deprecated: true
-    tags:
-      - network-cm-proxy
-    summary: Replace a node with descendants
-    operationId: replaceNode
-    parameters:
-      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
-      - $ref: 'components.yaml#/components/parameters/xpathInQuery'
-    requestBody:
-      required: true
-      content:
-        application/json:
-          schema:
-            type: object
-          examples:
-            dataSampleRequest:
-              $ref: 'components.yaml#/components/examples/dataSampleRequest'
-    responses:
-      200:
-        $ref: 'components.yaml#/components/responses/Ok'
-      400:
-        $ref: 'components.yaml#/components/responses/BadRequest'
-      401:
-        $ref: 'components.yaml#/components/responses/Unauthorized'
-      403:
-        $ref: 'components.yaml#/components/responses/Forbidden'
-      404:
-        $ref: 'components.yaml#/components/responses/NotFound'
-
-listNodeByCmHandleAndXpath:
-  post:
-    description: Add one or more list-node child elements under existing node for the given CM Handle
-    deprecated: true
-    tags:
-      - network-cm-proxy
-    summary: Add list-node child element(s)
-    operationId: addListNodeElements
-    parameters:
-      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
-      - $ref: 'components.yaml#/components/parameters/requiredXpathInQuery'
-    requestBody:
-      required: true
-      content:
-        application/json:
-          schema:
-            type: object
-          examples:
-            dataSampleRequest:
-              $ref: 'components.yaml#/components/examples/dataSampleRequest'
-    responses:
-      201:
-        $ref: 'components.yaml#/components/responses/Created'
-      400:
-        $ref: 'components.yaml#/components/responses/BadRequest'
-      401:
-        $ref: 'components.yaml#/components/responses/Unauthorized'
-      403:
-        $ref: 'components.yaml#/components/responses/Forbidden'
-      404:
-        $ref: 'components.yaml#/components/responses/NotFound'
-
 getResourceDataForPassthroughOperational:
   get:
     tags:
index 64a74c5..838a0d0 100755 (executable)
@@ -1,5 +1,5 @@
 #  ============LICENSE_START=======================================================
-#  Copyright (C) 2021 Nordix Foundation
+#  Copyright (C) 2021-2022 Nordix Foundation
 #  Modifications Copyright (C) 2021 Pantheon.tech
 #  Modifications Copyright (C) 2021 Bell Canada
 #  ================================================================================
@@ -26,18 +26,6 @@ info:
 servers:
   - url: /ncmp
 paths:
-  /v1/cm-handles/{cm-handle}/node:
-    $ref: 'ncmp.yml#/nodeByCmHandleAndXpath'
-
-  /v1/cm-handles/{cm-handle}/list-node:
-    $ref: 'ncmp.yml#/listNodeByCmHandleAndXpath'
-
-  /v1/cm-handles/{cm-handle}/nodes/query:
-    $ref: 'ncmp.yml#/nodesByCmHandleAndCpsPath'
-
-  /v1/cm-handles/{cm-handle}/nodes:
-    $ref: 'ncmp.yml#/nodesByCmHandleAndXpath'
-
   /v1/ch/{cm-handle}/data/ds/ncmp-datastore:passthrough-operational:
     $ref: 'ncmp.yml#/getResourceDataForPassthroughOperational'
 
index e3c457e..a97852f 100755 (executable)
@@ -1,7 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
- *  Modifications (C) 2021 Nordix Foundation
+ *  Modifications (C) 2021-2022 Nordix Foundation
  *  Modification Copyright (C) 2021 highstreet technologies GmbH
  *  Modifications (C) 2021 Bell Canada
  *  ================================================================================
@@ -48,9 +48,6 @@ import org.onap.cps.ncmp.rest.model.Conditions;
 import org.onap.cps.ncmp.rest.model.ModuleNameAsJsonObject;
 import org.onap.cps.ncmp.rest.model.ModuleNamesAsJsonArray;
 import org.onap.cps.ncmp.rest.model.ModuleReference;
-import org.onap.cps.spi.FetchDescendantsOption;
-import org.onap.cps.spi.model.DataNode;
-import org.onap.cps.utils.DataMapUtils;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -75,89 +72,6 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
         this.networkCmProxyDataService = networkCmProxyDataService;
     }
 
-    /**
-     * Create Node.
-     * @deprecated This Method is no longer used as part of NCMP.
-     */
-    // All deprecated APIs methods will be address into https://jira.onap.org/browse/CPS-642
-    @Override
-    @Deprecated(forRemoval = false)
-    public ResponseEntity<Void> createNode(final String cmHandle, @Valid final Object jsonData,
-        @Valid final String parentNodeXpath) {
-        networkCmProxyDataService.createDataNode(cmHandle, parentNodeXpath, GSON.toJson(jsonData));
-        return new ResponseEntity<>(HttpStatus.CREATED);
-    }
-
-    /**
-     * Add List-node Child Element.
-     * @deprecated This Method is no longer used as part of NCMP.
-     */
-    // All deprecated APIs methods will be address into https://jira.onap.org/browse/CPS-642
-    @Override
-    @Deprecated(forRemoval = false)
-    public ResponseEntity<Void> addListNodeElements(@NotNull @Valid final String parentNodeXpath,
-        final String cmHandle, @Valid final Object jsonData) {
-        networkCmProxyDataService.addListNodeElements(cmHandle, parentNodeXpath, GSON.toJson(jsonData));
-        return new ResponseEntity<>(HttpStatus.CREATED);
-    }
-
-    /**
-     * Get Node By CM Handle and X-Path.
-     * @deprecated This Method is no longer used as part of NCMP.
-     */
-    // All deprecated APIs methods will be address into https://jira.onap.org/browse/CPS-642
-    @Override
-    @Deprecated(forRemoval = false)
-    public ResponseEntity<Object> getNodeByCmHandleAndXpath(final String cmHandle, @Valid final String xpath,
-        @Valid final Boolean includeDescendants) {
-        final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
-            ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
-        final var dataNode = networkCmProxyDataService.getDataNode(cmHandle, xpath, fetchDescendantsOption);
-        return new ResponseEntity<>(DataMapUtils.toDataMap(dataNode), HttpStatus.OK);
-    }
-
-    /**
-     * Query Data Nodes.
-     * @deprecated This Method is no longer used as part of NCMP.
-     */
-    // All deprecated APIs methods will be address into https://jira.onap.org/browse/CPS-642
-    @Override
-    @Deprecated(forRemoval = false)
-    public ResponseEntity<Object> queryNodesByCmHandleAndCpsPath(final String cmHandle, @Valid final String cpsPath,
-        @Valid final Boolean includeDescendants) {
-        final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
-            ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
-        final Collection<DataNode> dataNodes =
-            networkCmProxyDataService.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption);
-        return new ResponseEntity<>(GSON.toJson(dataNodes), HttpStatus.OK);
-    }
-
-    /**
-     * Replace Node With Descendants.
-     * @deprecated This Method is no longer used as part of NCMP.
-     */
-    // All deprecated APIs methods will be address into https://jira.onap.org/browse/CPS-642
-    @Override
-    @Deprecated(forRemoval = false)
-    public ResponseEntity<Object> replaceNode(final String cmHandle, @Valid final Object jsonData,
-        @Valid final String parentNodeXpath) {
-        networkCmProxyDataService.replaceNodeTree(cmHandle, parentNodeXpath, GSON.toJson(jsonData));
-        return new ResponseEntity<>(HttpStatus.OK);
-    }
-
-    /**
-     * Update Node Leaves.
-     * @deprecated This Method is no longer used as part of NCMP.
-     */
-    // All deprecated APIs methods will be address into https://jira.onap.org/browse/CPS-642
-    @Override
-    @Deprecated(forRemoval = false)
-    public ResponseEntity<Object> updateNodeLeaves(final String cmHandle, @Valid final Object jsonData,
-        @Valid final String parentNodeXpath) {
-        networkCmProxyDataService.updateNodeLeaves(cmHandle, parentNodeXpath, GSON.toJson(jsonData));
-        return new ResponseEntity<>(HttpStatus.OK);
-    }
-
     /**
      * Get resource data from operational datastore.
      *
index a3d8afa..b5dc2ea 100644 (file)
@@ -2,7 +2,7 @@
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
  *  Modification Copyright (C) 2021 highstreet technologies GmbH
- *  Modification Copyright (C) 2021 Nordix Foundation
+ *  Modification Copyright (C) 2021-2022 Nordix Foundation
  *  Modification Copyright (C) 2021 Bell Canada.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,8 +26,6 @@ import org.onap.cps.TestUtils
 import org.onap.cps.spi.model.ModuleReference
 
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
@@ -37,9 +35,7 @@ import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.DELETE
 
-import com.google.gson.Gson
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.spi.model.DataNodeBuilder
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.beans.factory.annotation.Value
@@ -61,115 +57,8 @@ class NetworkCmProxyControllerSpec extends Specification {
     @Value('${rest.api.ncmp-base-path}/v1')
     def ncmpBasePathV1
 
-    def cmHandle = 'some handle'
-    def xpath = 'some xpath'
     def jsonString = '{"some-key":"some-value"}'
 
-    def 'Query data node by cps path for the given cm handle with #scenario.'() {
-        given: 'service method returns a list containing a data node'
-            def dataNode = new DataNodeBuilder().withXpath('/xpath').build()
-            def cpsPath = 'some cps-path'
-            mockNetworkCmProxyDataService.queryDataNodes(cmHandle, cpsPath, expectedCpsDataServiceOption) >> [dataNode]
-        and: 'the query endpoint'
-            def dataNodeEndpoint = "$ncmpBasePathV1/cm-handles/$cmHandle/nodes/query"
-        when: 'query data nodes API is invoked'
-            def response = mvc.perform(get(dataNodeEndpoint)
-                    .param('cps-path', cpsPath)
-                    .param('include-descendants', includeDescendantsOption))
-                    .andReturn().response
-        then: 'the response contains the the datanode in json format'
-            response.status == HttpStatus.OK.value()
-            def expectedJsonContent = new Gson().toJson(dataNode)
-            response.getContentAsString().contains(expectedJsonContent)
-        where: 'the following options for include descendants are provided in the request'
-            scenario                    | includeDescendantsOption || expectedCpsDataServiceOption
-            'no descendants by default' | ''                       || OMIT_DESCENDANTS
-            'no descendant explicitly'  | 'false'                  || OMIT_DESCENDANTS
-            'descendants'               | 'true'                   || INCLUDE_ALL_DESCENDANTS
-    }
-
-    def 'Create data node: #scenario.'() {
-        when: 'post request is performed'
-            def response = mvc.perform(
-                    post("$ncmpBasePathV1/cm-handles/$cmHandle/nodes")
-                            .contentType(MediaType.APPLICATION_JSON)
-                            .content(jsonString)
-                            .param('xpath', reqXpath)
-            ).andReturn().response
-        then: 'the service method is invoked once with expected parameters'
-            1 * mockNetworkCmProxyDataService.createDataNode(cmHandle, usedXpath, jsonString)
-        and: 'response status indicates success'
-            response.status == HttpStatus.CREATED.value()
-        where: 'following parameters were used'
-            scenario             | reqXpath || usedXpath
-            'no xpath parameter' | ''       || '/'
-            'root xpath'         | '/'      || '/'
-            'parent node xpath'  | '/xpath' || '/xpath'
-    }
-
-    def 'Add list-node elements.'() {
-        given: ' parent node xpath'
-            def parentNodeXpath = 'parent node xpath'
-        when: 'post request is performed'
-            def response = mvc.perform(
-                    post("$ncmpBasePathV1/cm-handles/$cmHandle/list-node")
-                            .contentType(MediaType.APPLICATION_JSON)
-                            .content(jsonString)
-                            .param('xpath', parentNodeXpath)
-            ).andReturn().response
-        then: 'the service method is invoked once with expected parameters'
-            1 * mockNetworkCmProxyDataService.addListNodeElements(cmHandle, parentNodeXpath, jsonString)
-        and: 'response status indicates success'
-            response.status == HttpStatus.CREATED.value()
-    }
-
-    def 'Update data node leaves.'() {
-        given: 'the query endpoint'
-            def endpoint = "$ncmpBasePathV1/cm-handles/$cmHandle/nodes"
-        when: 'patch request is performed'
-            def response = mvc.perform(
-                    patch(endpoint)
-                            .contentType(MediaType.APPLICATION_JSON)
-                            .content(jsonString)
-                            .param('xpath', xpath)
-            ).andReturn().response
-        then: 'the service method is invoked once with expected parameters'
-            1 * mockNetworkCmProxyDataService.updateNodeLeaves(cmHandle, xpath, jsonString)
-        and: 'response status indicates success'
-            response.status == HttpStatus.OK.value()
-    }
-
-    def 'Replace data node tree.'() {
-        given: 'the query endpoint'
-            def endpoint = "$ncmpBasePathV1/cm-handles/$cmHandle/nodes"
-        when: 'put request is performed'
-            def response = mvc.perform(
-                    put(endpoint)
-                            .contentType(MediaType.APPLICATION_JSON)
-                            .content(jsonString)
-                            .param('xpath', xpath)
-            ).andReturn().response
-        then: 'the service method is invoked once with expected parameters'
-            1 * mockNetworkCmProxyDataService.replaceNodeTree(cmHandle, xpath, jsonString)
-        and: 'response status indicates success'
-            response.status == HttpStatus.OK.value()
-    }
-
-    def 'Get data node.'() {
-        given: 'the service returns a data node'
-            def xpath = 'some xpath'
-            def dataNode = new DataNodeBuilder().withXpath(xpath).withLeaves(["leaf": "value"]).build()
-            mockNetworkCmProxyDataService.getDataNode(cmHandle, xpath, OMIT_DESCENDANTS) >> dataNode
-        and: 'the query endpoint'
-            def endpoint = "$ncmpBasePathV1/cm-handles/$cmHandle/node"
-        when: 'get request is performed through REST API'
-            def response = mvc.perform(get(endpoint).param('xpath', xpath)).andReturn().response
-        then: 'a success response is returned'
-            response.status == HttpStatus.OK.value()
-        and: 'response contains expected leaf and value'
-            response.contentAsString.contains('"leaf":"value"')
-    }
-
     def 'Get Resource Data from pass-through operational.' () {
         given: 'resource data url'
             def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-operational" +
index 3fcf818..f36a706 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2021 highstreet technologies GmbH
- *  Modification Copyright (C) 2021 Nordix Foundation
+ *  Modification Copyright (C) 2021-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.
@@ -23,7 +23,6 @@ package org.onap.cps.ncmp.rest.exceptions
 import groovy.json.JsonSlurper
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
 import org.onap.cps.ncmp.api.impl.exception.NcmpException
-import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.exceptions.CpsException
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
@@ -55,9 +54,6 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
     @Shared
     def errorDetails = 'some error details'
 
-    def cmHandle = 'some handle'
-    def xpath = 'some xpath'
-
     def setup() {
         dataNodeBaseEndpoint = "$basePath/v1"
     }
@@ -75,18 +71,16 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
             'other'  | new IllegalStateException(errorMessage)       || null
     }
 
-    def setupTestException(exception) {
-        mockNetworkCmProxyDataService.getDataNode(cmHandle, xpath, FetchDescendantsOption.OMIT_DESCENDANTS) >>
+    def setupTestException(exception){
+        mockNetworkCmProxyDataService.getYangResourcesModuleReferences('testCmHandle')>>
                 { throw exception}
     }
 
-    def performTestRequest() {
-        return mvc.perform(get("$dataNodeBaseEndpoint/cm-handles/$cmHandle/node").param('xpath', xpath))
-                .andReturn().response
+    def performTestRequest(){
+        return mvc.perform(get("$dataNodeBaseEndpoint/ch/testCmHandle/modules")).andReturn().response
     }
 
-    static void assertTestResponse(response, expectedStatus,expectedErrorMessage,
-                                   expectedErrorDetails) {
+    static void assertTestResponse(response, expectedStatus , expectedErrorMessage , expectedErrorDetails) {
         assert response.status == expectedStatus.value()
         def content = new JsonSlurper().parseText(response.contentAsString)
         assert content['status'] == expectedStatus.toString()
index ec816ed..dddf089 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 highstreet technologies GmbH
- *  Modifications Copyright (C) 2021 Nordix Foundation
+ *  Modifications Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,10 +25,7 @@ package org.onap.cps.ncmp.api;
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
 
 import java.util.Collection;
-import org.checkerframework.checker.nullness.qual.NonNull;
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
-import org.onap.cps.spi.FetchDescendantsOption;
-import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.ModuleReference;
 
 /*
@@ -36,72 +33,6 @@ import org.onap.cps.spi.model.ModuleReference;
  */
 public interface NetworkCmProxyDataService {
 
-    /**
-     * Retrieves datanode by XPath for a given cm handle.
-     *
-     * @param cmHandle               The identifier for a network function, network element, subnetwork or any other cm
-     *                               object by managed Network CM Proxy
-     * @param xpath                  xpath
-     * @param fetchDescendantsOption defines the scope of data to fetch: either single node or all the descendant nodes
-     *                               (recursively) as well
-     * @return data node object
-     */
-    DataNode getDataNode(@NonNull String cmHandle, @NonNull String xpath,
-        @NonNull FetchDescendantsOption fetchDescendantsOption);
-
-    /**
-     * Get datanodes for the given cm handle by cps path.
-     *
-     * @param cmHandle               The identifier for a network function, network element, subnetwork or any other cm
-     *                               object by managed Network CM Proxy
-     * @param cpsPath                cps path
-     * @param fetchDescendantsOption defines whether the descendants of the node(s) found by the query should be
-     *                               included in the output
-     * @return a collection of datanodes
-     */
-    Collection<DataNode> queryDataNodes(@NonNull String cmHandle, @NonNull String cpsPath,
-        @NonNull FetchDescendantsOption fetchDescendantsOption);
-
-    /**
-     * Creates data node with descendants at root level or under existing node (if parent node xpath is provided).
-     *
-     * @param cmHandle        The identifier for a network function, network element, subnetwork or any other cm
-     *                        object managed by Network CM Proxy
-     * @param parentNodeXpath xpath to parent node or '/' for root level
-     * @param jsonData        data as JSON string
-     */
-    void createDataNode(@NonNull String cmHandle, @NonNull String parentNodeXpath, @NonNull String jsonData);
-
-    /**
-     * Creates one or more child node elements with descendants under existing node from list-node data fragment.
-     *
-     * @param cmHandle        The identifier for a network function, network element, subnetwork or any other cm
-     *                        object managed by Network CM Proxy
-     * @param parentNodeXpath xpath to parent node
-     * @param jsonData        data as JSON string
-     */
-    void addListNodeElements(@NonNull String cmHandle, @NonNull String parentNodeXpath, @NonNull String jsonData);
-
-    /**
-     * Updates data node for given cm handle using xpath to parent node.
-     *
-     * @param cmHandle        The identifier for a network function, network element, subnetwork or any other cm object
-     *                        by managed Network CM Proxy
-     * @param parentNodeXpath xpath to parent node
-     * @param jsonData        json data
-     */
-    void updateNodeLeaves(@NonNull String cmHandle, @NonNull String parentNodeXpath, @NonNull String jsonData);
-
-    /**
-     * Replaces existing data node content including descendants.
-     *
-     * @param cmHandle        The identifier for a network function, network element, subnetwork or any other cm object
-     *                        by managed Network CM Proxy
-     * @param parentNodeXpath xpath to parent node
-     * @param jsonData        json data
-     */
-    void replaceNodeTree(@NonNull String cmHandle, @NonNull String parentNodeXpath, @NonNull String jsonData);
-
     /**
      * Registration of New CM Handles.
      *
index 7ded95f..eeb004a 100755 (executable)
@@ -1,7 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 highstreet technologies GmbH
- *  Modifications Copyright (C) 2021 Nordix Foundation
+ *  Modifications Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021 Bell Canada
  *  ================================================================================
@@ -38,7 +38,6 @@ import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsAdminService;
 import org.onap.cps.api.CpsDataService;
 import org.onap.cps.api.CpsModuleService;
-import org.onap.cps.api.CpsQueryService;
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
 import org.onap.cps.ncmp.api.impl.exception.NcmpException;
 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
@@ -48,14 +47,11 @@ import org.onap.cps.ncmp.api.models.CmHandle;
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
 import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
 import org.onap.cps.ncmp.api.models.PersistenceCmHandlesList;
-import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
 import org.onap.cps.spi.exceptions.DataValidationException;
-import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.ModuleReference;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
 
 @Slf4j
 @Service
@@ -73,8 +69,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
 
     private ObjectMapper objectMapper;
 
-    private CpsQueryService cpsQueryService;
-
     private DmiDataOperations dmiDataOperations;
 
     private DmiModelOperations dmiModelOperations;
@@ -87,68 +81,22 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
      * Constructor Injection for Dependencies.
      * @param dmiDataOperations DMI operation
      * @param cpsDataService Data Service Interface
-     * @param cpsQueryService Query Service Interface
      * @param objectMapper Object Mapper
      */
     public NetworkCmProxyDataServiceImpl(final DmiDataOperations dmiDataOperations,
                                          final DmiModelOperations dmiModelOperations,
                                          final CpsModuleService cpsModuleService,
                                          final CpsDataService cpsDataService,
-                                         final CpsQueryService cpsQueryService,
                                          final CpsAdminService cpsAdminService,
                                          final ObjectMapper objectMapper) {
         this.dmiDataOperations = dmiDataOperations;
         this.dmiModelOperations = dmiModelOperations;
         this.cpsModuleService = cpsModuleService;
         this.cpsDataService = cpsDataService;
-        this.cpsQueryService = cpsQueryService;
         this.cpsAdminService = cpsAdminService;
         this.objectMapper = objectMapper;
     }
 
-    @Override
-    public DataNode getDataNode(final String cmHandle, final String xpath,
-        final FetchDescendantsOption fetchDescendantsOption) {
-        return cpsDataService
-            .getDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, xpath, fetchDescendantsOption);
-    }
-
-    @Override
-    public Collection<DataNode> queryDataNodes(final String cmHandle, final String cpsPath,
-        final FetchDescendantsOption fetchDescendantsOption) {
-        return cpsQueryService
-            .queryDataNodes(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, cpsPath, fetchDescendantsOption);
-    }
-
-    @Override
-    public void createDataNode(final String cmHandle, final String parentNodeXpath, final String jsonData) {
-        if (!StringUtils.hasText(parentNodeXpath) || "/".equals(parentNodeXpath)) {
-            cpsDataService.saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, jsonData, NO_TIMESTAMP);
-        } else {
-            cpsDataService
-                .saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData, NO_TIMESTAMP);
-        }
-    }
-
-    @Override
-    public void addListNodeElements(final String cmHandle, final String parentNodeXpath, final String jsonData) {
-        cpsDataService.saveListElements(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
-            NO_TIMESTAMP);
-    }
-
-    @Override
-    public void updateNodeLeaves(final String cmHandle, final String parentNodeXpath, final String jsonData) {
-        cpsDataService
-            .updateNodeLeaves(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
-                NO_TIMESTAMP);
-    }
-
-    @Override
-    public void replaceNodeTree(final String cmHandle, final String parentNodeXpath, final String jsonData) {
-        cpsDataService.replaceNodeTree(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
-            NO_TIMESTAMP);
-    }
-
     @Override
     public void updateDmiRegistrationAndSyncModule(final DmiPluginRegistration dmiPluginRegistration) {
         dmiPluginRegistration.validateDmiPluginRegistration();
index de60a01..b7f059a 100644 (file)
@@ -35,7 +35,7 @@ class NetworkCmProxyDataServiceImplModelSyncSpec extends Specification {
     def mockDmiModelOperations = Mock(DmiModelOperations)
 
     def objectUnderTest = new NetworkCmProxyDataServiceImpl(null, mockDmiModelOperations,
-        mockCpsModuleService, null, null, mockCpsAdminService, new ObjectMapper())
+        mockCpsModuleService, null, mockCpsAdminService, new ObjectMapper())
 
     def expectedDataspaceName = 'NFP-Operational'
 
index 304c08a..90fcbfc 100644 (file)
@@ -183,7 +183,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
 
     def getObjectUnderTestWithModelSyncDisabled() {
         def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(null, null, mockCpsModuleService,
-                mockCpsDataService, null, null, spyObjectMapper))
+                mockCpsDataService, null, spyObjectMapper))
         objectUnderTest.syncModulesAndCreateAnchor(*_) >> null
         return objectUnderTest
     }
index 6249271..5753d7b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021 Bell Canada
  *  ================================================================================
@@ -33,7 +33,6 @@ 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.api.CpsQueryService
 import org.onap.cps.ncmp.api.impl.exception.NcmpException
 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
 import org.onap.cps.spi.FetchDescendantsOption
@@ -45,52 +44,16 @@ import spock.lang.Specification
 class NetworkCmProxyDataServiceImplSpec extends Specification {
 
     def mockCpsDataService = Mock(CpsDataService)
-    def mockCpsQueryService = Mock(CpsQueryService)
     def mockCpsModuleService = Mock(CpsModuleService)
     def mockCpsAdminService = Mock(CpsAdminService)
     def spyObjectMapper = Spy(ObjectMapper)
     def mockDmiDataOperations = Mock(DmiDataOperations)
 
     def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockDmiDataOperations, null,
-        mockCpsModuleService, mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper)
+        mockCpsModuleService, mockCpsDataService, mockCpsAdminService, spyObjectMapper)
 
-    def cmHandle = 'some handle'
-    def noTimestamp = null
     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
-    def expectedDataspaceName = 'NFP-Operational'
 
-    def 'Create full data node: #scenario.'() {
-        given: 'json data'
-            def jsonData = 'some json'
-        when: 'createDataNode is invoked'
-            objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
-        then: 'save data is invoked once with the expected parameters'
-            1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, jsonData, noTimestamp)
-        where: 'following parameters were used'
-            scenario           | xpath
-            'no xpath'         | ''
-            'root level xpath' | '/'
-    }
-
-    def 'Create child data node.'() {
-        given: 'json data and xpath'
-            def jsonData = 'some json'
-            def xpath = '/test-node'
-        when: 'create data node is invoked'
-            objectUnderTest.createDataNode(cmHandle, xpath, jsonData)
-        then: 'save data is invoked once with the expected parameters'
-            1 * mockCpsDataService.saveData(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
-    }
-
-    def 'Add list-node elements.'() {
-        given: 'json data and xpath'
-            def jsonData = 'some json'
-            def xpath = '/test-node'
-        when: 'add list node element is invoked'
-            objectUnderTest.addListNodeElements(cmHandle, xpath, jsonData)
-        then: 'the save list elements is invoked once with the expected parameters'
-            1 * mockCpsDataService.saveListElements(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
-    }
 
     def 'Write resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
         given: 'a data node'
@@ -133,14 +96,6 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             exceptionThrown.details.contains('404')
     }
 
-    def 'Get data node.'() {
-        when: 'get data node is invoked'
-            objectUnderTest.getDataNode(cmHandle, 'some xpath', fetchDescendantsOption)
-        then: 'the persistence data service is called once with the correct parameters'
-            1 * mockCpsDataService.getDataNode(expectedDataspaceName, cmHandle, 'some xpath', fetchDescendantsOption)
-        where: 'all fetch descendants options are supported'
-            fetchDescendantsOption << FetchDescendantsOption.values()
-    }
 
     def 'Get resource data for pass-through operational from dmi.'() {
         given: 'a data node'
@@ -270,25 +225,6 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name'])
     }
 
-    def 'Update data node leaves.'() {
-        given: 'json data and xpath'
-            def jsonData = 'some json'
-            def xpath = '/xpath'
-        when: 'update node leaves is invoked'
-            objectUnderTest.updateNodeLeaves(cmHandle, xpath, jsonData)
-        then: 'the persistence service is called once with the correct parameters'
-            1 * mockCpsDataService.updateNodeLeaves(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
-    }
-
-    def 'Replace data node tree.'() {
-        given: 'json data and xpath'
-            def jsonData = 'some json'
-            def xpath = '/xpath'
-        when: 'replace node tree is invoked'
-            objectUnderTest.replaceNodeTree(cmHandle, xpath, jsonData)
-        then: 'the persistence service is called once with the correct parameters'
-            1 * mockCpsDataService.replaceNodeTree(expectedDataspaceName, cmHandle, xpath, jsonData, noTimestamp)
-    }
 
     def 'Update resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
         given: 'a data node'
@@ -331,17 +267,6 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
             'UPDATE' | UPDATE         || 'Not able to update resource data.'
     }
 
-    def 'Query data nodes by cps path with #fetchDescendantsOption.'() {
-        given: 'a cps path'
-            def cpsPath = '/cps-path'
-        when: 'query data nodes is invoked'
-            objectUnderTest.queryDataNodes(cmHandle, cpsPath, fetchDescendantsOption)
-        then: 'the persistence query service is called once with the correct parameters'
-            1 * mockCpsQueryService.queryDataNodes(expectedDataspaceName, cmHandle, cpsPath, fetchDescendantsOption)
-        where: 'all fetch descendants options are supported'
-            fetchDescendantsOption << FetchDescendantsOption.values()
-    }
-
     def getDataNode(boolean includeCmHandleProperties) {
         def dataNode = new DataNode()
         dataNode.leaves = ['dmi-service-name': 'testDmiService']
index 1445cca..a23bc95 100755 (executable)
@@ -1,7 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Nordix Foundation
- *  Modifications Copyright (C) 2020-2021 Bell Canada.
+ *  Modifications Copyright (C) 2020-2022 Bell Canada.
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,8 +27,8 @@ import java.util.Collection;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsAdminService;
 import org.onap.cps.api.CpsDataService;
-import org.onap.cps.api.CpsModuleService;
 import org.onap.cps.notification.NotificationService;
+import org.onap.cps.notification.Operation;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.exceptions.DataValidationException;
@@ -52,9 +52,6 @@ public class CpsDataServiceImpl implements CpsDataService {
     @Autowired
     private CpsAdminService cpsAdminService;
 
-    @Autowired
-    private CpsModuleService cpsModuleService;
-
     @Autowired
     private YangTextSchemaSourceSetCache yangTextSchemaSourceSetCache;
 
@@ -66,7 +63,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final OffsetDateTime observedTimestamp) {
         final var dataNode = buildDataNode(dataspaceName, anchorName, ROOT_NODE_XPATH, jsonData);
         cpsDataPersistenceService.storeDataNode(dataspaceName, anchorName, dataNode);
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, ROOT_NODE_XPATH, Operation.CREATE);
     }
 
     @Override
@@ -74,7 +71,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final String jsonData, final OffsetDateTime observedTimestamp) {
         final var dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData);
         cpsDataPersistenceService.addChildDataNode(dataspaceName, anchorName, parentNodeXpath, dataNode);
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.CREATE);
     }
 
     @Override
@@ -84,7 +81,7 @@ public class CpsDataServiceImpl implements CpsDataService {
             buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonData);
         cpsDataPersistenceService.addListElements(dataspaceName, anchorName, parentNodeXpath,
             listElementDataNodeCollection);
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE);
     }
 
     @Override
@@ -99,7 +96,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final var dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData);
         cpsDataPersistenceService
             .updateDataLeaves(dataspaceName, anchorName, dataNode.getXpath(), dataNode.getLeaves());
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE);
     }
 
     @Override
@@ -113,7 +110,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         for (final DataNode dataNodeUpdate : dataNodeUpdates) {
             processDataNodeUpdate(dataspaceName, anchorName, dataNodeUpdate);
         }
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE);
     }
 
     @Override
@@ -121,7 +118,7 @@ public class CpsDataServiceImpl implements CpsDataService {
         final String jsonData, final OffsetDateTime observedTimestamp) {
         final var dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData);
         cpsDataPersistenceService.replaceDataNodeTree(dataspaceName, anchorName, dataNode);
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE);
     }
 
     @Override
@@ -130,21 +127,21 @@ public class CpsDataServiceImpl implements CpsDataService {
         final Collection<DataNode> newListElements =
             buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonData);
         cpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, parentNodeXpath, newListElements);
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE);
     }
 
     @Override
     public void deleteDataNode(final String dataspaceName, final String anchorName, final String dataNodeXpath,
                                final OffsetDateTime observedTimestamp) {
         cpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, dataNodeXpath);
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, dataNodeXpath, Operation.DELETE);
     }
 
     @Override
     public void deleteListOrListElement(final String dataspaceName, final String anchorName, final String listNodeXpath,
         final OffsetDateTime observedTimestamp) {
         cpsDataPersistenceService.deleteListDataNode(dataspaceName, anchorName, listNodeXpath);
-        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp);
+        processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, listNodeXpath, Operation.DELETE);
     }
 
     private DataNode buildDataNode(final String dataspaceName, final String anchorName,
@@ -186,9 +183,10 @@ public class CpsDataServiceImpl implements CpsDataService {
     }
 
     private void processDataUpdatedEventAsync(final String dataspaceName, final String anchorName,
-        final OffsetDateTime observedTimestamp) {
+                                              final OffsetDateTime observedTimestamp, final String xpath,
+                                              final Operation operation) {
         try {
-            notificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp);
+            notificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, xpath, operation);
         } catch (final Exception exception) {
             log.error("Failed to send message to notification service", exception);
         }
@@ -210,4 +208,5 @@ public class CpsDataServiceImpl implements CpsDataService {
             processDataNodeUpdate(dataspaceName, anchorName, childDataNodeUpdate);
         }
     }
+
 }
index 2985ed5..6054ce5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (c) 2021 Bell Canada.
+ * Copyright (c) 2021-2022 Bell Canada.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -71,20 +71,21 @@ public class CpsDataUpdatedEventFactory {
      * @param dataspaceName     dataspaceName
      * @param anchorName        anchorName
      * @param observedTimestamp observedTimestamp
+     * @param operation         operation
      * @return CpsDataUpdatedEvent
      */
     public CpsDataUpdatedEvent createCpsDataUpdatedEvent(final String dataspaceName, final String anchorName,
-        final OffsetDateTime observedTimestamp) {
+        final OffsetDateTime observedTimestamp, final Operation operation) {
         final var dataNode = cpsDataService
             .getDataNode(dataspaceName, anchorName, "/", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
         final var anchor = cpsAdminService.getAnchor(dataspaceName, anchorName);
-        return toCpsDataUpdatedEvent(anchor, dataNode, observedTimestamp);
+        return toCpsDataUpdatedEvent(anchor, dataNode, observedTimestamp, operation);
     }
 
     private CpsDataUpdatedEvent toCpsDataUpdatedEvent(final Anchor anchor, final DataNode dataNode,
-        final OffsetDateTime observedTimestamp) {
+        final OffsetDateTime observedTimestamp, final Operation operation) {
         final var cpsDataUpdatedEvent = new CpsDataUpdatedEvent();
-        cpsDataUpdatedEvent.withContent(createContent(anchor, dataNode, observedTimestamp));
+        cpsDataUpdatedEvent.withContent(createContent(anchor, dataNode, observedTimestamp, operation));
         cpsDataUpdatedEvent.withId(UUID.randomUUID().toString());
         cpsDataUpdatedEvent.withSchema(EVENT_SCHEMA);
         cpsDataUpdatedEvent.withSource(EVENT_SOURCE);
@@ -99,12 +100,13 @@ public class CpsDataUpdatedEventFactory {
     }
 
     private Content createContent(final Anchor anchor, final DataNode dataNode,
-        final OffsetDateTime observedTimestamp) {
+        final OffsetDateTime observedTimestamp, final Operation operation) {
         final var content = new Content();
         content.withAnchorName(anchor.getName());
         content.withDataspaceName(anchor.getDataspaceName());
         content.withSchemaSetName(anchor.getSchemaSetName());
         content.withData(createData(dataNode));
+        content.withOperation(Content.Operation.fromValue(operation.name()));
         content.withObservedTimestamp(
             DATE_TIME_FORMATTER.format(observedTimestamp == null ? OffsetDateTime.now() : observedTimestamp));
         return content;
index 029efbe..97a1479 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (c) 2021 Bell Canada.
+ * Copyright (c) 2021-2022 Bell Canada.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,6 +36,8 @@ import org.springframework.stereotype.Service;
 @Slf4j
 public class NotificationService {
 
+    private static final String ROOT_NODE_XPATH = "/";
+
     private NotificationProperties notificationProperties;
     private NotificationPublisher notificationPublisher;
     private CpsDataUpdatedEventFactory cpsDataUpdatedEventFactory;
@@ -78,19 +80,23 @@ public class NotificationService {
     /**
      * Process Data Updated Event and publishes the notification.
      *
-     * @param dataspaceName dataspace name
-     * @param anchorName    anchor name
+     * @param dataspaceName     dataspace name
+     * @param anchorName        anchor name
      * @param observedTimestamp observedTimestamp
+     * @param xpath             xpath of changed data node
+     * @param operation         operation
      * @return future
      */
     @Async("notificationExecutor")
     public Future<Void> processDataUpdatedEvent(final String dataspaceName, final String anchorName,
-        final OffsetDateTime observedTimestamp) {
+                                                final OffsetDateTime observedTimestamp,
+                                                final String xpath, final Operation operation) {
         log.debug("process data updated event for dataspace '{}' & anchor '{}'", dataspaceName, anchorName);
         try {
             if (shouldSendNotification(dataspaceName)) {
                 final var cpsDataUpdatedEvent =
-                    cpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp);
+                    cpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(dataspaceName, anchorName,
+                        observedTimestamp, getRootNodeOperation(xpath, operation));
                 log.debug("data updated event to be published {}", cpsDataUpdatedEvent);
                 notificationPublisher.sendNotification(cpsDataUpdatedEvent);
             }
@@ -114,4 +120,8 @@ public class NotificationService {
             .anyMatch(pattern -> pattern.matcher(dataspaceName).find());
     }
 
+    private Operation getRootNodeOperation(final String xpath, final Operation operation) {
+        return ROOT_NODE_XPATH.equals(xpath) ? operation : Operation.UPDATE;
+    }
+
 }
diff --git a/cps-service/src/main/java/org/onap/cps/notification/Operation.java b/cps-service/src/main/java/org/onap/cps/notification/Operation.java
new file mode 100644 (file)
index 0000000..83e1ccf
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (c) 2022 Bell Canada.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.notification;
+
+public enum Operation {
+    CREATE,
+    UPDATE,
+    DELETE
+}
index ba9c156..6c899c7 100644 (file)
@@ -2,7 +2,7 @@
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
- *  Modifications Copyright (C) 2021 Bell Canada.
+ *  Modifications Copyright (C) 2021-2022 Bell Canada.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import org.onap.cps.TestUtils
 import org.onap.cps.api.CpsAdminService
 import org.onap.cps.api.CpsModuleService
 import org.onap.cps.notification.NotificationService
+import org.onap.cps.notification.Operation
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.exceptions.DataValidationException
@@ -40,7 +41,6 @@ import java.time.OffsetDateTime
 class CpsDataServiceImplSpec extends Specification {
     def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
     def mockCpsAdminService = Mock(CpsAdminService)
-    def mockCpsModuleService = Mock(CpsModuleService)
     def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache)
     def mockNotificationService = Mock(NotificationService)
 
@@ -49,7 +49,6 @@ class CpsDataServiceImplSpec extends Specification {
     def setup() {
         objectUnderTest.cpsDataPersistenceService = mockCpsDataPersistenceService
         objectUnderTest.cpsAdminService = mockCpsAdminService
-        objectUnderTest.cpsModuleService = mockCpsModuleService
         objectUnderTest.yangTextSchemaSourceSetCache = mockYangTextSchemaSourceSetCache
         objectUnderTest.notificationService = mockNotificationService
     }
@@ -69,7 +68,7 @@ class CpsDataServiceImplSpec extends Specification {
             1 * mockCpsDataPersistenceService.storeDataNode(dataspaceName, anchorName,
                 { dataNode -> dataNode.xpath == '/test-tree' })
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/', Operation.CREATE)
     }
 
     def 'Saving child data fragment under existing node.'() {
@@ -82,7 +81,7 @@ class CpsDataServiceImplSpec extends Specification {
             1 * mockCpsDataPersistenceService.addChildDataNode(dataspaceName, anchorName, '/test-tree',
                 { dataNode -> dataNode.xpath == '/test-tree/branch[@name=\'New\']' })
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/test-tree', Operation.CREATE)
     }
 
     def 'Saving list element data fragment under existing node.'() {
@@ -102,7 +101,7 @@ class CpsDataServiceImplSpec extends Specification {
                 }
             )
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/test-tree', Operation.UPDATE)
     }
 
     def 'Saving empty list element data fragment.'() {
@@ -134,7 +133,7 @@ class CpsDataServiceImplSpec extends Specification {
         then: 'the persistence service method is invoked with correct parameters'
             1 * mockCpsDataPersistenceService.updateDataLeaves(dataspaceName, anchorName, expectedNodeXpath, leaves)
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE)
         where: 'following parameters were used'
             scenario         | parentNodeXpath | jsonData                        || expectedNodeXpath                   | leaves
             'top level node' | '/'             | '{"test-tree": {"branch": []}}' || '/test-tree'                        | Collections.emptyMap()
@@ -167,7 +166,7 @@ class CpsDataServiceImplSpec extends Specification {
             1 * mockCpsDataPersistenceService.updateDataLeaves(dataspaceName, anchorName,
                 "/dmi-registry/cm-handles[@id='cmHandle001']", ['id': 'cmHandle001'])
         and: 'the data updated event is sent to the notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/dmi-registry', Operation.UPDATE)
     }
 
     def 'Replace data node: #scenario.'() {
@@ -179,7 +178,7 @@ class CpsDataServiceImplSpec extends Specification {
             1 * mockCpsDataPersistenceService.replaceDataNodeTree(dataspaceName, anchorName,
                 { dataNode -> dataNode.xpath == expectedNodeXpath })
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE)
         where: 'following parameters were used'
             scenario         | parentNodeXpath | jsonData                        || expectedNodeXpath
             'top level node' | '/'             | '{"test-tree": {"branch": []}}' || '/test-tree'
@@ -203,7 +202,7 @@ class CpsDataServiceImplSpec extends Specification {
                 }
             )
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/test-tree', Operation.UPDATE)
     }
 
     def 'Replace whole list content with empty list element.'() {
@@ -224,7 +223,7 @@ class CpsDataServiceImplSpec extends Specification {
         then: 'the persistence service method is invoked with correct parameters'
             1 * mockCpsDataPersistenceService.deleteListDataNode(dataspaceName, anchorName, '/test-tree/branch')
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/test-tree/branch', Operation.DELETE)
     }
 
     def 'Delete data node under anchor and dataspace.'() {
@@ -235,7 +234,7 @@ class CpsDataServiceImplSpec extends Specification {
         then: 'the persistence service method is invoked with the correct parameters'
             1 * mockCpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, '/data-node')
         and: 'data updated event is sent to notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/data-node', Operation.DELETE)
     }
 
     def setupSchemaSetMocks(String... yangResources) {
index aa0c7c0..67ed3d9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (c) 2021 Bell Canada.
+ * Copyright (c) 2021-2022 Bell Canada.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import java.time.format.DateTimeFormatter
 import org.onap.cps.utils.DateTimeUtility
 import org.onap.cps.api.CpsAdminService
 import org.onap.cps.api.CpsDataService
+import org.onap.cps.event.model.Content
 import org.onap.cps.event.model.Data
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.model.Anchor
@@ -45,7 +46,6 @@ class CpsDataUpdateEventFactorySpec extends Specification {
     def dateTimeFormat = 'yyyy-MM-dd\'T\'HH:mm:ss.SSSZ'
 
     def 'Create a CPS data updated event successfully: #scenario'() {
-
         given: 'cps admin service is able to return anchor details'
             mockCpsAdminService.getAnchor(myDataspaceName, myAnchorName) >>
                 new Anchor(myAnchorName, myDataspaceName, mySchemasetName)
@@ -54,13 +54,10 @@ class CpsDataUpdateEventFactorySpec extends Specification {
             def dataNode = new DataNodeBuilder().withXpath(xpath).withLeaves(['leafName': 'leafValue']).build()
             mockCpsDataService.getDataNode(
                 myDataspaceName, myAnchorName, xpath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
-
         when: 'CPS data updated event is created'
             def cpsDataUpdatedEvent = objectUnderTest.createCpsDataUpdatedEvent(myDataspaceName,
-                myAnchorName, DateTimeUtility.toOffsetDateTime(inputObservedTimestamp))
-
+                myAnchorName, DateTimeUtility.toOffsetDateTime(inputObservedTimestamp), Operation.CREATE)
         then: 'CPS data updated event is created with correct envelope'
-
             with(cpsDataUpdatedEvent) {
                 type == 'org.onap.cps.data-updated-event'
                 source == new URI('urn:cps:org.onap.cps')
@@ -79,6 +76,7 @@ class CpsDataUpdateEventFactorySpec extends Specification {
                 assert anchorName == myAnchorName
                 assert dataspaceName == myDataspaceName
                 assert schemaSetName == mySchemasetName
+                assert operation == Content.Operation.CREATE
                 assert data == new Data().withAdditionalProperty('leafName', 'leafValue')
             }
         where:
index ca704ed..306e187 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (c) 2021 Bell Canada.
+ *  Copyright (c) 2021-2022 Bell Canada.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -61,7 +61,7 @@ class NotificationServiceSpec extends Specification {
         given: 'notification is disabled'
             spyNotificationProperties.isEnabled() >> false
         when: 'dataUpdatedEvent is received'
-            objectUnderTest.processDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp)
+            objectUnderTest.processDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp, '/', Operation.CREATE)
         then: 'the notification is not sent'
             0 * mockNotificationPublisher.sendNotification(_)
     }
@@ -71,10 +71,12 @@ class NotificationServiceSpec extends Specification {
             spyNotificationProperties.isEnabled() >> true
         and: 'event factory can create event successfully'
             def cpsDataUpdatedEvent = new CpsDataUpdatedEvent()
-            mockCpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(dataspaceName, myAnchorName, myObservedTimestamp) >>
-                cpsDataUpdatedEvent
+            mockCpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(dataspaceName, myAnchorName, myObservedTimestamp,
+                    Operation.CREATE) >>
+                    cpsDataUpdatedEvent
         when: 'dataUpdatedEvent is received'
-            def future = objectUnderTest.processDataUpdatedEvent(dataspaceName, myAnchorName, myObservedTimestamp)
+            def future = objectUnderTest.processDataUpdatedEvent(dataspaceName, myAnchorName, myObservedTimestamp,
+                    '/', Operation.CREATE)
         and: 'wait for async processing to complete'
             future.get(10, TimeUnit.SECONDS)
         then: 'async process completed successfully'
@@ -87,14 +89,57 @@ class NotificationServiceSpec extends Specification {
             'dataspace name matches filter'        | myDataspacePublishedName || 1
     }
 
+    def 'Send UPDATE operation when non-root data nodes are changed.'() {
+        given: 'notification is enabled'
+            spyNotificationProperties.isEnabled() >> true
+        and: 'event factory creates event if operation is UPDATE'
+            def cpsDataUpdatedEvent = new CpsDataUpdatedEvent()
+            mockCpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp,
+                    Operation.UPDATE) >> cpsDataUpdatedEvent
+        when: 'dataUpdatedEvent is received for non-root xpath'
+            def future = objectUnderTest.processDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp, '/non-root-node',
+                    operation)
+        and: 'wait for async processing to complete'
+            future.get(10, TimeUnit.SECONDS)
+        then: 'async process completed successfully'
+            future.isDone()
+        and: 'notification is sent'
+            1 * mockNotificationPublisher.sendNotification(cpsDataUpdatedEvent)
+        where:
+            operation << [Operation.CREATE, Operation.UPDATE, Operation.DELETE]
+    }
+
+    def 'Send same operation when root nodes are changed.'() {
+        given: 'notification is enabled'
+            spyNotificationProperties.isEnabled() >> true
+        and: 'event factory creates event if operation is #operation'
+            def cpsDataUpdatedEvent = new CpsDataUpdatedEvent()
+            mockCpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp,
+                    operation) >> cpsDataUpdatedEvent
+        when: 'dataUpdatedEvent is received for root xpath'
+            def future = objectUnderTest.processDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp, '/',
+                    operation)
+        and: 'wait for async processing to complete'
+            future.get(10, TimeUnit.SECONDS)
+        then: 'async process completed successfully'
+            future.isDone()
+        and: 'notification is sent'
+            1 * mockNotificationPublisher.sendNotification(cpsDataUpdatedEvent)
+        where:
+            operation << [Operation.CREATE, Operation.UPDATE, Operation.DELETE]
+    }
+
+
     def 'Error handling in notification service.'() {
         given: 'notification is enabled'
             spyNotificationProperties.isEnabled() >> true
         and: 'event factory can not create event successfully'
-            mockCpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp) >>
-                { throw new Exception("Could not create event") }
+            mockCpsDataUpdatedEventFactory.createCpsDataUpdatedEvent(myDataspacePublishedName, myAnchorName,
+                    myObservedTimestamp, Operation.CREATE) >>
+                    { throw new Exception("Could not create event") }
         when: 'event is sent for processing'
-            def future = objectUnderTest.processDataUpdatedEvent(myDataspacePublishedName, myAnchorName, myObservedTimestamp)
+            def future = objectUnderTest.processDataUpdatedEvent(myDataspacePublishedName, myAnchorName,
+                    myObservedTimestamp, '/', Operation.CREATE)
         and: 'wait for async processing to complete'
             future.get(10, TimeUnit.SECONDS)
         then: 'async process completed successfully'
index 509adf4..a3b9dc7 100644 (file)
@@ -6,362 +6,6 @@ info:
 servers:
   - url: /ncmp
 paths:
-  /v1/cm-handles/{cm-handle}/node:
-    get:
-      tags:
-        - network-cm-proxy
-      summary: Get a node given a cm Handle and xpath
-      description: Get a node with an option to retrieve all the children for a given
-        cm Handle
-      operationId: getNodeByCmHandleAndXpath
-      parameters:
-        - name: cm-handle
-          in: path
-          description: "The identifier for a network function, network element, subnetwork\
-          \ or any other cm object by managed Network CM Proxy"
-          required: true
-          schema:
-            type: string
-        - name: xpath
-          in: query
-          description: xpath
-          required: false
-          schema:
-            type: string
-            default: /
-        - name: include-descendants
-          in: query
-          description: include-descendants
-          required: false
-          schema:
-            type: boolean
-            default: false
-      responses:
-        "200":
-          description: OK
-          content:
-            application/json:
-              schema:
-                type: object
-        "400":
-          description: Bad Request
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "401":
-          description: Unauthorized
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "403":
-          description: Forbidden
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "404":
-          description: The specified resource was not found
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-      deprecated: true
-  /v1/cm-handles/{cm-handle}/list-node:
-    post:
-      tags:
-        - network-cm-proxy
-      summary: Add list-node child element(s)
-      description: Add one or more list-node child elements under existing node for
-        the given CM Handle
-      operationId: addListNodeElements
-      parameters:
-        - name: cm-handle
-          in: path
-          description: "The identifier for a network function, network element, subnetwork\
-          \ or any other cm object by managed Network CM Proxy"
-          required: true
-          schema:
-            type: string
-        - name: xpath
-          in: query
-          description: xpath
-          required: true
-          schema:
-            type: string
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: string
-        required: true
-      responses:
-        "201":
-          description: Created
-          content: {}
-        "400":
-          description: Bad Request
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "401":
-          description: Unauthorized
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "403":
-          description: Forbidden
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "404":
-          description: The specified resource was not found
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-      deprecated: true
-  /v1/cm-handles/{cm-handle}/nodes/query:
-    get:
-      tags:
-        - network-cm-proxy
-      summary: Query data nodes
-      description: Query nodes for the given cps path and cm Handle
-      operationId: queryNodesByCmHandleAndCpsPath
-      parameters:
-        - name: cm-handle
-          in: path
-          description: "The identifier for a network function, network element, subnetwork\
-          \ or any other cm object by managed Network CM Proxy"
-          required: true
-          schema:
-            type: string
-        - name: cps-path
-          in: query
-          description: cps-path
-          required: false
-          schema:
-            type: string
-            default: /
-        - name: include-descendants
-          in: query
-          description: include-descendants
-          required: false
-          schema:
-            type: boolean
-            default: false
-      responses:
-        "200":
-          description: OK
-          content:
-            application/json:
-              schema:
-                type: object
-        "400":
-          description: Bad Request
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "401":
-          description: Unauthorized
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "403":
-          description: Forbidden
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "404":
-          description: The specified resource was not found
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-      deprecated: true
-  /v1/cm-handles/{cm-handle}/nodes:
-    put:
-      tags:
-        - network-cm-proxy
-      summary: Replace a node with descendants
-      description: Replace a node with descendants for the given cps path and cm Handle
-      operationId: replaceNode
-      parameters:
-        - name: cm-handle
-          in: path
-          description: "The identifier for a network function, network element, subnetwork\
-          \ or any other cm object by managed Network CM Proxy"
-          required: true
-          schema:
-            type: string
-        - name: xpath
-          in: query
-          description: xpath
-          required: false
-          schema:
-            type: string
-            default: /
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: string
-        required: true
-      responses:
-        "200":
-          description: OK
-          content:
-            application/json:
-              schema:
-                type: object
-        "400":
-          description: Bad Request
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "401":
-          description: Unauthorized
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "403":
-          description: Forbidden
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "404":
-          description: The specified resource was not found
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-      deprecated: true
-    post:
-      tags:
-        - network-cm-proxy
-      summary: Create a node with descendants
-      description: Create a node with descendants for the given CM Handle; top level
-        or under existing node (requires xpath)
-      operationId: createNode
-      parameters:
-        - name: cm-handle
-          in: path
-          description: "The identifier for a network function, network element, subnetwork\
-          \ or any other cm object by managed Network CM Proxy"
-          required: true
-          schema:
-            type: string
-        - name: xpath
-          in: query
-          description: xpath
-          required: false
-          schema:
-            type: string
-            default: /
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: string
-        required: true
-      responses:
-        "201":
-          description: Created
-          content: {}
-        "400":
-          description: Bad Request
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "401":
-          description: Unauthorized
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "403":
-          description: Forbidden
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "404":
-          description: The specified resource was not found
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-      deprecated: true
-    patch:
-      tags:
-        - network-cm-proxy
-      summary: Update node leaves
-      description: Update node leaves for the given cps path and cm Handle
-      operationId: updateNodeLeaves
-      parameters:
-        - name: cm-handle
-          in: path
-          description: "The identifier for a network function, network element, subnetwork\
-          \ or any other cm object by managed Network CM Proxy"
-          required: true
-          schema:
-            type: string
-        - name: xpath
-          in: query
-          description: xpath
-          required: false
-          schema:
-            type: string
-            default: /
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: string
-        required: true
-      responses:
-        "200":
-          description: OK
-          content:
-            application/json:
-              schema:
-                type: object
-        "400":
-          description: Bad Request
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "401":
-          description: Unauthorized
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "403":
-          description: Forbidden
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-        "404":
-          description: The specified resource was not found
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-      deprecated: true
   /v1/ch/{cm-handle}/data/ds/ncmp-datastore:passthrough-operational:
     get:
       tags: