9087054fe30d5f2a8e4d2698f9157ca717558bd5
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2023 Nordix Foundation.
4  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.clamp.acm.participant.intermediary.handler;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.UUID;
30 import lombok.Getter;
31 import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
32 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
33 import org.onap.policy.clamp.acm.participant.intermediary.parameters.ParticipantParameters;
34 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
35 import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
37 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
38 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
39 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo;
40 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo;
41 import org.onap.policy.clamp.models.acm.concepts.DeployState;
42 import org.onap.policy.clamp.models.acm.concepts.LockState;
43 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
44 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
45 import org.onap.policy.clamp.models.acm.concepts.ParticipantSupportedElementType;
46 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
47 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
48 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck;
49 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
50 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
51 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
52 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
53 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
54 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
55 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
56 import org.onap.policy.models.base.PfModelException;
57 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
58 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61 import org.springframework.stereotype.Component;
62
63 /*
64  * This class is responsible for managing the state of all automation compositions in the participant.
65  */
66 @Component
67 public class AutomationCompositionHandler {
68     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
69
70     private final UUID participantId;
71     private final ParticipantMessagePublisher publisher;
72     private final AcInstanceStateResolver acInstanceStateResolver;
73     private final List<ParticipantSupportedElementType> supportedAcElementTypes;
74     private final List<AutomationCompositionElementListener> listeners = new ArrayList<>();
75
76     @Getter
77     private final Map<UUID, AutomationComposition> automationCompositionMap = new LinkedHashMap<>();
78
79     /**
80      * Constructor, set the participant ID and messageSender.
81      *
82      * @param parameters the parameters of the participant
83      * @param publisher the ParticipantMessage Publisher
84      */
85     public AutomationCompositionHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) {
86         this.participantId = parameters.getIntermediaryParameters().getParticipantId();
87         this.publisher = publisher;
88         this.acInstanceStateResolver = new AcInstanceStateResolver();
89         this.supportedAcElementTypes = parameters.getIntermediaryParameters().getParticipantSupportedElementTypes();
90     }
91
92     public void registerAutomationCompositionElementListener(AutomationCompositionElementListener listener) {
93         listeners.add(listener);
94     }
95
96     /**
97      * Handle a automation composition element state change message.
98      *
99      * @param automationCompositionId the automationComposition Id
100      * @param id the automationComposition UUID
101      * @param deployState the DeployState state
102      * @param lockState the LockState state
103      */
104     public void updateAutomationCompositionElementState(UUID automationCompositionId, UUID id, DeployState deployState,
105             LockState lockState, String message) {
106
107         if (automationCompositionId == null || id == null) {
108             LOGGER.error("Cannot update Automation composition element state, id is null");
109             return;
110         }
111
112         if ((deployState != null && lockState != null) || (deployState == null && lockState == null)) {
113             LOGGER.error("state error {} and {} cannot be handled", deployState, lockState);
114             return;
115         }
116
117         var automationComposition = automationCompositionMap.get(automationCompositionId);
118         if (automationComposition == null) {
119             LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
120                     automationComposition);
121             return;
122         }
123
124         var element = automationComposition.getElements().get(id);
125         if (element == null) {
126             var msg = "Cannot update Automation composition element state, AC Element id {} not present";
127             LOGGER.error(msg, automationComposition);
128             return;
129         }
130
131         if (deployState != null) {
132             element.setDeployState(deployState);
133             element.setLockState(
134                     DeployState.DEPLOYED.equals(element.getDeployState()) ? LockState.LOCKED : LockState.NONE);
135             var checkOpt = automationComposition.getElements().values().stream()
136                     .filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
137             if (checkOpt.isEmpty()) {
138                 automationComposition.setDeployState(deployState);
139                 automationComposition.setLockState(element.getLockState());
140             }
141         }
142         if (lockState != null) {
143             element.setLockState(lockState);
144             var checkOpt = automationComposition.getElements().values().stream()
145                     .filter(acElement -> !lockState.equals(acElement.getLockState())).findAny();
146             if (checkOpt.isEmpty()) {
147                 automationComposition.setLockState(lockState);
148             }
149         }
150
151         var automationCompositionStateChangeAck =
152                 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
153         automationCompositionStateChangeAck.setParticipantId(participantId);
154         automationCompositionStateChangeAck.setMessage(message);
155         automationCompositionStateChangeAck.setAutomationCompositionId(automationCompositionId);
156         automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
157                 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
158                         element.getUseState(), element.getOutProperties(), true,
159                         "Automation composition element {} state changed to {}\", id, newState)"));
160         LOGGER.debug("Automation composition element {} state changed to {}", id, deployState);
161         automationCompositionStateChangeAck.setResult(true);
162         publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
163     }
164
165     /**
166      * Handle a automation composition state change message.
167      *
168      * @param stateChangeMsg the state change message
169      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
170      */
171     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg,
172             List<AutomationCompositionElementDefinition> acElementDefinitions) {
173         if (stateChangeMsg.getAutomationCompositionId() == null) {
174             return;
175         }
176
177         var automationComposition = automationCompositionMap.get(stateChangeMsg.getAutomationCompositionId());
178
179         if (automationComposition == null) {
180             var automationCompositionAck =
181                     new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
182             automationCompositionAck.setParticipantId(participantId);
183             automationCompositionAck.setMessage("Automation composition " + stateChangeMsg.getAutomationCompositionId()
184                     + " does not use this participant " + participantId);
185             automationCompositionAck.setResult(false);
186             automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
187             automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
188             publisher.sendAutomationCompositionAck(automationCompositionAck);
189             LOGGER.debug("Automation composition {} does not use this participant",
190                     stateChangeMsg.getAutomationCompositionId());
191             return;
192         }
193
194         if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
195                 stateChangeMsg.getLockOrderedState())) {
196             LOGGER.warn("Not Consistant OrderState Automation composition {}",
197                     stateChangeMsg.getAutomationCompositionId());
198             return;
199         }
200
201         if (DeployOrder.NONE.equals(stateChangeMsg.getDeployOrderedState())) {
202             handleLockOrderState(automationComposition, stateChangeMsg.getLockOrderedState(),
203                     stateChangeMsg.getStartPhase(), acElementDefinitions);
204         } else {
205             handleDeployOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
206                     stateChangeMsg.getStartPhase(), acElementDefinitions);
207         }
208     }
209
210     private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder,
211             LockOrder lockOrder) {
212         return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
213                 automationComposition.getLockState()) != null;
214     }
215
216     /**
217      * Method to handle state changes.
218      *
219      * @param automationComposition participant response
220      * @param orderedState automation composition ordered state
221      * @param startPhaseMsg startPhase from message
222      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
223      */
224     private void handleDeployOrderState(final AutomationComposition automationComposition, DeployOrder orderedState,
225             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
226
227         switch (orderedState) {
228             case UNDEPLOY:
229                 handleUndeployState(automationComposition, startPhaseMsg, acElementDefinitions);
230                 break;
231             case DELETE:
232                 handleDeleteState(automationComposition, startPhaseMsg, acElementDefinitions);
233                 break;
234
235             default:
236                 LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
237                 break;
238         }
239     }
240
241     /**
242      * Method to handle state changes.
243      *
244      * @param automationComposition participant response
245      * @param orderedState automation composition ordered state
246      * @param startPhaseMsg startPhase from message
247      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
248      */
249     private void handleLockOrderState(final AutomationComposition automationComposition, LockOrder orderedState,
250             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
251
252         switch (orderedState) {
253             case LOCK:
254                 handleLockState(automationComposition, startPhaseMsg, acElementDefinitions);
255                 break;
256             case UNLOCK:
257                 handleUnlockState(automationComposition, startPhaseMsg, acElementDefinitions);
258                 break;
259             default:
260                 LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
261                 break;
262         }
263     }
264
265     /**
266      * Handle a automation composition properties update message.
267      *
268      * @param updateMsg the properties update message
269      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
270      */
271     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg,
272                                        List<AutomationCompositionElementDefinition> acElementDefinitions) {
273
274         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
275             LOGGER.warn("No AutomationCompositionElement updates in message {}",
276                     updateMsg.getAutomationCompositionId());
277             return;
278         }
279
280         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
281             if (participantId.equals(participantDeploy.getParticipantId())) {
282
283                 initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
284                             participantDeploy, DeployState.UPDATING);
285
286                 callParticipantUpdateProperty(participantDeploy.getAcElementList(), acElementDefinitions,
287                         updateMsg.getAutomationCompositionId());
288             }
289         }
290     }
291
292     /**
293      * Handle a automation composition Deploy message.
294      *
295      * @param updateMsg the Deploy message
296      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
297      */
298     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy updateMsg,
299             List<AutomationCompositionElementDefinition> acElementDefinitions) {
300
301         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
302             LOGGER.warn("No AutomationCompositionElement updates in message {}",
303                     updateMsg.getAutomationCompositionId());
304             return;
305         }
306
307         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
308             if (participantId.equals(participantDeploy.getParticipantId())) {
309                 if (updateMsg.isFirstStartPhase()) {
310                     initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
311                             participantDeploy, DeployState.DEPLOYING);
312                 }
313                 callParticipantDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
314                         updateMsg.getStartPhase(), updateMsg.getAutomationCompositionId());
315             }
316         }
317     }
318
319     private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy,
320                                   DeployState deployState) {
321         if (automationCompositionMap.containsKey(instanceId)) {
322             updateExistingElementsOnThisParticipant(instanceId, participantDeploy, deployState);
323         } else {
324             var automationComposition = new AutomationComposition();
325             automationComposition.setInstanceId(instanceId);
326             var acElements = storeElementsOnThisParticipant(participantDeploy, deployState);
327             automationComposition.setElements(prepareAcElementMap(acElements));
328             automationCompositionMap.put(instanceId, automationComposition);
329         }
330     }
331
332     private void callParticipantDeploy(List<AcElementDeploy> acElements,
333                                        List<AutomationCompositionElementDefinition> acElementDefinitions,
334                                        Integer startPhaseMsg, UUID automationCompositionId) {
335         try {
336             for (var element : acElements) {
337                 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
338                         element.getDefinition());
339                 if (acElementNodeTemplate != null) {
340                     int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
341                     if (startPhaseMsg.equals(startPhase)) {
342                         for (var acElementListener : listeners) {
343                             var map = new HashMap<>(acElementNodeTemplate.getProperties());
344                             map.putAll(element.getProperties());
345                             acElementListener.deploy(automationCompositionId, element, map);
346                         }
347                     }
348                 }
349             }
350         } catch (PfModelException e) {
351             LOGGER.debug("Automation composition element update failed {}", automationCompositionId);
352         }
353
354     }
355
356     private void callParticipantUpdateProperty(List<AcElementDeploy> acElements,
357                                        List<AutomationCompositionElementDefinition> acElementDefinitions,
358                                        UUID automationCompositionId) {
359         try {
360             for (var element : acElements) {
361                 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
362                         element.getDefinition());
363                 if (acElementNodeTemplate != null) {
364                     for (var acElementListener : listeners) {
365                         var map = new HashMap<>(acElementNodeTemplate.getProperties());
366                         map.putAll(element.getProperties());
367                         acElementListener.update(automationCompositionId, element, map);
368                     }
369                 }
370             }
371         } catch (PfModelException e) {
372             LOGGER.error("Automation composition element update failed for {} {}", automationCompositionId, e);
373         }
374
375     }
376
377     private ToscaNodeTemplate getAcElementNodeTemplate(
378             List<AutomationCompositionElementDefinition> acElementDefinitions, ToscaConceptIdentifier acElementDefId) {
379
380         for (var acElementDefinition : acElementDefinitions) {
381             if (acElementDefId.getName().contains(acElementDefinition.getAcElementDefinitionId().getName())) {
382                 return acElementDefinition.getAutomationCompositionElementToscaNodeTemplate();
383             }
384         }
385         return null;
386     }
387
388     private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy,
389                                                                               DeployState deployState) {
390         List<AutomationCompositionElement> acElementList = new ArrayList<>();
391         for (var element : participantDeploy.getAcElementList()) {
392             var acElement = new AutomationCompositionElement();
393             acElement.setId(element.getId());
394             acElement.setParticipantId(participantDeploy.getParticipantId());
395             acElement.setDefinition(element.getDefinition());
396             acElement.setDeployState(deployState);
397             acElement.setLockState(LockState.NONE);
398             acElementList.add(acElement);
399         }
400         return acElementList;
401     }
402
403     private void updateExistingElementsOnThisParticipant(
404             UUID instanceId, ParticipantDeploy participantDeploy, DeployState deployState) {
405
406         Map<UUID, AutomationCompositionElement> elementList = automationCompositionMap.get(instanceId).getElements();
407         for (var element : participantDeploy.getAcElementList()) {
408             automationCompositionMap.get(instanceId).getElements().get(element.getId()).getProperties()
409                     .putAll(element.getProperties());
410             automationCompositionMap.get(instanceId).getElements().get(element.getId()).setDeployState(deployState);
411         }
412     }
413
414     private Map<UUID, AutomationCompositionElement> prepareAcElementMap(List<AutomationCompositionElement> acElements) {
415         Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
416         for (var element : acElements) {
417             acElementMap.put(element.getId(), element);
418         }
419         return acElementMap;
420     }
421
422     /**
423      * Method to handle when the new state from participant is UNINITIALISED state.
424      *
425      * @param automationComposition participant response
426      * @param startPhaseMsg startPhase from message
427      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
428      */
429     private void handleUndeployState(final AutomationComposition automationComposition, Integer startPhaseMsg,
430             List<AutomationCompositionElementDefinition> acElementDefinitions) {
431
432         automationComposition.getElements().values().stream()
433                 .forEach(acElement -> automationCompositionElementUndeploy(automationComposition.getInstanceId(),
434                         acElement, startPhaseMsg, acElementDefinitions));
435     }
436
437     private void handleDeleteState(final AutomationComposition automationComposition, Integer startPhaseMsg,
438             List<AutomationCompositionElementDefinition> acElementDefinitions) {
439
440         automationComposition.getElements().values().stream()
441                 .forEach(acElement -> automationCompositionElementDelete(automationComposition.getInstanceId(),
442                         acElement, startPhaseMsg, acElementDefinitions));
443
444         boolean isAllUninitialised = automationComposition.getElements().values().stream()
445                 .filter(element -> !DeployState.DELETED.equals(element.getDeployState())).findAny().isEmpty();
446         if (isAllUninitialised) {
447             automationCompositionMap.remove(automationComposition.getInstanceId());
448         }
449     }
450
451     /**
452      * Method to handle when the new state from participant is PASSIVE state.
453      *
454      * @param automationComposition participant response
455      * @param startPhaseMsg startPhase from message
456      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
457      */
458     private void handleLockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
459             List<AutomationCompositionElementDefinition> acElementDefinitions) {
460         automationComposition.getElements().values().stream()
461                 .forEach(acElement -> automationCompositionElementLock(automationComposition.getInstanceId(), acElement,
462                         startPhaseMsg, acElementDefinitions));
463     }
464
465     /**
466      * Method to handle when the new state from participant is RUNNING state.
467      *
468      * @param automationComposition participant response
469      * @param startPhaseMsg startPhase from message
470      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
471      */
472     private void handleUnlockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
473             List<AutomationCompositionElementDefinition> acElementDefinitions) {
474         automationComposition.getElements().values().stream()
475                 .forEach(acElement -> automationCompositionElementUnlock(automationComposition.getInstanceId(),
476                         acElement, startPhaseMsg, acElementDefinitions));
477     }
478
479     private void automationCompositionElementLock(UUID instanceId, AutomationCompositionElement acElement,
480             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
481         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
482         if (acElementNodeTemplate != null) {
483             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
484             if (startPhaseMsg.equals(startPhase)) {
485                 for (var acElementListener : listeners) {
486                     try {
487                         acElementListener.lock(instanceId, acElement.getId());
488                         updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.LOCKED,
489                                 "Locked");
490                     } catch (PfModelException e) {
491                         LOGGER.error("Automation composition element lock failed {}", instanceId);
492                     }
493                 }
494             }
495         }
496     }
497
498     private void automationCompositionElementUnlock(UUID instanceId, AutomationCompositionElement acElement,
499             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
500         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
501         if (acElementNodeTemplate != null) {
502             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
503             if (startPhaseMsg.equals(startPhase)) {
504                 for (var acElementListener : listeners) {
505                     try {
506                         acElementListener.unlock(instanceId, acElement.getId());
507                         updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.UNLOCKED,
508                                 "Unlocked");
509                     } catch (PfModelException e) {
510                         LOGGER.error("Automation composition element unlock failed {}", instanceId);
511                     }
512                 }
513             }
514         }
515     }
516
517     private void automationCompositionElementUndeploy(UUID instanceId, AutomationCompositionElement acElement,
518             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
519         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
520         if (acElementNodeTemplate != null) {
521             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
522             if (startPhaseMsg.equals(startPhase)) {
523                 undeployInstanceElements(instanceId, acElement.getId());
524             }
525         }
526     }
527
528     private void automationCompositionElementDelete(UUID instanceId, AutomationCompositionElement acElement,
529             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
530         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
531         if (acElementNodeTemplate != null) {
532             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
533             if (startPhaseMsg.equals(startPhase)) {
534                 for (var acElementListener : listeners) {
535                     try {
536                         acElementListener.delete(instanceId, acElement.getId());
537                         updateAutomationCompositionElementState(instanceId, acElement.getId(), DeployState.DELETED,
538                                 null, "Deleted");
539                     } catch (PfModelException e) {
540                         LOGGER.error("Automation composition element unlock failed {}", instanceId);
541                     }
542                 }
543             }
544         }
545     }
546
547     /**
548      * Undeploy Instance Elements On Participant.
549      */
550     public void undeployInstances() {
551         automationCompositionMap.values().forEach(this::undeployInstance);
552     }
553
554     private void undeployInstance(AutomationComposition automationComposition) {
555         automationComposition.getElements().values().forEach(element -> {
556             if (element.getParticipantId().equals(participantId)) {
557                 undeployInstanceElements(automationComposition.getInstanceId(), element.getId());
558             }
559         });
560     }
561
562     private void undeployInstanceElements(UUID instanceId, UUID elementId) {
563         for (var acElementListener : listeners) {
564             try {
565                 acElementListener.undeploy(instanceId, elementId);
566             } catch (PfModelException e) {
567                 LOGGER.error("Automation composition element update failed {}", instanceId);
568             }
569         }
570     }
571
572     /**
573      * Send Ac Element Info.
574      *
575      * @param automationCompositionId the automationComposition Id
576      * @param elementId the automationComposition Element id
577      * @param useState the use State
578      * @param operationalState the operational State
579      * @param outProperties the output Properties Map
580      */
581     public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
582             String operationalState, Map<String, Object> outProperties) {
583
584         if (automationCompositionId == null || elementId == null) {
585             LOGGER.error("Cannot update Automation composition element state, id is null");
586             return;
587         }
588
589         var automationComposition = automationCompositionMap.get(automationCompositionId);
590         if (automationComposition == null) {
591             LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
592                     automationComposition);
593             return;
594         }
595
596         var element = automationComposition.getElements().get(elementId);
597         if (element == null) {
598             var msg = "Cannot update Automation composition element state, AC Element id {} not present";
599             LOGGER.error(msg, automationComposition);
600             return;
601         }
602         element.setOperationalState(operationalState);
603         element.setUseState(useState);
604         element.setOutProperties(outProperties);
605
606         var statusMsg = new ParticipantStatus();
607         statusMsg.setParticipantId(participantId);
608         statusMsg.setState(ParticipantState.ON_LINE);
609         statusMsg.setParticipantSupportedElementType(new ArrayList<>(supportedAcElementTypes));
610         var acInfo = new AutomationCompositionInfo();
611         acInfo.setAutomationCompositionId(automationCompositionId);
612         acInfo.setDeployState(automationComposition.getDeployState());
613         acInfo.setLockState(automationComposition.getLockState());
614         acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
615         statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
616         publisher.sendParticipantStatus(statusMsg);
617     }
618
619     /**
620      * get AutomationComposition Info List.
621      *
622      * @return list of AutomationCompositionInfo
623      */
624     public List<AutomationCompositionInfo> getAutomationCompositionInfoList() {
625         List<AutomationCompositionInfo> automationCompositionInfoList = new ArrayList<>();
626         for (var entry : automationCompositionMap.entrySet()) {
627             var acInfo = new AutomationCompositionInfo();
628             acInfo.setAutomationCompositionId(entry.getKey());
629             acInfo.setDeployState(entry.getValue().getDeployState());
630             acInfo.setLockState(entry.getValue().getLockState());
631             for (var element : entry.getValue().getElements().values()) {
632                 acInfo.getElements().add(getAutomationCompositionElementInfo(element));
633             }
634             automationCompositionInfoList.add(acInfo);
635         }
636         return automationCompositionInfoList;
637     }
638
639     private AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
640         var elementInfo = new AutomationCompositionElementInfo();
641         elementInfo.setAutomationCompositionElementId(element.getId());
642         elementInfo.setDeployState(element.getDeployState());
643         elementInfo.setLockState(element.getLockState());
644         elementInfo.setOperationalState(element.getOperationalState());
645         elementInfo.setUseState(element.getUseState());
646         elementInfo.setOutProperties(element.getOutProperties());
647         return elementInfo;
648     }
649 }