Write data for cm handle passthrough:running 08/123408/8
authorniamhcore <niamh.core@est.tech>
Fri, 20 Aug 2021 10:24:06 +0000 (11:24 +0100)
committerniamhcore <niamh.core@est.tech>
Wed, 25 Aug 2021 10:25:31 +0000 (11:25 +0100)
Issue-ID: CPS-574
Signed-off-by: niamhcore <niamh.core@est.tech>
Change-Id: I15e2ad500d2bbf7a1d408b8a852287e55bddbecb

12 files changed:
docs/openapi/components.yml
docs/openapi/openapi.yml
src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java
src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java
src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java
src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java
src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java
src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy
src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy
src/test/groovy/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClientSpec.groovy
src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy
src/test/resources/WriteDataForCmHandle.json [new file with mode: 0644]

index cb39fa4..ba2a0ec 100644 (file)
@@ -58,7 +58,7 @@ components:
               namespace:
                 type: string
 
-    OperationalRequest:
+    DataAccessReadRequest:
       type: object
       properties:
         operation:
@@ -69,6 +69,21 @@ components:
           additionalProperties:
             type: string
 
+    DataAccessWriteRequest:
+      type: object
+      properties:
+        operation:
+          type: string
+          enum: [ create ]
+        dataType:
+          type: string
+        data:
+          type: object
+        cmHandleProperties:
+          type: object
+          additionalProperties:
+            type: string
+
   responses:
     NotFound:
       description: The specified resource was not found
index af285f4..f169efd 100644 (file)
@@ -136,7 +136,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: 'components.yml#/components/schemas/OperationalRequest'
+              $ref: 'components.yml#/components/schemas/DataAccessReadRequest'
       responses:
         '200':
           $ref: 'components.yml#/components/responses/Ok'
@@ -165,7 +165,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: 'components.yml#/components/schemas/OperationalRequest'
+              $ref: 'components.yml#/components/schemas/DataAccessReadRequest'
       responses:
         '200':
           $ref: 'components.yml#/components/responses/Ok'
@@ -175,3 +175,29 @@ paths:
           $ref: 'components.yml#/components/responses/Unauthorized'
         '403':
           $ref: 'components.yml#/components/responses/Forbidden'
+
+    post:
+      description: Write data for a cmHandle using passthrough-running
+      tags:
+        - dmi-plugin
+      summary: Write data for a cmHandle
+      operationId: writeDataByPassthroughRunningForCmHandle
+      parameters:
+        - $ref: 'components.yml#/components/parameters/cmHandleInPath'
+        - $ref: 'components.yml#/components/parameters/resourceIdentifierInPath'
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: 'components.yml#/components/schemas/DataAccessWriteRequest'
+      responses:
+        '200':
+          $ref: 'components.yml#/components/responses/Ok'
+        '400':
+          $ref: 'components.yml#/components/responses/BadRequest'
+        '401':
+          $ref: 'components.yml#/components/responses/Unauthorized'
+        '403':
+          $ref: 'components.yml#/components/responses/Forbidden'
+
index 79c11a4..32651e4 100644 (file)
@@ -27,14 +27,16 @@ import javax.validation.Valid;
 import javax.validation.constraints.Min;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.dmi.model.CmHandles;
+import org.onap.cps.ncmp.dmi.model.DataAccessReadRequest;
+import org.onap.cps.ncmp.dmi.model.DataAccessWriteRequest;
 import org.onap.cps.ncmp.dmi.model.ModuleReference;
 import org.onap.cps.ncmp.dmi.model.ModuleRequestParent;
 import org.onap.cps.ncmp.dmi.model.ModuleSet;
-import org.onap.cps.ncmp.dmi.model.OperationalRequest;
 import org.onap.cps.ncmp.dmi.rest.api.DmiPluginApi;
 import org.onap.cps.ncmp.dmi.rest.api.DmiPluginInternalApi;
 import org.onap.cps.ncmp.dmi.service.DmiService;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -61,7 +63,7 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi {
 
     @Override
     public ResponseEntity<Object> retrieveModuleResources(@Valid final ModuleRequestParent moduleRequestParent,
-                                                          final String cmHandle) {
+        final String cmHandle) {
         if (moduleRequestParent.getOperation().toString().equals("read")) {
             final var moduleReferenceList = convertRestObjectToJavaApiObject(moduleRequestParent);
             final var response = dmiService.getModuleResources(cmHandle, moduleReferenceList);
@@ -73,6 +75,25 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi {
         return new ResponseEntity<>("Unsupported operation", HttpStatus.CONFLICT);
     }
 
+    /**
+     * Write data using passthrough for the given cmHandle.
+     *
+     * @param dataAccessWriteRequest pass through request
+     * @param cmHandle               cmHandle
+     * @param resourceIdentifier     resource identifier
+     * @return (@ code ResponseEntity) response entity
+     */
+    @Override
+    public ResponseEntity<Object> writeDataByPassthroughRunningForCmHandle(
+        final DataAccessWriteRequest dataAccessWriteRequest,
+        final String cmHandle, final String resourceIdentifier) {
+        final String response = dmiService.writeResourceDataPassthroughForCmHandle(cmHandle,
+            resourceIdentifier,
+            MediaType.APPLICATION_JSON_VALUE,
+            dataAccessWriteRequest.getData());
+        return new ResponseEntity<>(response, HttpStatus.OK);
+    }
+
     /**
      * This method register given list of cm-handles to ncmp.
      *
@@ -89,60 +110,58 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi {
     }
 
     /**
-     * This method fetches the resource for given cm handle using pass
-     * through operational. It filters the response on the basis of depth and field
-     * query parameters and returns response.
+     * This method fetches the resource for given cm handle using pass through operational. It filters the response on
+     * the basis of depth and field query parameters and returns response.
      *
-     * @param cmHandle cm handle identifier
-     * @param resourceIdentifier resource identifier to fetch data
-     * @param body operational body
-     * @param accept accept header parameter
-     * @param fields fields to filter the response data
-     * @param depth depth parameter for the response
+     * @param cmHandle              cm handle identifier
+     * @param resourceIdentifier    resource identifier to fetch data
+     * @param dataAccessReadRequest data Access Read Request
+     * @param accept                accept header parameter
+     * @param fields                fields to filter the response data
+     * @param depth                 depth parameter for the response
      * @return {@code ResponseEntity} response entity
      */
     @Override
     public ResponseEntity<Object> getResourceDataOperationalForCmHandle(final String cmHandle,
-                                                                        final String resourceIdentifier,
-                                                                        final @Valid OperationalRequest body,
-                                                                        final String accept,
-                                                                        final @Valid String fields,
-                                                                        final @Min(1) @Valid Integer depth) {
+        final String resourceIdentifier,
+        final @Valid DataAccessReadRequest dataAccessReadRequest,
+        final String accept,
+        final @Valid String fields,
+        final @Min(1) @Valid Integer depth) {
         final var modulesListAsJson = dmiService.getResourceDataOperationalForCmHandle(cmHandle,
-                resourceIdentifier,
-                accept,
-                fields,
-                depth,
-                body.getCmHandleProperties());
+            resourceIdentifier,
+            accept,
+            fields,
+            depth,
+            dataAccessReadRequest.getCmHandleProperties());
         return ResponseEntity.ok(modulesListAsJson);
     }
 
     /**
-     * This method fetches the resource for given cm handle using pass
-     * through running. It filters the response on the basis of depth and field
-     * query parameters and returns response.
+     * This method fetches the resource for given cm handle using pass through running. It filters the response on the
+     * basis of depth and field query parameters and returns response.
      *
-     * @param cmHandle cm handle identifier
-     * @param resourceIdentifier resource identifier to fetch data
-     * @param body operational body
-     * @param accept accept header parameter
-     * @param fields fields to filter the response data
-     * @param depth depth parameter for the response
+     * @param cmHandle              cm handle identifier
+     * @param resourceIdentifier    resource identifier to fetch data
+     * @param dataAccessReadRequest data Access Read Request
+     * @param accept                accept header parameter
+     * @param fields                fields to filter the response data
+     * @param depth                 depth parameter for the response
      * @return {@code ResponseEntity} response entity
      */
     @Override
     public ResponseEntity<Object> getResourceDataPassthroughRunningForCmHandle(final String cmHandle,
-                                                                               final String resourceIdentifier,
-                                                                               final @Valid OperationalRequest body,
-                                                                               final String accept,
-                                                                               final @Valid String fields,
-                                                                               final @Min(1) @Valid Integer depth) {
+        final String resourceIdentifier,
+        final @Valid DataAccessReadRequest dataAccessReadRequest,
+        final String accept,
+        final @Valid String fields,
+        final @Min(1) @Valid Integer depth) {
         final var modulesListAsJson = dmiService.getResourceDataPassThroughRunningForCmHandle(cmHandle,
-                resourceIdentifier,
-                accept,
-                fields,
-                depth,
-                body.getCmHandleProperties());
+            resourceIdentifier,
+            accept,
+            fields,
+            depth,
+            dataAccessReadRequest.getCmHandleProperties());
         return ResponseEntity.ok(modulesListAsJson);
     }
 
index 8330127..f144608 100644 (file)
@@ -42,8 +42,8 @@ public interface DmiService {
     ModuleSet getModulesForCmHandle(String cmHandle) throws DmiException;
 
     /**
-     * This method used to register the given {@code CmHandles}
-     * which contains list of {@code CmHandle} to cps repository.
+     * This method used to register the given {@code CmHandles} which contains list of {@code CmHandle} to cps
+     * repository.
      *
      * @param cmHandles list of cm-handles
      */
@@ -53,50 +53,58 @@ public interface DmiService {
      * Get module resources for the given cm handle and modules.
      *
      * @param cmHandle cmHandle
-     * @param modules a list of module data
+     * @param modules  a list of module data
      * @return returns all module resources
      */
     String getModuleResources(String cmHandle, List<ModuleReference> modules);
 
     /**
-     * This method use to fetch the resource data from cm handle
-     * for datastore pass-through operational and resource Identifier. Fields and depths query
-     * parameter are used to filter the response from network resource.
+     * This method use to fetch the resource data from cm handle for datastore pass-through operational and resource
+     * Identifier. Fields and depths query parameter are used to filter the response from network resource.
      *
-     * @param cmHandle cm handle identifier
-     * @param resourceIdentifier resource identifier
-     * @param acceptParam accept header parameter
-     * @param fieldsQuery fields query parameter
-     * @param depthQuery depth query parameter
+     * @param cmHandle            cm handle identifier
+     * @param resourceIdentifier  resource identifier
+     * @param acceptParam         accept header parameter
+     * @param fieldsQuery         fields query parameter
+     * @param depthQuery          depth query parameter
      * @param cmHandlePropertyMap cm handle properties
-     *
      * @return {@code Object} response from network function
      */
     Object getResourceDataOperationalForCmHandle(@NotNull String cmHandle,
-                                      @NotNull String resourceIdentifier,
-                                      String acceptParam,
-                                      String fieldsQuery,
-                                      Integer depthQuery,
-                                      Map<String, String> cmHandlePropertyMap);
+        @NotNull String resourceIdentifier,
+        String acceptParam,
+        String fieldsQuery,
+        Integer depthQuery,
+        Map<String, String> cmHandlePropertyMap);
 
     /**
-     * This method use to fetch the resource data from cm handle
-     * for datastore pass-through running and resource Identifier. Fields and depths query
-     * parameter are used to filter the response from network resource.
+     * This method use to fetch the resource data from cm handle for datastore pass-through running and resource
+     * Identifier. Fields and depths query parameter are used to filter the response from network resource.
      *
-     * @param cmHandle cm handle identifier
-     * @param resourceIdentifier resource identifier
-     * @param acceptParam accept header parameter
-     * @param fieldsQuery fields query parameter
-     * @param depthQuery depth query parameter
+     * @param cmHandle            cm handle identifier
+     * @param resourceIdentifier  resource identifier
+     * @param acceptParam         accept header parameter
+     * @param fieldsQuery         fields query parameter
+     * @param depthQuery          depth query parameter
      * @param cmHandlePropertyMap cm handle properties
-     *
      * @return {@code Object} response from network function
      */
     Object getResourceDataPassThroughRunningForCmHandle(@NotNull String cmHandle,
-                                                 @NotNull String resourceIdentifier,
-                                                 String acceptParam,
-                                                 String fieldsQuery,
-                                                 Integer depthQuery,
-                                                 Map<String, String> cmHandlePropertyMap);
+        @NotNull String resourceIdentifier,
+        String acceptParam,
+        String fieldsQuery,
+        Integer depthQuery,
+        Map<String, String> cmHandlePropertyMap);
+
+    /**
+     * Write resource data to sdnc using passthrough running.
+     *
+     * @param cmHandle           cmHandle
+     * @param resourceIdentifier resource identifier
+     * @param dataType           accept header parameter
+     * @param data               request data
+     * @return response from sdnc
+     */
+    String writeResourceDataPassthroughForCmHandle(String cmHandle, String resourceIdentifier, String dataType,
+        Object data);
 }
\ No newline at end of file
index 62f93e6..a139f7b 100644 (file)
@@ -69,8 +69,8 @@ public class DmiServiceImpl implements DmiService {
      * @param objectMapper        objectMapper
      */
     public DmiServiceImpl(final DmiPluginProperties dmiPluginProperties,
-                          final NcmpRestClient ncmpRestClient,
-                          final SdncOperations sdncOperations, final ObjectMapper objectMapper) {
+        final NcmpRestClient ncmpRestClient,
+        final SdncOperations sdncOperations, final ObjectMapper objectMapper) {
         this.dmiPluginProperties = dmiPluginProperties;
         this.ncmpRestClient = ncmpRestClient;
         this.objectMapper = objectMapper;
@@ -88,7 +88,7 @@ public class DmiServiceImpl implements DmiService {
             return createModuleSchema(responseBody);
         } else {
             throw new DmiException("SDNC is not able to process request.",
-                    "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody());
+                "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody());
         }
     }
 
@@ -103,7 +103,7 @@ public class DmiServiceImpl implements DmiService {
             } else {
                 log.error("SDNC did not return a module resource for the given cmHandle {}", cmHandle);
                 throw new ModuleResourceNotFoundException(cmHandle,
-                        "SDNC did not return a module resource for the given cmHandle.");
+                    "SDNC did not return a module resource for the given cmHandle.");
             }
         }
         return getModuleResponses.toJSONString();
@@ -126,7 +126,7 @@ public class DmiServiceImpl implements DmiService {
         } catch (final JsonProcessingException e) {
             log.error("Parsing error occurred while converting cm-handles to JSON {}", cmHandles);
             throw new DmiException("Internal Server Error.",
-                    "Parsing error occurred while converting given cm-handles object list to JSON ");
+                "Parsing error occurred while converting given cm-handles object list to JSON ");
         }
         final ResponseEntity<String> responseEntity = ncmpRestClient.registerCmHandlesWithNcmp(cmHandlesJson);
         if ((responseEntity.getStatusCode() != HttpStatus.CREATED)) {
@@ -166,44 +166,66 @@ public class DmiServiceImpl implements DmiService {
 
     @Override
     public Object getResourceDataOperationalForCmHandle(final @NotNull String cmHandle,
-                                             final @NotNull String resourceIdentifier,
-                                             final String acceptParam,
-                                             final String fieldsQuery,
-                                             final Integer depthQuery,
-                                             final Map<String, String> cmHandlePropertyMap) {
+        final @NotNull String resourceIdentifier,
+        final String acceptParam,
+        final String fieldsQuery,
+        final Integer depthQuery,
+        final Map<String, String> cmHandlePropertyMap) {
         // not using cmHandlePropertyMap of onap dmi impl , other dmi impl might use this.
         final ResponseEntity<String> responseEntity = sdncOperations.getResouceDataForOperationalAndRunning(cmHandle,
-                resourceIdentifier,
-                fieldsQuery,
-                depthQuery,
-                acceptParam,
+            resourceIdentifier,
+            fieldsQuery,
+            depthQuery,
+            acceptParam,
                 CONTENT_QUERY_PASSTHROUGH_OPERATIONAL);
         return prepareAndSendResponse(responseEntity, cmHandle);
     }
 
     @Override
     public Object getResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle,
-                                                               final @NotNull String resourceIdentifier,
-                                                               final String acceptParam,
-                                                               final String fieldsQuery,
-                                                               final Integer depthQuery,
-                                                               final Map<String, String> cmHandlePropertyMap) {
+        final @NotNull String resourceIdentifier,
+        final String acceptParam,
+        final String fieldsQuery,
+        final Integer depthQuery,
+        final Map<String, String> cmHandlePropertyMap) {
         // not using cmHandlePropertyMap of onap dmi impl , other dmi impl might use this.
         final ResponseEntity<String> responseEntity = sdncOperations.getResouceDataForOperationalAndRunning(cmHandle,
-                resourceIdentifier,
-                fieldsQuery,
-                depthQuery,
-                acceptParam,
-                CONTENT_QUERY_PASSTHROUGH_RUNNING);
+            resourceIdentifier,
+            fieldsQuery,
+            depthQuery,
+            acceptParam,
+            CONTENT_QUERY_PASSTHROUGH_RUNNING);
         return prepareAndSendResponse(responseEntity, cmHandle);
     }
 
+    @Override
+    public String writeResourceDataPassthroughForCmHandle(final String cmHandle, final String resourceIdentifier,
+        final String dataType, final Object data) {
+        final String jsonData;
+        try {
+            jsonData = objectMapper.writeValueAsString(data);
+        } catch (final JsonProcessingException e) {
+            log.error("JSON exception occurred when processing pass through request data for the given cmHandle {}",
+                cmHandle);
+            throw new DmiException("Unable to process incoming JSON from the request body.",
+                "JSON exception occurred when writing data for the given cmHandle " + cmHandle, e);
+        }
+        final ResponseEntity<String> responseEntity =
+            sdncOperations.writeResourceDataPassthroughRunning(cmHandle, resourceIdentifier, dataType, jsonData);
+        if (responseEntity.getStatusCode() == HttpStatus.CREATED) {
+            return responseEntity.getBody();
+        } else {
+            throw new DmiException(cmHandle,
+                "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody());
+        }
+    }
+
     private String prepareAndSendResponse(final ResponseEntity<String> responseEntity, final String cmHandle) {
         if (responseEntity.getStatusCode() == HttpStatus.OK) {
             return responseEntity.getBody();
         } else {
             throw new ResourceDataNotFound(cmHandle,
-                    "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody());
+                "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody());
         }
     }
 
@@ -217,9 +239,9 @@ public class DmiServiceImpl implements DmiService {
             moduleRequest = writer.writeValueAsString(ietfNetconfModuleReferences);
         } catch (final JsonProcessingException e) {
             log.error("JSON exception occurred when creating the module request for the given module reference {}",
-                    moduleReference.getName());
+                moduleReference.getName());
             throw new DmiException("Unable to process JSON.",
-                    "JSON exception occurred when creating the module request.", e);
+                "JSON exception occurred when creating the module request.", e);
         }
         return moduleRequest;
     }
index 499033d..fe13a38 100644 (file)
@@ -23,7 +23,6 @@ package org.onap.cps.ncmp.dmi.service.client;
 import org.onap.cps.ncmp.dmi.config.DmiConfiguration.SdncProperties;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
 import org.springframework.web.client.RestTemplate;
@@ -43,7 +42,6 @@ public class SdncRestconfClient {
      * restconf get operation on sdnc.
      *
      * @param getResourceUrl sdnc get url
-     *
      * @return the response entity
      */
     public ResponseEntity<String> getOperation(final String getResourceUrl) {
@@ -54,8 +52,7 @@ public class SdncRestconfClient {
      * Overloaded restconf get operation on sdnc with http headers.
      *
      * @param getResourceUrl sdnc get url
-     * @param httpHeaders http headers
-     *
+     * @param httpHeaders    http headers
      * @return the response entity
      */
     public ResponseEntity<String> getOperation(final String getResourceUrl, final HttpHeaders httpHeaders) {
@@ -71,20 +68,15 @@ public class SdncRestconfClient {
      *
      * @param postResourceUrl sdnc post resource url
      * @param jsonData        json data
+     * @param httpHeaders     HTTP headers
      * @return the response entity
      */
     public ResponseEntity<String> postOperationWithJsonData(final String postResourceUrl,
-                                                            final String jsonData) {
+        final String jsonData, final HttpHeaders httpHeaders) {
         final var sdncBaseUrl = sdncProperties.getBaseUrl();
         final var sdncRestconfUrl = sdncBaseUrl.concat(postResourceUrl);
-        final var httpEntity = new HttpEntity<>(jsonData, configureHttpHeaders());
-        return restTemplate.postForEntity(sdncRestconfUrl, httpEntity, String.class);
-    }
-
-    private HttpHeaders configureHttpHeaders() {
-        final var httpHeaders = new HttpHeaders();
         httpHeaders.setBasicAuth(sdncProperties.getAuthUsername(), sdncProperties.getAuthPassword());
-        httpHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
-        return httpHeaders;
+        final var httpEntity = new HttpEntity<>(jsonData, httpHeaders);
+        return restTemplate.postForEntity(sdncRestconfUrl, httpEntity, String.class);
     }
 }
\ No newline at end of file
index ab9c7e1..73503d2 100644 (file)
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
 import org.onap.cps.ncmp.dmi.config.DmiConfiguration.SdncProperties;
 import org.onap.cps.ncmp.dmi.service.client.SdncRestconfClient;
 import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
 
@@ -34,9 +35,9 @@ import org.springframework.stereotype.Component;
 public class SdncOperations {
 
     private static final String TOPOLOGY_URL_TEMPLATE_DATA =
-            "/rests/data/network-topology:network-topology/topology={topologyId}";
+        "/rests/data/network-topology:network-topology/topology={topologyId}";
     private static final String TOPOLOGY_URL_TEMPLATE_OPERATIONAL =
-            "/rests/operations/network-topology:network-topology/topology={topologyId}";
+        "/rests/operations/network-topology:network-topology/topology={topologyId}";
     private static final String MOUNT_URL_TEMPLATE = "/node={nodeId}/yang-ext:mount";
     private static final String GET_SCHEMA_URL = "/ietf-netconf-monitoring:netconf-state/schemas";
     private static final String GET_SCHEMA_SOURCES_URL = "/ietf-netconf-monitoring:get-schema";
@@ -56,7 +57,7 @@ public class SdncOperations {
         this.sdncProperties = sdncProperties;
         this.sdncRestconfClient = sdncRestconfClient;
         topologyUrlOperational =
-                TOPOLOGY_URL_TEMPLATE_OPERATIONAL.replace("{topologyId}", this.sdncProperties.getTopologyId());
+            TOPOLOGY_URL_TEMPLATE_OPERATIONAL.replace("{topologyId}", this.sdncProperties.getTopologyId());
         topologyUrlData = TOPOLOGY_URL_TEMPLATE_DATA.replace("{topologyId}", this.sdncProperties.getTopologyId());
     }
 
@@ -79,30 +80,32 @@ public class SdncOperations {
      * @return response entity
      */
     public ResponseEntity<String> getModuleResource(final String nodeId, final String moduleProperties) {
-        final String getYangResourceUrl = prepareGetOperationSchemaUrl(nodeId);
-        return sdncRestconfClient.postOperationWithJsonData(getYangResourceUrl, moduleProperties);
+        final var getYangResourceUrl = prepareGetOperationSchemaUrl(nodeId);
+        final var httpHeaders = new HttpHeaders();
+        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+        return sdncRestconfClient
+            .postOperationWithJsonData(getYangResourceUrl, moduleProperties, httpHeaders);
     }
 
     /**
-     * This method fetches the resource data for given node identifier on given resource
-     * using sdnc client.
+     * This method fetches the resource data for given node identifier on given resource using sdnc client.
      *
-     * @param nodeId network resource identifier
-     * @param resourceId resource identifier
+     * @param nodeId      network resource identifier
+     * @param resourceId  resource identifier
      * @param fieldsValue fields query
-     * @param depthValue depth query
+     * @param depthValue  depth query
      * @param acceptParam accept parameter
      * @return {@code ResponseEntity} response entity
      */
     public ResponseEntity<String> getResouceDataForOperationalAndRunning(final String nodeId,
-                                                                         final String resourceId,
-                                                                         final String fieldsValue,
-                                                                         final Integer depthValue,
-                                                                         final String acceptParam,
+        final String resourceId,
+        final String fieldsValue,
+        final Integer depthValue,
+        final String acceptParam,
                                                                          final String contentQuery) {
         final String getResourceDataUrl = prepareResourceDataUrl(nodeId,
-                resourceId,
-                getQueryList(fieldsValue, depthValue, contentQuery));
+            resourceId,
+            getQueryList(fieldsValue, depthValue, contentQuery));
         final HttpHeaders httpHeaders = new HttpHeaders();
         if (!StringUtils.isEmpty(acceptParam)) {
             httpHeaders.set(HttpHeaders.ACCEPT, acceptParam);
@@ -110,6 +113,23 @@ public class SdncOperations {
         return sdncRestconfClient.getOperation(getResourceDataUrl, httpHeaders);
     }
 
+    /**
+     * Write resource data using passthrough running.
+     *
+     * @param nodeId      network resource identifier
+     * @param resourceId  resource identifier
+     * @param contentType http content type
+     * @param requestData request data
+     * @return {@code ResponseEntity} response entity
+     */
+    public ResponseEntity<String> writeResourceDataPassthroughRunning(final String nodeId,
+        final String resourceId, final String contentType, final String requestData) {
+        final var getResourceDataUrl = preparePassthroughRunningUrl(nodeId, resourceId);
+        final var httpHeaders = new HttpHeaders();
+        httpHeaders.setContentType(MediaType.parseMediaType(contentType));
+        return sdncRestconfClient.postOperationWithJsonData(getResourceDataUrl, requestData, httpHeaders);
+    }
+
     @NotNull
     private List<String> getQueryList(final String fieldsValue, final Integer depthValue, final String contentQuery) {
         final List<String> queryList = new LinkedList<>();
@@ -131,6 +151,10 @@ public class SdncOperations {
         return addResource(addTopologyDataUrlwithNode(nodeId), GET_SCHEMA_URL);
     }
 
+    private String preparePassthroughRunningUrl(final String nodeId, final String resourceId) {
+        return addResource(addTopologyDataUrlwithNode(nodeId), "/" + resourceId);
+    }
+
     private String prepareGetOperationSchemaUrl(final String nodeId) {
         final var topologyMountUrl = topologyUrlOperational + MOUNT_URL_TEMPLATE;
         final var topologyMountUrlWithNodeId = topologyMountUrl.replace("{nodeId}", nodeId);
@@ -139,8 +163,8 @@ public class SdncOperations {
 
     @NotNull
     private String prepareResourceDataUrl(final String nodeId,
-                                          final String resourceId,
-                                          final List<String> queryList) {
+        final String resourceId,
+        final List<String> queryList) {
         return addQuery(addResource(addTopologyDataUrlwithNode(nodeId), resourceId), queryList);
     }
 
@@ -152,7 +176,7 @@ public class SdncOperations {
             return url.concat("/" + resourceId);
         }
     }
-    
+
     @NotNull
     private String addQuery(final String url, final List<String> queryList) {
         if (queryList.isEmpty()) {
@@ -173,5 +197,4 @@ public class SdncOperations {
         final String topologyMountUrl = topologyUrlData + MOUNT_URL_TEMPLATE;
         return topologyMountUrl.replace("{nodeId}", nodeId);
     }
-
 }
\ No newline at end of file
index b1528c7..e08870f 100644 (file)
@@ -26,7 +26,8 @@ import org.onap.cps.ncmp.dmi.TestUtils
 import org.onap.cps.ncmp.dmi.exception.DmiException
 import org.onap.cps.ncmp.dmi.exception.ModuleResourceNotFoundException
 import org.onap.cps.ncmp.dmi.exception.ModulesNotFoundException
-
+import org.onap.cps.ncmp.dmi.model.DataAccessReadRequest
+import org.onap.cps.ncmp.dmi.model.DataAccessWriteRequest
 import org.onap.cps.ncmp.dmi.model.ModuleReference
 import org.onap.cps.ncmp.dmi.model.ModuleSchemaList
 import org.onap.cps.ncmp.dmi.model.ModuleSchemaProperties
@@ -44,7 +45,6 @@ import org.springframework.http.MediaType
 import org.springframework.test.web.servlet.MockMvc
 import spock.lang.Specification
 
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
 
@@ -121,7 +121,7 @@ class DmiRestControllerSpec extends Specification {
     def 'Register given list of cm handles.'() {
         given: 'register cm handle url and cm handles json'
             def registerCmhandlesPost = "${basePathV1}/inventory/cmHandles"
-            def cmHandleJson =  '{"cmHandles":["node1", "node2"]}'
+            def cmHandleJson = '{"cmHandles":["node1", "node2"]}'
         when: 'post register cm handles api is invoked'
             def response = mvc.perform(
                     post(registerCmhandlesPost)
@@ -161,12 +161,12 @@ class DmiRestControllerSpec extends Specification {
             moduleReference2.name = 'nc-notifications'
             moduleReference2.revision = '2008-07-14'
             def moduleReferences = [moduleReference1, moduleReference2]
-            mockDmiService.getModuleResources('some-cm-handle', moduleReferences ) >> '{some-json}'
+            mockDmiService.getModuleResources('some-cm-handle', moduleReferences) >> '{some-json}'
         when: 'get module resource api is invoked'
             def response = mvc.perform(post(getModulesEndpoint)
                     .contentType(MediaType.APPLICATION_JSON)
                     .content(jsonData)).andReturn().response
-        then:'a OK status is returned'
+        then: 'a OK status is returned'
             response.status == HttpStatus.OK.value()
         and: 'the expected response is returned'
             response.getContentAsString() == '{some-json}'
@@ -204,7 +204,24 @@ class DmiRestControllerSpec extends Specification {
                     'application/json',
                     'myfields',
                     5,
-                    ['prop1':'value1', 'prop2':'value2'])
+                    ['prop1': 'value1', 'prop2': 'value2'])
+    }
+
+    def 'Write data using passthrough running for a cm handle.'() {
+        given: 'write data for cmHandle url and jsonData'
+            def writeDataforCmHandlePassthroughRunning = "${basePathV1}/ch/some-cmHandle/data/ds/ncmp-datastore:passthrough-running/some-resourceIdentifier"
+            def jsonData = TestUtils.getResourceFileContent('WriteDataForCmHandle.json')
+        and: 'dmi service is called'
+            mockDmiService.writeResourceDataPassthroughForCmHandle('some-cmHandle', 'some-resourceIdentifier', 'application/json',  ['some-data': 'some-value']) >> '{some-json}'
+        when: 'write cmHandle passthrough running post api is invoked with json data'
+            def response = mvc.perform(
+                    post(writeDataforCmHandlePassthroughRunning).contentType(MediaType.APPLICATION_JSON)
+                            .content(jsonData)
+            ).andReturn().response
+       then: 'response status is ok'
+            response.status == HttpStatus.OK.value()
+        and: 'the data in the request body is as expected'
+            response.getContentAsString() == '{some-json}'
     }
 
     def 'Get resource data for pass-through running from cm handle.'() {
index 31b60a7..e370302 100644 (file)
@@ -68,7 +68,7 @@ class DmiServiceImplSpec extends Specification {
         when: 'get modules for cm-handle is called'
             def result = objectUnderTest.getModulesForCmHandle(cmHandle)
         then: 'a dmi exception is thrown'
-           thrown(DmiException)
+            thrown(DmiException)
     }
 
     def 'Call get modules for cm-handle and SDNC returns "bad request" status.'() {
@@ -149,8 +149,8 @@ class DmiServiceImplSpec extends Specification {
         when: 'get module resources is invoked with the given cm handle and a module list'
             def response = objectUnderTest.getModuleResources(cmHandle, moduleList)
         then: 'then get modules resources called correctly'
-            1 * mockSdncOperations.getModuleResource(cmHandle,excpectedModulesJson1) >> new ResponseEntity<String>('response-body1', HttpStatus.OK)
-            1 * mockSdncOperations.getModuleResource(cmHandle,excpectedModulesJson2) >> new ResponseEntity<String>('response-body2', HttpStatus.OK)
+            1 * mockSdncOperations.getModuleResource(cmHandle, excpectedModulesJson1) >> new ResponseEntity<String>('response-body1', HttpStatus.OK)
+            1 * mockSdncOperations.getModuleResource(cmHandle, excpectedModulesJson2) >> new ResponseEntity<String>('response-body2', HttpStatus.OK)
         and: 'the response equals to the expected response body'
             response == '["response-body1","response-body2"]'
     }
@@ -159,7 +159,7 @@ class DmiServiceImplSpec extends Specification {
         given: 'get module schema is invoked and returns not found'
             mockSdncOperations.getModuleResource(_ as String, _ as String) >> new ResponseEntity<String>('some-response-body', HttpStatus.BAD_REQUEST)
         when: 'get module resources is invoked with the given cm handle and a module list'
-            objectUnderTest.getModuleResources('some-cmHandle', [new ModuleReference()] as LinkedList<ModuleReference> )
+            objectUnderTest.getModuleResources('some-cmHandle', [new ModuleReference()] as LinkedList<ModuleReference>)
         then: 'ModuleResourceNotFoundException is thrown'
             thrown(ModuleResourceNotFoundException)
     }
@@ -173,8 +173,7 @@ class DmiServiceImplSpec extends Specification {
             def depthParam = 10
             def contentQuery = 'content=all'
         and: 'sdnc operation returns OK response'
-            mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam,
-                    depthParam, acceptHeaderParam,  contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK)
+            mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK)
         when: 'get resource data from cm handles service method invoked'
             def response = objectUnderTest.getResourceDataOperationalForCmHandle(cmHandle,
                     resourceId, acceptHeaderParam,
@@ -191,8 +190,7 @@ class DmiServiceImplSpec extends Specification {
             def fieldsParam = 'testFields'
             def depthParam = 10
         and: 'sdnc operation returns "NOT_FOUND" response'
-            mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam,
-                    depthParam, acceptHeaderParam, _ as String) >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
+            mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, depthParam, acceptHeaderParam, _ as String) >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
         when: 'get resource data from cm handles service method invoked'
             objectUnderTest.getResourceDataOperationalForCmHandle(cmHandle,
                     resourceId, acceptHeaderParam,
@@ -211,7 +209,7 @@ class DmiServiceImplSpec extends Specification {
             def contentQuery = 'content=config'
         and: 'sdnc operation returns OK response'
             mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam,
-                    depthParam, acceptHeaderParam,  contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK)
+                    depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK)
         when: 'get resource data from cm handles service method invoked'
             def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle(cmHandle,
                     resourceId, acceptHeaderParam,
@@ -219,4 +217,31 @@ class DmiServiceImplSpec extends Specification {
         then: 'response have expected json'
             response == 'response json'
     }
+
+    def 'Write resource data using for passthrough running for the given cm handle.'() {
+        given: 'sdnc returns a created response'
+            mockSdncOperations.writeResourceDataPassthroughRunning(_, _, _, _) >> new ResponseEntity<String>('response json', HttpStatus.CREATED)
+        when: 'write resource data from cm handles service method invoked'
+            def response = objectUnderTest.writeResourceDataPassthroughForCmHandle('some-cmHandle',
+                    'some-resourceIdentifier', 'some-dataType', '{some-data}')
+        then: 'response have expected json'
+            response == 'response json'
+    }
+
+    def 'Write resource data for passthrough running with a #scenario.'() {
+        given: 'sdnc returns a response for the write operation'
+            mockSdncOperations.writeResourceDataPassthroughRunning(_, _, _, _) >> new ResponseEntity<String>('response json', httpStatus)
+        and: 'the data provided in the request body is written as a string'
+            objectUnderTest.objectMapper = mockObjectMapper
+            mockObjectMapper.writeValueAsString(_) >> jsonString
+        when: 'write resource data for pass through method is invoked'
+            objectUnderTest.writeResourceDataPassthroughForCmHandle('some-cmHandle',
+                    'some-resourceIdentifier', 'some-dataType', new Object())
+        then: 'a dmi exception is thrown'
+            thrown(DmiException.class)
+        where: 'the following combinations are tested'
+            scenario                     | httpStatus                       | jsonString
+            '500 response from sdnc'     | HttpStatus.INTERNAL_SERVER_ERROR | '{some-json-data}'
+            'json processing exception ' | HttpStatus.OK                    | { throw new JsonProcessingException('some error.') }
+    }
 }
\ No newline at end of file
index e2621e4..9a7ed18 100644 (file)
@@ -57,7 +57,7 @@ class SdncRestconfClientSpec extends Specification {
         and: 'the rest template returns a valid response entity'
             def mockResponseEntity = Mock(ResponseEntity)
         when: 'get module resources is invoked'
-            def result = objectUnderTest.postOperationWithJsonData(getModuleResourceUrl, jsonData)
+            def result = objectUnderTest.postOperationWithJsonData(getModuleResourceUrl, jsonData, new HttpHeaders())
         then: 'the rest template is called with the correct uri and json in the body'
             1 * mockRestTemplate.postForEntity({ it.toString() == 'http://some-uri/getModuleResourceUrl' },
                     { it.body.contains(jsonData) }, String.class) >> mockResponseEntity
index 3557bc1..c9d7d1b 100644 (file)
@@ -56,7 +56,7 @@ class SdncOperationsSpec extends Specification {
         when: 'get module resources is called with the expected parameters'
             objectUnderTest.getModuleResource(nodeId, 'some-json-data')
         then: 'the SDNC Rest client is invoked with the correct URL and json data'
-            1 * mockSdncRestClient.postOperationWithJsonData(expectedUrl, 'some-json-data')
+            1 * mockSdncRestClient.postOperationWithJsonData(expectedUrl, 'some-json-data', _ as HttpHeaders)
     }
 
     def 'Get resource data from node to SDNC.'() {
@@ -68,4 +68,13 @@ class SdncOperationsSpec extends Specification {
         then: 'the get operation is executed with the correct URL'
             1 * mockSdncRestClient.getOperation(expectedUrl, _ as HttpHeaders)
     }
+
+    def 'Write resource data to SDNC.'() {
+        given: 'excpected url, topology-id, sdncOperation object'
+            def expectedUrl = '/rests/data/network-topology:network-topology/topology=test-topology/node=node1/yang-ext:mount/testResourceId'
+        when: 'write resource data for pass through running is called'
+            objectUnderTest.writeResourceDataPassthroughRunning('node1', 'testResourceId', 'application/json','testData')
+        then: 'the post operation is executed with the correct URL'
+            1 * mockSdncRestClient.postOperationWithJsonData(expectedUrl, _ as String, _ as HttpHeaders)
+    }
 }
\ No newline at end of file
diff --git a/src/test/resources/WriteDataForCmHandle.json b/src/test/resources/WriteDataForCmHandle.json
new file mode 100644 (file)
index 0000000..8eb1959
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "operation": "create",
+  "dataType": "application/json",
+  "data": {
+    "some-data": "some-value"
+  },
+  "cmHandleProperties": {
+    "some-property": "some-property-value"
+  }
+}
\ No newline at end of file