NSLCM Statuses are now being offered as an array of Json Nodes

This MR updates the tmf.api to allow for the correct listing of all NSLCM statuses. To this end, we updated the process of adding a new NSLCM status to the list of all status. Before, we were working with string arraylists, which resulted in the incorrect encoding of the JSON NSLCM statuses payloads. Now, we are using the appropriate JSON-appropriate artifacts to manipulate the list of NSLCM statuses and append new statuses. This MR thus fixes the issue of the NSLCM statuses being showned as strings, as it is proven by the image below.

Screenshot_2024-09-07_at_21.34.39

Additionally, the updates were tested with various tests. These can be performed by executing the following command:

docker run -it --rm \
  -v "/home/ubuntu/.m2":/root/.m2 \
  -v "$(pwd)":/opt/maven \
  -w /opt/maven \
  maven:3.9.5-ibm-semeru-17-focal \
  mvn clean verify \
  -Dtest="ServiceRepoServiceTest#testUpdateNSLCMCharacteristicMethodWhenNSLCMValueToUpdateIsNull,ServiceRepoServiceTest#testUpdateNSLCMCharacteristicMethodWhenNSLCMValueToUpdateIsNotNullAndNSLCMDoesntAlreadyExist,ServiceRepoServiceTest#testUpdateNSLCMCharacteristicMethodWhenNSLCMValueToUpdateIsNotNullAndNSLCMAlreadyExists"

Closes #45 (closed)

Edited by Rafael Direito

Merge request reports

Loading
+56 −27
Changes for src/main/java/org/etsi/osl/tmf/sim638/service/ServiceRepoService.java: 56 added lines, 27 removed lines.
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ import java.util.Optional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -760,45 +762,74 @@ public class ServiceRepoService {
        ObjectMapper primitivesObjectMapper = new ObjectMapper();

        // Retrieve the service characteristic based on the name
        Characteristic aNSLCMCharacteristic = service.getServiceCharacteristicByName(n.getName());

        // Retrieve the current value as a string directly from the service characteristic
        String aNSLCMCharacteristicValue = service.getServiceCharacteristicByName(n.getName()).getValue().getValue();

        // Check if the current service characteristic value is null or explicitly "null" and initialize if needed
        if (aNSLCMCharacteristicValue == null || "null".equals(aNSLCMCharacteristicValue) || aNSLCMCharacteristicValue.equals("")) {
            service.getServiceCharacteristicByName(n.getName()).getValue().setValue("[]");
        }

        // Check if the current characteristic value is not null and not explicitly "null"
        if (n.getValue().getValue() != null || !"null".equals(n.getValue().getValue())) {
			aNSLCMCharacteristicValue = service.getServiceCharacteristicByName(n.getName()).getValue().getValue();

            ArrayList<String> arrayList = null;

            // Deserialize the current value back to an array list
        Characteristic aNSLCMStatusesCharacteristic = service.getServiceCharacteristicByName(n.getName());

        // Retrieve the current NSLCM statuses, and extract the new status 
		// to be appended
		String aNSLCMStatusesBeforeUpdate = service
				.getServiceCharacteristicByName(n.getName()).getValue().getValue();
		String aNSLCMNewStatus = n.getValue().getValue();

        // Check if the current NSLCM statuses value is null or explicitly "null" 
		// and, if thats the case start an empty JSON array (this takes place when initializing the characteristic)
        if ( aNSLCMStatusesBeforeUpdate == null ||
			aNSLCMStatusesBeforeUpdate.isEmpty() ||
			aNSLCMStatusesBeforeUpdate.equals("null")
		){
			try {
                arrayList = primitivesObjectMapper.readValue(aNSLCMCharacteristicValue, new TypeReference<ArrayList<String>>() {});
				service.getServiceCharacteristicByName(n.getName()).getValue().setValue(
					primitivesObjectMapper.writeValueAsString(primitivesObjectMapper.createArrayNode())
				);
			} catch (JsonProcessingException e) {
                e.printStackTrace();
            }

            // Add the new value to the list if it's not already present and is not null
            if (!arrayList.contains(n.getValue().getValue()) && n.getValue().getValue() != null) {
                arrayList.add(n.getValue().getValue());
		}

            // Update the characteristic with the newly modified list
        // Check if the current characteristic value is not null and not explicitly "null"
        if ( aNSLCMNewStatus != null &&
			!aNSLCMNewStatus.isEmpty() &&
			!aNSLCMNewStatus.equals("null")
		) {
            try {
                aNSLCMCharacteristic.setValue(new Any(primitivesObjectMapper.writeValueAsString(arrayList), n.getValue().getAlias()));
				// Deserialize the current statuses back to an array list
				ArrayNode nslcmStatusesJsonArray = (ArrayNode) primitivesObjectMapper.readTree(
					service.getServiceCharacteristicByName(n.getName()).getValue().getValue()
				);

				// Map the current status to json
				JsonNode currenNSLCMStatus = primitivesObjectMapper.readTree(n.getValue().getValue());

				// Add the new status to the list if it's not already present and is not null
				if (!containsNode(nslcmStatusesJsonArray, currenNSLCMStatus)) {
					nslcmStatusesJsonArray.add(currenNSLCMStatus);
				}

				// Finally, map the statuses list to a Json encoded one
				aNSLCMStatusesCharacteristic.setValue(
					new Any(primitivesObjectMapper.writeValueAsString(nslcmStatusesJsonArray), n.getValue().getAlias())
				);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
		}

		return service;
    }

	/**
     * Helper method to check if an ArrayNode contains a specific JsonNode.
     * This method uses Jackson's `equals()` for deep equality.
	 * @param arrayNode Array of Json Nodes
     * @param jsonNode	the object encoded as Jsons
     */
    private static boolean containsNode(ArrayNode arrayNode, JsonNode jsonNode) {
        for (JsonNode node : arrayNode) {
            if (node.equals(jsonNode)) {
                return true;
            }
        }
        return false;
    }


	/**
	 * @param service
@@ -1249,6 +1280,4 @@ public class ServiceRepoService {
    }
    
	
    
	
}
+49 −7
Changes for src/test/java/org/etsi/osl/services/service/ServiceRepoServiceTest.java: 49 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -43,6 +43,9 @@ import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;

@RunWith(SpringRunner.class)
@ActiveProfiles("testing")
@@ -174,7 +177,22 @@ public class ServiceRepoServiceTest {

                                    serviceRepoService.updateNSLCMCharacteristic(service, n);

                                    assertEquals("[\"null\"]", service.getServiceCharacteristicByName(n.getName()).getValue().getValue());
                                    try {
                                        ArrayNode expected = (ArrayNode) objectMapper.readTree(
                                            "[]"
                                        );
                                        ArrayNode actual = (ArrayNode) objectMapper.readTree(
                                            service.getServiceCharacteristicByName(n.getName()).getValue().getValue()
                                        );

                                        assertEquals(
                                            expected,
                                            actual
                                        );
                                        break;
                                    } catch (JsonProcessingException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }   
@@ -211,10 +229,22 @@ public class ServiceRepoServiceTest {

                                    serviceRepoService.updateNSLCMCharacteristic(service, n);

                                    assertEquals(
                                            "[\"{\\\"queuePosition\\\":0,\\\"lcmOperationType\\\":\\\"instantiate\\\",\\\"detailed-status\\\":\\\"Done\\\",\\\"operationState\\\":\\\"COMPLETED\\\",\\\"errorMessage\\\":null,\\\"nsInstanceId\\\":\\\"420fa806-f2f8-405e-8348-11e4fcd13f25\\\",\\\"_admin\\\":{\\\"projects_write\\\":[\\\"92636b50-d607-4801-98b5-f0da541363be\\\"],\\\"created\\\":1.7169792184842422E9,\\\"modified\\\":1.7169794444025614E9,\\\"worker\\\":\\\"d6f95b754d12\\\",\\\"projects_read\\\":[\\\"92636b50-d607-4801-98b5-f0da541363be\\\"]},\\\"detailedStatus\\\":null,\\\"stage\\\":\\\"\\\",\\\"operationParams\\\":{\\\"nsInstanceId\\\":\\\"420fa806-f2f8-405e-8348-11e4fcd13f25\\\",\\\"ssh_keys\\\":[\\\"\\\"],\\\"lcmOperationType\\\":\\\"instantiate\\\",\\\"nsdId\\\":\\\"338d3a8c-af70-446a-af37-ed8bb97a6641\\\",\\\"nsName\\\":\\\"Service_Order_65bcf307-1a47-4a48-b211-be94c3390b81\\\",\\\"vimAccountId\\\":\\\"479356bf-72ff-4dfd-8483-5c23f48dd0bc\\\"},\\\"startTime\\\":1.7169792184841862E9,\\\"links\\\":{\\\"nsInstance\\\":\\\"/osm/nslcm/v1/ns_instances/420fa806-f2f8-405e-8348-11e4fcd13f25\\\",\\\"self\\\":\\\"/osm/nslcm/v1/ns_lcm_op_occs/e0836187-7d4a-49ac-a317-fc4108ed2f93\\\"},\\\"_id\\\":\\\"e0836187-7d4a-49ac-a317-fc4108ed2f93\\\",\\\"id\\\":\\\"e0836187-7d4a-49ac-a317-fc4108ed2f93\\\",\\\"isAutomaticInvocation\\\":false,\\\"isCancelPending\\\":false,\\\"statusEnteredTime\\\":1.7169794444025595E9}\"]",
                                    try {
                                        ArrayNode expected = (ArrayNode) objectMapper.readTree(
                                            "[{\"queuePosition\":0,\"lcmOperationType\":\"instantiate\",\"detailed-status\":\"Done\",\"operationState\":\"COMPLETED\",\"errorMessage\":null,\"nsInstanceId\":\"420fa806-f2f8-405e-8348-11e4fcd13f25\",\"_admin\":{\"projects_write\":[\"92636b50-d607-4801-98b5-f0da541363be\"],\"created\":1.7169792184842422E9,\"modified\":1.7169794444025614E9,\"worker\":\"d6f95b754d12\",\"projects_read\":[\"92636b50-d607-4801-98b5-f0da541363be\"]},\"detailedStatus\":null,\"stage\":\"\",\"operationParams\":{\"nsInstanceId\":\"420fa806-f2f8-405e-8348-11e4fcd13f25\",\"ssh_keys\":[\"\"],\"lcmOperationType\":\"instantiate\",\"nsdId\":\"338d3a8c-af70-446a-af37-ed8bb97a6641\",\"nsName\":\"Service_Order_65bcf307-1a47-4a48-b211-be94c3390b81\",\"vimAccountId\":\"479356bf-72ff-4dfd-8483-5c23f48dd0bc\"},\"startTime\":1.7169792184841862E9,\"links\":{\"nsInstance\":\"/osm/nslcm/v1/ns_instances/420fa806-f2f8-405e-8348-11e4fcd13f25\",\"self\":\"/osm/nslcm/v1/ns_lcm_op_occs/e0836187-7d4a-49ac-a317-fc4108ed2f93\"},\"_id\":\"e0836187-7d4a-49ac-a317-fc4108ed2f93\",\"id\":\"e0836187-7d4a-49ac-a317-fc4108ed2f93\",\"isAutomaticInvocation\":false,\"isCancelPending\":false,\"statusEnteredTime\":1.7169794444025595E9}]"
                                        );
                                        ArrayNode actual = (ArrayNode) objectMapper.readTree(
                                            service.getServiceCharacteristicByName(n.getName()).getValue().getValue()
                                        );

                                        assertEquals(
                                            expected,
                                            actual
                                        );
                                        break;
                                    } catch (JsonProcessingException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }   
@@ -247,15 +277,27 @@ public class ServiceRepoServiceTest {
                                // Check if the name contains "NSLCM" in any case
                                if (n.getName().toUpperCase().contains("NSLCM")) {
                                    
                                    // Set the value of NSLCM to null
                                    service.getServiceCharacteristicByName(n.getName()).getValue().setValue("[\"existingValue\"]");
                                    // Set the value of NSLCM
                                    service.getServiceCharacteristicByName(n.getName()).getValue().setValue("[{\"test\": 2}]");

                                    serviceRepoService.updateNSLCMCharacteristic(service, n);

                                    assertEquals(
                                            "[\"existingValue\",\"{\\\"queuePosition\\\":0,\\\"lcmOperationType\\\":\\\"instantiate\\\",\\\"detailed-status\\\":\\\"Done\\\",\\\"operationState\\\":\\\"COMPLETED\\\",\\\"errorMessage\\\":null,\\\"nsInstanceId\\\":\\\"420fa806-f2f8-405e-8348-11e4fcd13f25\\\",\\\"_admin\\\":{\\\"projects_write\\\":[\\\"92636b50-d607-4801-98b5-f0da541363be\\\"],\\\"created\\\":1.7169792184842422E9,\\\"modified\\\":1.7169794444025614E9,\\\"worker\\\":\\\"d6f95b754d12\\\",\\\"projects_read\\\":[\\\"92636b50-d607-4801-98b5-f0da541363be\\\"]},\\\"detailedStatus\\\":null,\\\"stage\\\":\\\"\\\",\\\"operationParams\\\":{\\\"nsInstanceId\\\":\\\"420fa806-f2f8-405e-8348-11e4fcd13f25\\\",\\\"ssh_keys\\\":[\\\"\\\"],\\\"lcmOperationType\\\":\\\"instantiate\\\",\\\"nsdId\\\":\\\"338d3a8c-af70-446a-af37-ed8bb97a6641\\\",\\\"nsName\\\":\\\"Service_Order_65bcf307-1a47-4a48-b211-be94c3390b81\\\",\\\"vimAccountId\\\":\\\"479356bf-72ff-4dfd-8483-5c23f48dd0bc\\\"},\\\"startTime\\\":1.7169792184841862E9,\\\"links\\\":{\\\"nsInstance\\\":\\\"/osm/nslcm/v1/ns_instances/420fa806-f2f8-405e-8348-11e4fcd13f25\\\",\\\"self\\\":\\\"/osm/nslcm/v1/ns_lcm_op_occs/e0836187-7d4a-49ac-a317-fc4108ed2f93\\\"},\\\"_id\\\":\\\"e0836187-7d4a-49ac-a317-fc4108ed2f93\\\",\\\"id\\\":\\\"e0836187-7d4a-49ac-a317-fc4108ed2f93\\\",\\\"isAutomaticInvocation\\\":false,\\\"isCancelPending\\\":false,\\\"statusEnteredTime\\\":1.7169794444025595E9}\"]", 
                                    try {
                                        ArrayNode expected = (ArrayNode) objectMapper.readTree(
                                            "[{\"test\": 2}, {\"queuePosition\":0,\"lcmOperationType\":\"instantiate\",\"detailed-status\":\"Done\",\"operationState\":\"COMPLETED\",\"errorMessage\":null,\"nsInstanceId\":\"420fa806-f2f8-405e-8348-11e4fcd13f25\",\"_admin\":{\"projects_write\":[\"92636b50-d607-4801-98b5-f0da541363be\"],\"created\":1.7169792184842422E9,\"modified\":1.7169794444025614E9,\"worker\":\"d6f95b754d12\",\"projects_read\":[\"92636b50-d607-4801-98b5-f0da541363be\"]},\"detailedStatus\":null,\"stage\":\"\",\"operationParams\":{\"nsInstanceId\":\"420fa806-f2f8-405e-8348-11e4fcd13f25\",\"ssh_keys\":[\"\"],\"lcmOperationType\":\"instantiate\",\"nsdId\":\"338d3a8c-af70-446a-af37-ed8bb97a6641\",\"nsName\":\"Service_Order_65bcf307-1a47-4a48-b211-be94c3390b81\",\"vimAccountId\":\"479356bf-72ff-4dfd-8483-5c23f48dd0bc\"},\"startTime\":1.7169792184841862E9,\"links\":{\"nsInstance\":\"/osm/nslcm/v1/ns_instances/420fa806-f2f8-405e-8348-11e4fcd13f25\",\"self\":\"/osm/nslcm/v1/ns_lcm_op_occs/e0836187-7d4a-49ac-a317-fc4108ed2f93\"},\"_id\":\"e0836187-7d4a-49ac-a317-fc4108ed2f93\",\"id\":\"e0836187-7d4a-49ac-a317-fc4108ed2f93\",\"isAutomaticInvocation\":false,\"isCancelPending\":false,\"statusEnteredTime\":1.7169794444025595E9}]"
                                        );
                                        ArrayNode actual = (ArrayNode) objectMapper.readTree(
                                            service.getServiceCharacteristicByName(n.getName()).getValue().getValue()
                                        );

                                        assertEquals(
                                            expected,
                                            actual
                                        );
                                        break;
                                    } catch (JsonProcessingException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }   
+616 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading