diff options
author | FrancescoFioraEst <francesco.fiora@est.tech> | 2024-01-16 09:39:06 +0000 |
---|---|---|
committer | FrancescoFioraEst <francesco.fiora@est.tech> | 2024-03-26 17:00:53 +0000 |
commit | 1cf51a2280fb2f9a0435b8a3f2c64492cb7e6659 (patch) | |
tree | 345e7748d5efedd14aa3570655f2c1681fc6f56c /models/src | |
parent | b7291f81e63c5d4e30351ed0429167937934bc71 (diff) |
Recursive updates of the properties
Merge properties during update and migrate.
Issue-ID: POLICY-4951
Change-Id: I0c9a896a5abb8331937a73d7e39fbce2d87b415f
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
Diffstat (limited to 'models/src')
3 files changed, 134 insertions, 1 deletions
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java b/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java index 504d3ef06..1155bd4f4 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java @@ -21,12 +21,15 @@ package org.onap.policy.clamp.models.acm.utils; import jakarta.ws.rs.core.Response; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Queue; import java.util.UUID; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -35,6 +38,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.tuple.Pair; import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; import org.onap.policy.clamp.models.acm.concepts.AcElementRestart; import org.onap.policy.clamp.models.acm.concepts.AcTypeState; @@ -443,4 +447,47 @@ public final class AcmUtils { acElementRestart.setOutProperties(PfUtils.mapMap(element.getOutProperties(), UnaryOperator.identity())); return acElementRestart; } + + /** + * Recursive Merge. + * + * @param map1 Map where to merge + * @param map2 Map + */ + public static void recursiveMerge(Map<String, Object> map1, Map<String, Object> map2) { + Deque<Pair<Map<String, Object>, Map<String, Object>>> stack = new ArrayDeque<>(); + stack.push(Pair.of(map1, map2)); + while (!stack.isEmpty()) { + var pair = stack.pop(); + var mapLeft = pair.getLeft(); + var mapRight = pair.getRight(); + for (var entryRight : mapRight.entrySet()) { + var valueLeft = mapLeft.get(entryRight.getKey()); + var valueRight = entryRight.getValue(); + if (valueLeft instanceof Map subMapLeft && valueRight instanceof Map subMapRight) { + stack.push(Pair.of(subMapLeft, subMapRight)); + } else if ((valueLeft instanceof List subListLeft && valueRight instanceof List subListRight) + && (subListLeft.size() == subListRight.size())) { + recursiveMerge(subListLeft, subListRight); + } else { + mapLeft.put(entryRight.getKey(), valueRight); + } + } + } + } + + private static void recursiveMerge(List<Object> list1, List<Object> list2) { + for (var i = 0; i < list1.size(); i++) { + var valueLeft = list1.get(i); + var valueRight = list2.get(i); + if (valueLeft instanceof Map subMapLeft && valueRight instanceof Map subMapRight) { + recursiveMerge(subMapLeft, subMapRight); + } else if ((valueLeft instanceof List subListLeft && valueRight instanceof List subListRight) + && (subListLeft.size() == subListRight.size())) { + recursiveMerge(subListLeft, subListRight); + } else { + list1.set(i, valueRight); + } + } + } } diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/utils/AcmUtilsTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/utils/AcmUtilsTest.java index bc8741e65..1561533e8 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/utils/AcmUtilsTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/utils/AcmUtilsTest.java @@ -293,4 +293,74 @@ class AcmUtilsTest { nodeTemplates.put("org.onap.dcae.acm.DCAEMicroserviceAutomationCompositionParticipant", nodeTemplate); return nodeTemplates; } + + @Test + void testRecursiveMergeMap() { + var oldProperties = """ + chart: + chartId: + name: acelement + version: 0.1.0 + namespace: default + releaseName: acm-starter + podName: acm-starter + """; + + var newProperties = """ + chart: + releaseName: acm-starter-new + podName: null + """; + + Map<String, Object> map = CommonTestData.getObject(oldProperties, Map.class); + Map<String, Object> mapMigrate = CommonTestData.getObject(newProperties, Map.class); + + AcmUtils.recursiveMerge(map, mapMigrate); + assertEquals("default", ((Map<String, Object>) map.get("chart")).get("namespace")); + assertEquals("acm-starter-new", ((Map<String, Object>) map.get("chart")).get("releaseName")); + assertNotNull(((Map<String, Object>) map.get("chart")).get("chartId")); + assertNull(((Map<String, Object>) map.get("chart")).get("podName")); + } + + @Test + void testRecursiveMergeList() { + var oldProperties = """ + baseUrl: http://{{address}}:30800 + httpHeaders: + Content-Type: application/json + Authorization: Basic YWNtVXNlcjp6YiFYenRHMzQ= + configurationEntities: + - configurationEntityId: + name: onap.policy.clamp.ac.starter + version: 1.0.0 + restSequence: + - restRequestId: + name: request1 + version: 1.0.1 + myParameterToUpdate: 9 + myParameterToRemove: 8 + """; + + var newProperties = """ + configurationEntities: + - myParameterToUpdate: "90" + myParameterToRemove: null + myParameter: "I am new" + """; + + Map<String, Object> map = CommonTestData.getObject(oldProperties, Map.class); + Map<String, Object> mapMigrate = CommonTestData.getObject(newProperties, Map.class); + + AcmUtils.recursiveMerge(map, mapMigrate); + assertEquals("http://{{address}}:30800", map.get("baseUrl")); + assertEquals("application/json", ((Map<String, Object>) map.get("httpHeaders")).get("Content-Type")); + var configurationEntities = (List<Object>) map.get("configurationEntities"); + var subMap = (Map<String, Object>) configurationEntities.get(0); + assertEquals("onap.policy.clamp.ac.starter", + ((Map<String, Object>) subMap.get("configurationEntityId")).get("name")); + assertThat((List<Object>) subMap.get("restSequence")).isNotEmpty(); + assertEquals("90", subMap.get("myParameterToUpdate")); + assertNull(subMap.get("myParameterToRemove")); + assertEquals("I am new", subMap.get("myParameter")); + } } diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java b/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java index 03a3fb11a..131c8eefd 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java @@ -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. @@ -83,6 +83,22 @@ public class CommonTestData { } /** + * Get Object from string in yaml format. + * + * @param yaml the string in yaml format + * @param clazz the Class of the Object + * @return the Object + */ + public static <T> T getObject(String yaml, Class<T> clazz) { + try { + return YAML_TRANSLATOR.decode(yaml, clazz); + } catch (CoderException e) { + fail("Cannot decode " + yaml); + return null; + } + } + + /** * Get new AutomationCompositionElementDefinition. * * @param id the ToscaConceptIdentifier |