514bc655f377f494ad6fac1304de857894bb8995
[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         if (DeployOrder.UPDATE.equals(deployOrder)) {
213             return true;
214         }
215         return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
216                 automationComposition.getLockState(), automationComposition.getStateChangeResult()) != null;
217     }
218
219     /**
220      * Method to handle state changes.
221      *
222      * @param automationComposition participant response
223      * @param orderedState automation composition ordered state
224      * @param startPhaseMsg startPhase from message
225      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
226      */
227     private void handleDeployOrderState(final AutomationComposition automationComposition, DeployOrder orderedState,
228             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
229
230         switch (orderedState) {
231             case UNDEPLOY:
232                 handleUndeployState(automationComposition, startPhaseMsg, acElementDefinitions);
233                 break;
234             case DELETE:
235                 handleDeleteState(automationComposition, startPhaseMsg, acElementDefinitions);
236                 break;
237
238             default:
239                 LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
240                 break;
241         }
242     }
243
244     /**
245      * Method to handle state changes.
246      *
247      * @param automationComposition participant response
248      * @param orderedState automation composition ordered state
249      * @param startPhaseMsg startPhase from message
250      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
251      */
252     private void handleLockOrderState(final AutomationComposition automationComposition, LockOrder orderedState,
253             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
254
255         switch (orderedState) {
256             case LOCK:
257                 handleLockState(automationComposition, startPhaseMsg, acElementDefinitions);
258                 break;
259             case UNLOCK:
260                 handleUnlockState(automationComposition, startPhaseMsg, acElementDefinitions);
261                 break;
262             default:
263                 LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
264                 break;
265         }
266     }
267
268     /**
269      * Handle a automation composition properties update message.
270      *
271      * @param updateMsg the properties update message
272      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
273      */
274     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg,
275                                        List<AutomationCompositionElementDefinition> acElementDefinitions) {
276
277         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
278             LOGGER.warn("No AutomationCompositionElement updates in message {}",
279                     updateMsg.getAutomationCompositionId());
280             return;
281         }
282
283         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
284             if (participantId.equals(participantDeploy.getParticipantId())) {
285
286                 initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
287                             participantDeploy, DeployState.UPDATING);
288
289                 callParticipantUpdateProperty(participantDeploy.getAcElementList(), acElementDefinitions,
290                         updateMsg.getAutomationCompositionId());
291             }
292         }
293     }
294
295     /**
296      * Handle a automation composition Deploy message.
297      *
298      * @param updateMsg the Deploy message
299      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
300      */
301     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy updateMsg,
302             List<AutomationCompositionElementDefinition> acElementDefinitions) {
303
304         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
305             LOGGER.warn("No AutomationCompositionElement updates in message {}",
306                     updateMsg.getAutomationCompositionId());
307             return;
308         }
309
310         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
311             if (participantId.equals(participantDeploy.getParticipantId())) {
312                 if (updateMsg.isFirstStartPhase()) {
313                     initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
314                             participantDeploy, DeployState.DEPLOYING);
315                 }
316                 callParticipantDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
317                         updateMsg.getStartPhase(), updateMsg.getAutomationCompositionId());
318             }
319         }
320     }
321
322     private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy,
323                                   DeployState deployState) {
324         if (automationCompositionMap.containsKey(instanceId)) {
325             updateExistingElementsOnThisParticipant(instanceId, participantDeploy, deployState);
326         } else {
327             var automationComposition = new AutomationComposition();
328             automationComposition.setInstanceId(instanceId);
329             var acElements = storeElementsOnThisParticipant(participantDeploy, deployState);
330             automationComposition.setElements(prepareAcElementMap(acElements));
331             automationCompositionMap.put(instanceId, automationComposition);
332         }
333     }
334
335     private void callParticipantDeploy(List<AcElementDeploy> acElements,
336                                        List<AutomationCompositionElementDefinition> acElementDefinitions,
337                                        Integer startPhaseMsg, UUID automationCompositionId) {
338         try {
339             for (var element : acElements) {
340                 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
341                         element.getDefinition());
342                 if (acElementNodeTemplate != null) {
343                     int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
344                     if (startPhaseMsg.equals(startPhase)) {
345                         for (var acElementListener : listeners) {
346                             var map = new HashMap<>(acElementNodeTemplate.getProperties());
347                             map.putAll(element.getProperties());
348                             acElementListener.deploy(automationCompositionId, element, map);
349                         }
350                     }
351                 }
352             }
353         } catch (PfModelException e) {
354             LOGGER.debug("Automation composition element update failed {}", automationCompositionId);
355         }
356
357     }
358
359     private void callParticipantUpdateProperty(List<AcElementDeploy> acElements,
360                                        List<AutomationCompositionElementDefinition> acElementDefinitions,
361                                        UUID automationCompositionId) {
362         try {
363             for (var element : acElements) {
364                 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
365                         element.getDefinition());
366                 if (acElementNodeTemplate != null) {
367                     for (var acElementListener : listeners) {
368                         var map = new HashMap<>(acElementNodeTemplate.getProperties());
369                         map.putAll(element.getProperties());
370                         acElementListener.update(automationCompositionId, element, map);
371                     }
372                 }
373             }
374         } catch (PfModelException e) {
375             LOGGER.error("Automation composition element update failed for {} {}", automationCompositionId, e);
376         }
377
378     }
379
380     private ToscaNodeTemplate getAcElementNodeTemplate(
381             List<AutomationCompositionElementDefinition> acElementDefinitions, ToscaConceptIdentifier acElementDefId) {
382
383         for (var acElementDefinition : acElementDefinitions) {
384             if (acElementDefId.getName().contains(acElementDefinition.getAcElementDefinitionId().getName())) {
385                 return acElementDefinition.getAutomationCompositionElementToscaNodeTemplate();
386             }
387         }
388         return null;
389     }
390
391     private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy,
392                                                                               DeployState deployState) {
393         List<AutomationCompositionElement> acElementList = new ArrayList<>();
394         for (var element : participantDeploy.getAcElementList()) {
395             var acElement = new AutomationCompositionElement();
396             acElement.setId(element.getId());
397             acElement.setParticipantId(participantDeploy.getParticipantId());
398             acElement.setDefinition(element.getDefinition());
399             acElement.setDeployState(deployState);
400             acElement.setLockState(LockState.NONE);
401             acElementList.add(acElement);
402         }
403         return acElementList;
404     }
405
406     private void updateExistingElementsOnThisParticipant(
407             UUID instanceId, ParticipantDeploy participantDeploy, DeployState deployState) {
408
409         Map<UUID, AutomationCompositionElement> elementList = automationCompositionMap.get(instanceId).getElements();
410         for (var element : participantDeploy.getAcElementList()) {
411             automationCompositionMap.get(instanceId).getElements().get(element.getId()).getProperties()
412                     .putAll(element.getProperties());
413             automationCompositionMap.get(instanceId).getElements().get(element.getId()).setDeployState(deployState);
414         }
415     }
416
417     private Map<UUID, AutomationCompositionElement> prepareAcElementMap(List<AutomationCompositionElement> acElements) {
418         Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
419         for (var element : acElements) {
420             acElementMap.put(element.getId(), element);
421         }
422         return acElementMap;
423     }
424
425     /**
426      * Method to handle when the new state from participant is UNINITIALISED state.
427      *
428      * @param automationComposition participant response
429      * @param startPhaseMsg startPhase from message
430      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
431      */
432     private void handleUndeployState(final AutomationComposition automationComposition, Integer startPhaseMsg,
433             List<AutomationCompositionElementDefinition> acElementDefinitions) {
434
435         automationComposition.getElements().values().stream()
436                 .forEach(acElement -> automationCompositionElementUndeploy(automationComposition.getInstanceId(),
437                         acElement, startPhaseMsg, acElementDefinitions));
438     }
439
440     private void handleDeleteState(final AutomationComposition automationComposition, Integer startPhaseMsg,
441             List<AutomationCompositionElementDefinition> acElementDefinitions) {
442
443         automationComposition.getElements().values().stream()
444                 .forEach(acElement -> automationCompositionElementDelete(automationComposition.getInstanceId(),
445                         acElement, startPhaseMsg, acElementDefinitions));
446
447         boolean isAllUninitialised = automationComposition.getElements().values().stream()
448                 .filter(element -> !DeployState.DELETED.equals(element.getDeployState())).findAny().isEmpty();
449         if (isAllUninitialised) {
450             automationCompositionMap.remove(automationComposition.getInstanceId());
451         }
452     }
453
454     /**
455      * Method to handle when the new state from participant is PASSIVE state.
456      *
457      * @param automationComposition participant response
458      * @param startPhaseMsg startPhase from message
459      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
460      */
461     private void handleLockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
462             List<AutomationCompositionElementDefinition> acElementDefinitions) {
463         automationComposition.getElements().values().stream()
464                 .forEach(acElement -> automationCompositionElementLock(automationComposition.getInstanceId(), acElement,
465                         startPhaseMsg, acElementDefinitions));
466     }
467
468     /**
469      * Method to handle when the new state from participant is RUNNING state.
470      *
471      * @param automationComposition participant response
472      * @param startPhaseMsg startPhase from message
473      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
474      */
475     private void handleUnlockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
476             List<AutomationCompositionElementDefinition> acElementDefinitions) {
477         automationComposition.getElements().values().stream()
478                 .forEach(acElement -> automationCompositionElementUnlock(automationComposition.getInstanceId(),
479                         acElement, startPhaseMsg, acElementDefinitions));
480     }
481
482     private void automationCompositionElementLock(UUID instanceId, AutomationCompositionElement acElement,
483             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
484         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
485         if (acElementNodeTemplate != null) {
486             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
487             if (startPhaseMsg.equals(startPhase)) {
488                 for (var acElementListener : listeners) {
489                     try {
490                         acElementListener.lock(instanceId, acElement.getId());
491                         updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.LOCKED,
492                                 "Locked");
493                     } catch (PfModelException e) {
494                         LOGGER.error("Automation composition element lock failed {}", instanceId);
495                     }
496                 }
497             }
498         }
499     }
500
501     private void automationCompositionElementUnlock(UUID instanceId, AutomationCompositionElement acElement,
502             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
503         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
504         if (acElementNodeTemplate != null) {
505             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
506             if (startPhaseMsg.equals(startPhase)) {
507                 for (var acElementListener : listeners) {
508                     try {
509                         acElementListener.unlock(instanceId, acElement.getId());
510                         updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.UNLOCKED,
511                                 "Unlocked");
512                     } catch (PfModelException e) {
513                         LOGGER.error("Automation composition element unlock failed {}", instanceId);
514                     }
515                 }
516             }
517         }
518     }
519
520     private void automationCompositionElementUndeploy(UUID instanceId, AutomationCompositionElement acElement,
521             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
522         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
523         if (acElementNodeTemplate != null) {
524             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
525             if (startPhaseMsg.equals(startPhase)) {
526                 undeployInstanceElements(instanceId, acElement.getId());
527             }
528         }
529     }
530
531     private void automationCompositionElementDelete(UUID instanceId, AutomationCompositionElement acElement,
532             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
533         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
534         if (acElementNodeTemplate != null) {
535             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
536             if (startPhaseMsg.equals(startPhase)) {
537                 for (var acElementListener : listeners) {
538                     try {
539                         acElementListener.delete(instanceId, acElement.getId());
540                         updateAutomationCompositionElementState(instanceId, acElement.getId(), DeployState.DELETED,
541                                 null, "Deleted");
542                     } catch (PfModelException e) {
543                         LOGGER.error("Automation composition element unlock failed {}", instanceId);
544                     }
545                 }
546             }
547         }
548     }
549
550     /**
551      * Undeploy Instance Elements On Participant.
552      */
553     public void undeployInstances() {
554         automationCompositionMap.values().forEach(this::undeployInstance);
555     }
556
557     private void undeployInstance(AutomationComposition automationComposition) {
558         automationComposition.getElements().values().forEach(element -> {
559             if (element.getParticipantId().equals(participantId)) {
560                 undeployInstanceElements(automationComposition.getInstanceId(), element.getId());
561             }
562         });
563     }
564
565     private void undeployInstanceElements(UUID instanceId, UUID elementId) {
566         for (var acElementListener : listeners) {
567             try {
568                 acElementListener.undeploy(instanceId, elementId);
569             } catch (PfModelException e) {
570                 LOGGER.error("Automation composition element update failed {}", instanceId);
571             }
572         }
573     }
574
575     /**
576      * Send Ac Element Info.
577      *
578      * @param automationCompositionId the automationComposition Id
579      * @param elementId the automationComposition Element id
580      * @param useState the use State
581      * @param operationalState the operational State
582      * @param outProperties the output Properties Map
583      */
584     public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
585             String operationalState, Map<String, Object> outProperties) {
586
587         if (automationCompositionId == null || elementId == null) {
588             LOGGER.error("Cannot update Automation composition element state, id is null");
589             return;
590         }
591
592         var automationComposition = automationCompositionMap.get(automationCompositionId);
593         if (automationComposition == null) {
594             LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
595                     automationComposition);
596             return;
597         }
598
599         var element = automationComposition.getElements().get(elementId);
600         if (element == null) {
601             var msg = "Cannot update Automation composition element state, AC Element id {} not present";
602             LOGGER.error(msg, automationComposition);
603             return;
604         }
605         element.setOperationalState(operationalState);
606         element.setUseState(useState);
607         element.setOutProperties(outProperties);
608
609         var statusMsg = new ParticipantStatus();
610         statusMsg.setParticipantId(participantId);
611         statusMsg.setState(ParticipantState.ON_LINE);
612         statusMsg.setParticipantSupportedElementType(new ArrayList<>(supportedAcElementTypes));
613         var acInfo = new AutomationCompositionInfo();
614         acInfo.setAutomationCompositionId(automationCompositionId);
615         acInfo.setDeployState(automationComposition.getDeployState());
616         acInfo.setLockState(automationComposition.getLockState());
617         acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
618         statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
619         publisher.sendParticipantStatus(statusMsg);
620     }
621
622     /**
623      * get AutomationComposition Info List.
624      *
625      * @return list of AutomationCompositionInfo
626      */
627     public List<AutomationCompositionInfo> getAutomationCompositionInfoList() {
628         List<AutomationCompositionInfo> automationCompositionInfoList = new ArrayList<>();
629         for (var entry : automationCompositionMap.entrySet()) {
630             var acInfo = new AutomationCompositionInfo();
631             acInfo.setAutomationCompositionId(entry.getKey());
632             acInfo.setDeployState(entry.getValue().getDeployState());
633             acInfo.setLockState(entry.getValue().getLockState());
634             for (var element : entry.getValue().getElements().values()) {
635                 acInfo.getElements().add(getAutomationCompositionElementInfo(element));
636             }
637             automationCompositionInfoList.add(acInfo);
638         }
639         return automationCompositionInfoList;
640     }
641
642     private AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
643         var elementInfo = new AutomationCompositionElementInfo();
644         elementInfo.setAutomationCompositionElementId(element.getId());
645         elementInfo.setDeployState(element.getDeployState());
646         elementInfo.setLockState(element.getLockState());
647         elementInfo.setOperationalState(element.getOperationalState());
648         elementInfo.setUseState(element.getUseState());
649         elementInfo.setOutProperties(element.getOutProperties());
650         return elementInfo;
651     }
652 }