Update AC Element properties on the DEPLOYED state 95/134595/2
authorrameshiyer27 <ramesh.murugan.iyer@est.tech>
Thu, 18 May 2023 15:47:10 +0000 (16:47 +0100)
committerLiam Fallon <liam.fallon@est.tech>
Tue, 23 May 2023 15:25:03 +0000 (15:25 +0000)
User can update the instance property values on DEPLOYED state.
The runtime sends PROPERTY_UPDATE event to the participants and the updated values are stored on the runtime database.
Participants can implement the update method to perform the required action.

Issue-ID: POLICY-4682
Signed-off-by: zrrmmua <ramesh.murugan.iyer@est.tech>
Change-Id: Ic35fba669b5ffcf2c75d6deaa8c309d58e4026f0

13 files changed:
models/src/main/java/org/onap/policy/clamp/models/acm/concepts/DeployState.java
models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantMessageType.java
models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/PropertiesUpdate.java [new file with mode: 0644]
models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/DeployOrder.java
participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java
participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPropertyUpdateListener.java [new file with mode: 0644]
participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java
participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java [new file with mode: 0644]
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java

index 474bcd3..e60a132 100644 (file)
@@ -100,5 +100,16 @@ public enum ParticipantMessageType {
     /**
      * Used by automation composition runtime to request for PARTICIPANT_STATUS message immediately.
      */
-    PARTICIPANT_STATUS_REQ
+    PARTICIPANT_STATUS_REQ,
+
+    /**
+     * Used by automation composition runtime to send the element properties update to participant.
+     */
+    PROPERTIES_UPDATE,
+
+    /**
+     * Used by participant to acknowledge the receipt of PROPERTIES_UPDATE message
+     * from automation composition runtime.
+     */
+    PROPERTIES_UPDATE_ACK
 }
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/PropertiesUpdate.java b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/PropertiesUpdate.java
new file mode 100644 (file)
index 0000000..43573cc
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.models.acm.messages.dmaap.participant;
+
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
+import org.onap.policy.models.base.PfUtils;
+
+
+/**
+ * Class to represent the PROPERTIES_UPDATE message that the ACM runtime sends to a participant.
+ * The ACM Runtime sends updated automation composition element property values to Participants.
+ */
+@Getter
+@Setter
+@ToString(callSuper = true)
+public class PropertiesUpdate extends ParticipantMessage {
+
+    // A list of updates to AC element properties
+    private List<ParticipantDeploy> participantUpdatesList = new ArrayList<>();
+
+    /**
+     * Constructor for instantiating properties update class with message name.
+     *
+     */
+    public PropertiesUpdate() {
+        super(ParticipantMessageType.PROPERTIES_UPDATE);
+    }
+
+    /**
+     * Constructs the object, making a deep copy.
+     *
+     * @param source source from which to copy
+     */
+    public PropertiesUpdate(PropertiesUpdate source) {
+        super(source);
+        this.participantUpdatesList = PfUtils.mapList(source.participantUpdatesList, ParticipantDeploy::new);
+    }
+}
index d6ef80f..c8fd91d 100644 (file)
@@ -62,4 +62,9 @@ public interface AutomationCompositionElementListener {
             throws PfModelException {
         // default Delete Operation
     }
+
+    public default void update(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
+            throws PfModelException {
+        // default update Operation
+    }
 }
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPropertyUpdateListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPropertyUpdateListener.java
new file mode 100644 (file)
index 0000000..d6f1970
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.acm.participant.intermediary.comm;
+
+import org.onap.policy.clamp.acm.participant.intermediary.handler.ParticipantHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for AC Element property update messages sent by ACM.
+ */
+@Component
+public class AcPropertyUpdateListener extends ParticipantListener<PropertiesUpdate> {
+
+    /**
+     * Constructs the object.
+     *
+     * @param participantHandler the handler for managing the state of the participant
+     */
+    public AcPropertyUpdateListener(final ParticipantHandler participantHandler) {
+        super(PropertiesUpdate.class, participantHandler,
+            participantHandler::handleAcPropertyUpdate);
+    }
+
+    @Override
+    public String getType() {
+        return ParticipantMessageType.PROPERTIES_UPDATE.name();
+    }
+}
index d334985..9087054 100644 (file)
@@ -49,6 +49,7 @@ import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCom
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
 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;
@@ -261,6 +262,33 @@ public class AutomationCompositionHandler {
         }
     }
 
+    /**
+     * Handle a automation composition properties update message.
+     *
+     * @param updateMsg the properties update message
+     * @param acElementDefinitions the list of AutomationCompositionElementDefinition
+     */
+    public void handleAcPropertyUpdate(PropertiesUpdate updateMsg,
+                                       List<AutomationCompositionElementDefinition> acElementDefinitions) {
+
+        if (updateMsg.getParticipantUpdatesList().isEmpty()) {
+            LOGGER.warn("No AutomationCompositionElement updates in message {}",
+                    updateMsg.getAutomationCompositionId());
+            return;
+        }
+
+        for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
+            if (participantId.equals(participantDeploy.getParticipantId())) {
+
+                initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
+                            participantDeploy, DeployState.UPDATING);
+
+                callParticipantUpdateProperty(participantDeploy.getAcElementList(), acElementDefinitions,
+                        updateMsg.getAutomationCompositionId());
+            }
+        }
+    }
+
     /**
      * Handle a automation composition Deploy message.
      *
@@ -280,28 +308,34 @@ public class AutomationCompositionHandler {
             if (participantId.equals(participantDeploy.getParticipantId())) {
                 if (updateMsg.isFirstStartPhase()) {
                     initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
-                            participantDeploy);
+                            participantDeploy, DeployState.DEPLOYING);
                 }
-                callParticipanDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
+                callParticipantDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
                         updateMsg.getStartPhase(), updateMsg.getAutomationCompositionId());
             }
         }
     }
 
-    private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy) {
-        var automationComposition = new AutomationComposition();
-        automationComposition.setInstanceId(instanceId);
-        var acElements = storeElementsOnThisParticipant(participantDeploy);
-        automationComposition.setElements(prepareAcElementMap(acElements));
-        automationCompositionMap.put(instanceId, automationComposition);
+    private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy,
+                                  DeployState deployState) {
+        if (automationCompositionMap.containsKey(instanceId)) {
+            updateExistingElementsOnThisParticipant(instanceId, participantDeploy, deployState);
+        } else {
+            var automationComposition = new AutomationComposition();
+            automationComposition.setInstanceId(instanceId);
+            var acElements = storeElementsOnThisParticipant(participantDeploy, deployState);
+            automationComposition.setElements(prepareAcElementMap(acElements));
+            automationCompositionMap.put(instanceId, automationComposition);
+        }
     }
 
-    private void callParticipanDeploy(List<AcElementDeploy> acElements,
-            List<AutomationCompositionElementDefinition> acElementDefinitions, Integer startPhaseMsg,
-            UUID automationCompositionId) {
+    private void callParticipantDeploy(List<AcElementDeploy> acElements,
+                                       List<AutomationCompositionElementDefinition> acElementDefinitions,
+                                       Integer startPhaseMsg, UUID automationCompositionId) {
         try {
             for (var element : acElements) {
-                var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, element.getDefinition());
+                var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
+                        element.getDefinition());
                 if (acElementNodeTemplate != null) {
                     int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
                     if (startPhaseMsg.equals(startPhase)) {
@@ -319,6 +353,27 @@ public class AutomationCompositionHandler {
 
     }
 
+    private void callParticipantUpdateProperty(List<AcElementDeploy> acElements,
+                                       List<AutomationCompositionElementDefinition> acElementDefinitions,
+                                       UUID automationCompositionId) {
+        try {
+            for (var element : acElements) {
+                var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
+                        element.getDefinition());
+                if (acElementNodeTemplate != null) {
+                    for (var acElementListener : listeners) {
+                        var map = new HashMap<>(acElementNodeTemplate.getProperties());
+                        map.putAll(element.getProperties());
+                        acElementListener.update(automationCompositionId, element, map);
+                    }
+                }
+            }
+        } catch (PfModelException e) {
+            LOGGER.error("Automation composition element update failed for {} {}", automationCompositionId, e);
+        }
+
+    }
+
     private ToscaNodeTemplate getAcElementNodeTemplate(
             List<AutomationCompositionElementDefinition> acElementDefinitions, ToscaConceptIdentifier acElementDefId) {
 
@@ -330,20 +385,32 @@ public class AutomationCompositionHandler {
         return null;
     }
 
-    private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy) {
+    private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy,
+                                                                              DeployState deployState) {
         List<AutomationCompositionElement> acElementList = new ArrayList<>();
         for (var element : participantDeploy.getAcElementList()) {
             var acElement = new AutomationCompositionElement();
             acElement.setId(element.getId());
             acElement.setParticipantId(participantDeploy.getParticipantId());
             acElement.setDefinition(element.getDefinition());
-            acElement.setDeployState(DeployState.DEPLOYING);
+            acElement.setDeployState(deployState);
             acElement.setLockState(LockState.NONE);
             acElementList.add(acElement);
         }
         return acElementList;
     }
 
+    private void updateExistingElementsOnThisParticipant(
+            UUID instanceId, ParticipantDeploy participantDeploy, DeployState deployState) {
+
+        Map<UUID, AutomationCompositionElement> elementList = automationCompositionMap.get(instanceId).getElements();
+        for (var element : participantDeploy.getAcElementList()) {
+            automationCompositionMap.get(instanceId).getElements().get(element.getId()).getProperties()
+                    .putAll(element.getProperties());
+            automationCompositionMap.get(instanceId).getElements().get(element.getId()).setDeployState(deployState);
+        }
+    }
+
     private Map<UUID, AutomationCompositionElement> prepareAcElementMap(List<AutomationCompositionElement> acElements) {
         Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
         for (var element : acElements) {
index 44a988a..9e1216c 100644 (file)
@@ -47,6 +47,7 @@ import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRe
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegisterAck;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatusReq;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
@@ -120,6 +121,19 @@ public class ParticipantHandler {
                 acElementDefsMap.get(stateChangeMsg.getCompositionId()));
     }
 
+    /**
+     * Handle a automation composition property update message.
+     *
+     * @param propertyUpdateMsg the property update message
+     */
+    @Timed(
+            value = "listener.properties_update",
+            description = "PROPERTIES_UPDATE message received")
+    public void handleAcPropertyUpdate(PropertiesUpdate propertyUpdateMsg) {
+        automationCompositionHandler.handleAcPropertyUpdate(propertyUpdateMsg,
+                acElementDefsMap.get(propertyUpdateMsg.getCompositionId()));
+    }
+
     /**
      * Check if a participant message applies to this participant handler.
      *
index 4665fec..7875478 100644 (file)
@@ -21,6 +21,8 @@
 
 package org.onap.policy.clamp.acm.runtime.instantiation;
 
+
+import java.util.Map;
 import java.util.UUID;
 import javax.validation.Valid;
 import javax.ws.rs.core.Response;
@@ -29,8 +31,10 @@ import lombok.AllArgsConstructor;
 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
 import org.onap.policy.clamp.models.acm.concepts.DeployState;
+import org.onap.policy.clamp.models.acm.concepts.LockState;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
@@ -100,33 +104,72 @@ public class AutomationCompositionInstantiationProvider {
      */
     public InstantiationResponse updateAutomationComposition(UUID compositionId,
             AutomationComposition automationComposition) {
+        var response = new InstantiationResponse();
         var instanceId = automationComposition.getInstanceId();
         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
         if (!compositionId.equals(acToUpdate.getCompositionId())) {
             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
         }
-        if (!DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
-                    "Not allow to update for state in " + acToUpdate.getDeployState());
+        if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
+            acToUpdate.setElements(automationComposition.getElements());
+            acToUpdate.setName(automationComposition.getName());
+            acToUpdate.setVersion(automationComposition.getVersion());
+            acToUpdate.setDescription(automationComposition.getDescription());
+            acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
+            var validationResult = validateAutomationComposition(acToUpdate);
+            if (!validationResult.isValid()) {
+                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
+            }
+            automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
+            response.setInstanceId(instanceId);
+            response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
+            return response;
+
+        } else if (DeployState.DEPLOYED.equals(acToUpdate.getDeployState())
+                && LockState.LOCKED.equals(acToUpdate.getLockState())) {
+            return updateDeployedAutomationComposition(compositionId, automationComposition, acToUpdate);
+        }
+        throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+                    "Not allowed to update in the state " + acToUpdate.getDeployState());
+    }
+
+    /**
+     * Update deployed AC Element properties.
+     *
+     * @param compositionId The UUID of the automation composition definition
+     * @param automationComposition the automation composition
+     * @param acToBeUpdated the composition to be updated
+     * @return the result of the update
+     */
+    public InstantiationResponse updateDeployedAutomationComposition(UUID compositionId,
+                                                                     AutomationComposition automationComposition,
+                                                                     AutomationComposition acToBeUpdated) {
+
+        // Iterate and update the element property values
+        for (Map.Entry<UUID, AutomationCompositionElement> dbAcElement : acToBeUpdated.getElements().entrySet()) {
+            var elementId = dbAcElement.getKey();
+            if (automationComposition.getElements().containsKey(elementId)) {
+                dbAcElement.getValue().getProperties().putAll(automationComposition.getElements().get(elementId)
+                        .getProperties());
+            }
         }
-        acToUpdate.setElements(automationComposition.getElements());
-        acToUpdate.setName(automationComposition.getName());
-        acToUpdate.setVersion(automationComposition.getVersion());
-        acToUpdate.setDescription(automationComposition.getDescription());
-        acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
-        var validationResult = validateAutomationComposition(acToUpdate);
+        // Publish property update event to the participants
+        supervisionAcHandler.update(acToBeUpdated);
+
+        var validationResult = validateAutomationComposition(acToBeUpdated);
         if (!validationResult.isValid()) {
             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
         }
-        automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
-
+        automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
         var response = new InstantiationResponse();
+        var instanceId = automationComposition.getInstanceId();
         response.setInstanceId(instanceId);
         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
         return response;
     }
 
+
     /**
      * Validate AutomationComposition.
      *
index 654c311..da3cbc3 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import lombok.AllArgsConstructor;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AcElementPropertiesPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
 import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck;
@@ -55,6 +56,8 @@ public class SupervisionAcHandler {
     private final AutomationCompositionDeployPublisher automationCompositionDeployPublisher;
     private final AutomationCompositionStateChangePublisher automationCompositionStateChangePublisher;
 
+    private final AcElementPropertiesPublisher acElementPropertiesPublisher;
+
     /**
      * Handle Deploy an AutomationComposition instance.
      *
@@ -108,6 +111,15 @@ public class SupervisionAcHandler {
         automationCompositionStateChangePublisher.send(automationComposition, startPhase, true);
     }
 
+    /**
+     * Handle Element property update on a deployed instance.
+     * @param automationComposition the AutomationComposition
+     */
+    public void update(AutomationComposition automationComposition) {
+        AcmUtils.setCascadedState(automationComposition, DeployState.UPDATING, LockState.NONE);
+        acElementPropertiesPublisher.send(automationComposition);
+    }
+
     /**
      * Handle Delete an AutomationComposition instance.
      *
diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java
new file mode 100644 (file)
index 0000000..c5f33ad
--- /dev/null
@@ -0,0 +1,89 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.acm.runtime.supervision.comm;
+
+import io.micrometer.core.annotation.Timed;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.UnaryOperator;
+import lombok.AllArgsConstructor;
+import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
+import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
+import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
+import org.onap.policy.models.base.PfUtils;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to send PropertiesUpdate messages to participants.
+ */
+@Component
+@AllArgsConstructor
+public class AcElementPropertiesPublisher extends AbstractParticipantPublisher<PropertiesUpdate> {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionDeployPublisher.class);
+
+    /**
+     * Send ACElementPropertiesUpdate to Participant.
+     *
+     * @param automationComposition the AutomationComposition
+     */
+    @Timed(value = "publisher.properties_update",
+            description = "AC Element Properties Update published")
+    public void send(AutomationComposition automationComposition) {
+        Map<UUID, List<AcElementDeploy>> map = new HashMap<>();
+        for (var element : automationComposition.getElements().values()) {
+            var acElementDeploy = new AcElementDeploy();
+            acElementDeploy.setId(element.getId());
+            acElementDeploy.setDefinition(new ToscaConceptIdentifier(element.getDefinition()));
+            acElementDeploy.setOrderedState(DeployOrder.UPDATE);
+            acElementDeploy.setProperties(PfUtils.mapMap(element.getProperties(), UnaryOperator.identity()));
+
+            map.putIfAbsent(element.getParticipantId(), new ArrayList<>());
+            map.get(element.getParticipantId()).add(acElementDeploy);
+        }
+        List<ParticipantDeploy> participantDeploys = new ArrayList<>();
+        for (var entry : map.entrySet()) {
+            var participantDeploy = new ParticipantDeploy();
+            participantDeploy.setParticipantId(entry.getKey());
+            participantDeploy.setAcElementList(entry.getValue());
+            participantDeploys.add(participantDeploy);
+        }
+
+        var propertiesUpdate = new PropertiesUpdate();
+        propertiesUpdate.setCompositionId(automationComposition.getCompositionId());
+        propertiesUpdate.setAutomationCompositionId(automationComposition.getInstanceId());
+        propertiesUpdate.setMessageId(UUID.randomUUID());
+        propertiesUpdate.setTimestamp(Instant.now());
+        propertiesUpdate.setParticipantUpdatesList(participantDeploys);
+
+        LOGGER.debug("AC Element properties update sent {}", propertiesUpdate);
+        super.send(propertiesUpdate);
+    }
+}
index faf356c..54a0c96 100644 (file)
@@ -312,22 +312,6 @@ class AutomationCompositionInstantiationProviderTest {
                         + " Commissioned automation composition definition not primed\n");
     }
 
-    @Test
-    void testUpdateBadRequest() {
-        var automationComposition = InstantiationUtils
-                .getAutomationCompositionFromResource(AC_INSTANTIATION_AC_DEFINITION_NOT_FOUND_JSON, "AcNotFound");
-
-        var acProvider = mock(AutomationCompositionProvider.class);
-        automationComposition.setDeployState(DeployState.DEPLOYED);
-        when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
-                .thenReturn(automationComposition);
-        var provider = new AutomationCompositionInstantiationProvider(acProvider,
-                mock(AcDefinitionProvider.class), null, null);
-
-        assertThatThrownBy(() -> provider.updateAutomationComposition(automationComposition.getCompositionId(),
-                automationComposition)).hasMessageMatching("Not allow to update for state in DEPLOYED");
-    }
-
     @Test
     void testCompositionInstanceState() {
         var acDefinitionProvider = mock(AcDefinitionProvider.class);
index c61984b..e763127 100644 (file)
@@ -33,6 +33,7 @@ import java.util.Optional;
 import java.util.UUID;
 import org.junit.jupiter.api.Test;
 import org.onap.policy.clamp.acm.runtime.instantiation.InstantiationUtils;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AcElementPropertiesPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher;
 import org.onap.policy.clamp.acm.runtime.util.CommonTestData;
@@ -59,7 +60,8 @@ class SupervisionAcHandlerTest {
 
         var handler = new SupervisionAcHandler(automationCompositionProvider,
                 mock(AutomationCompositionDeployPublisher.class),
-                mock(AutomationCompositionStateChangePublisher.class));
+                mock(AutomationCompositionStateChangePublisher.class),
+                mock(AcElementPropertiesPublisher.class));
 
         var automationCompositionAckMessage =
                 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
@@ -97,7 +99,8 @@ class SupervisionAcHandlerTest {
 
         var handler = new SupervisionAcHandler(automationCompositionProvider,
                 mock(AutomationCompositionDeployPublisher.class),
-                mock(AutomationCompositionStateChangePublisher.class));
+                mock(AutomationCompositionStateChangePublisher.class),
+                mock(AcElementPropertiesPublisher.class));
 
         handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage);
 
@@ -110,7 +113,7 @@ class SupervisionAcHandlerTest {
         var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var handler = new SupervisionAcHandler(automationCompositionProvider,
                 mock(AutomationCompositionDeployPublisher.class),
-                acStateChangePublisher);
+                acStateChangePublisher, mock(AcElementPropertiesPublisher.class));
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =
@@ -127,7 +130,7 @@ class SupervisionAcHandlerTest {
         var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var handler = new SupervisionAcHandler(automationCompositionProvider,
                 mock(AutomationCompositionDeployPublisher.class),
-                acStateChangePublisher);
+                acStateChangePublisher, mock(AcElementPropertiesPublisher.class));
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =
@@ -144,7 +147,7 @@ class SupervisionAcHandlerTest {
         var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class);
         var handler = new SupervisionAcHandler(automationCompositionProvider,
                 mock(AutomationCompositionDeployPublisher.class),
-                acStateChangePublisher);
+                acStateChangePublisher, mock(AcElementPropertiesPublisher.class));
         var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var automationComposition =