e35582058c72c8233823f9d04c7bca20da95cd65
[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.rest.instantiation.DeployOrder;
53 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
54 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
55 import org.onap.policy.models.base.PfModelException;
56 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
57 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.springframework.stereotype.Component;
61
62 /*
63  * This class is responsible for managing the state of all automation compositions in the participant.
64  */
65 @Component
66 public class AutomationCompositionHandler {
67     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
68
69     private final UUID participantId;
70     private final ParticipantMessagePublisher publisher;
71     private final AcInstanceStateResolver acInstanceStateResolver;
72     private final List<ParticipantSupportedElementType> supportedAcElementTypes;
73     private final List<AutomationCompositionElementListener> listeners = new ArrayList<>();
74
75     @Getter
76     private final Map<UUID, AutomationComposition> automationCompositionMap = new LinkedHashMap<>();
77
78     /**
79      * Constructor, set the participant ID and messageSender.
80      *
81      * @param parameters the parameters of the participant
82      * @param publisher the ParticipantMessage Publisher
83      */
84     public AutomationCompositionHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) {
85         this.participantId = parameters.getIntermediaryParameters().getParticipantId();
86         this.publisher = publisher;
87         this.acInstanceStateResolver = new AcInstanceStateResolver();
88         this.supportedAcElementTypes = parameters.getIntermediaryParameters().getParticipantSupportedElementTypes();
89     }
90
91     public void registerAutomationCompositionElementListener(AutomationCompositionElementListener listener) {
92         listeners.add(listener);
93     }
94
95     /**
96      * Handle a automation composition element state change message.
97      *
98      * @param automationCompositionId the automationComposition Id
99      * @param id the automationComposition UUID
100      * @param deployState the DeployState state
101      * @param lockState the LockState state
102      */
103     public void updateAutomationCompositionElementState(UUID automationCompositionId, UUID id, DeployState deployState,
104             LockState lockState, String message) {
105
106         if (automationCompositionId == null || id == null) {
107             LOGGER.error("Cannot update Automation composition element state, id is null");
108             return;
109         }
110
111         if ((deployState != null && lockState != null) || (deployState == null && lockState == null)) {
112             LOGGER.error("state error {} and {} cannot be handled", deployState, lockState);
113             return;
114         }
115
116         var automationComposition = automationCompositionMap.get(automationCompositionId);
117         if (automationComposition == null) {
118             LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
119                     automationComposition);
120             return;
121         }
122
123         var element = automationComposition.getElements().get(id);
124         if (element == null) {
125             var msg = "Cannot update Automation composition element state, AC Element id {} not present";
126             LOGGER.error(msg, automationComposition);
127             return;
128         }
129
130         if (deployState != null) {
131             element.setDeployState(deployState);
132             var checkOpt = automationComposition.getElements().values().stream()
133                     .filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
134             if (checkOpt.isEmpty()) {
135                 automationComposition.setDeployState(deployState);
136             }
137             element.setLockState(
138                     DeployState.DEPLOYED.equals(element.getDeployState()) ? LockState.LOCKED : LockState.NONE);
139         }
140         if (lockState != null) {
141             element.setLockState(lockState);
142             var checkOpt = automationComposition.getElements().values().stream()
143                     .filter(acElement -> !lockState.equals(acElement.getLockState())).findAny();
144             if (checkOpt.isEmpty()) {
145                 automationComposition.setLockState(lockState);
146             }
147         }
148
149         var automationCompositionStateChangeAck =
150                 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
151         automationCompositionStateChangeAck.setParticipantId(participantId);
152         automationCompositionStateChangeAck.setMessage(message);
153         automationCompositionStateChangeAck.setAutomationCompositionId(automationCompositionId);
154         automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
155                 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
156                         element.getUseState(), element.getStatusProperties(), true,
157                         "Automation composition element {} state changed to {}\", id, newState)"));
158         LOGGER.debug("Automation composition element {} state changed to {}", id, deployState);
159         automationCompositionStateChangeAck.setResult(true);
160         publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
161     }
162
163     /**
164      * Handle a automation composition state change message.
165      *
166      * @param stateChangeMsg the state change message
167      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
168      */
169     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg,
170             List<AutomationCompositionElementDefinition> acElementDefinitions) {
171         if (stateChangeMsg.getAutomationCompositionId() == null) {
172             return;
173         }
174
175         var automationComposition = automationCompositionMap.get(stateChangeMsg.getAutomationCompositionId());
176
177         if (automationComposition == null) {
178             var automationCompositionAck =
179                     new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
180             automationCompositionAck.setParticipantId(participantId);
181             automationCompositionAck.setMessage("Automation composition " + stateChangeMsg.getAutomationCompositionId()
182                     + " does not use this participant " + participantId);
183             automationCompositionAck.setResult(false);
184             automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
185             automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
186             publisher.sendAutomationCompositionAck(automationCompositionAck);
187             LOGGER.debug("Automation composition {} does not use this participant",
188                     stateChangeMsg.getAutomationCompositionId());
189             return;
190         }
191
192         if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
193                 stateChangeMsg.getLockOrderedState())) {
194             var automationCompositionAck =
195                     new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
196             automationCompositionAck.setParticipantId(participantId);
197             automationCompositionAck.setMessage("Automation composition is already in state "
198                     + stateChangeMsg.getDeployOrderedState() + " and " + stateChangeMsg.getLockOrderedState());
199             automationCompositionAck.setResult(false);
200             automationCompositionAck.setAutomationCompositionId(automationComposition.getInstanceId());
201             publisher.sendAutomationCompositionAck(automationCompositionAck);
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         return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
217                 automationComposition.getLockState()) != null;
218     }
219
220     /**
221      * Method to handle state changes.
222      *
223      * @param automationComposition participant response
224      * @param orderedState automation composition ordered state
225      * @param startPhaseMsg startPhase from message
226      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
227      */
228     private void handleDeployOrderState(final AutomationComposition automationComposition, DeployOrder orderedState,
229             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
230
231         if (DeployOrder.UNDEPLOY.equals(orderedState)) {
232             handleUndeployState(automationComposition, startPhaseMsg, acElementDefinitions);
233         } else {
234             LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
235         }
236     }
237
238     /**
239      * Method to handle state changes.
240      *
241      * @param automationComposition participant response
242      * @param orderedState automation composition ordered state
243      * @param startPhaseMsg startPhase from message
244      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
245      */
246     private void handleLockOrderState(final AutomationComposition automationComposition, LockOrder orderedState,
247             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
248
249         switch (orderedState) {
250             case LOCK:
251                 handleLockState(automationComposition, startPhaseMsg, acElementDefinitions);
252                 break;
253             case UNLOCK:
254                 handleUnlockState(automationComposition, startPhaseMsg, acElementDefinitions);
255                 break;
256             default:
257                 LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
258                 break;
259         }
260     }
261
262     /**
263      * Handle a automation composition Deploy message.
264      *
265      * @param updateMsg the Deploy message
266      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
267      */
268     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy updateMsg,
269             List<AutomationCompositionElementDefinition> acElementDefinitions) {
270
271         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
272             LOGGER.warn("No AutomationCompositionElement updates in message {}",
273                     updateMsg.getAutomationCompositionId());
274             return;
275         }
276
277         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
278             if (participantId.equals(participantDeploy.getParticipantId())) {
279                 if (updateMsg.isFirstStartPhase()) {
280                     initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
281                             participantDeploy);
282                 }
283                 callParticipanDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
284                         updateMsg.getStartPhase(), updateMsg.getAutomationCompositionId());
285             }
286         }
287     }
288
289     private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy) {
290         var automationComposition = automationCompositionMap.get(instanceId);
291
292         if (automationComposition != null) {
293             var automationCompositionUpdateAck =
294                     new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY_ACK);
295             automationCompositionUpdateAck.setParticipantId(participantId);
296
297             automationCompositionUpdateAck.setMessage(
298                     "Automation composition " + instanceId + " already defined on participant " + participantId);
299             automationCompositionUpdateAck.setResult(false);
300             automationCompositionUpdateAck.setResponseTo(messageId);
301             automationCompositionUpdateAck.setAutomationCompositionId(instanceId);
302             publisher.sendAutomationCompositionAck(automationCompositionUpdateAck);
303             return;
304         }
305
306         automationComposition = new AutomationComposition();
307         automationComposition.setInstanceId(instanceId);
308         var acElements = storeElementsOnThisParticipant(participantDeploy);
309         automationComposition.setElements(prepareAcElementMap(acElements));
310         automationCompositionMap.put(instanceId, automationComposition);
311     }
312
313     private void callParticipanDeploy(List<AcElementDeploy> acElements,
314             List<AutomationCompositionElementDefinition> acElementDefinitions, Integer startPhaseMsg,
315             UUID automationCompositionId) {
316         try {
317             for (var element : acElements) {
318                 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, element.getDefinition());
319                 if (acElementNodeTemplate != null) {
320                     int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
321                     if (startPhaseMsg.equals(startPhase)) {
322                         for (var acElementListener : listeners) {
323                             var map = new HashMap<>(acElementNodeTemplate.getProperties());
324                             map.putAll(element.getProperties());
325                             acElementListener.deploy(automationCompositionId, element, map);
326                         }
327                     }
328                 }
329             }
330         } catch (PfModelException e) {
331             LOGGER.debug("Automation composition element update failed {}", automationCompositionId);
332         }
333
334     }
335
336     private ToscaNodeTemplate getAcElementNodeTemplate(
337             List<AutomationCompositionElementDefinition> acElementDefinitions, ToscaConceptIdentifier acElementDefId) {
338
339         for (var acElementDefinition : acElementDefinitions) {
340             if (acElementDefId.getName().contains(acElementDefinition.getAcElementDefinitionId().getName())) {
341                 return acElementDefinition.getAutomationCompositionElementToscaNodeTemplate();
342             }
343         }
344         return null;
345     }
346
347     private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy) {
348         List<AutomationCompositionElement> acElementList = new ArrayList<>();
349         for (var element : participantDeploy.getAcElementList()) {
350             var acElement = new AutomationCompositionElement();
351             acElement.setId(element.getId());
352             acElement.setParticipantId(participantDeploy.getParticipantId());
353             acElement.setDefinition(element.getDefinition());
354             acElement.setDeployState(DeployState.DEPLOYING);
355             acElement.setLockState(LockState.NONE);
356             acElementList.add(acElement);
357         }
358         return acElementList;
359     }
360
361     private Map<UUID, AutomationCompositionElement> prepareAcElementMap(List<AutomationCompositionElement> acElements) {
362         Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
363         for (var element : acElements) {
364             acElementMap.put(element.getId(), element);
365         }
366         return acElementMap;
367     }
368
369     /**
370      * Method to handle when the new state from participant is UNINITIALISED state.
371      *
372      * @param automationComposition participant response
373      * @param startPhaseMsg startPhase from message
374      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
375      */
376     private void handleUndeployState(final AutomationComposition automationComposition, Integer startPhaseMsg,
377             List<AutomationCompositionElementDefinition> acElementDefinitions) {
378
379         automationComposition.getElements().values().stream()
380                 .forEach(acElement -> automationCompositionElementUndeploy(automationComposition.getInstanceId(),
381                         acElement, startPhaseMsg, acElementDefinitions));
382
383         boolean isAllUninitialised = automationComposition.getElements().values().stream()
384                 .filter(element -> !DeployState.UNDEPLOYED.equals(element.getDeployState())).findAny().isEmpty();
385         if (isAllUninitialised) {
386             automationCompositionMap.remove(automationComposition.getInstanceId());
387         }
388     }
389
390     /**
391      * Method to handle when the new state from participant is PASSIVE state.
392      *
393      * @param automationComposition participant response
394      * @param startPhaseMsg startPhase from message
395      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
396      */
397     private void handleLockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
398             List<AutomationCompositionElementDefinition> acElementDefinitions) {
399         automationComposition.getElements().values().stream()
400                 .forEach(acElement -> automationCompositionElementLock(automationComposition.getInstanceId(), acElement,
401                         startPhaseMsg, acElementDefinitions));
402     }
403
404     /**
405      * Method to handle when the new state from participant is RUNNING state.
406      *
407      * @param automationComposition participant response
408      * @param startPhaseMsg startPhase from message
409      * @param acElementDefinitions the list of AutomationCompositionElementDefinition
410      */
411     private void handleUnlockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
412             List<AutomationCompositionElementDefinition> acElementDefinitions) {
413         automationComposition.getElements().values().stream()
414                 .forEach(acElement -> automationCompositionElementUnlock(automationComposition.getInstanceId(),
415                         acElement, startPhaseMsg, acElementDefinitions));
416     }
417
418     private void automationCompositionElementLock(UUID instanceId, AutomationCompositionElement acElement,
419             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
420         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
421         if (acElementNodeTemplate != null) {
422             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
423             if (startPhaseMsg.equals(startPhase)) {
424                 for (var acElementListener : listeners) {
425                     try {
426                         acElementListener.lock(instanceId, acElement.getId());
427                         updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.LOCKED,
428                                 "Locked");
429                     } catch (PfModelException e) {
430                         LOGGER.error("Automation composition element lock failed {}", instanceId);
431                     }
432                 }
433             }
434         }
435     }
436
437     private void automationCompositionElementUnlock(UUID instanceId, AutomationCompositionElement acElement,
438             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
439         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
440         if (acElementNodeTemplate != null) {
441             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
442             if (startPhaseMsg.equals(startPhase)) {
443                 for (var acElementListener : listeners) {
444                     try {
445                         acElementListener.unlock(instanceId, acElement.getId());
446                         updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.UNLOCKED,
447                                 "Unlocked");
448                     } catch (PfModelException e) {
449                         LOGGER.error("Automation composition element unlock failed {}", instanceId);
450                     }
451                 }
452             }
453         }
454     }
455
456     private void automationCompositionElementUndeploy(UUID instanceId, AutomationCompositionElement acElement,
457             Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
458         var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
459         if (acElementNodeTemplate != null) {
460             int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
461             if (startPhaseMsg.equals(startPhase)) {
462                 undeployInstanceElements(instanceId, acElement.getId());
463             }
464         }
465     }
466
467
468     /**
469      * Undeploy Instance Elements On Participant.
470      */
471     public void undeployInstances() {
472         automationCompositionMap.values().forEach(this::undeployInstance);
473     }
474
475     private void undeployInstance(AutomationComposition automationComposition) {
476         automationComposition.getElements().values().forEach(element -> {
477             if (element.getParticipantId().equals(participantId)) {
478                 undeployInstanceElements(automationComposition.getInstanceId(), element.getId());
479             }
480         });
481     }
482
483     private void undeployInstanceElements(UUID instanceId, UUID elementId) {
484         for (var acElementListener : listeners) {
485             try {
486                 acElementListener.undeploy(instanceId, elementId);
487             } catch (PfModelException e) {
488                 LOGGER.error("Automation composition element update failed {}", instanceId);
489             }
490         }
491     }
492
493     /**
494      * Send Ac Element Info.
495      *
496      * @param automationCompositionId the automationComposition Id
497      * @param elementId the automationComposition Element id
498      * @param useState the use State
499      * @param operationalState the operational State
500      * @param statusProperties the status Properties Map
501      */
502     public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
503             String operationalState, Map<String, Object> statusProperties) {
504
505         if (automationCompositionId == null || elementId == null) {
506             LOGGER.error("Cannot update Automation composition element state, id is null");
507             return;
508         }
509
510         var automationComposition = automationCompositionMap.get(automationCompositionId);
511         if (automationComposition == null) {
512             LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
513                     automationComposition);
514             return;
515         }
516
517         var element = automationComposition.getElements().get(elementId);
518         if (element == null) {
519             var msg = "Cannot update Automation composition element state, AC Element id {} not present";
520             LOGGER.error(msg, automationComposition);
521             return;
522         }
523         element.setOperationalState(operationalState);
524         element.setUseState(useState);
525         element.setStatusProperties(statusProperties);
526
527         var statusMsg = new ParticipantStatus();
528         statusMsg.setParticipantId(participantId);
529         statusMsg.setState(ParticipantState.ON_LINE);
530         statusMsg.setParticipantSupportedElementType(new ArrayList<>(supportedAcElementTypes));
531         var acInfo = new AutomationCompositionInfo();
532         acInfo.setAutomationCompositionId(automationCompositionId);
533         acInfo.setDeployState(automationComposition.getDeployState());
534         acInfo.setLockState(automationComposition.getLockState());
535         acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
536         statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
537         publisher.sendParticipantStatus(statusMsg);
538     }
539
540     /**
541      * get AutomationComposition Info List.
542      *
543      * @return list of AutomationCompositionInfo
544      */
545     public List<AutomationCompositionInfo> getAutomationCompositionInfoList() {
546         List<AutomationCompositionInfo> automationCompositionInfoList = new ArrayList<>();
547         for (var entry : automationCompositionMap.entrySet()) {
548             var acInfo = new AutomationCompositionInfo();
549             acInfo.setAutomationCompositionId(entry.getKey());
550             acInfo.setDeployState(entry.getValue().getDeployState());
551             acInfo.setLockState(entry.getValue().getLockState());
552             for (var element : entry.getValue().getElements().values()) {
553                 acInfo.getElements().add(getAutomationCompositionElementInfo(element));
554             }
555             automationCompositionInfoList.add(acInfo);
556         }
557         return automationCompositionInfoList;
558     }
559
560     private AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
561         var elementInfo = new AutomationCompositionElementInfo();
562         elementInfo.setAutomationCompositionElementId(element.getId());
563         elementInfo.setDeployState(element.getDeployState());
564         elementInfo.setLockState(element.getLockState());
565         elementInfo.setOperationalState(element.getOperationalState());
566         elementInfo.setUseState(element.getUseState());
567         elementInfo.setStatusProperties(element.getStatusProperties());
568         return elementInfo;
569     }
570 }