Implement getDataNode(anchorName, xPath) in NF-Proxy

Added spring-boot-starter-validation instead of cps-ri.
Added test 'Data node without leaves and without children.' to MultipartFileUtilSpec groovy test
Created a method getNodeByCmHandleIdAndXpath(cmHandleId, cpsPath)
Added hardcoded value of NFS DataspaceName as: "NFP-Operation".
Issue-ID: CPS-172

Signed-off-by: Hanif Kukkalli <lte-ng@outlook.com>
Change-Id: Ie8086ede01a9c5069b1ee75864b04a0ee5e8a4f6
diff --git a/cps-nf-proxy-rest/docs/openapi/components.yaml b/cps-nf-proxy-rest/docs/openapi/components.yaml
index 5352199..0b5d52a 100644
--- a/cps-nf-proxy-rest/docs/openapi/components.yaml
+++ b/cps-nf-proxy-rest/docs/openapi/components.yaml
@@ -20,7 +20,29 @@
           format: binary
 
   parameters:
-
+    cmHandleInPath:
+      name: cm-handle
+      in: path
+      description: The identifier for a network function, network element, subnetwork or any other cm object by managed NF-Proxy
+      required: true
+      schema:
+        type: string
+    xpathInQuery:
+      name: xpath
+      in: query
+      description: xpath
+      required: false
+      schema:
+        type: string
+        default: /
+    includeDescendantsOptionInQuery:
+      name: include-descendants
+      in: query
+      description: include-descendants
+      required: false
+      schema:
+        type: boolean
+        default: false
 
   responses:
     NotFound:
@@ -53,6 +75,12 @@
         application/json:
           schema:
             $ref: '#/components/schemas/ErrorMessage'
+    NotImplemented:
+      description: The given path has not been implemented
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
     Ok:
       description: OK
       content:
diff --git a/cps-nf-proxy-rest/docs/openapi/openapi.yml b/cps-nf-proxy-rest/docs/openapi/openapi.yml
index 0dbab34..efa8e72 100755
--- a/cps-nf-proxy-rest/docs/openapi/openapi.yml
+++ b/cps-nf-proxy-rest/docs/openapi/openapi.yml
@@ -6,8 +6,6 @@
 servers:
   - url: //localhost:8088/
 paths:
-  /v1/hello-world:
-    $ref: 'xnfProxy.yml#/helloWorld'
-  /v1/hello-error:
-    $ref: 'xnfProxy.yml#/helloError'
+  /v1/cm-handles/{cm-handle}/node:
+    $ref: 'xnfProxy.yml#/nodeByCmHandleAndXpath'
 
diff --git a/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml b/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml
index 0bb673a..4abe81a 100644
--- a/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml
+++ b/cps-nf-proxy-rest/docs/openapi/xnfProxy.yml
@@ -1,9 +1,14 @@
-helloWorld:
+nodeByCmHandleAndXpath:
   get:
+    description: Get a node with an option to retrieve all the children for a given cm Handle
     tags:
       - nf-proxy
-    summary: rest interface validation
-    operationId: helloWorld
+    summary: Get a node given a cm Handle and xpath
+    operationId: getNodeByCmHandleAndXpath
+    parameters:
+      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+      - $ref: 'components.yaml#/components/parameters/xpathInQuery'
+      - $ref: 'components.yaml#/components/parameters/includeDescendantsOptionInQuery'
     responses:
       200:
         $ref: 'components.yaml#/components/responses/Ok'
@@ -13,19 +18,7 @@
         $ref: 'components.yaml#/components/responses/Unauthorized'
       403:
         $ref: 'components.yaml#/components/responses/Forbidden'
-
-helloError:
-  get:
-    tags:
-      - nf-proxy
-    summary: error handler validation
-    operationId: helloError
-    responses:
-      200:
-        $ref: 'components.yaml#/components/responses/Ok'
-      400:
-        $ref: 'components.yaml#/components/responses/BadRequest'
-      401:
-        $ref: 'components.yaml#/components/responses/Unauthorized'
-      403:
-        $ref: 'components.yaml#/components/responses/Forbidden'
\ No newline at end of file
+      404:
+        $ref: 'components.yaml#/components/responses/NotFound'
+      501:
+        $ref: 'components.yaml#/components/responses/NotImplemented'
diff --git a/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java b/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java
index 99451e6..494e7f6 100644
--- a/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java
+++ b/cps-nf-proxy-rest/src/main/java/org/onap/cps/nfproxy/rest/controller/NfProxyController.java
@@ -2,6 +2,8 @@
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
+ *  Modification Copyright (C) 2021 highstreet technologies GmbH
+ *  ================================================================================
  *  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
@@ -19,24 +21,37 @@
 
 package org.onap.cps.nfproxy.rest.controller;
 
+import javax.validation.Valid;
+import org.onap.cps.nfproxy.api.NfProxyDataService;
 import org.onap.cps.nfproxy.rest.api.NfProxyApi;
-import org.onap.cps.spi.exceptions.CpsException;
+import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.spi.model.DataNode;
+import org.onap.cps.utils.DataMapUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+
 @RestController
 @RequestMapping("${rest.api.xnf-base-path}")
 public class NfProxyController implements NfProxyApi {
 
-    @Override
-    public ResponseEntity<Object> helloWorld() {
-        return new ResponseEntity<>("Hello World!", HttpStatus.OK);
-    }
+    private static final String XPATH_ROOT = "/";
+
+    @Autowired
+    private NfProxyDataService nfProxyDataService;
 
     @Override
-    public ResponseEntity<Object> helloError() {
-        throw new CpsException("Example error Message", "Example error description");
+    public ResponseEntity<Object> getNodeByCmHandleAndXpath(final String cmHandle, @Valid final String xpath,
+                                                            @Valid final Boolean includeDescendants) {
+        if (XPATH_ROOT.equals(xpath)) {
+            return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+        }
+        final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants)
+            ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS;
+        final DataNode dataNode = nfProxyDataService.getDataNode(cmHandle, xpath, fetchDescendantsOption);
+        return new ResponseEntity<>(DataMapUtils.toDataMap(dataNode), HttpStatus.OK);
     }
 }
diff --git a/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy b/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy
index 874a1b0..3cd6b9a 100644
--- a/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy
+++ b/cps-nf-proxy-rest/src/test/groovy/org/onap/cps/nfproxy/rest/controller/NfProxyControllerSpec.groovy
@@ -2,6 +2,8 @@
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
+ *  Modification Copyright (C) 2021 highstreet technologies GmbH
+ *  ================================================================================
  *  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
@@ -19,13 +21,19 @@
 
 package org.onap.cps.nfproxy.rest.controller
 
+import org.onap.cps.nfproxy.api.NfProxyDataService
+import org.onap.cps.spi.model.DataNodeBuilder
+import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.beans.factory.annotation.Value
 import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
 import org.springframework.http.HttpStatus
 import org.springframework.test.web.servlet.MockMvc
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
 import spock.lang.Specification
+import spock.lang.Unroll
+
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
 
 @WebMvcTest
 class NfProxyControllerSpec extends Specification {
@@ -33,22 +41,31 @@
     @Autowired
     MockMvc mvc
 
+    @SpringBean
+    NfProxyDataService mockNfProxyDataService = Mock()
+
     @Value('${rest.api.xnf-base-path}')
     def basePath
 
-    def 'Hello world method invocation.'(){
-        when: 'hello-world request performed'
-            def response = mvc.perform(MockMvcRequestBuilders.get("$basePath/v1/hello-world")).andReturn().response
-        then: 'success response returned'
-            response.status == HttpStatus.OK.value()
-            response.getContentAsString().contains("Hello World!")
+    def dataNodeBaseEndpoint
+
+    def setup() {
+        dataNodeBaseEndpoint = "$basePath/v1"
     }
 
-    def 'Example error handling.'(){
-        when: 'hello-error request performed'
-            def response = mvc.perform(MockMvcRequestBuilders.get("$basePath/v1/hello-error")).andReturn().response
-        then: 'error response returned'
-            response.status == HttpStatus.INTERNAL_SERVER_ERROR.value()
-            response.getContentAsString().contains("Example error")
+    @Unroll
+    def 'Get data node.'() {
+        given: 'the service returns a data node'
+            def xpath = 'some xpath'
+            def cmHandle = 'some handle'
+            def dataNode = new DataNodeBuilder().withXpath(xpath).withLeaves(["leaf": "value"]).build()
+            def endpoint = "$dataNodeBaseEndpoint/cm-handles/$cmHandle/node"
+            mockNfProxyDataService.getDataNode(cmHandle, xpath, OMIT_DESCENDANTS) >> dataNode
+        when: 'get request is performed through REST API'
+            def response = mvc.perform(get(endpoint).param('xpath', xpath)).andReturn().response
+        then: 'a success response is returned'
+            response.status == HttpStatus.OK.value()
+        and: 'response contains expected leaf and value'
+            response.contentAsString.contains('"leaf":"value"')
     }
 }