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