aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java47
-rw-r--r--models/src/test/java/org/onap/policy/clamp/models/acm/utils/AcmUtilsTest.java70
-rw-r--r--models/src/test/java/org/onap/policy/clamp/models/acm/utils/CommonTestData.java18
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java3
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java2
5 files changed, 137 insertions, 3 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
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java
index fefa637da..3f3d5756a 100644
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java
@@ -53,6 +53,7 @@ import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpd
import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
+import org.onap.policy.clamp.models.acm.utils.AcmUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@@ -307,7 +308,7 @@ public class AutomationCompositionHandler {
var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
for (var element : participantDeploy.getAcElementList()) {
var acElement = acElementList.get(element.getId());
- acElement.getProperties().putAll(element.getProperties());
+ AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
acElement.setDeployState(deployState);
acElement.setDefinition(element.getDefinition());
}
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
index 84920dd03..4c22db956 100644
--- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
+++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
@@ -163,7 +163,7 @@ public class AutomationCompositionInstantiationProvider {
if (dbAcElement == null) {
throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, "Element id not present " + elementId);
}
- dbAcElement.getProperties().putAll(element.getValue().getProperties());
+ AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
}
if (automationComposition.getRestarting() != null) {
throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Update not allowed");