Create Endpoint For Get Cm Handles By Name

Create endpoint and implement logic for
get cm handle details by cm handle name

Issue-ID: CPS-817
Change-Id: I83bd2da9219d13fac715a08b19108028ca6f6751
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index fd02b6e..d82813b 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -50,7 +50,7 @@
         createdCmHandles:
           type: array
           items:
-            $ref: '#/components/schemas/RestCmHandle'
+            $ref: '#/components/schemas/RestInputCmHandle'
         updatedCmHandles:
           type: array
           example:
@@ -64,14 +64,14 @@
               update-my-property: updated-property
               delete-my-property: '~'
           items:
-            $ref: '#/components/schemas/RestCmHandle'
+            $ref: '#/components/schemas/RestInputCmHandle'
         removedCmHandles:
           type: array
           items:
             type: string
             example: [my-cm-handle1, my-cm-handle2, my-cm-handle3]
 
-    RestCmHandle:
+    RestInputCmHandle:
       required:
         - cmHandle
       type: object
@@ -146,6 +146,23 @@
           type: string
           example: my-module-revision
 
+    RestOutputCmHandle:
+      type: object
+      title: CM handle Details
+      properties:
+        cmHandle:
+          type: string
+          example: my-cm-handle1
+        publicCmHandleProperties:
+          $ref: '#/components/schemas/CmHandlePublicProperties'
+    CmHandlePublicProperties:
+      type: array
+      items:
+        type: object
+        additionalProperties:
+          type: string
+          example: Book Type
+
   examples:
     dataSampleRequest:
         summary: Sample request
diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml
index 3a71aba..a267fb4 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp.yml
@@ -262,3 +262,30 @@
         $ref: 'components.yaml#/components/responses/Forbidden'
       500:
         $ref: 'components.yaml#/components/responses/InternalServerError'
+
+retrieveCmHandleDetailsById:
+  get:
+    description: Retrieve CM handle details and properties by cm handle id
+    tags:
+      - network-cm-proxy
+    summary: Retrieve CM handle details
+    operationId: retrieveCmHandleDetailsById
+    parameters:
+      - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+    responses:
+      200:
+        description: OK
+        content:
+          application/json:
+            schema:
+              $ref: 'components.yaml#/components/schemas/RestOutputCmHandle'
+      400:
+        $ref: 'components.yaml#/components/responses/BadRequest'
+      401:
+        $ref: 'components.yaml#/components/responses/Unauthorized'
+      403:
+        $ref: 'components.yaml#/components/responses/Forbidden'
+      404:
+        $ref: 'components.yaml#/components/responses/NotFound'
+      500:
+        $ref: 'components.yaml#/components/responses/InternalServerError'
\ No newline at end of file
diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml
index 838a0d0..12a8318 100755
--- a/cps-ncmp-rest/docs/openapi/openapi.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi.yml
@@ -36,4 +36,7 @@
     $ref: 'ncmp.yml#/fetchModuleReferencesByCmHandle'
 
   /v1/ch/searches:
-    $ref: 'ncmp.yml#/executeCmHandleSearch'
\ No newline at end of file
+    $ref: 'ncmp.yml#/executeCmHandleSearch'
+
+  /v1/ch/{cm-handle}:
+    $ref: 'ncmp.yml#/retrieveCmHandleDetailsById'
\ No newline at end of file
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
index 419f6e9..86f4460 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
@@ -1,7 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
- *  Modifications (C) 2021-2022 Nordix Foundation
+ *  Modifications Copyright (C) 2021-2022 Nordix Foundation
  *  Modification Copyright (C) 2021 highstreet technologies GmbH
  *  Modifications (C) 2021 Bell Canada
  *  ================================================================================
@@ -10,6 +10,7 @@
  *  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.
@@ -38,15 +39,18 @@
 import lombok.extern.slf4j.Slf4j;
 import org.modelmapper.ModelMapper;
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
 import org.onap.cps.ncmp.rest.model.CmHandleProperties;
 import org.onap.cps.ncmp.rest.model.CmHandleProperty;
+import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties;
 import org.onap.cps.ncmp.rest.model.CmHandles;
 import org.onap.cps.ncmp.rest.model.ConditionProperties;
 import org.onap.cps.ncmp.rest.model.Conditions;
 import org.onap.cps.ncmp.rest.model.ModuleNameAsJsonObject;
 import org.onap.cps.ncmp.rest.model.ModuleNamesAsJsonArray;
 import org.onap.cps.ncmp.rest.model.ModuleReference;
+import org.onap.cps.ncmp.rest.model.RestOutputCmHandle;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -186,6 +190,18 @@
     }
 
     /**
+     * Search for Cm Handle and Properties by Name.
+     * @param cmHandleId cm-handle identifier
+     * @return cm handle and its properties
+     */
+    @Override
+    public ResponseEntity<RestOutputCmHandle> retrieveCmHandleDetailsById(final String cmHandleId) {
+        final NcmpServiceCmHandle ncmpServiceCmHandle = networkCmProxyDataService.getNcmpServiceCmHandle(cmHandleId);
+        final RestOutputCmHandle restOutputCmHandle = toRestOutputCmHandle(ncmpServiceCmHandle);
+        return ResponseEntity.ok(restOutputCmHandle);
+    }
+
+    /**
      * Return module references for a cm handle.
      *
      * @param cmHandle the cm handle
@@ -233,4 +249,13 @@
         }
         return cmHandleProperties;
     }
+
+    private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) {
+        final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle();
+        final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties();
+        restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleID());
+        cmHandlePublicProperties.add(ncmpServiceCmHandle.getPublicProperties());
+        restOutputCmHandle.setPublicCmHandleProperties(cmHandlePublicProperties);
+        return restOutputCmHandle;
+    }
 }
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/RestInputMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/RestInputMapper.java
index d38204c..a1d046e 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/RestInputMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/RestInputMapper.java
@@ -22,13 +22,12 @@
 
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
 import org.mapstruct.NullValueMappingStrategy;
 import org.mapstruct.NullValuePropertyMappingStrategy;
-import org.onap.cps.ncmp.api.models.CmHandle;
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
-import org.onap.cps.ncmp.rest.model.RestCmHandle;
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration;
+import org.onap.cps.ncmp.rest.model.RestInputCmHandle;
 
 @Mapper(componentModel = "spring", nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
     nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
@@ -36,11 +35,9 @@
 
     DmiPluginRegistration toDmiPluginRegistration(final RestDmiPluginRegistration restDmiPluginRegistration);
 
-    @Mappings({
-        @Mapping(source = "cmHandle", target = "cmHandleID"),
-        @Mapping(source = "cmHandleProperties", target = "dmiProperties"),
-        @Mapping(source = "publicCmHandleProperties", target = "publicProperties")
-    })
-    CmHandle toCmHandle(final RestCmHandle restCmHandle);
+    @Mapping(source = "cmHandle", target = "cmHandleID")
+    @Mapping(source = "cmHandleProperties", target = "dmiProperties")
+    @Mapping(source = "publicCmHandleProperties", target = "publicProperties")
+    NcmpServiceCmHandle toNcmpServiceCmHandle(final RestInputCmHandle restInputCmHandle);
 
 }
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java
index fd01096..5aaf1c3 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java
@@ -59,23 +59,13 @@
         return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception);
     }
 
-    @ExceptionHandler({CpsException.class})
-    public static ResponseEntity<Object> handleAnyOtherCpsExceptions(final CpsException exception) {
+    @ExceptionHandler({CpsException.class, ServerNcmpException.class})
+    public static ResponseEntity<Object> handleAnyOtherCpsExceptions(final Exception exception) {
         return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception);
     }
 
-    @ExceptionHandler({ServerNcmpException.class})
-    public static ResponseEntity<Object> handleServerNcmpExceptions(final ServerNcmpException exception) {
-        return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception);
-    }
-
-    @ExceptionHandler({DmiRequestException.class})
-    public static ResponseEntity<Object> handleDmiRequestExceptions(final DmiRequestException exception) {
-        return buildErrorResponse(HttpStatus.BAD_REQUEST, exception);
-    }
-
-    @ExceptionHandler({DataValidationException.class, HttpMessageNotReadableException.class})
-    public static ResponseEntity<Object> handleDataValidatedExceptions(final Exception exception) {
+    @ExceptionHandler({DmiRequestException.class, DataValidationException.class, HttpMessageNotReadableException.class})
+    public static ResponseEntity<Object> handleDmiRequestExceptions(final Exception exception) {
         return buildErrorResponse(HttpStatus.BAD_REQUEST, exception);
     }
 
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index 0c8b222..c997714 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -22,6 +22,9 @@
 
 package org.onap.cps.ncmp.rest.controller
 
+
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
+
 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
@@ -180,6 +183,28 @@
             response.contentAsString == '{"cmHandles":[{"cmHandleId":"some-cmhandle-id1"},{"cmHandleId":"some-cmhandle-id2"}]}'
     }
 
+    def 'Get Cm Handle details by Cm Handle id.' () {
+        given: 'an endpoint and a cm handle'
+            def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/Some-Cm-Handle"
+        and: 'an existing ncmp service cm handle'
+            def cmHandleId = 'Some-Cm-Handle'
+            def dmiProperties = [ prop:'some DMI property' ]
+            def publicProperties = [ "public prop":'some public property' ]
+            def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleID: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties)
+        and: 'the service method is invoked with the cm handle id'
+            1 * mockNetworkCmProxyDataService.getNcmpServiceCmHandle('Some-Cm-Handle') >> ncmpServiceCmHandle
+        when: 'the cm handle details api is invoked'
+            def response = mvc.perform(get(cmHandleDetailsEndpoint)).andReturn().response
+        then: 'the correct response is returned'
+            response.status == HttpStatus.OK.value()
+        and: 'the response returns public properties and the correct properties'
+            response.contentAsString.contains('publicCmHandleProperties')
+            response.contentAsString.contains('public prop')
+            response.contentAsString.contains('some public property')
+        and: 'the content does not contain dmi properties'
+            !response.contentAsString.contains("some DMI property")
+    }
+
     def 'Call execute cm handle searches with unrecognized condition name.'() {
         given: 'an endpoint and json data'
             def searchesEndpoint = "$ncmpBasePathV1/ch/searches"
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/RestInputMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/RestInputMapperSpec.groovy
index c48a8ed..ed93881 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/RestInputMapperSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/RestInputMapperSpec.groovy
@@ -21,8 +21,8 @@
 package org.onap.cps.ncmp.rest.controller
 
 import org.mapstruct.factory.Mappers
-import org.onap.cps.ncmp.rest.model.RestCmHandle
 import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration
+import org.onap.cps.ncmp.rest.model.RestInputCmHandle
 import spock.lang.Specification
 
 class RestInputMapperSpec extends Specification {
@@ -31,7 +31,7 @@
 
     def 'Convert a created REST CM Handle Input to an NCMP Service CM Handle with #scenario'() {
         given: 'a rest cm handle input'
-            def inputRestCmHandle = new RestCmHandle(cmHandle : 'example-id', cmHandleProperties: dmiProperties,
+            def inputRestCmHandle = new RestInputCmHandle(cmHandle : 'example-id', cmHandleProperties: dmiProperties,
                 publicCmHandleProperties: publicProperties)
             def restDmiPluginRegistration = new RestDmiPluginRegistration(
                 createdCmHandles: [inputRestCmHandle])
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
index 306f546..8004328 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy
@@ -29,6 +29,7 @@
 import org.onap.cps.ncmp.api.impl.exception.ServerNcmpException
 import org.onap.cps.ncmp.rest.controller.RestInputMapper
 import org.onap.cps.spi.exceptions.CpsException
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.utils.JsonObjectMapper
 import org.spockframework.spring.SpringBean
@@ -78,6 +79,8 @@
     def errorMessage = 'some error message'
     @Shared
     def errorDetails = 'some error details'
+    @Shared
+    def dataNodeNotFoundErrorMessage = 'DataNode not found'
 
     def setup() {
         dataNodeBaseEndpointNcmp = "$basePathNcmp/v1"
@@ -89,13 +92,14 @@
             setupTestException(exception, NCMP)
             def response = performTestRequest(NCMP)
         then: 'an HTTP response is returned with correct message and details'
-            assertTestResponse(response, expectedErrorCode, errorMessage, expectedErrorDetails)
+            assertTestResponse(response, expectedErrorCode, expectedErrorMessage, expectedErrorDetails)
         where:
-            scenario      | exception                                           || expectedErrorDetails | expectedErrorCode
-            'CPS'         | new CpsException(errorMessage, errorDetails)        || errorDetails         | INTERNAL_SERVER_ERROR
-            'NCMP-server' | new ServerNcmpException(errorMessage, errorDetails) || null                 | INTERNAL_SERVER_ERROR
-            'NCMP-client' | new DmiRequestException(errorMessage, errorDetails) || null                 | BAD_REQUEST
-            'other'       | new IllegalStateException(errorMessage)             || null                 | INTERNAL_SERVER_ERROR
+            scenario              | exception                                                                 || expectedErrorDetails | expectedErrorMessage          | expectedErrorCode
+            'CPS'                 | new CpsException(errorMessage, errorDetails)                              || errorDetails         |  errorMessage                 | INTERNAL_SERVER_ERROR
+            'NCMP-server'         | new ServerNcmpException(errorMessage, errorDetails)                       || null                 |  errorMessage                 | INTERNAL_SERVER_ERROR
+            'NCMP-client'         | new DmiRequestException(errorMessage, errorDetails)                       || null                 |  errorMessage                 | BAD_REQUEST
+            'DataNode Validation' | new DataNodeNotFoundException(dataNodeNotFoundErrorMessage, errorDetails) || null                 |  dataNodeNotFoundErrorMessage | BAD_REQUEST
+            'other'               | new IllegalStateException(errorMessage)                                   || null                 |  errorMessage                 | INTERNAL_SERVER_ERROR
     }
 
     def 'Post request with exception returns correct HTTP Status.'() {