Merge "Springboot Integration tests improvements"
authorSourabh Sourabh <sourabh.sourabh@est.tech>
Thu, 26 Jan 2023 12:03:10 +0000 (12:03 +0000)
committerGerrit Code Review <gerrit@onap.org>
Thu, 26 Jan 2023 12:03:10 +0000 (12:03 +0000)
40 files changed:
INFO.yaml
cps-application/src/main/resources/application.yml
cps-ncmp-events/src/main/resources/schemas/avc-event-schema-v1.json [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.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/notifications/avc/AvcEventConsumer.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy
cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json [new file with mode: 0644]
cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/performance/CpsPathUtilPerfTest.groovy
cps-rest/docs/openapi/components.yml
cps-rest/docs/openapi/cpsData.yml
cps-rest/docs/openapi/cpsDataV1Deprecated.yml
cps-rest/docs/openapi/cpsDataV2.yml [new file with mode: 0644]
cps-rest/docs/openapi/cpsQueryV1Deprecated.yml [moved from cps-rest/docs/openapi/cpsQuery.yml with 94% similarity]
cps-rest/docs/openapi/cpsQueryV2.yml [new file with mode: 0644]
cps-rest/docs/openapi/openapi.yml
cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java
cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy
cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java [new file with mode: 0644]
cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java [new file with mode: 0644]
cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryMultiPathQueryImpl.java
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy
cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy
cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java
cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy
cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy
docs/api/swagger/cps/openapi.yaml
docs/api/swagger/ncmp/openapi-inventory.yaml
docs/api/swagger/ncmp/openapi.yaml

index ca4f250..cb44996 100755 (executable)
--- a/INFO.yaml
+++ b/INFO.yaml
@@ -47,21 +47,21 @@ meetings:
       time: '08:00 America/New_York'
 committers:
     - <<: *onap_releng_ptl
-    - name: 'Aditya Puthuparambil'
-      email: 'aditya.puthuparambil@bell.ca'
-      company: 'Bell Canada'
-      id: 'puthuparambil.aditya'
-      timezone: 'Europe/Dublin'
-    - name: 'Joseph Keenan'
-      email: 'joseph.keenan@est.tech'
-      company: 'Ericsson Software Technology'
-      id: 'JosephKeenan'
-      timezone: 'Europe/Dublin'
     - name: 'Sourabh Sharma'
       email: 'sourabh.sourabh@est.tech'
       company: 'Ericsson Software Technology'
       id: 'sourabh_sourabh'
       timezone: 'Europe/Dublin'
+    - name: 'Luke Gleeson'
+      email: 'luke.gleeson@est.tech'
+      company: 'Ericsson Software Technology'
+      id: 'lukegleeson'
+      timezone: 'Europe/Dublin'
+    - name: 'Priyank Maheshwari'
+      email: 'priyank.maheshwari@est.tech'
+      company: 'Ericsson Software Technology'
+      id: 'mpriyank'
+      timezone: 'Europe/Dublin'
 repositories:
     - cps
 tsc:
index b5b10b0..f7fe46e 100644 (file)
@@ -1,7 +1,7 @@
 #  ============LICENSE_START=======================================================\r
 #  Copyright (C) 2021 Pantheon.tech\r
 #  Modifications Copyright (C) 2021-2022 Bell Canada\r
-#  Modifications Copyright (C) 2021-2022 Nordix Foundation\r
+#  Modifications Copyright (C) 2021-2023 Nordix Foundation\r
 #  ================================================================================\r
 #  Licensed under the Apache License, Version 2.0 (the "License");\r
 #  you may not use this file except in compliance with the License.\r
@@ -84,16 +84,15 @@ spring:
             properties:\r
                 spring.deserializer.key.delegate.class: org.apache.kafka.common.serialization.StringDeserializer\r
                 spring.deserializer.value.delegate.class: org.springframework.kafka.support.serializer.JsonDeserializer\r
-                spring.json.value.default.type: org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent\r
                 spring.json.use.type.headers: false\r
 \r
     jackson:\r
-      default-property-inclusion: NON_NULL\r
-      serialization:\r
-        FAIL_ON_EMPTY_BEANS: false\r
+        default-property-inclusion: NON_NULL\r
+        serialization:\r
+            FAIL_ON_EMPTY_BEANS: false\r
     sql:\r
-      init:\r
-        mode: ALWAYS\r
+        init:\r
+            mode: ALWAYS\r
 app:\r
     ncmp:\r
         async-m2m:\r
@@ -104,6 +103,7 @@ app:
         events:\r
             topic: ${LCM_EVENTS_TOPIC:ncmp-events}\r
 \r
+\r
 notification:\r
     enabled: true\r
     data-updated:\r
diff --git a/cps-ncmp-events/src/main/resources/schemas/avc-event-schema-v1.json b/cps-ncmp-events/src/main/resources/schemas/avc-event-schema-v1.json
new file mode 100644 (file)
index 0000000..6db03f6
--- /dev/null
@@ -0,0 +1,57 @@
+{
+  "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "$id": "urn:cps:org.onap.cps.ncmp.events:avc-event-schema:v1",
+  "$ref": "#/definitions/AvcEvent",
+  "definitions": {
+    "AvcEvent": {
+      "description": "The payload for AVC event.",
+      "type": "object",
+      "properties": {
+        "eventId": {
+          "description": "The unique id identifying the event generated by DMI for this AVC event.",
+          "type": "string"
+        },
+        "eventCorrelationId": {
+          "description": "The request id passed by NCMP for this AVC event.",
+          "type": "string"
+        },
+        "eventTime": {
+          "description": "The time of the AVC event. The expected format is 'yyyy-MM-dd'T'HH:mm:ss.SSSZ'.",
+          "type": "string"
+        },
+        "eventTarget": {
+          "description": "The target of the AVC event.",
+          "type": "string"
+        },
+        "eventType": {
+          "description": "The type of the AVC event.",
+          "type": "string"
+        },
+        "eventSchema": {
+          "description": "The event schema for AVC events.",
+          "type": "string"
+        },
+        "eventSchemaVersion": {
+          "description": "The event schema version for AVC events.",
+          "type": "string"
+        },
+        "event": {
+        "$ref": "#/definitions/Event"
+        }
+      },
+      "required": [
+        "eventId",
+        "eventCorrelationId",
+        "eventTime",
+        "eventTarget",
+        "eventType",
+        "eventSchema",
+        "eventSchemaVersion"
+      ]
+    },
+    "Event": {
+      "description": "The AVC event content.",
+      "type": "object"
+    }
+  }
+}
\ No newline at end of file
index a9e7164..bc6624d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (c) 2022 Nordix Foundation.
+ * 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.
@@ -45,7 +45,9 @@ public class NcmpAsyncRequestResponseEventConsumer {
      *
      * @param dmiAsyncRequestResponseEvent the event to be consumed and produced.
      */
-    @KafkaListener(topics = "${app.ncmp.async-m2m.topic}")
+    @KafkaListener(
+            topics = "${app.ncmp.async-m2m.topic}",
+            properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent"})
     public void consumeAndForward(final DmiAsyncRequestResponseEvent dmiAsyncRequestResponseEvent) {
         log.debug("Consuming event {} ...", dmiAsyncRequestResponseEvent);
 
index 5c3cb60..ac2bd45 100644 (file)
@@ -38,7 +38,7 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 public class SynchronizationCacheConfig {
 
-    public static final int MODULE_SYNC_STARTED_TTL_SECS = 120;
+    public static final int MODULE_SYNC_STARTED_TTL_SECS = 600;
     public static final int DATA_SYNC_SEMAPHORE_TTL_SECS = 1800;
 
     private static final QueueConfig commonQueueConfig = createQueueConfig();
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java
new file mode 100644 (file)
index 0000000..79a36bf
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ============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.notifications.avc;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.event.model.AvcEvent;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for AVC events.
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true)
+public class AvcEventConsumer {
+
+    private final AvcEventProducer avcEventProducer;
+
+    /**
+     * Consume the specified event.
+     *
+     * @param avcEvent the event to be consumed and produced.
+     */
+    @KafkaListener(
+            topics = "dmi-cm-events",
+            properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.AvcEvent"})
+    public void consumeAndForward(final AvcEvent avcEvent) {
+        log.debug("Consuming AVC event {} ...", avcEvent);
+        avcEventProducer.sendMessage(avcEvent);
+    }
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java
new file mode 100644 (file)
index 0000000..531de46
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * ============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.notifications.avc;
+
+import java.util.UUID;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Named;
+import org.onap.cps.ncmp.event.model.AvcEvent;
+
+
+/**
+ * Mapper for converting incoming {@link AvcEvent} to outgoing {@link AvcEvent}.
+ */
+@Mapper(componentModel = "spring")
+public interface AvcEventMapper {
+
+    @Mapping(source = "eventTime", target = "eventTime")
+    @Mapping(source = "eventId", target = "eventId", qualifiedByName = "avcEventId")
+    @Mapping(source = "eventCorrelationId", target = "eventCorrelationId")
+    @Mapping(source = "eventSchema", target = "eventSchema")
+    @Mapping(source = "eventSchemaVersion", target = "eventSchemaVersion")
+    @Mapping(source = "eventTarget", target = "eventTarget")
+    @Mapping(source = "eventType", target = "eventType")
+    AvcEvent toOutgoingAvcEvent(AvcEvent incomingAvcEvent);
+
+    @Named("avcEventId")
+    static String getAvcEventId(String eventId) {
+        return UUID.randomUUID().toString();
+    }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java
new file mode 100644 (file)
index 0000000..049f661
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * ============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.notifications.avc;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.ncmp.event.model.AvcEvent;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Service;
+
+/**
+ * Producer for AVC events.
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class AvcEventProducer {
+
+    private final KafkaTemplate<String, AvcEvent> kafkaTemplate;
+
+    private final AvcEventMapper avcEventMapper;
+
+    /**
+     * Sends message to the configured topic with a message key.
+     *
+     * @param incomingAvcEvent message payload
+     */
+    public void sendMessage(final AvcEvent incomingAvcEvent) {
+        // generate new event id while keeping other data
+        final AvcEvent outgoingAvcEvent = avcEventMapper.toOutgoingAvcEvent(incomingAvcEvent);
+        log.debug("Forwarding AVC event {} to topic {} ", outgoingAvcEvent.getEventId(), "cm-events");
+        kafkaTemplate.send("cm-events", outgoingAvcEvent.getEventId(), outgoingAvcEvent);
+    }
+}
index 3fbebe0..d778afc 100644 (file)
@@ -71,13 +71,13 @@ public class ModuleSyncTasks {
                     moduleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle);
                     cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.READY);
                 } catch (final Exception e) {
-                    log.warn("Processing of {} module sync failed.", cmHandleId);
+                    log.warn("Processing of {} module sync failed due to reason {}.", cmHandleId, e.getMessage());
                     syncUtils.updateLockReasonDetailsAndAttempts(compositeState,
                             LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, e.getMessage());
                     setCmHandleStateLocked(yangModelCmHandle, compositeState.getLockReason());
                     cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED);
                 }
-                log.debug("{} is now in {} state", cmHandleId, compositeState.getCmHandleState().name());
+                log.info("{} is now in {} state", cmHandleId, compositeState.getCmHandleState().name());
             }
             lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandelStatePerCmHandle);
         } finally {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy
new file mode 100644 (file)
index 0000000..0089f77
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * ============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.notifications.avc
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.apache.kafka.clients.consumer.KafkaConsumer
+import org.mapstruct.factory.Mappers
+import org.onap.cps.ncmp.api.impl.async.NcmpAsyncRequestResponseEventMapper
+import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec
+import org.onap.cps.ncmp.event.model.AvcEvent
+import org.onap.cps.ncmp.utils.TestUtils
+import org.onap.cps.utils.JsonObjectMapper
+import org.spockframework.spring.SpringBean
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.annotation.DirtiesContext
+import org.testcontainers.spock.Testcontainers
+
+import java.time.Duration
+
+@SpringBootTest(classes = [AvcEventProducer, AvcEventConsumer, ObjectMapper, JsonObjectMapper])
+@Testcontainers
+@DirtiesContext
+class AvcEventProducerIntegrationSpec extends MessagingBaseSpec {
+
+    @SpringBean
+    AvcEventMapper avcEventMapper = Mappers.getMapper(AvcEventMapper.class)
+
+    @SpringBean
+    AvcEventProducer avcEventProducer = new AvcEventProducer(kafkaTemplate, avcEventMapper)
+
+    @SpringBean
+    AvcEventConsumer acvEventConsumer = new AvcEventConsumer(avcEventProducer)
+
+    @Autowired
+    JsonObjectMapper jsonObjectMapper
+
+    def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group'))
+
+    def 'Consume and forward valid message'() {
+        given: 'consumer has a subscription'
+            kafkaConsumer.subscribe(['cm-events'] as List<String>)
+        and: 'an event is sent'
+            def jsonData = TestUtils.getResourceFileContent('sampleAvcInputEvent.json')
+            def testEventSent = jsonObjectMapper.convertJsonString(jsonData, AvcEvent.class)
+        when: 'the event is consumed'
+            acvEventConsumer.consumeAndForward(testEventSent)
+        and: 'the topic is polled'
+            def records = kafkaConsumer.poll(Duration.ofMillis(1500))
+        then: 'poll returns one record'
+            assert records.size() == 1
+        and: 'record can be converted to AVC event'
+            def record = records.iterator().next()
+            def convertedAvcEvent = jsonObjectMapper.convertJsonString(record.value(), AvcEvent)
+        and: 'consumed forwarded NCMP event id differs from DMI event id'
+            assert testEventSent.eventId != convertedAvcEvent.getEventId()
+        and: 'correlation id matches'
+            assert testEventSent.eventCorrelationId == convertedAvcEvent.getEventCorrelationId()
+        and: 'timestamps match'
+            assert testEventSent.eventTime == convertedAvcEvent.getEventTime()
+        and: 'target matches'
+            assert testEventSent.eventTarget == convertedAvcEvent.getEventTarget()
+    }
+
+}
\ No newline at end of file
index f7c41ec..bb0ce87 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (c) 2022 Nordix Foundation.
+ * 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.
@@ -33,14 +33,14 @@ import spock.lang.Specification
 
 class MessagingBaseSpec extends Specification {
 
-    static {
-        Runtime.getRuntime().addShutdownHook(new Thread(kafkaTestContainer::stop))
-    }
-
     def setupSpec() {
         kafkaTestContainer.start()
     }
 
+    def cleanupSpec() {
+        kafkaTestContainer.stop()
+    }
+
     static kafkaTestContainer = new KafkaContainer(DockerImageName.parse('registry.nordix.org/onaptest/confluentinc/cp-kafka:6.2.1').asCompatibleSubstituteFor('confluentinc/cp-kafka'))
 
     def producerConfigProperties() {
diff --git a/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json b/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json
new file mode 100644 (file)
index 0000000..d7d252b
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "eventId": "4cb32729-85e3-44d1-aa6e-c923b9b059a5",
+  "eventCorrelationId": "68f15800-8ed4-4bae-9e53-27a9e03e1911",
+  "eventTime": "2022-12-12T14:29:23.876+0000",
+  "eventTarget": "NCMP",
+  "eventType": "org.onap.cps.ncmp.event.model.AvcEvent",
+  "eventSchema": "urn:cps:org.onap.cps.ncmp.event.model.AvcEvent",
+  "eventSchemaVersion": "v1",
+  "event": {
+    "payload": "Hello world!"
+  }
+}
\ No newline at end of file
index e5e304b..1dfd194 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.
@@ -35,9 +35,8 @@ class CpsPathUtilPerfTest extends Specification {
                 CpsPathUtil.getNormalizedXpath('//child[@other-leaf=1]/leaf-name[text()="search"]/ancestor::parent')
             }
             stopWatch.stop()
-        then: 'it takes less then 1,100 milliseconds'
-            // In CI this actually takes about 0.3-0.5 sec  which  is approx. 50+ parser executions per millisecond!
-            assert stopWatch.getTotalTimeMillis() < 1100
+        then: 'it takes less then 2100 milliseconds'
+            assert stopWatch.getTotalTimeMillis() < 2100
     }
 
 }
index e700da6..60b4ca3 100644 (file)
@@ -1,7 +1,7 @@
 # ============LICENSE_START=======================================================
 # Copyright (c) 2021-2022 Bell Canada.
 # Modifications Copyright (C) 2021-2022 Nordix Foundation
-# Modifications Copyright (C) 2022 TechMahindra Ltd.
+# Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
 # Modifications Copyright (C) 2022 Deutsche Telekom AG
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -240,6 +240,15 @@ components:
         type: string
         example: 'application/json'
       required: true
+    descendantsInQuery:
+      name: descendants
+      in: query
+      description: descendents to query depth of children. allowed values are none, all, any number starting from -1
+      required: false
+      schema:
+        type: string
+        default: none
+        example: 3
 
   responses:
     NotFound:
index 0dc3887..1d60e1f 100644 (file)
@@ -1,7 +1,7 @@
 # ============LICENSE_START=======================================================
 # Copyright (c) 2021-2022 Bell Canada.
 # Modifications Copyright (C) 2021-2022 Nordix Foundation
-# Modifications Copyright (C) 2022 TechMahindra Ltd.
+# Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
 # Modifications Copyright (C) 2022 Deutsche Telekom AG
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 
-nodeByDataspaceAndAnchor:
-  get:
-    description: Get a node with an option to retrieve all the children for a given anchor and dataspace
-    tags:
-      - cps-data
-    summary: Get a node
-    operationId: getNodeByDataspaceAndAnchor
-    parameters:
-      - $ref: 'components.yml#/components/parameters/apiVersionInPath'
-      - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
-      - $ref: 'components.yml#/components/parameters/anchorNameInPath'
-      - $ref: 'components.yml#/components/parameters/xpathInQuery'
-      - $ref: 'components.yml#/components/parameters/includeDescendantsOptionInQuery'
-    responses:
-      '200':
-        description: OK
-        content:
-          application/json:
-            schema:
-              type: object
-            examples:
-              dataSample:
-                $ref: 'components.yml#/components/examples/dataSample'
-      '400':
-        $ref: 'components.yml#/components/responses/BadRequest'
-      '401':
-        $ref: 'components.yml#/components/responses/Unauthorized'
-      '403':
-        $ref: 'components.yml#/components/responses/Forbidden'
-      '500':
-        $ref: 'components.yml#/components/responses/InternalServerError'
-    x-codegen-request-body-name: xpath
-
 listElementByDataspaceAndAnchor:
   post:
     description: Add list element(s) to a list for a given anchor and dataspace
index 194ca3e..67ddecd 100644 (file)
@@ -1,5 +1,5 @@
 # ============LICENSE_START=======================================================
-# Copyright (C) 2022 TechMahindra Ltd.
+# Copyright (C) 2022-2023 TechMahindra Ltd.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 
+nodeByDataspaceAndAnchor:
+  get:
+    description: Get a node with an option to retrieve all the children for a given anchor and dataspace
+    deprecated: true
+    tags:
+      - cps-data
+    summary: Get a node
+    operationId: getNodeByDataspaceAndAnchor
+    parameters:
+      - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+      - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+      - $ref: 'components.yml#/components/parameters/xpathInQuery'
+      - $ref: 'components.yml#/components/parameters/includeDescendantsOptionInQuery'
+    responses:
+      '200':
+        description: OK
+        content:
+          application/json:
+            schema:
+              type: object
+            examples:
+              dataSample:
+                $ref: 'components.yml#/components/examples/dataSample'
+      '400':
+        $ref: 'components.yml#/components/responses/BadRequest'
+      '401':
+        $ref: 'components.yml#/components/responses/Unauthorized'
+      '403':
+        $ref: 'components.yml#/components/responses/Forbidden'
+      '500':
+        $ref: 'components.yml#/components/responses/InternalServerError'
+    x-codegen-request-body-name: xpath
+
 listElementByDataspaceAndAnchor:
   delete:
     description: Delete one or all list element(s) for a given anchor and dataspace
diff --git a/cps-rest/docs/openapi/cpsDataV2.yml b/cps-rest/docs/openapi/cpsDataV2.yml
new file mode 100644 (file)
index 0000000..61663ab
--- /dev/null
@@ -0,0 +1,49 @@
+# ============LICENSE_START=======================================================
+# Copyright (c) 2022-2023 TechMahindra Ltd.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+
+nodeByDataspaceAndAnchor:
+  get:
+    description: Get a node with an option to retrieve all the children for a given anchor and dataspace
+    tags:
+      - cps-data
+    summary: Get a node
+    operationId: getNodeByDataspaceAndAnchorV2
+    parameters:
+      - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+      - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+      - $ref: 'components.yml#/components/parameters/xpathInQuery'
+      - $ref: 'components.yml#/components/parameters/descendantsInQuery'
+    responses:
+      '200':
+        description: OK
+        content:
+          application/json:
+            schema:
+              type: object
+            examples:
+              dataSample:
+                $ref: 'components.yml#/components/examples/dataSample'
+      '400':
+        $ref: 'components.yml#/components/responses/BadRequest'
+      '401':
+        $ref: 'components.yml#/components/responses/Unauthorized'
+      '403':
+        $ref: 'components.yml#/components/responses/Forbidden'
+      '500':
+        $ref: 'components.yml#/components/responses/InternalServerError'
+    x-codegen-request-body-name: xpath
similarity index 94%
rename from cps-rest/docs/openapi/cpsQuery.yml
rename to cps-rest/docs/openapi/cpsQueryV1Deprecated.yml
index 45fc70c..6ec117f 100644 (file)
@@ -1,7 +1,7 @@
 #  ============LICENSE_START=======================================================
 #  Copyright (C) 2021 Nordix Foundation
 #  Modifications Copyright (c) 2022 Bell Canada.
-#  Modifications Copyright (c) 2022 TechMahindra Ltd.
+#  Modifications Copyright (c) 2023 TechMahindra Ltd.
 #  ================================================================================
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -24,9 +24,9 @@ nodesByDataspaceAndAnchorAndCpsPath:
     tags:
       - cps-query
     summary: Query data nodes
+    deprecated: true
     operationId: getNodesByDataspaceAndAnchorAndCpsPath
     parameters:
-      - $ref: 'components.yml#/components/parameters/apiVersionInPath'
       - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
       - $ref: 'components.yml#/components/parameters/anchorNameInPath'
       - $ref: 'components.yml#/components/parameters/cpsPathInQuery'
diff --git a/cps-rest/docs/openapi/cpsQueryV2.yml b/cps-rest/docs/openapi/cpsQueryV2.yml
new file mode 100644 (file)
index 0000000..5bfd1bb
--- /dev/null
@@ -0,0 +1,49 @@
+#  ============LICENSE_START=======================================================
+#  Copyright (C) 2023 TechMahindra Ltd.
+#  ================================================================================
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+
+nodesByDataspaceAndAnchorAndCpsPath:
+  get:
+    description: Query data nodes for the given dataspace and anchor using CPS path
+    tags:
+      - cps-query
+    summary: Query data nodes
+    operationId: getNodesByDataspaceAndAnchorAndCpsPathV2
+    parameters:
+      - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+      - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+      - $ref: 'components.yml#/components/parameters/cpsPathInQuery'
+      - $ref: 'components.yml#/components/parameters/descendantsInQuery'
+    responses:
+      '200':
+        description: OK
+        content:
+          application/json:
+            schema:
+              type: object
+            examples:
+              dataSample:
+                $ref: 'components.yml#/components/examples/dataSample'
+      '400':
+        $ref: 'components.yml#/components/responses/BadRequest'
+      '401':
+        $ref: 'components.yml#/components/responses/Unauthorized'
+      '403':
+        $ref: 'components.yml#/components/responses/Forbidden'
+      '500':
+        $ref: 'components.yml#/components/responses/InternalServerError'
+    x-codegen-request-body-name: xpath
index 0918b56..0ac825a 100644 (file)
@@ -2,7 +2,7 @@
 #  Copyright (C) 2021 Nordix Foundation
 #  Modifications Copyright (C) 2021 Pantheon.tech
 #  Modifications Copyright (C) 2021 Bell Canada.
-#  Modifications Copyright (C) 2022 TechMahindra Ltd.
+#  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
 #  ================================================================================
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -89,8 +89,11 @@ paths:
   /{apiVersion}/dataspaces/{dataspace-name}/schema-sets/{schema-set-name}:
     $ref: 'cpsAdmin.yml#/schemaSetBySchemaSetName'
 
-  /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
-    $ref: 'cpsData.yml#/nodeByDataspaceAndAnchor'
+  /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
+    $ref: 'cpsDataV1Deprecated.yml#/nodeByDataspaceAndAnchor'
+
+  /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
+    $ref: 'cpsDataV2.yml#/nodeByDataspaceAndAnchor'
 
   /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes:
     $ref: 'cpsData.yml#/nodesByDataspaceAndAnchor'
@@ -101,8 +104,11 @@ paths:
   /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
     $ref: 'cpsData.yml#/listElementByDataspaceAndAnchor'
 
-  /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
-    $ref: 'cpsQuery.yml#/nodesByDataspaceAndAnchorAndCpsPath'
+  /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
+    $ref: 'cpsQueryV1Deprecated.yml#/nodesByDataspaceAndAnchorAndCpsPath'
+
+  /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
+    $ref: 'cpsQueryV2.yml#/nodesByDataspaceAndAnchorAndCpsPath'
 
 security:
   - basicAuth: []
index 30bed12..3a9c764 100755 (executable)
@@ -3,7 +3,7 @@
  *  Copyright (C) 2020-2022 Bell Canada.
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Nordix Foundation
- *  Modifications Copyright (C) 2022 TechMahindra Ltd.
+ *  Modifications Copyright (C) 2023 TechMahindra Ltd.
  *  Modifications Copyright (C) 2022 Deutsche Telekom AG
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
@@ -93,8 +93,8 @@ public class DataRestController implements CpsDataApi {
     }
 
     @Override
-    public ResponseEntity<Object> getNodeByDataspaceAndAnchor(final String apiVersion,
-        final String dataspaceName, final String anchorName, final String xpath, final Boolean includeDescendants) {
+    public ResponseEntity<Object> getNodeByDataspaceAndAnchor(final String dataspaceName,
+        final String anchorName, final String xpath, final Boolean includeDescendants) {
         final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
             ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
         final DataNode dataNode = cpsDataService.getDataNode(dataspaceName, anchorName, xpath,
@@ -103,6 +103,17 @@ public class DataRestController implements CpsDataApi {
         return new ResponseEntity<>(DataMapUtils.toDataMapWithIdentifier(dataNode, prefix), HttpStatus.OK);
     }
 
+    @Override
+    public ResponseEntity<Object> getNodeByDataspaceAndAnchorV2(final String dataspaceName, final String anchorName,
+        final String xpath, final String fetchDescendantsOptionAsString) {
+        final FetchDescendantsOption fetchDescendantsOption =
+            FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString);
+        final DataNode dataNode = cpsDataService.getDataNode(dataspaceName, anchorName, xpath,
+            fetchDescendantsOption);
+        final String prefix = prefixResolver.getPrefix(dataspaceName, anchorName, xpath);
+        return new ResponseEntity<>(DataMapUtils.toDataMapWithIdentifier(dataNode, prefix), HttpStatus.OK);
+    }
+
     @Override
     public ResponseEntity<Object> updateNodeLeaves(final String apiVersion, final String dataspaceName,
         final String anchorName, final Object jsonData, final String parentNodeXpath, final String observedTimestamp) {
@@ -151,4 +162,5 @@ public class DataRestController implements CpsDataApi {
                 String.format("observed-timestamp must be in '%s' format", ISO_TIMESTAMP_FORMAT));
         }
     }
+
 }
index 3e162ae..81938dc 100644 (file)
@@ -2,7 +2,7 @@
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2022 Bell Canada.
- *  Modifications Copyright (C) 2022 TechMahindra Ltd.
+ *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -49,22 +49,36 @@ public class QueryRestController implements CpsQueryApi {
     private final PrefixResolver prefixResolver;
 
     @Override
-    public ResponseEntity<Object> getNodesByDataspaceAndAnchorAndCpsPath(final String apiVersion,
-        final String dataspaceName, final String anchorName, final String cpsPath, final Boolean includeDescendants) {
+    public ResponseEntity<Object> getNodesByDataspaceAndAnchorAndCpsPath(final String dataspaceName,
+        final String anchorName, final String cpsPath, final Boolean includeDescendants) {
         final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
             ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
+        return executeNodesByDataspaceQueryAndCreateResponse(dataspaceName, anchorName, cpsPath,
+                fetchDescendantsOption);
+    }
+
+    @Override
+    public ResponseEntity<Object> getNodesByDataspaceAndAnchorAndCpsPathV2(final String dataspaceName,
+        final String anchorName, final String cpsPath, final String fetchDescendantsOptionAsString) {
+        final FetchDescendantsOption fetchDescendantsOption =
+            FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString);
+        return executeNodesByDataspaceQueryAndCreateResponse(dataspaceName, anchorName, cpsPath,
+                fetchDescendantsOption);
+    }
+
+    private ResponseEntity<Object> executeNodesByDataspaceQueryAndCreateResponse(final String dataspaceName,
+             final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) {
         final Collection<DataNode> dataNodes =
             cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption);
-        final List<Map<String, Object>> dataMaps = new ArrayList<>(dataNodes.size());
+        final List<Map<String, Object>> dataNodesAsListOfMaps = new ArrayList<>(dataNodes.size());
         String prefix = null;
         for (final DataNode dataNode : dataNodes) {
             if (prefix == null) {
                 prefix = prefixResolver.getPrefix(dataspaceName, anchorName, dataNode.getXpath());
             }
             final Map<String, Object> dataMap = DataMapUtils.toDataMapWithIdentifier(dataNode, prefix);
-            dataMaps.add(dataMap);
+            dataNodesAsListOfMaps.add(dataMap);
         }
-
-        return new ResponseEntity<>(jsonObjectMapper.asJsonString(dataMaps), HttpStatus.OK);
+        return new ResponseEntity<>(jsonObjectMapper.asJsonString(dataNodesAsListOfMaps), HttpStatus.OK);
     }
 }
index 94f62f8..16d106b 100755 (executable)
@@ -4,6 +4,7 @@
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
  *  Modifications Copyright (C) 2022 Deutsche Telekom AG
+ *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -68,6 +69,7 @@ class DataRestControllerSpec extends Specification {
     def basePath
 
     def dataNodeBaseEndpoint
+    def dataNodeBaseEndpointV2
     def dataspaceName = 'my_dataspace'
     def anchorName = 'my_anchor'
     def noTimestamp = null
@@ -94,6 +96,7 @@ class DataRestControllerSpec extends Specification {
 
     def setup() {
         dataNodeBaseEndpoint = "$basePath/v1/dataspaces/$dataspaceName"
+        dataNodeBaseEndpointV2 = "$basePath/v2/dataspaces/$dataspaceName"
     }
 
     def 'Create a node: #scenario.'() {
@@ -237,6 +240,28 @@ class DataRestControllerSpec extends Specification {
             'with descendants'          | dataNodeWithChild            | 'true'                   || INCLUDE_ALL_DESCENDANTS      | true                  | 'parent'
     }
 
+
+    def 'Get data node using v2 api'() {
+        given: 'the service returns data node'
+            def xpath = 'some xPath'
+            def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/node"
+            mockCpsDataService.getDataNode(dataspaceName, anchorName, xpath, {descendantsOption -> {
+                assert descendantsOption.depth == 2}}) >> dataNodeWithChild
+        when: 'get request is performed through REST API'
+            def response =
+                mvc.perform(
+                        get(endpoint)
+                                .param('xpath', xpath)
+                                .param('descendants', '2'))
+                        .andReturn().response
+        then: 'a success response is returned'
+            assert response.status == HttpStatus.OK.value()
+        and: 'the response contains the root node identifier'
+            assert response.contentAsString.contains('parent')
+        and: 'the response contains child is true'
+            assert response.contentAsString.contains('"child"') == true
+    }
+
     def 'Update data node leaves: #scenario.'() {
         given: 'endpoint to update a node '
             def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes"
index 27ca0cc..b881c38 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
  *  Modifications Copyright (C) 2021 Pantheon.tech
+ *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -58,13 +59,19 @@ class QueryRestControllerSpec extends Specification {
     @Value('${rest.api.cps-base-path}')
     def basePath
 
+    def dataspaceName = 'my_dataspace'
+    def anchorName = 'my_anchor'
+    def cpsPath = 'some cps-path'
+    def dataNodeEndpointV2
+
+    def setup() {
+         dataNodeEndpointV2 = "$basePath/v2/dataspaces/$dataspaceName/anchors/$anchorName/nodes/query"
+    }
+
     def 'Query data node by cps path for the given dataspace and anchor with #scenario.'() {
         given: 'service method returns a list containing a data node'
              def dataNode1 = new DataNodeBuilder().withXpath('/xpath')
                     .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
-            def dataspaceName = 'my_dataspace'
-            def anchorName = 'my_anchor'
-            def cpsPath = 'some cps-path'
             mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, expectedCpsDataServiceOption) >> [dataNode1, dataNode1]
         and: 'the query endpoint'
             def dataNodeEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName/nodes/query"
@@ -84,4 +91,23 @@ class QueryRestControllerSpec extends Specification {
             'no descendant explicitly'  | 'false'                  || OMIT_DESCENDANTS
             'descendants'               | 'true'                   || INCLUDE_ALL_DESCENDANTS
     }
+
+   def 'Query data node v2 api by cps path for the given dataspace and anchor with #scenario.'() {
+        given: 'service method returns a list containing a data node'
+            def dataNode1 = new DataNodeBuilder().withXpath('/xpath')
+                .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build()
+            mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, { descendantsOption -> {
+                    assert descendantsOption.depth == 2}}) >> [dataNode1, dataNode1]
+        when: 'query data nodes API is invoked'
+            def response =
+                mvc.perform(
+                        get(dataNodeEndpointV2)
+                                .param('cps-path', cpsPath)
+                                .param('descendants', '2'))
+                        .andReturn().response
+        then: 'the response contains the the datanode in json format'
+            assert response.status == HttpStatus.OK.value()
+            assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}')
+    }
+
 }
index 2fdfa05..2ffbb4a 100755 (executable)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- * Copyright (C) 2020 Nordix Foundation.
+ * Copyright (C) 2020-2023 Nordix Foundation.
  * Modifications Copyright (C) 2021 Pantheon.tech
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,6 +40,7 @@ import javax.validation.constraints.NotNull;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
@@ -58,6 +59,7 @@ import org.hibernate.annotations.TypeDef;
 @Entity
 @Table(name = "fragment")
 @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
 public class FragmentEntity implements Serializable {
 
     private static final long serialVersionUID = 7737669789097119667L;
@@ -68,6 +70,7 @@ public class FragmentEntity implements Serializable {
 
     @NotNull
     @Column(columnDefinition = "text")
+    @EqualsAndHashCode.Include
     private String xpath;
 
     @Column(name = "parent_id")
index 5b0683e..d2b7273 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2023 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2020-2022 Bell Canada.
  *  Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -61,6 +61,7 @@ import org.onap.cps.spi.model.DataNode;
 import org.onap.cps.spi.model.DataNodeBuilder;
 import org.onap.cps.spi.repository.AnchorRepository;
 import org.onap.cps.spi.repository.DataspaceRepository;
+import org.onap.cps.spi.repository.FragmentNativeRepository;
 import org.onap.cps.spi.repository.FragmentQueryBuilder;
 import org.onap.cps.spi.repository.FragmentRepository;
 import org.onap.cps.spi.utils.SessionManager;
@@ -78,6 +79,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     private final FragmentRepository fragmentRepository;
     private final JsonObjectMapper jsonObjectMapper;
     private final SessionManager sessionManager;
+    private final FragmentNativeRepository fragmentNativeRepositoryImpl;
 
     private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?]){0,1})";
 
@@ -262,13 +264,28 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                                              final FetchDescendantsOption fetchDescendantsOption) {
         final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
         final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
-        final List<FragmentEntity> fragmentEntities =
-                fragmentRepository.findByAnchorAndMultipleCpsPaths(anchorEntity.getId(), xpaths);
-        final Collection<DataNode> dataNodesCollection = new ArrayList<>(fragmentEntities.size());
-        for (final FragmentEntity fragmentEntity : fragmentEntities) {
-            dataNodesCollection.add(toDataNode(fragmentEntity, fetchDescendantsOption));
+
+        final Collection<String> nonRootXpaths = new HashSet<>(xpaths);
+        final boolean haveRootXpath = nonRootXpaths.removeIf(CpsDataPersistenceServiceImpl::isRootXpath);
+
+        final Collection<String> normalizedXpaths = new HashSet<>(nonRootXpaths.size());
+        for (final String xpath : nonRootXpaths) {
+            try {
+                normalizedXpaths.add(CpsPathUtil.getNormalizedXpath(xpath));
+            } catch (final PathParsingException e) {
+                log.warn("Error parsing xpath \"{}\" in getDataNodes: {}", xpath, e.getMessage());
+            }
+        }
+        final Collection<FragmentEntity> fragmentEntities =
+            new HashSet<>(fragmentRepository.findByAnchorAndMultipleCpsPaths(anchorEntity.getId(), normalizedXpaths));
+
+        if (haveRootXpath) {
+            final List<FragmentExtract> fragmentExtracts = fragmentRepository.getTopLevelFragments(dataspaceEntity,
+                anchorEntity);
+            fragmentEntities.addAll(FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts));
         }
-        return dataNodesCollection;
+
+        return toDataNodes(fragmentEntities, fetchDescendantsOption);
     }
 
     private FragmentEntity getFragmentWithoutDescendantsByXpath(final String dataspaceName,
@@ -449,6 +466,15 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                 .withChildDataNodes(childDataNodes).build();
     }
 
+    private Collection<DataNode> toDataNodes(final Collection<FragmentEntity> fragmentEntities,
+                                             final FetchDescendantsOption fetchDescendantsOption) {
+        final Collection<DataNode> dataNodes = new ArrayList<>(fragmentEntities.size());
+        for (final FragmentEntity fragmentEntity : fragmentEntities) {
+            dataNodes.add(toDataNode(fragmentEntity, fetchDescendantsOption));
+        }
+        return dataNodes;
+    }
+
     private List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity,
                                              final FetchDescendantsOption fetchDescendantsOption) {
         if (fetchDescendantsOption.hasNext()) {
@@ -630,7 +656,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
     private boolean deleteDataNode(final FragmentEntity parentFragmentEntity, final String targetXpath) {
         final String normalizedTargetXpath = CpsPathUtil.getNormalizedXpath(targetXpath);
         if (parentFragmentEntity.getXpath().equals(normalizedTargetXpath)) {
-            fragmentRepository.delete(parentFragmentEntity);
+            fragmentNativeRepositoryImpl.deleteFragmentEntity(parentFragmentEntity.getId());
             return true;
         }
         if (parentFragmentEntity.getChildFragments()
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java
new file mode 100644 (file)
index 0000000..4cfd79d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  ============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.spi.repository;
+
+/**
+ * This interface is used in delete fragment entity by id with child using native sql queries.
+ */
+public interface FragmentNativeRepository {
+    void deleteFragmentEntity(long fragmentEntityId);
+}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
new file mode 100644 (file)
index 0000000..57dca56
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  ============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.spi.repository;
+
+import java.sql.PreparedStatement;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import org.hibernate.Session;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class FragmentNativeRepositoryImpl implements FragmentNativeRepository {
+
+    private static final String DROP_FRAGMENT_CONSTRAINT
+            = "ALTER TABLE fragment DROP CONSTRAINT fragment_parent_id_fkey;";
+    private static final String ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
+            = "ALTER TABLE fragment ADD CONSTRAINT fragment_parent_id_fkey FOREIGN KEY (parent_id) "
+            + "REFERENCES fragment (id) ON DELETE CASCADE;";
+    private static final String DELETE_FRAGMENT = "DELETE FROM fragment WHERE id =?;";
+    private static final String ADD_ORIGINAL_FRAGMENT_CONSTRAINT
+            = "ALTER TABLE fragment ADD CONSTRAINT fragment_parent_id_fkey FOREIGN KEY (parent_id) "
+            + "REFERENCES fragment (id) ON DELETE NO ACTION;";
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @Override
+    public void deleteFragmentEntity(final long fragmentEntityId) {
+        final Session session = entityManager.unwrap(Session.class);
+        session.doWork(connection -> {
+            try (PreparedStatement preparedStatement = connection.prepareStatement(
+                    DROP_FRAGMENT_CONSTRAINT
+                            + ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
+                            + DELETE_FRAGMENT
+                            + DROP_FRAGMENT_CONSTRAINT
+                            + ADD_ORIGINAL_FRAGMENT_CONSTRAINT)) {
+                preparedStatement.setLong(1, fragmentEntityId);
+                preparedStatement.executeUpdate();
+            }
+        });
+    }
+}
+
index b936e5c..8c357bb 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.
@@ -23,6 +23,7 @@ package org.onap.cps.spi.repository;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import javax.persistence.EntityManager;
@@ -46,6 +47,9 @@ public class FragmentRepositoryMultiPathQueryImpl implements FragmentRepositoryM
     @Transactional
     public List<FragmentEntity> findByAnchorAndMultipleCpsPaths(final Integer anchorId,
                                                                 final Collection<String> cpsPathQueryList) {
+        if (cpsPathQueryList.isEmpty()) {
+            return Collections.emptyList();
+        }
         final Collection<List<String>> sqlData = new HashSet<>(cpsPathQueryList.size());
         for (final String query : cpsPathQueryList) {
             final List<String> row = new ArrayList<>(1);
index b6d2c5d..ba8425f 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021 Bell Canada.
+ *  Modifications Copyright (C) 2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,6 +23,7 @@
 package org.onap.cps.spi.impl
 
 import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.exceptions.CpsPathException
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.test.context.jdbc.Sql
@@ -41,7 +43,7 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase {
     @Sql([CLEAR_DATA, SET_DATA])
     def 'Cps Path query for leaf value(s) with : #scenario.'() {
         when: 'a query is executed to get a data node by the given cps path'
-            def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_SHOP_EXAMPLE, cpsPath, includeDescendantsOption)
+            def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_SHOP_EXAMPLE, cpsPath, fetchDescendantsOption)
         then: 'the correct number of parent nodes are returned'
             result.size() == expectedNumberOfParentNodes
         then: 'the correct data is returned'
@@ -49,10 +51,12 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase {
                 assert it.getChildDataNodes().size() == expectedNumberOfChildNodes
             }
         where: 'the following data is used'
-            scenario                      | cpsPath                                                      | includeDescendantsOption || expectedNumberOfParentNodes | expectedNumberOfChildNodes
-            'String and no descendants'   | '/shops/shop[@id=1]/categories[@code=1]/book[@title="Dune"]' | OMIT_DESCENDANTS         || 1                           | 0
-            'Integer and descendants'     | '/shops/shop[@id=1]/categories[@code=1]/book[@price=5]'      | INCLUDE_ALL_DESCENDANTS  || 1                           | 1
-            'No condition no descendants' | '/shops/shop[@id=1]/categories'                              | OMIT_DESCENDANTS         || 3                           | 0
+            scenario                          | cpsPath                                                      | fetchDescendantsOption         || expectedNumberOfParentNodes | expectedNumberOfChildNodes
+            'String and no descendants'       | '/shops/shop[@id=1]/categories[@code=1]/book[@title="Dune"]' | OMIT_DESCENDANTS               || 1                           | 0
+            'Integer and descendants'         | '/shops/shop[@id=1]/categories[@code=1]/book[@price=5]'      | INCLUDE_ALL_DESCENDANTS        || 1                           | 1
+            'No condition no descendants'     | '/shops/shop[@id=1]/categories'                              | OMIT_DESCENDANTS               || 3                           | 0
+            'Integer and level 1 descendants' | '/shops'                                                     | new FetchDescendantsOption(1)  || 1                           | 5
+            'Integer and level 2 descendants' | '/shops/shop[@id=1]'                                         | new FetchDescendantsOption(2)  || 1                           | 3
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
index cc2369d..5f48469 100755 (executable)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2023 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
  *  Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -20,6 +20,7 @@
  *  SPDX-License-Identifier: Apache-2.0
  *  ============LICENSE_END=========================================================
  */
+
 package org.onap.cps.spi.impl
 
 import com.fasterxml.jackson.databind.ObjectMapper
@@ -295,6 +296,44 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase {
             'invalid xpath'          | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | 'INVALID XPATH' || CpsPathException
     }
 
+    @Sql([CLEAR_DATA, SET_DATA])
+    def 'Get multiple data nodes by xpath.'() {
+        when: 'fetch #scenario.'
+            def results = objectUnderTest.getDataNodes(DATASPACE_NAME, ANCHOR_NAME3, inputXpaths, OMIT_DESCENDANTS)
+        then: 'the expected number of data nodes are returned'
+            assert results.size() == expectedResultSize
+        where: 'following parameters were used'
+            scenario                               | inputXpaths                                     || expectedResultSize
+            '0 nodes'                              | []                                              || 0
+            '1 node'                               | ["/parent-200"]                                 || 1
+            '2 unique nodes'                       | ["/parent-200", "/parent-201"]                  || 2
+            '3 unique nodes'                       | ["/parent-200", "/parent-201", "/parent-202"]   || 3
+            '1 unique node with duplicate xpath'   | ["/parent-200", "/parent-200"]                  || 1
+            '2 unique nodes with duplicate xpath'  | ["/parent-200", "/parent-202", "/parent-200"]   || 2
+            'list element with key (single quote)' | ["/parent-201/child-204[@key='A']"]             || 1
+            'list element with key (double quote)' | ['/parent-201/child-204[@key="A"]']             || 1
+            'non-existing xpath'                   | ["/NO-XPATH"]                                   || 0
+            'existing and non-existing xpaths'     | ["/parent-200", "/NO-XPATH", "/parent-201"]     || 2
+            'invalid xpath'                        | ["INVALID XPATH"]                               || 0
+            'valid and invalid xpaths'             | ["/parent-200", "INVALID XPATH", "/parent-201"] || 2
+            'root xpath'                           | ["/"]                                           || 7
+            'empty (root) xpath'                   | [""]                                            || 7
+            'root and top-level xpaths'            | ["/", "/parent-200", "/parent-201"]             || 7
+            'root and child xpaths'                | ["/", "/parent-200/child-201"]                  || 8
+    }
+
+    @Sql([CLEAR_DATA, SET_DATA])
+    def 'Get multiple data nodes error scenario: #scenario.'() {
+        when: 'attempt to get data nodes with #scenario'
+            objectUnderTest.getDataNodes(dataspaceName, anchorName, ['/not-relevant'], OMIT_DESCENDANTS)
+        then: 'a #expectedException is thrown'
+            thrown(expectedException)
+        where: 'the following data is used'
+            scenario                 | dataspaceName  | anchorName     || expectedException
+            'non-existing dataspace' | 'NO DATASPACE' | 'not relevant' || DataspaceNotFoundException
+            'non-existing anchor'    | DATASPACE_NAME | 'NO ANCHOR'    || AnchorNotFoundException
+    }
+
     @Sql([CLEAR_DATA, SET_DATA])
     def 'Update data node leaves.'() {
         when: 'update is performed for leaves'
index 01c1dc7..5dab87e 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * ============LICENSE_START=======================================================
  * Copyright (c) 2021 Bell Canada.
- * Modifications Copyright (C) 2021-2022 Nordix Foundation
- *  Modifications Copyright (C) 2022 TechMahindra Ltd.
+ * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2022 TechMahindra Ltd.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@ import org.onap.cps.spi.model.DataNode
 import org.onap.cps.spi.model.DataNodeBuilder
 import org.onap.cps.spi.repository.AnchorRepository
 import org.onap.cps.spi.repository.DataspaceRepository
+import org.onap.cps.spi.repository.FragmentNativeRepository
 import org.onap.cps.spi.repository.FragmentRepository
 import org.onap.cps.spi.utils.SessionManager
 import org.onap.cps.utils.JsonObjectMapper
@@ -45,8 +46,10 @@ class CpsDataPersistenceServiceSpec extends Specification {
     def mockFragmentRepository = Mock(FragmentRepository)
     def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
     def mockSessionManager = Mock(SessionManager)
+    def stubFragmentNativeRepository = Stub(FragmentNativeRepository)
 
-    def objectUnderTest = Spy(new CpsDataPersistenceServiceImpl(mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper, mockSessionManager))
+    def objectUnderTest = Spy(new CpsDataPersistenceServiceImpl(mockDataspaceRepository, mockAnchorRepository,
+            mockFragmentRepository, jsonObjectMapper, mockSessionManager, stubFragmentNativeRepository))
 
     def 'Storing data nodes individually when batch operation fails'(){
         given: 'two data nodes and supporting repository mock behavior'
@@ -146,11 +149,11 @@ class CpsDataPersistenceServiceSpec extends Specification {
            def anchorEntity = new AnchorEntity(id:123)
            mockAnchorRepository.getByDataspaceAndName(*_) >> anchorEntity
         and: 'fragment repository returns a collection of fragments'
-            def fragmentEntity1 = new FragmentEntity(xpath: 'xpath1', childFragments: [])
-            def fragmentEntity2 = new FragmentEntity(xpath: 'xpath2', childFragments: [])
-           mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['xpath1','xpath2']) >> [ fragmentEntity1, fragmentEntity2 ]
+            def fragmentEntity1 = new FragmentEntity(xpath: '/xpath1', childFragments: [])
+            def fragmentEntity2 = new FragmentEntity(xpath: '/xpath2', childFragments: [])
+            mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['/xpath1', '/xpath2'] as Set<String>) >> [fragmentEntity1, fragmentEntity2]
         when: 'getting data nodes for 2 xpaths'
-            def result = objectUnderTest.getDataNodes('some-dataspace', 'some-anchor', ['xpath1','xpath2'],FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
+            def result = objectUnderTest.getDataNodes('some-dataspace', 'some-anchor', ['/xpath1', '/xpath2'], FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)
         then: '2 data nodes are returned'
             assert result.size() == 2
     }
index 5aae285..4dd4823 100644 (file)
@@ -61,8 +61,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase
             }
             stopWatch.stop()
             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is under 6000 milliseconds'
-            assert deleteDurationInMillis < 6000
+        then: 'delete duration is under 300 milliseconds'
+            assert deleteDurationInMillis < 300
     }
 
     def 'Delete 50 grandchildren (that have no descendants)'() {
@@ -74,8 +74,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase
             }
             stopWatch.stop()
             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is under 500 milliseconds'
-            assert deleteDurationInMillis < 500
+        then: 'delete duration is under 350 milliseconds'
+            assert deleteDurationInMillis < 350
     }
 
     def 'Delete 1 large data node with many descendants'() {
@@ -84,8 +84,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase
             objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, PERF_TEST_PARENT)
             stopWatch.stop()
             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is under 2500 milliseconds'
-            assert deleteDurationInMillis < 2500
+        then: 'delete duration is under 250 milliseconds'
+            assert deleteDurationInMillis < 250
     }
 
     @Sql([CLEAR_DATA, PERF_TEST_DATA])
@@ -108,8 +108,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase
             }
             stopWatch.stop()
             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is under 4000 milliseconds'
-            assert deleteDurationInMillis < 4000
+        then: 'delete duration is under 1000 milliseconds'
+            assert deleteDurationInMillis < 1000
     }
 
     def 'Delete 10 list elements with keys'() {
@@ -122,8 +122,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase
             }
             stopWatch.stop()
             def deleteDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'delete duration is under 6000 milliseconds'
-            assert deleteDurationInMillis < 6000
+        then: 'delete duration is under 1200 milliseconds'
+            assert deleteDurationInMillis < 1200
     }
 
     @Sql([CLEAR_DATA, PERF_TEST_DATA])
index 28363d7..0407490 100644 (file)
@@ -29,8 +29,6 @@ import org.onap.cps.spi.repository.FragmentRepository
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.test.context.jdbc.Sql
 
-import java.util.concurrent.TimeUnit
-
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 
@@ -51,8 +49,6 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase {
     static def NUMBER_OF_CHILDREN = 200
     static def NUMBER_OF_GRAND_CHILDREN = 50
     static def TOTAL_NUMBER_OF_NODES = 1 + NUMBER_OF_CHILDREN + (NUMBER_OF_CHILDREN * NUMBER_OF_GRAND_CHILDREN)  //  Parent + Children +  Grand-children
-    static def ALLOWED_SETUP_TIME_MS = TimeUnit.SECONDS.toMillis(10)
-    static def ALLOWED_READ_TIME_AL_NODES_MS = 500
 
     def stopWatch = new StopWatch()
     def readStopWatch = new StopWatch()
@@ -64,8 +60,8 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase {
             createLineage(objectUnderTest, NUMBER_OF_CHILDREN, NUMBER_OF_GRAND_CHILDREN, false)
             stopWatch.stop()
             def setupDurationInMillis = stopWatch.getTotalTimeMillis()
-        and: 'setup duration is under #ALLOWED_SETUP_TIME_MS milliseconds'
-            assert setupDurationInMillis < ALLOWED_SETUP_TIME_MS
+        and: 'setup duration is under 10 seconds'
+            assert setupDurationInMillis < 10000
     }
 
     def 'Get data node with many descendants by xpath #scenario'() {
@@ -75,7 +71,7 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase {
             stopWatch.stop()
             def readDurationInMillis = stopWatch.getTotalTimeMillis()
         then: 'read duration is under 500 milliseconds'
-            assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS
+            assert readDurationInMillis < 500
         and: 'data node is returned with all the descendants populated'
             assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES
         where: 'the following xPaths are used'
@@ -91,7 +87,7 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase {
             stopWatch.stop()
             def readDurationInMillis = stopWatch.getTotalTimeMillis()
         then: 'read duration is under 500 milliseconds'
-            assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS
+            assert readDurationInMillis < 500
         and: 'data node is returned with all the descendants populated'
             assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES
     }
@@ -115,12 +111,12 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase {
             def result = objectUnderTest.queryDataNodes(PERF_DATASPACE, PERF_ANCHOR,  '//perf-test-grand-child-1', descendantsOption)
             stopWatch.stop()
             def readDurationInMillis = stopWatch.getTotalTimeMillis()
-        then: 'read duration is under 500 milliseconds'
-            assert readDurationInMillis < alowedDuration
+        then: 'read duration is under #allowedDuration milliseconds'
+            assert readDurationInMillis < allowedDuration
         and: 'data node is returned with all the descendants populated'
             assert result.size() == NUMBER_OF_CHILDREN
         where: 'the following options are used'
-            scenario                                        | descendantsOption        || alowedDuration
+            scenario                                        | descendantsOption        || allowedDuration
             'omit descendants                             ' | OMIT_DESCENDANTS         || 150
             'include descendants (although there are none)' | INCLUDE_ALL_DESCENDANTS  || 150
     }
index b80054a..0c8cddc 100644 (file)
@@ -2,6 +2,7 @@
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
 
 package org.onap.cps.spi;
 
+import com.google.common.base.Strings;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import lombok.RequiredArgsConstructor;
+import org.onap.cps.spi.exceptions.DataValidationException;
 
 @RequiredArgsConstructor
 public class FetchDescendantsOption {
@@ -29,6 +34,9 @@ public class FetchDescendantsOption {
     public static final FetchDescendantsOption OMIT_DESCENDANTS = new FetchDescendantsOption(0);
     public static final FetchDescendantsOption INCLUDE_ALL_DESCENDANTS = new FetchDescendantsOption(-1);
 
+    private static final Pattern FETCH_DESCENDANTS_OPTION_PATTERN =
+        Pattern.compile("^$|^all$|^none$|^[0-9]+$|^-1$");
+
     private final int depth;
 
     /**
@@ -58,6 +66,36 @@ public class FetchDescendantsOption {
         return nextDescendantsOption;
     }
 
+    /**
+     * get fetch descendants option for given descendant.
+     *
+     * @param fetchDescendantsOptionAsString fetch descendants option string
+     * @return fetch descendants option for given descendant
+     */
+    public static FetchDescendantsOption getFetchDescendantsOption(final String fetchDescendantsOptionAsString) {
+        validateFetchDescendantsOption(fetchDescendantsOptionAsString);
+        if (Strings.isNullOrEmpty(fetchDescendantsOptionAsString)
+                || "0".equals(fetchDescendantsOptionAsString) || "none".equals(fetchDescendantsOptionAsString)) {
+            return FetchDescendantsOption.OMIT_DESCENDANTS;
+        } else if ("-1".equals(fetchDescendantsOptionAsString) || "all".equals(fetchDescendantsOptionAsString)) {
+            return FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
+        } else {
+            final Integer depth = Integer.valueOf(fetchDescendantsOptionAsString);
+            return new FetchDescendantsOption(depth);
+        }
+    }
+
+    private static void validateFetchDescendantsOption(final String fetchDescendantsOptionAsString) {
+        if (Strings.isNullOrEmpty(fetchDescendantsOptionAsString)) {
+            return;
+        }
+        final Matcher matcher = FETCH_DESCENDANTS_OPTION_PATTERN.matcher(fetchDescendantsOptionAsString);
+        if (!matcher.matches()) {
+            throw new DataValidationException("FetchDescendantsOption validation error.",
+                    fetchDescendantsOptionAsString + " is not valid fetch descendants option");
+        }
+    }
+
     private static void validateDepth(final int depth) {
         if (depth < -1) {
             throw new IllegalArgumentException("A depth of less than minus one is not allowed");
index 8b232b4..60286b6 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Modifications Copyright (C) 2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -43,7 +44,8 @@ class CpsQueryServiceImplSpec extends Specification {
         and: 'the CpsValidator is called on the dataspaceName, schemaSetName and anchorName'
             1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName)
         where: 'all fetch descendants options are supported'
-            fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS]
+            fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS,
+                FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY, new FetchDescendantsOption(10)]
     }
 
 }
index 6273835..c4d3dd8 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Nordix Foundation
+ *  Modifications Copyright (C) 2023 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -20,7 +21,7 @@
 
 package org.onap.cps.spi
 
-
+import org.onap.cps.spi.exceptions.DataValidationException
 import spock.lang.Specification
 
 class FetchDescendantsOptionSpec extends Specification {
@@ -72,4 +73,18 @@ class FetchDescendantsOptionSpec extends Specification {
         then: 'exception thrown'
             thrown IllegalArgumentException
     }
+
+    def 'Create fetch descendant option with  descendant using #scenario'() {
+        when: 'the next level of depth is not allowed'
+           def FetchDescendantsOption fetchDescendantsOption = FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString)
+        then: 'fetch descendant object created'
+            assert fetchDescendantsOption.depth == expectedDepth
+        where: 'following parameters are used'
+            scenario                            | fetchDescendantsOptionAsString || expectedDepth
+            'all descendants using number'      | '-1'                           || -1
+            'all descendants using all'         | 'all'                          || -1
+            'No descendants by default'         | ''                             || 0
+            'No descendants using none'         | 'none'                         || 0
+            'til 10th descendants using number' | '10'                           || 10
+    }
 }
index ec7d295..53c72f5 100644 (file)
@@ -15,29 +15,30 @@ info:
   x-logo:
     url: cps_logo.png
 servers:
-- url: /cps/api
+  - url: /cps/api
+security:
+  - basicAuth: []
 tags:
-- name: cps-admin
-  description: cps Admin
-- name: cps-data
-  description: cps Data
+  - name: cps-admin
+    description: cps Admin
+  - name: cps-data
+    description: cps Data
 paths:
   /v1/dataspaces:
     post:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Create a dataspace
       description: Create a new dataspace
       operationId: createDataspace
-      deprecated: true
       parameters:
-      - name: dataspace-name
-        in: query
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
+        - name: dataspace-name
+          in: query
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
       responses:
         "201":
           description: Created
@@ -96,24 +97,36 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
-  /v2/dataspaces:
-    post:
+      deprecated: true
+  /{apiVersion}/dataspaces:
+    delete:
       tags:
-      - cps-admin
-      summary: Create a dataspace
-      description: Create a new dataspace
-      operationId: createDataspaceV2
+        - cps-admin
+      summary: Delete a dataspace
+      description: Delete a dataspace
+      operationId: deleteDataspace
       parameters:
-      - name: dataspace-name
-        in: query
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: query
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
       responses:
-        "201":
-          description: Created
+        "204":
+          description: No Content
+          content: {}
         "400":
           description: Bad Request
           content:
@@ -164,26 +177,24 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
-  /{apiVersion}/dataspaces:
-    delete:
+  /v2/dataspaces:
+    post:
       tags:
-      - cps-admin
-      summary: Delete a dataspace
-      description: Delete a dataspace
-      operationId: deleteDataspace
+        - cps-admin
+      summary: Create a dataspace
+      description: Create a new dataspace
+      operationId: createDataspaceV2
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: query
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
+        - name: dataspace-name
+          in: query
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
       responses:
-        "204":
-          description: No Content
-          content: {}
+        "201":
+          description: Created without response body
         "400":
           description: Bad Request
           content:
@@ -237,12 +248,21 @@ paths:
   /{apiVersion}/admin/dataspaces:
     get:
       tags:
-      - cps-admin
-      summary: Get dataspaces
-      description: "Read all dataspaces"
+        - cps-admin
+      summary: Get all dataspaces
+      description: Read all dataspaces
       operationId: getAllDataspaces
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
       responses:
         "200":
           description: OK
@@ -295,19 +315,28 @@ paths:
   /{apiVersion}/admin/dataspaces/{dataspace-name}:
     get:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Get a dataspace
-      description: Read an dataspace given a dataspace name
+      description: Read a dataspace given a dataspace name
       operationId: getDataspace
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
       responses:
         "200":
           description: OK
@@ -355,31 +384,43 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
-  /{apiVersion}/dataspaces/{dataspace-name}/anchors:
-    get:
+  /v1/dataspaces/{dataspace-name}/anchors:
+    post:
       tags:
-      - cps-admin
-      summary: Get anchors
-      description: "Read all anchors, given a dataspace"
-      operationId: getAnchors
+        - cps-admin
+      summary: Create an anchor
+      description: Create a new anchor in the given dataspace
+      operationId: createAnchor
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: schema-set-name
+          in: query
+          description: schema-set-name
+          required: true
+          schema:
+            type: string
+            example: my-schema-set
+        - name: anchor-name
+          in: query
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
       responses:
-        "200":
-          description: OK
+        "201":
+          description: Created
           content:
-            application/json:
+            text/plain:
               schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/AnchorDetails'
+                type: string
+                example: my-resource
         "400":
           description: Bad Request
           content:
@@ -410,6 +451,16 @@ paths:
                 status: 403
                 message: Request Forbidden
                 details: This request is forbidden
+        "409":
+          description: Conflict
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 409
+                message: Conflicting request
+                details: The request cannot be processed as the resource is in use.
         "500":
           description: Internal Server Error
           content:
@@ -420,44 +471,39 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
-  /v1/dataspaces/{dataspace-name}/anchors:
+      deprecated: true
+  /v2/dataspaces/{dataspace-name}/anchors:
     post:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Create an anchor
-      deprecated: true
       description: Create a new anchor in the given dataspace
-      operationId: createAnchor
+      operationId: createAnchorV2
       parameters:
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: schema-set-name
-        in: query
-        description: schema-set-name
-        required: true
-        schema:
-          type: string
-          example: my-schema-set
-      - name: anchor-name
-        in: query
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: schema-set-name
+          in: query
+          description: schema-set-name
+          required: true
+          schema:
+            type: string
+            example: my-schema-set
+        - name: anchor-name
+          in: query
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
       responses:
         "201":
-          description: Created
-          content:
-            text/plain:
-              schema:
-                type: string
-                example: my-resource
+          description: Created without response body
         "400":
           description: Bad Request
           content:
@@ -508,38 +554,40 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
-  /v2/dataspaces/{dataspace-name}/anchors:
-    post:
+  /{apiVersion}/dataspaces/{dataspace-name}/anchors:
+    get:
       tags:
-      - cps-admin
-      summary: Create an anchor
-      description: Create a new anchor in the given dataspace
-      operationId: createAnchorV2
+        - cps-admin
+      summary: Get anchors
+      description: "Read all anchors, given a dataspace"
+      operationId: getAnchors
       parameters:
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: schema-set-name
-        in: query
-        description: schema-set-name
-        required: true
-        schema:
-          type: string
-          example: my-schema-set
-      - name: anchor-name
-        in: query
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
       responses:
-        "201":
-          description: Created
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/AnchorDetails'
         "400":
           description: Bad Request
           content:
@@ -570,16 +618,6 @@ paths:
                 status: 403
                 message: Request Forbidden
                 details: This request is forbidden
-        "409":
-          description: Conflict
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/ErrorMessage'
-              example:
-                status: 409
-                message: Conflicting request
-                details: The request cannot be processed as the resource is in use.
         "500":
           description: Internal Server Error
           content:
@@ -593,26 +631,35 @@ paths:
   /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}:
     get:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Get an anchor
       description: Read an anchor given an anchor name and a dataspace
       operationId: getAnchor
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
       responses:
         "200":
           description: OK
@@ -662,26 +709,35 @@ paths:
                 details: Internal Server Error occurred
     delete:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Delete an anchor
       description: Delete an anchor given an anchor name and a dataspace
       operationId: deleteAnchor
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
       responses:
         "204":
           description: No Content
@@ -729,25 +785,25 @@ paths:
   /v1/dataspaces/{dataspace-name}/schema-sets:
     post:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Create a schema set
       description: Create a new schema set in the given dataspace
       operationId: createSchemaSet
       parameters:
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: schema-set-name
-        in: query
-        description: schema-set-name
-        required: true
-        schema:
-          type: string
-          example: my-schema-set
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: schema-set-name
+          in: query
+          description: schema-set-name
+          required: true
+          schema:
+            type: string
+            example: my-schema-set
       requestBody:
         content:
           multipart/form-data:
@@ -812,28 +868,29 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
+      deprecated: true
   /v2/dataspaces/{dataspace-name}/schema-sets:
     post:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Create a schema set
       description: Create a new schema set in the given dataspace
       operationId: createSchemaSetV2
       parameters:
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: schema-set-name
-        in: query
-        description: schema-set-name
-        required: true
-        schema:
-          type: string
-          example: my-schema-set
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: schema-set-name
+          in: query
+          description: schema-set-name
+          required: true
+          schema:
+            type: string
+            example: my-schema-set
       requestBody:
         content:
           multipart/form-data:
@@ -842,7 +899,7 @@ paths:
         required: true
       responses:
         "201":
-          description: Created
+          description: Created without response body
         "400":
           description: Bad Request
           content:
@@ -896,19 +953,28 @@ paths:
   /{apiVersion}/dataspaces/{dataspace-name}/schema-sets:
     get:
       tags:
-      - cps-admin
-      summary: Get schema sets for a given dataspace
-      description: "Read schema sets for a given dataspace"
+        - cps-admin
+      summary: Get schema sets
+      description: "Read all schema sets, given a dataspace"
       operationId: getSchemaSets
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
       responses:
         "200":
           description: OK
@@ -961,26 +1027,35 @@ paths:
   /{apiVersion}/dataspaces/{dataspace-name}/schema-sets/{schema-set-name}:
     get:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Get a schema set
       description: Read a schema set given a schema set name and a dataspace
       operationId: getSchemaSet
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: schema-set-name
-        in: path
-        description: schema-set-name
-        required: true
-        schema:
-          type: string
-          example: my-schema-set
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: schema-set-name
+          in: path
+          description: schema-set-name
+          required: true
+          schema:
+            type: string
+            example: my-schema-set
       responses:
         "200":
           description: OK
@@ -1030,26 +1105,35 @@ paths:
                 details: Internal Server Error occurred
     delete:
       tags:
-      - cps-admin
+        - cps-admin
       summary: Delete a schema set
       description: Delete a schema set given a schema set name and a dataspace
       operationId: deleteSchemaSet
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: schema-set-name
-        in: path
-        description: schema-set-name
-        required: true
-        schema:
-          type: string
-          example: my-schema-set
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: schema-set-name
+          in: path
+          description: schema-set-name
+          required: true
+          schema:
+            type: string
+            example: my-schema-set
       responses:
         "204":
           description: No Content
@@ -1104,50 +1188,145 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
-  /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
+  /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
     get:
       tags:
-      - cps-data
+        - cps-data
       summary: Get a node
       description: Get a node with an option to retrieve all the children for a given
         anchor and dataspace
       operationId: getNodeByDataspaceAndAnchor
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: false
-        schema:
-          type: string
-          default: /
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: include-descendants
-        in: query
-        description: include-descendants
-        required: false
-        schema:
-          type: boolean
-          example: false
-          default: false
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: include-descendants
+          in: query
+          description: include-descendants
+          required: false
+          schema:
+            type: boolean
+            example: false
+            default: false
+      responses:
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: object
+              examples:
+                dataSample:
+                  $ref: '#/components/examples/dataSample'
+        "400":
+          description: Bad Request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 400
+                message: Bad Request
+                details: The provided request is not valid
+        "401":
+          description: Unauthorized
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 401
+                message: Unauthorized request
+                details: This request is unauthorized
+        "403":
+          description: Forbidden
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 403
+                message: Request Forbidden
+                details: This request is forbidden
+        "500":
+          description: Internal Server Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 500
+                message: Internal Server Error
+                details: Internal Server Error occurred
+      deprecated: true
+      x-codegen-request-body-name: xpath
+  /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
+    get:
+      tags:
+        - cps-data
+      summary: Get a node
+      description: Get a node with an option to retrieve all the children for a given
+        anchor and dataspace
+      operationId: getNodeByDataspaceAndAnchorV2
+      parameters:
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: descendants
+          in: query
+          description: "descendents to query depth of children. allowed values are none,\
+          \ all, any number starting from -1"
+          required: false
+          schema:
+            type: string
+            example: "3"
+            default: none
       responses:
         "200":
           description: OK
@@ -1202,46 +1381,55 @@ paths:
   /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes:
     put:
       tags:
-      - cps-data
+        - cps-data
       summary: Replace a node with descendants
       description: "Replace a node with descendants for a given dataspace, anchor\
         \ and a parent node xpath"
       operationId: replaceNode
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: false
-        schema:
-          type: string
-          default: /
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: observed-timestamp
-        in: query
-        description: observed-timestamp
-        required: false
-        schema:
-          type: string
-          example: 2021-03-21T00:10:34.030-0100
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: observed-timestamp
+          in: query
+          description: observed-timestamp
+          required: false
+          schema:
+            type: string
+            example: 2021-03-21T00:10:34.030-0100
       requestBody:
         content:
           application/json:
@@ -1303,53 +1491,77 @@ paths:
                 details: Internal Server Error occurred
     post:
       tags:
-      - cps-data
+        - cps-data
       summary: Create a node
       description: Create a node for a given anchor and dataspace
       operationId: createNode
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: false
-        schema:
-          type: string
-          default: /
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: observed-timestamp
-        in: query
-        description: observed-timestamp
-        required: false
-        schema:
-          type: string
-          example: 2021-03-21T00:10:34.030-0100
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: observed-timestamp
+          in: query
+          description: observed-timestamp
+          required: false
+          schema:
+            type: string
+            example: 2021-03-21T00:10:34.030-0100
+        - name: Content-Type
+          in: header
+          description: Content type header
+          required: true
+          schema:
+            type: string
+            example: application/json
       requestBody:
         content:
           application/json:
             schema:
-              type: object
+              type: string
             examples:
               dataSample:
                 $ref: '#/components/examples/dataSample'
+          application/xml:
+            schema:
+              type: object
+              xml:
+                name: stores
+            examples:
+              dataSample:
+                $ref: '#/components/examples/dataSampleXml'
         required: true
       responses:
         "201":
@@ -1411,46 +1623,55 @@ paths:
                 details: Internal Server Error occurred
     delete:
       tags:
-      - cps-data
+        - cps-data
       summary: Delete a data node
       description: Delete a datanode for a given dataspace and anchor given a node
         xpath.
       operationId: deleteDataNode
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: false
-        schema:
-          type: string
-          default: /
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: observed-timestamp
-        in: query
-        description: observed-timestamp
-        required: false
-        schema:
-          type: string
-          example: 2021-03-21T00:10:34.030-0100
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: observed-timestamp
+          in: query
+          description: observed-timestamp
+          required: false
+          schema:
+            type: string
+            example: 2021-03-21T00:10:34.030-0100
       responses:
         "204":
           description: No Content
@@ -1497,46 +1718,55 @@ paths:
                 details: Internal Server Error occurred
     patch:
       tags:
-      - cps-data
+        - cps-data
       summary: Update node leaves
       description: Update a data node leaves for a given dataspace and anchor and
         a parent node xpath
       operationId: updateNodeLeaves
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: false
-        schema:
-          type: string
-          default: /
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: observed-timestamp
-        in: query
-        description: observed-timestamp
-        required: false
-        schema:
-          type: string
-          example: 2021-03-21T00:10:34.030-0100
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: observed-timestamp
+          in: query
+          description: observed-timestamp
+          required: false
+          schema:
+            type: string
+            example: 2021-03-21T00:10:34.030-0100
       requestBody:
         content:
           application/json:
@@ -1596,47 +1826,141 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
+  /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
+    delete:
+      tags:
+        - cps-data
+      summary: Delete one or all list element(s)
+      description: Delete one or all list element(s) for a given anchor and dataspace
+      operationId: deleteListOrListElement
+      parameters:
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: true
+          schema:
+            type: string
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: observed-timestamp
+          in: query
+          description: observed-timestamp
+          required: false
+          schema:
+            type: string
+            example: 2021-03-21T00:10:34.030-0100
+      responses:
+        "204":
+          description: No Content
+          content: {}
+        "400":
+          description: Bad Request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 400
+                message: Bad Request
+                details: The provided request is not valid
+        "401":
+          description: Unauthorized
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 401
+                message: Unauthorized request
+                details: This request is unauthorized
+        "403":
+          description: Forbidden
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 403
+                message: Request Forbidden
+                details: This request is forbidden
+        "500":
+          description: Internal Server Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 500
+                message: Internal Server Error
+                details: Internal Server Error occurred
+      deprecated: true
   /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
     put:
       tags:
-      - cps-data
+        - cps-data
       summary: Replace list content
       description: "Replace list content under a given parent, anchor and dataspace"
       operationId: replaceListContent
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: true
-        schema:
-          type: string
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: observed-timestamp
-        in: query
-        description: observed-timestamp
-        required: false
-        schema:
-          type: string
-          example: 2021-03-21T00:10:34.030-0100
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: true
+          schema:
+            type: string
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: observed-timestamp
+          in: query
+          description: observed-timestamp
+          required: false
+          schema:
+            type: string
+            example: 2021-03-21T00:10:34.030-0100
       requestBody:
         content:
           application/json:
@@ -1698,44 +2022,53 @@ paths:
                 details: Internal Server Error occurred
     post:
       tags:
-      - cps-data
+        - cps-data
       summary: Add list element(s)
       description: Add list element(s) to a list for a given anchor and dataspace
       operationId: addListElements
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: true
-        schema:
-          type: string
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: observed-timestamp
-        in: query
-        description: observed-timestamp
-        required: false
-        schema:
-          type: string
-          example: 2021-03-21T00:10:34.030-0100
+        - name: apiVersion
+          in: path
+          description: apiVersion
+          required: true
+          schema:
+            type: string
+            default: v2
+            enum:
+              - v1
+              - v2
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: xpath
+          in: query
+          description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: true
+          schema:
+            type: string
+          examples:
+            container xpath:
+              value: /shops/bookstore
+            list attributes xpath:
+              value: "/shops/bookstore/categories[@code=1]"
+        - name: observed-timestamp
+          in: query
+          description: observed-timestamp
+          required: false
+          schema:
+            type: string
+            example: 2021-03-21T00:10:34.030-0100
       requestBody:
         content:
           application/json:
@@ -1793,50 +2126,58 @@ paths:
                 status: 500
                 message: Internal Server Error
                 details: Internal Server Error occurred
-    delete:
+  /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
+    get:
       tags:
-      - cps-data
-      summary: Delete one or all list element(s)
-      description: Delete one or all list element(s) for a given anchor and dataspace
-      operationId: deleteListOrListElement
+        - cps-query
+      summary: Query data nodes
+      description: Query data nodes for the given dataspace and anchor using CPS path
+      operationId: getNodesByDataspaceAndAnchorAndCpsPath
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: xpath
-        in: query
-        description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: true
-        schema:
-          type: string
-        examples:
-          container xpath:
-            value: /shops/bookstore
-          list attributes xpath:
-            value: "/shops/bookstore/categories[@code=1]"
-      - name: observed-timestamp
-        in: query
-        description: observed-timestamp
-        required: false
-        schema:
-          type: string
-          example: 2021-03-21T00:10:34.030-0100
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: cps-path
+          in: query
+          description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container cps path:
+              value: //bookstore
+            list attributes cps path:
+              value: "//categories[@code=1]"
+        - name: include-descendants
+          in: query
+          description: include-descendants
+          required: false
+          schema:
+            type: boolean
+            example: false
+            default: false
       responses:
-        "204":
-          description: No Content
-          content: {}
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: object
+              examples:
+                dataSample:
+                  $ref: '#/components/examples/dataSample'
         "400":
           description: Bad Request
           content:
@@ -1878,49 +2219,50 @@ paths:
                 message: Internal Server Error
                 details: Internal Server Error occurred
       deprecated: true
-  /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
+      x-codegen-request-body-name: xpath
+  /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
     get:
       tags:
-      - cps-query
+        - cps-query
       summary: Query data nodes
       description: Query data nodes for the given dataspace and anchor using CPS path
-      operationId: getNodesByDataspaceAndAnchorAndCpsPath
+      operationId: getNodesByDataspaceAndAnchorAndCpsPathV2
       parameters:
-      - $ref: '#/components/parameters/apiVersionInPath'
-      - name: dataspace-name
-        in: path
-        description: dataspace-name
-        required: true
-        schema:
-          type: string
-          example: my-dataspace
-      - name: anchor-name
-        in: path
-        description: anchor-name
-        required: true
-        schema:
-          type: string
-          example: my-anchor
-      - name: cps-path
-        in: query
-        description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
-        required: false
-        schema:
-          type: string
-          default: /
-        examples:
-          container cps path:
-            value: //bookstore
-          list attributes cps path:
-            value: "//categories[@code=1]"
-      - name: include-descendants
-        in: query
-        description: include-descendants
-        required: false
-        schema:
-          type: boolean
-          example: false
-          default: false
+        - name: dataspace-name
+          in: path
+          description: dataspace-name
+          required: true
+          schema:
+            type: string
+            example: my-dataspace
+        - name: anchor-name
+          in: path
+          description: anchor-name
+          required: true
+          schema:
+            type: string
+            example: my-anchor
+        - name: cps-path
+          in: query
+          description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container cps path:
+              value: //bookstore
+            list attributes cps path:
+              value: "//categories[@code=1]"
+        - name: descendants
+          in: query
+          description: "descendents to query depth of children. allowed values are none,\
+          \ all, any number starting from -1"
+          required: false
+          schema:
+            type: string
+            example: "3"
+            default: none
       responses:
         "200":
           description: OK
@@ -1973,20 +2315,6 @@ paths:
                 details: Internal Server Error occurred
       x-codegen-request-body-name: xpath
 components:
-  parameters:
-    apiVersionInPath:
-      name: apiVersion
-      in: path
-      description: apiVersion
-      required: true
-      schema:
-        type: string
-        enum: [v1, v2]
-        default: v2
-  securitySchemes:
-    basicAuth:
-      type: http
-      scheme: basic
   schemas:
     ErrorMessage:
       title: Error
@@ -1998,6 +2326,13 @@ components:
           type: string
         details:
           type: string
+    DataspaceDetails:
+      title: Dataspace details by dataspace Name
+      type: object
+      properties:
+        name:
+          type: string
+          example: my-dataspace
     AnchorDetails:
       title: Anchor details by anchor Name
       type: object
@@ -2011,16 +2346,9 @@ components:
         schemaSetName:
           type: string
           example: my-schema-set
-    DataspaceDetails:
-      title: Dataspace details by dataspace Name
-      type: object
-      properties:
-        name:
-          type: string
-          example: my-dataspace
     MultipartFile:
       required:
-      - file
+        - file
       type: object
       properties:
         file:
@@ -2030,7 +2358,7 @@ components:
     SchemaSetDetails:
       title: Schema set details by dataspace and schemasetName
       required:
-      - moduleReferences
+        - moduleReferences
       type: object
       properties:
         dataspaceName:
@@ -2062,10 +2390,15 @@ components:
         test:bookstore:
           bookstore-name: Chapters
           categories:
-          - code: 1
-            name: SciFi
-          - code: 2
-            name: kids
-
-security:
-  - basicAuth: []
+            - code: 1
+              name: SciFi
+            - code: 2
+              name: kids
+    dataSampleXml:
+      value: <stores xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <bookstore xmlns="org:onap:ccsdk:sample">
+        <bookstore-name>Chapters</bookstore-name> <categories> <code>1</code> <name>SciFi</name>
+        </categories> </bookstore> </stores>
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
index 9e84f3a..3bf93a1 100644 (file)
@@ -4,12 +4,14 @@ info:
   description: NCMP Inventory API
   version: "1.0"
 servers:
-- url: /ncmpInventory
+  - url: /ncmpInventory
+security:
+  - basicAuth: []
 paths:
   /v1/ch:
     post:
       tags:
-      - network-cm-proxy-inventory
+        - network-cm-proxy-inventory
       summary: DMI notifies NCMP of new CM Handles
       description: "Register a DMI Plugin with any new, updated or removed CM Handles."
       operationId: updateDmiPluginRegistration
@@ -63,51 +65,104 @@ paths:
                 $ref: '#/components/schemas/DmiPluginRegistrationErrorResponse'
               example:
                 failedCreatedCmHandles:
-                - cmHandle: my-cm-handle-01
-                  errorCode: "00"
-                  errorText: Unknown error. <error-details>
-                - cmHandle: my-cm-handle-02
-                  errorCode: "01"
-                  errorText: cm-handle already exists
-                - cmHandle: my-cm-handle-03
-                  errorCode: "03"
-                  errorText: cm-handle has an invalid character(s) in id
+                  - cmHandle: my-cm-handle-01
+                    errorCode: "00"
+                    errorText: Unknown error. <error-details>
+                  - cmHandle: my-cm-handle-02
+                    errorCode: "01"
+                    errorText: cm-handle already exists
+                  - cmHandle: my-cm-handle-03
+                    errorCode: "03"
+                    errorText: cm-handle has an invalid character(s) in id
                 failedUpdatedCmHandles:
-                - cmHandle: my-cm-handle-01
-                  errorCode: "00"
-                  errorText: Unknown error. <error-details>
-                - cmHandle: my-cm-handle-02
-                  errorCode: "02"
-                  errorText: cm-handle does not exist
-                - cmHandle: my-cm-handle-03
-                  errorCode: "03"
-                  errorText: cm-handle has an invalid character(s) in id
+                  - cmHandle: my-cm-handle-01
+                    errorCode: "00"
+                    errorText: Unknown error. <error-details>
+                  - cmHandle: my-cm-handle-02
+                    errorCode: "02"
+                    errorText: cm-handle does not exist
+                  - cmHandle: my-cm-handle-03
+                    errorCode: "03"
+                    errorText: cm-handle has an invalid character(s) in id
                 failedRemovedCmHandles:
-                - cmHandle: my-cm-handle-01
-                  errorCode: "00"
-                  errorText: Unknown error. <error-details>
-                - cmHandle: my-cm-handle-02
-                  errorCode: "02"
-                  errorText: cm-handle does not exists
-                - cmHandle: my-cm-handle-03
-                  errorCode: "03"
-                  errorText: cm-handle has an invalid character(s) in id
+                  - cmHandle: my-cm-handle-01
+                    errorCode: "00"
+                    errorText: Unknown error. <error-details>
+                  - cmHandle: my-cm-handle-02
+                    errorCode: "02"
+                    errorText: cm-handle does not exists
+                  - cmHandle: my-cm-handle-03
+                    errorCode: "03"
+                    errorText: cm-handle has an invalid character(s) in id
   /v1/ch/cmHandles:
     get:
       tags:
-      - network-cm-proxy-inventory
+        - network-cm-proxy-inventory
       summary: "Get all cm handle IDs for a registered DMI plugin (DMI plugin, DMI\
         \ data plugin, DMI model plugin)"
       description: Get all cm handle IDs for a registered DMI plugin
       operationId: getAllCmHandleIdsForRegisteredDmi
       parameters:
-      - name: dmi-plugin-identifier
-        in: query
-        description: dmi-plugin-identifier
+        - name: dmi-plugin-identifier
+          in: query
+          description: dmi-plugin-identifier
+          required: true
+          schema:
+            type: string
+            example: my-dmi-plugin
+      responses:
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  type: string
+        "401":
+          description: Unauthorized
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 401
+                message: Unauthorized error message
+                details: Unauthorized error details
+        "403":
+          description: Forbidden
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 403
+                message: Forbidden error message
+                details: Forbidden error details
+        "500":
+          description: Internal Server Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 500
+                message: Internal Server Error
+                details: Internal Server Error occurred
+  /v1/ch/searches:
+    post:
+      tags:
+        - network-cm-proxy-inventory
+      summary: Query for CM Handle IDs
+      description: "Query and get CMHandleIds for additional properties, public properties\
+        \ and registered DMI plugin (DMI plugin, DMI data plugin, DMI model plugin)."
+      operationId: searchCmHandleIds
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/CmHandleQueryParameters'
         required: true
-        schema:
-          type: string
-          example: my-dmi-plugin
       responses:
         "200":
           description: OK
@@ -148,10 +203,6 @@ paths:
                 message: Internal Server Error
                 details: Internal Server Error occurred
 components:
-  securitySchemes:
-    basicAuth:
-      type: http
-      scheme: basic
   schemas:
     RestDmiPluginRegistration:
       type: object
@@ -179,14 +230,14 @@ components:
         removedCmHandles:
           type: array
           example:
-          - my-cm-handle1
-          - my-cm-handle2
-          - my-cm-handle3
+            - my-cm-handle1
+            - my-cm-handle2
+            - my-cm-handle3
           items:
             type: string
     RestInputCmHandle:
       required:
-      - cmHandle
+        - cmHandle
       type: object
       properties:
         cmHandle:
@@ -238,6 +289,45 @@ components:
         errorText:
           type: string
           example: Unknown error. <error-details>
-
-security:
-  - basicAuth: []
\ No newline at end of file
+    CmHandleQueryParameters:
+      title: Cm Handle query parameters for executing cm handle search
+      type: object
+      properties:
+        cmHandleQueryParameters:
+          type: array
+          items:
+            $ref: '#/components/schemas/ConditionProperties'
+        conditions:
+          type: array
+          description: "not necessary, it is just for backward compatibility"
+          deprecated: true
+          items:
+            $ref: '#/components/schemas/OldConditionProperties'
+    ConditionProperties:
+      properties:
+        conditionName:
+          type: string
+        conditionParameters:
+          type: array
+          items:
+            type: object
+            additionalProperties:
+              type: string
+    OldConditionProperties:
+      properties:
+        name:
+          type: string
+        conditionParameters:
+          type: array
+          items:
+            $ref: '#/components/schemas/ModuleNameAsJsonObject'
+      deprecated: true
+    ModuleNameAsJsonObject:
+      properties:
+        moduleName:
+          type: string
+          example: my-module
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
index 44c4788..1883966 100644 (file)
@@ -4,87 +4,89 @@ info:
   description: NCMP to CPS Proxy API
   version: "1.0"
 servers:
-- url: /ncmp
+  - url: /ncmp
+security:
+  - basicAuth: []
 paths:
   /v1/ch/{cm-handle}/data/ds/{datastore-name}:
     get:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Get resource data for cm handle
       description: Get resource data for given cm handle
       operationId: getResourceDataForCmHandle
       parameters:
-      - name: datastore-name
-        in: path
-        description: The type of the requested data
-        required: true
-        schema:
-          type: string
-          example: ncmp-datastore:operational
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - name: datastore-name
+          in: path
+          description: The type of the requested data
+          required: true
+          schema:
+            type: string
+            example: ncmp-datastore:operational
+        - 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
-          example: my-cm-handle
-      - name: resourceIdentifier
-        in: query
-        description: The format of resource identifier depend on the associated DMI
-          Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
-          it can really be anything.
-        required: true
-        allowReserved: true
-        schema:
-          type: string
-        examples:
-          sample 1:
-            value:
-              resourceIdentifier: \shops\bookstore
-          sample 2:
-            value:
-              resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
-          sample 3:
-            value:
-              resourceIdentifier: "parent=shops,child=bookstore"
-      - name: options
-        in: query
-        description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
+        - name: resourceIdentifier
+          in: query
+          description: The format of resource identifier depend on the associated DMI
+            Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
+            it can really be anything.
+          required: true
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                resourceIdentifier: \shops\bookstore
+            sample 2:
+              value:
+                resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
+            sample 3:
+              value:
+                resourceIdentifier: "parent=shops,child=bookstore"
+        - name: options
+          in: query
+          description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
           \ in parenthesis'()'. The format of options parameter depend on the associated\
           \ DMI Plugin implementation."
-        required: false
-        allowReserved: true
-        schema:
-          type: string
-        examples:
-          sample 1:
-            value:
-              options: (depth=3)
-          sample 2:
-            value:
-              options: (fields=book)
-          sample 3:
-            value:
-              options: "(depth=2,fields=book/authors)"
-      - name: topic
-        in: query
-        description: topic parameter in query.
-        required: false
-        allowReserved: true
-        schema:
-          type: string
-        examples:
-          sample 1:
-            value:
-              topic: my-topic-name
-      - name: include-descendants
-        in: query
-        description: Determines if descendants are included in response
-        required: false
-        schema:
-          type: boolean
-          default: false
+          required: false
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                options: (depth=3)
+            sample 2:
+              value:
+                options: (fields=book)
+            sample 3:
+              value:
+                options: "(depth=2,fields=book/authors)"
+        - name: topic
+          in: query
+          description: topic parameter in query.
+          required: false
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                topic: my-topic-name
+        - name: include-descendants
+          in: query
+          description: Determines if descendants are included in response
+          required: false
+          schema:
+            type: boolean
+            default: false
       responses:
         "200":
           description: OK
@@ -148,55 +150,55 @@ paths:
                   body: Bad Request
     put:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Update resource data from pass-through running for a cm handle
       description: Update resource data from pass-through running for the given cm
         handle
       operationId: updateResourceDataRunningForCmHandle
       parameters:
-      - name: datastore-name
-        in: path
-        description: The type of the requested data
-        required: true
-        schema:
-          type: string
-          example: ncmp-datastore:operational
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - name: datastore-name
+          in: path
+          description: The type of the requested data
+          required: true
+          schema:
+            type: string
+            example: ncmp-datastore:operational
+        - 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
-          example: my-cm-handle
-      - name: resourceIdentifier
-        in: query
-        description: The format of resource identifier depend on the associated DMI
-          Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
-          it can really be anything.
-        required: true
-        allowReserved: true
-        schema:
-          type: string
-        examples:
-          sample 1:
-            value:
-              resourceIdentifier: \shops\bookstore
-          sample 2:
-            value:
-              resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
-          sample 3:
-            value:
-              resourceIdentifier: "parent=shops,child=bookstore"
-      - name: Content-Type
-        in: header
-        description: "Content parameter for request, if content parameter is null,\
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
+        - name: resourceIdentifier
+          in: query
+          description: The format of resource identifier depend on the associated DMI
+            Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
+            it can really be anything.
+          required: true
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                resourceIdentifier: \shops\bookstore
+            sample 2:
+              value:
+                resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
+            sample 3:
+              value:
+                resourceIdentifier: "parent=shops,child=bookstore"
+        - name: Content-Type
+          in: header
+          description: "Content parameter for request, if content parameter is null,\
           \ default value is application/json."
-        required: false
-        schema:
-          type: string
-          example: application/yang-data+json
-          default: application/json
+          required: false
+          schema:
+            type: string
+            example: application/yang-data+json
+            default: application/json
       requestBody:
         content:
           application/json:
@@ -272,54 +274,54 @@ paths:
                   body: Bad Request
     post:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: create resource data from pass-through running for cm handle
       description: create resource data from pass-through running for given cm handle
       operationId: createResourceDataRunningForCmHandle
       parameters:
-      - name: datastore-name
-        in: path
-        description: The type of the requested data
-        required: true
-        schema:
-          type: string
-          example: ncmp-datastore:operational
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - name: datastore-name
+          in: path
+          description: The type of the requested data
+          required: true
+          schema:
+            type: string
+            example: ncmp-datastore:operational
+        - 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
-          example: my-cm-handle
-      - name: resourceIdentifier
-        in: query
-        description: The format of resource identifier depend on the associated DMI
-          Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
-          it can really be anything.
-        required: true
-        allowReserved: true
-        schema:
-          type: string
-        examples:
-          sample 1:
-            value:
-              resourceIdentifier: \shops\bookstore
-          sample 2:
-            value:
-              resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
-          sample 3:
-            value:
-              resourceIdentifier: "parent=shops,child=bookstore"
-      - name: Content-Type
-        in: header
-        description: "Content parameter for request, if content parameter is null,\
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
+        - name: resourceIdentifier
+          in: query
+          description: The format of resource identifier depend on the associated DMI
+            Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
+            it can really be anything.
+          required: true
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                resourceIdentifier: \shops\bookstore
+            sample 2:
+              value:
+                resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
+            sample 3:
+              value:
+                resourceIdentifier: "parent=shops,child=bookstore"
+        - name: Content-Type
+          in: header
+          description: "Content parameter for request, if content parameter is null,\
           \ default value is application/json."
-        required: false
-        schema:
-          type: string
-          example: application/yang-data+json
-          default: application/json
+          required: false
+          schema:
+            type: string
+            example: application/yang-data+json
+            default: application/json
       requestBody:
         content:
           application/json:
@@ -392,54 +394,54 @@ paths:
                   body: Bad Request
     delete:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Delete resource data
       description: Delete resource data from pass-through running for a given cm handle
       operationId: deleteResourceDataRunningForCmHandle
       parameters:
-      - name: datastore-name
-        in: path
-        description: The type of the requested data
-        required: true
-        schema:
-          type: string
-          example: ncmp-datastore:operational
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - name: datastore-name
+          in: path
+          description: The type of the requested data
+          required: true
+          schema:
+            type: string
+            example: ncmp-datastore:operational
+        - 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
-          example: my-cm-handle
-      - name: resourceIdentifier
-        in: query
-        description: The format of resource identifier depend on the associated DMI
-          Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
-          it can really be anything.
-        required: true
-        allowReserved: true
-        schema:
-          type: string
-        examples:
-          sample 1:
-            value:
-              resourceIdentifier: \shops\bookstore
-          sample 2:
-            value:
-              resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
-          sample 3:
-            value:
-              resourceIdentifier: "parent=shops,child=bookstore"
-      - name: Content-Type
-        in: header
-        description: "Content parameter for request, if content parameter is null,\
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
+        - name: resourceIdentifier
+          in: query
+          description: The format of resource identifier depend on the associated DMI
+            Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
+            it can really be anything.
+          required: true
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                resourceIdentifier: \shops\bookstore
+            sample 2:
+              value:
+                resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
+            sample 3:
+              value:
+                resourceIdentifier: "parent=shops,child=bookstore"
+        - name: Content-Type
+          in: header
+          description: "Content parameter for request, if content parameter is null,\
           \ default value is application/json."
-        required: false
-        schema:
-          type: string
-          example: application/yang-data+json
-          default: application/json
+          required: false
+          schema:
+            type: string
+            example: application/yang-data+json
+            default: application/json
       responses:
         "204":
           description: No Content
@@ -507,55 +509,55 @@ paths:
                   body: Bad Request
     patch:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Patch resource data from pass-through running
       description: Patch resource data from pass-through running for the given cm
         handle
       operationId: patchResourceDataRunningForCmHandle
       parameters:
-      - name: datastore-name
-        in: path
-        description: The type of the requested data
-        required: true
-        schema:
-          type: string
-          example: ncmp-datastore:operational
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - name: datastore-name
+          in: path
+          description: The type of the requested data
+          required: true
+          schema:
+            type: string
+            example: ncmp-datastore:operational
+        - 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
-          example: my-cm-handle
-      - name: resourceIdentifier
-        in: query
-        description: The format of resource identifier depend on the associated DMI
-          Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
-          it can really be anything.
-        required: true
-        allowReserved: true
-        schema:
-          type: string
-        examples:
-          sample 1:
-            value:
-              resourceIdentifier: \shops\bookstore
-          sample 2:
-            value:
-              resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
-          sample 3:
-            value:
-              resourceIdentifier: "parent=shops,child=bookstore"
-      - name: Content-Type
-        in: header
-        description: "Content parameter for request, if content parameter is null,\
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
+        - name: resourceIdentifier
+          in: query
+          description: The format of resource identifier depend on the associated DMI
+            Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
+            it can really be anything.
+          required: true
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                resourceIdentifier: \shops\bookstore
+            sample 2:
+              value:
+                resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]"
+            sample 3:
+              value:
+                resourceIdentifier: "parent=shops,child=bookstore"
+        - name: Content-Type
+          in: header
+          description: "Content parameter for request, if content parameter is null,\
           \ default value is application/json."
-        required: false
-        schema:
-          type: string
-          example: application/yang-data+json
-          default: application/json
+          required: false
+          schema:
+            type: string
+            example: application/yang-data+json
+            default: application/json
       requestBody:
         content:
           '*/*':
@@ -623,23 +625,156 @@ paths:
                 dmi-response:
                   http-code: 400
                   body: Bad Request
+  /v1/ch/{cm-handle}/data/ds/{datastore-name}/query:
+    get:
+      tags:
+        - network-cm-proxy
+      summary: Query resource data for a given cm handle
+      description: Query resource data for a given cm handle
+      operationId: queryResourceDataForCmHandle
+      parameters:
+        - name: datastore-name
+          in: path
+          description: The type of the requested data
+          required: true
+          schema:
+            type: string
+            example: ncmp-datastore:operational
+        - 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
+            example: my-cm-handle
+        - name: cps-path
+          in: query
+          description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+          required: false
+          schema:
+            type: string
+            default: /
+          examples:
+            container cps path:
+              value: //bookstore
+            list attributes cps path:
+              value: "//categories[@code=1]"
+        - name: options
+          in: query
+          description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\
+          \ in parenthesis'()'. The format of options parameter depend on the associated\
+          \ DMI Plugin implementation."
+          required: false
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                options: (depth=3)
+            sample 2:
+              value:
+                options: (fields=book)
+            sample 3:
+              value:
+                options: "(depth=2,fields=book/authors)"
+        - name: topic
+          in: query
+          description: topic parameter in query.
+          required: false
+          allowReserved: true
+          schema:
+            type: string
+          examples:
+            sample 1:
+              value:
+                topic: my-topic-name
+        - name: include-descendants
+          in: query
+          description: Determines if descendants are included in response
+          required: false
+          schema:
+            type: boolean
+            default: false
+      responses:
+        "200":
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: object
+              examples:
+                dataSampleResponse:
+                  $ref: '#/components/examples/dataSampleResponse'
+        "400":
+          description: Bad Request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 400 BAD_REQUEST
+                message: Bad request error message
+                details: Bad request error details
+        "401":
+          description: Unauthorized
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 401
+                message: Unauthorized error message
+                details: Unauthorized error details
+        "403":
+          description: Forbidden
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 403
+                message: Forbidden error message
+                details: Forbidden error details
+        "500":
+          description: Internal Server Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 500
+                message: Internal Server Error
+                details: Internal Server Error occurred
+        "502":
+          description: Bad Gateway
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/DmiErrorMessage'
+              example:
+                message: Bad Gateway Error Message NCMP
+                dmi-response:
+                  http-code: 400
+                  body: Bad Request
   /v1/ch/{cm-handle}/modules:
     get:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Fetch all module references (name and revision) for a given cm handle
       description: fetch all module references (name and revision) for a given cm
         handle
       operationId: getModuleReferencesByCmHandle
       parameters:
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - 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
-          example: my-cm-handle
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
       responses:
         "200":
           description: OK
@@ -692,21 +827,21 @@ paths:
   /v1/ch/{cm-handle}/modules/definitions:
     get:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: "Fetch all module definitions (name, revision, yang resource) for a\
         \ given cm handle"
       description: "Fetch all module definitions (name, revision, yang resource) for\
         \ a given cm handle"
       operationId: getModuleDefinitionsByCmHandleId
       parameters:
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - 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
-          example: my-cm-handle
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
       responses:
         "200":
           description: OK
@@ -749,7 +884,7 @@ paths:
   /v1/ch/searches:
     post:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Execute cm handle search using the available conditions
       description: Execute cm handle query search and return a list of cm handle details.
         Any number of conditions can be applied. To be included in the result a cm-handle
@@ -831,19 +966,19 @@ paths:
   /v1/ch/{cm-handle}:
     get:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Retrieve CM handle details
       description: Retrieve CM handle details and properties by cm handle id
       operationId: retrieveCmHandleDetailsById
       parameters:
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - 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
-          example: my-cm-handle
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
       responses:
         "200":
           description: OK
@@ -894,19 +1029,19 @@ paths:
   /v1/ch/{cm-handle}/properties:
     get:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Get CM handle properties
       description: Get CM handle properties by cm handle id
       operationId: getCmHandlePublicPropertiesByCmHandleId
       parameters:
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - 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
-          example: my-cm-handle
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
       responses:
         "200":
           description: OK
@@ -957,7 +1092,7 @@ paths:
   /v1/ch/id-searches:
     post:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Execute cm handle query upon a given set of query parameters
       description: Execute cm handle query search and return a list of cm handle ids.
         Any number of conditions can be applied. To be included in the result a cm-handle
@@ -1049,19 +1184,19 @@ paths:
   /v1/ch/{cm-handle}/state:
     get:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Get CM handle state
       description: Get CM handle state by cm handle id
       operationId: getCmHandleStateByCmHandleId
       parameters:
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - 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
-          example: my-cm-handle
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
       responses:
         "200":
           description: OK
@@ -1112,28 +1247,28 @@ paths:
   /v1/ch/{cm-handle}/data-sync:
     put:
       tags:
-      - network-cm-proxy
+        - network-cm-proxy
       summary: Set the Data Sync Enabled Flag
       description: Set the data sync enabled flag to true or false for a specified
         Cm-Handle. This will in turn set the data sync state to UNSYNCHRONIZED and
         NONE_REQUESTED respectfully.
       operationId: setDataSyncEnabledFlagForCmHandle
       parameters:
-      - name: cm-handle
-        in: path
-        description: "The identifier for a network function, network element, subnetwork\
+        - 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
-          example: my-cm-handle
-      - name: dataSyncEnabled
-        in: query
-        description: Is used to enable or disable the data synchronization flag
-        required: true
-        schema:
-          type: boolean
-          example: true
+          required: true
+          schema:
+            type: string
+            example: my-cm-handle
+        - name: dataSyncEnabled
+          in: query
+          description: Is used to enable or disable the data synchronization flag
+          required: true
+          schema:
+            type: boolean
+            example: true
       responses:
         "200":
           description: OK
@@ -1193,10 +1328,6 @@ paths:
                   http-code: 400
                   body: Bad Request
 components:
-  securitySchemes:
-    basicAuth:
-      type: http
-      scheme: basic
   schemas:
     ErrorMessage:
       title: Error
@@ -1365,17 +1496,17 @@ components:
       value:
         bookstore:
           categories:
-          - code: "01"
-            books:
-            - authors:
-              - Iain M. Banks
-              - Ursula K. Le Guin
-            name: SciFi
-          - code: "02"
-            books:
-            - authors:
-              - Philip Pullman
-            name: kids
+            - code: "01"
+              books:
+                - authors:
+                    - Iain M. Banks
+                    - Ursula K. Le Guin
+              name: SciFi
+            - code: "02"
+              books:
+                - authors:
+                    - Philip Pullman
+              name: kids
     dataSampleRequest:
       summary: Sample request
       description: Sample request body
@@ -1383,17 +1514,17 @@ components:
         test:bookstore:
           bookstore-name: Chapters
           categories:
-          - code: "01"
-            name: SciFi
-            books:
-            - authors:
-              - Iain M. Banks
-              - Ursula K. Le Guin
-          - code: "02"
-            name: kids
-            books:
-            - authors:
-              - Philip Pullman
+            - code: "01"
+              name: SciFi
+              books:
+                - authors:
+                    - Iain M. Banks
+                    - Ursula K. Le Guin
+            - code: "02"
+              name: kids
+              books:
+                - authors:
+                    - Philip Pullman
     dataSamplePatchRequest:
       summary: Sample patch request
       description: Sample patch request body
@@ -1401,86 +1532,87 @@ components:
         ietf-restconf:yang-patch:
           patch-id: patch-1
           edit:
-          - edit-id: edit1
-            operation: merge
-            target: /
-            value:
-              test:bookstore:
-                bookstore-name: Chapters
-                categories:
-                - code: "01"
-                  name: Science
-                  books:
-                  - authors:
-                    - Author1
-                    - Author2
-                - code: "02"
-                  name: Arts
-                  books:
-                  - authors:
-                    - Author3
-          - edit-id: edit2
-            operation: merge
-            target: /
-            value:
-              test:bookstore:
-                bookstore-name: Novels
-                categories:
-                - code: "03"
-                  name: History
-                  books:
-                  - authors:
-                    - Iain M. Banks
-                    - Ursula K. Le Guin
-                - code: "04"
-                  name: Fiction
-                  books:
-                  - authors:
-                    - Philip Pullman
+            - edit-id: edit1
+              operation: merge
+              target: /
+              value:
+                test:bookstore:
+                  bookstore-name: Chapters
+                  categories:
+                    - code: "01"
+                      name: Science
+                      books:
+                        - authors:
+                            - Author1
+                            - Author2
+                    - code: "02"
+                      name: Arts
+                      books:
+                        - authors:
+                            - Author3
+            - edit-id: edit2
+              operation: merge
+              target: /
+              value:
+                test:bookstore:
+                  bookstore-name: Novels
+                  categories:
+                    - code: "03"
+                      name: History
+                      books:
+                        - authors:
+                            - Iain M. Banks
+                            - Ursula K. Le Guin
+                    - code: "04"
+                      name: Fiction
+                      books:
+                        - authors:
+                            - Philip Pullman
     pubPropCmHandleQueryParameters:
       value:
         cmHandleQueryParameters:
-        - conditionName: hasAllProperties
-          conditionParameters:
-          - Color: yellow
-          - Shape: circle
-          - Size: small
+          - conditionName: hasAllProperties
+            conditionParameters:
+              - Color: yellow
+              - Shape: circle
+              - Size: small
     modulesCmHandleQueryParameters:
       value:
         cmHandleQueryParameters:
-        - conditionName: hasAllModules
-          conditionParameters:
-          - moduleName: my-module-1
-          - moduleName: my-module-2
-          - moduleName: my-module-3
+          - conditionName: hasAllModules
+            conditionParameters:
+              - moduleName: my-module-1
+              - moduleName: my-module-2
+              - moduleName: my-module-3
     allCmHandleQueryParameters:
       value:
         cmHandleQueryParameters:
-        - conditionName: hasAllModules
-          conditionParameters:
-          - moduleName: my-module-1
-          - moduleName: my-module-2
-          - moduleName: my-module-3
-        - conditionName: hasAllProperties
-          conditionParameters:
-          - Color: yellow
-          - Shape: circle
-          - Size: small
-        - conditionName: cmHandleWithCpsPath
-          conditionParameters:
-          - cpsPath: "//state[@cm-handle-state='ADVISED']"
+          - conditionName: hasAllModules
+            conditionParameters:
+              - moduleName: my-module-1
+              - moduleName: my-module-2
+              - moduleName: my-module-3
+          - conditionName: hasAllProperties
+            conditionParameters:
+              - Color: yellow
+              - Shape: circle
+              - Size: small
+          - conditionName: cmHandleWithCpsPath
+            conditionParameters:
+              - cpsPath: "//state[@cm-handle-state='ADVISED']"
     cpsPathCmHandleStateQueryParameters:
       value:
         cmHandleQueryParameters:
-        - conditionName: cmHandleWithCpsPath
-          conditionParameters:
-          - cpsPath: "//state[@cm-handle-state='LOCKED']"
+          - conditionName: cmHandleWithCpsPath
+            conditionParameters:
+              - cpsPath: "//state[@cm-handle-state='LOCKED']"
     cpsPathCmHandleDataSyncQueryParameters:
       value:
         cmHandleQueryParameters:
-        - conditionName: cmHandleWithCpsPath
-          conditionParameters:
-          - cpsPath: "//state[@data-sync-enabled='true']"
-
-security:
-  - basicAuth: []
+          - conditionName: cmHandleWithCpsPath
+            conditionParameters:
+              - cpsPath: "//state[@data-sync-enabled='true']"
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic