Add moduleSetTag to the request towards dmi plugin
[cps.git] / dmi-plugin-demo-and-csit-stub / dmi-plugin-demo-and-csit-stub-service / src / main / java / org / onap / cps / ncmp / dmi / rest / stub / controller / DmiRestStubController.java
index b7e67d7..f154be6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation
+ *  Copyright (C) 2023-2024 Nordix Foundation
  *  ================================================================================
  *  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.ncmp.dmi.rest.stub.controller;
 
+import static org.onap.cps.ncmp.api.NcmpResponseStatus.SUCCESS;
+
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
-import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.json.simple.parser.JSONParser;
 import org.json.simple.parser.ParseException;
-import org.onap.cps.ncmp.api.NcmpEventResponseCode;
 import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter;
 import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.CmHandle;
 import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.DataOperationRequest;
-import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.ResourceDataOperationRequests;
+import org.onap.cps.ncmp.dmi.rest.stub.model.data.operational.DmiDataOperationRequest;
 import org.onap.cps.ncmp.dmi.rest.stub.utils.ResourceFileReaderUtil;
 import org.onap.cps.ncmp.events.async1_0_0.Data;
 import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent;
 import org.onap.cps.ncmp.events.async1_0_0.Response;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.Resource;
 import org.springframework.core.io.ResourceLoader;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
@@ -61,69 +68,174 @@ import org.springframework.web.bind.annotation.RestController;
 @Slf4j
 public class DmiRestStubController {
 
+    private static final String DEFAULT_TAG = "tagD";
+    private static final String dataOperationEventType = "org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent";
+    private static final Map<String, String> moduleSetTagPerCmHandleId = new HashMap<>();
     private final KafkaTemplate<String, CloudEvent> cloudEventKafkaTemplate;
     private final ObjectMapper objectMapper;
     private final ApplicationContext applicationContext;
-
     @Value("${app.ncmp.async-m2m.topic}")
     private String ncmpAsyncM2mTopic;
+    @Value("${delay.module-references-delay-ms}")
+    private long moduleReferencesDelayMs;
+    @Value("${delay.module-resources-delay-ms}")
+    private long moduleResourcesDelayMs;
+    @Value("${delay.data-for-cm-handle-delay-ms}")
+    private long dataForCmHandleDelayMs;
 
-    private String dataOperationEventType = "org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent";
+    /**
+     * This code defines a REST API endpoint for adding new the module set tag mapping. The endpoint receives the
+     * cmHandleId and moduleSetTag as request body and add into moduleSetTagPerCmHandleId map with the provided
+     * values.
+     *
+     * @param requestBody map of cmHandleId and moduleSetTag
+     * @return a ResponseEntity object containing the updated moduleSetTagPerCmHandleId map as the response body
+     */
+    @PostMapping("/v1/tagMapping")
+    public ResponseEntity<Map<String, String>> addTagForMapping(@RequestBody final Map<String, String> requestBody) {
+        moduleSetTagPerCmHandleId.putAll(requestBody);
+        return new ResponseEntity<>(requestBody, HttpStatus.CREATED);
+    }
+
+    /**
+     * This code defines a GET endpoint of  module set tag mapping.
+     *
+     * @return The map represents the module set tag mapping.
+     */
+    @GetMapping("/v1/tagMapping")
+    public ResponseEntity<Map<String, String>> getTagMapping() {
+        return ResponseEntity.ok(moduleSetTagPerCmHandleId);
+    }
+
+    /**
+     * This code defines a GET endpoint of  module set tag by cm handle ID.
+     *
+     * @return The map represents the module set tag mapping filtered by cm handle ID.
+     */
+    @GetMapping("/v1/tagMapping/ch/{cmHandleId}")
+    public ResponseEntity<String> getTagMappingByCmHandleId(@PathVariable final String cmHandleId) {
+        return ResponseEntity.ok(moduleSetTagPerCmHandleId.get(cmHandleId));
+    }
+
+    /**
+     * This code defines a REST API endpoint for updating the module set tag mapping. The endpoint receives the
+     * cmHandleId and moduleSetTag as request body and updates the moduleSetTagPerCmHandleId map with the provided
+     * values.
+     *
+     * @param requestBody map of cmHandleId and moduleSetTag
+     * @return a ResponseEntity object containing the updated moduleSetTagPerCmHandleId map as the response body
+     */
+
+    @PutMapping("/v1/tagMapping")
+    public ResponseEntity<Map<String, String>> updateTagMapping(@RequestBody final Map<String, String> requestBody) {
+        moduleSetTagPerCmHandleId.putAll(requestBody);
+        return ResponseEntity.noContent().build();
+    }
+
+    /**
+     * It contains a method to delete an entry from the moduleSetTagPerCmHandleId map.
+     * The method takes a cmHandleId as a parameter and removes the corresponding entry from the map.
+     *
+     * @return a ResponseEntity containing the updated map.
+     */
+    @DeleteMapping("/v1/tagMapping/ch/{cmHandleId}")
+    public ResponseEntity<String> deleteTagMappingByCmHandleId(@PathVariable final String cmHandleId) {
+        moduleSetTagPerCmHandleId.remove(cmHandleId);
+        return ResponseEntity.ok(String.format("Mapping of %s is deleted successfully", cmHandleId));
+    }
 
     /**
      * Get all modules for given cm handle.
      *
-     * @param cmHandle                The identifier for a network function, network element, subnetwork,
+     * @param cmHandleId              The identifier for a network function, network element, subnetwork,
      *                                or any other cm object by managed Network CM Proxy
      * @param moduleReferencesRequest module references request body
      * @return ResponseEntity response entity having module response as json string.
      */
-    @PostMapping("/v1/ch/{cmHandle}/modules")
-    public ResponseEntity<String> getModuleReferences(@PathVariable final String cmHandle,
+    @PostMapping("/v1/ch/{cmHandleId}/modules")
+    public ResponseEntity<String> getModuleReferences(@PathVariable("cmHandleId") final String cmHandleId,
                                                       @RequestBody final Object moduleReferencesRequest) {
-        final String moduleResponseContent = ResourceFileReaderUtil
-                .getResourceFileContent(applicationContext.getResource(
-                        ResourceLoader.CLASSPATH_URL_PREFIX + "module/moduleResponse.json"));
+        delay(moduleReferencesDelayMs);
+        try {
+            log.info("Incoming DMI request body: {}",
+                    objectMapper.writeValueAsString(moduleReferencesRequest));
+        } catch (final JsonProcessingException jsonProcessingException) {
+            log.info("Unable to parse dmi data operation request to json string");
+        }
+        final String moduleResponseContent = getModuleResourceResponse(cmHandleId,
+                "ModuleResponse.json");
+        log.info("cm handle: {} requested for modules", cmHandleId);
         return ResponseEntity.ok(moduleResponseContent);
     }
 
     /**
-     * Get all module resources for given cm handle.
+     * Retrieves module resources for a given cmHandleId.
      *
-     * @param cmHandle                   The identifier for a network function, network element, subnetwork,
+     * @param cmHandleId                 The identifier for a network function, network element, subnetwork,
      *                                   or any other cm object by managed Network CM Proxy
      * @param moduleResourcesReadRequest module resources read request body
      * @return ResponseEntity response entity having module resources response as json string.
      */
-    @PostMapping("/v1/ch/{cmHandle}/moduleResources")
+    @PostMapping("/v1/ch/{cmHandleId}/moduleResources")
     public ResponseEntity<String> retrieveModuleResources(
-            @PathVariable final String cmHandle,
+            @PathVariable("cmHandleId") final String cmHandleId,
             @RequestBody final Object moduleResourcesReadRequest) {
-        final String moduleResourcesResponseContent = ResourceFileReaderUtil
-                .getResourceFileContent(applicationContext.getResource(
-                        ResourceLoader.CLASSPATH_URL_PREFIX + "module/moduleResourcesResponse.json"));
+        delay(moduleResourcesDelayMs);
+        final String moduleResourcesResponseContent = getModuleResourceResponse(cmHandleId,
+                "ModuleResourcesResponse.json");
+        log.info("cm handle: {} requested for modules resources", cmHandleId);
         return ResponseEntity.ok(moduleResourcesResponseContent);
     }
 
+    /**
+     * Create resource data from passthrough operational or running for a cm handle.
+     *
+     * @param cmHandleId              The identifier for a network function, network element, subnetwork,
+     *                                or any other cm object by managed Network CM Proxy
+     * @param datastoreName           datastore name
+     * @param resourceIdentifier      resource identifier
+     * @param options                 options
+     * @param topic                   client given topic name
+     * @return (@ code ResponseEntity) response entity
+     */
+    @PostMapping("/v1/ch/{cmHandleId}/data/ds/{datastoreName}")
+    public ResponseEntity<String> getResourceDataForCmHandle(
+            @PathVariable("cmHandleId") final String cmHandleId,
+            @PathVariable("datastoreName") final String datastoreName,
+            @RequestParam(value = "resourceIdentifier") final String resourceIdentifier,
+            @RequestParam(value = "options", required = false) final String options,
+            @RequestParam(value = "topic", required = false) final String topic,
+            @RequestHeader(value = "Authorization", required = false) final String authorization) {
+        log.info("DMI AUTH HEADER: {}", authorization);
+        delay(dataForCmHandleDelayMs);
+        final String sampleJson = ResourceFileReaderUtil.getResourceFileContent(applicationContext.getResource(
+                ResourceLoader.CLASSPATH_URL_PREFIX + "data/operational/ietf-network-topology-sample-rfc8345.json"));
+        return ResponseEntity.ok(sampleJson);
+    }
+
     /**
      * This method is not implemented for ONAP DMI plugin.
      *
-     * @param topic                         client given topic name
-     * @param requestId                     requestId generated by NCMP as an ack for client
-     * @param resourceDataOperationRequests list of operation details
+     * @param topic                   client given topic name
+     * @param requestId               requestId generated by NCMP as an ack for client
+     * @param dmiDataOperationRequest list of operation details
      * @return (@ code ResponseEntity) response entity
      */
     @PostMapping("/v1/data")
-    public ResponseEntity<Void> getResourceDataForCmHandleDataOperation(@RequestParam(value = "topic")
-                                                                            final String topic,
-                                                                        @RequestParam(value = "requestId")
-                                                                        final String requestId,
-                                                                        @RequestBody final ResourceDataOperationRequests
-                                                                                resourceDataOperationRequests) {
-        log.info("Request received from the NCMP to DMI Plugin");
-        resourceDataOperationRequests.forEach(resourceDataOperationRequest -> {
-            final DataOperationEvent dataOperationEvent = getDataOperationEvent(resourceDataOperationRequest);
-            resourceDataOperationRequest.getCmHandles().forEach(cmHandle -> {
+    public ResponseEntity<Void> getResourceDataForCmHandleDataOperation(
+            @RequestParam(value = "topic") final String topic,
+            @RequestParam(value = "requestId") final String requestId,
+            @RequestBody final DmiDataOperationRequest dmiDataOperationRequest) {
+        delay(dataForCmHandleDelayMs);
+        try {
+            log.info("Request received from the NCMP to DMI Plugin: {}",
+                    objectMapper.writeValueAsString(dmiDataOperationRequest));
+        } catch (final JsonProcessingException jsonProcessingException) {
+            log.info("Unable to process dmi data operation request to json string");
+        }
+        dmiDataOperationRequest.getOperations().forEach(dmiDataOperation -> {
+            final DataOperationEvent dataOperationEvent = getDataOperationEvent(dmiDataOperation);
+            dmiDataOperation.getCmHandles().forEach(cmHandle -> {
                 dataOperationEvent.getData().getResponses().get(0).setIds(List.of(cmHandle.getId()));
                 final CloudEvent cloudEvent = buildAndGetCloudEvent(topic, requestId, dataOperationEvent);
                 cloudEventKafkaTemplate.send(ncmpAsyncM2mTopic, UUID.randomUUID().toString(), cloudEvent);
@@ -156,9 +268,11 @@ public class DmiRestStubController {
     private DataOperationEvent getDataOperationEvent(final DataOperationRequest dataOperationRequest) {
         final Response response = new Response();
         response.setOperationId(dataOperationRequest.getOperationId());
-        response.setStatusCode(NcmpEventResponseCode.SUCCESS.getStatusCode());
-        response.setStatusMessage(NcmpEventResponseCode.SUCCESS.getStatusMessage());
-        response.setIds(dataOperationRequest.getCmHandles().stream().map(CmHandle::getId).collect(Collectors.toList()));
+        response.setStatusCode(SUCCESS.getCode());
+        response.setStatusMessage(SUCCESS.getMessage());
+        response.setIds(dataOperationRequest.getCmHandles().stream().map(CmHandle::getId).toList());
+        response.setResourceIdentifier(dataOperationRequest.getResourceIdentifier());
+        response.setOptions(dataOperationRequest.getOptions());
         final String ietfNetworkTopologySample = ResourceFileReaderUtil
                 .getResourceFileContent(applicationContext.getResource(
                         ResourceLoader.CLASSPATH_URL_PREFIX
@@ -169,7 +283,7 @@ public class DmiRestStubController {
         } catch (final ParseException parseException) {
             log.error("Unable to parse event result as json object. cause : {}", parseException.getMessage());
         }
-        final List<Response> responseList = new ArrayList<>();
+        final List<Response> responseList = new ArrayList<>(1);
         responseList.add(response);
         final Data data = new Data();
         data.setResponses(responseList);
@@ -177,4 +291,28 @@ public class DmiRestStubController {
         dataOperationEvent.setData(data);
         return dataOperationEvent;
     }
+
+    private String getModuleResourceResponse(final String cmHandleId, final String moduleResponseType) {
+        if (moduleSetTagPerCmHandleId.isEmpty()) {
+            log.info("Using default module responses of type ietfYang");
+            return ResourceFileReaderUtil.getResourceFileContent(applicationContext.getResource(
+                    ResourceLoader.CLASSPATH_URL_PREFIX
+                            + String.format("module/ietfYang-%s", moduleResponseType)));
+        }
+        final String moduleSetTag = moduleSetTagPerCmHandleId.getOrDefault(cmHandleId, DEFAULT_TAG);
+        final String moduleResponseFilePath = String.format("module/%s-%s", moduleSetTag, moduleResponseType);
+        final Resource moduleResponseResource = applicationContext.getResource(
+                ResourceLoader.CLASSPATH_URL_PREFIX + moduleResponseFilePath);
+        log.info("Using module responses from : {}", moduleResponseFilePath);
+        return ResourceFileReaderUtil.getResourceFileContent(moduleResponseResource);
+    }
+
+    private void delay(final long milliseconds) {
+        try {
+            Thread.sleep(milliseconds);
+        } catch (final InterruptedException e) {
+            log.error("Thread sleep interrupted: {}", e.getMessage());
+            Thread.currentThread().interrupt();
+        }
+    }
 }