3f3d5756abd7f98a0afc65e099e7e198dd332d51
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2024 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.List;
27 import java.util.Map;
28 import java.util.UUID;
29 import java.util.stream.Collectors;
30 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto;
31 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
32 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
33 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
34 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
35 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
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.DeployState;
40 import org.onap.policy.clamp.models.acm.concepts.LockState;
41 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
42 import org.onap.policy.clamp.models.acm.concepts.ParticipantRestartAc;
43 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
44 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
45 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
46 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
47 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
48 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
49 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange;
50 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
51 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck;
52 import org.onap.policy.clamp.models.acm.messages.kafka.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.clamp.models.acm.utils.AcmUtils;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.springframework.stereotype.Component;
60
61 /*
62  * This class is responsible for managing the state of all automation compositions in the participant.
63  */
64 @Component
65 public class AutomationCompositionHandler {
66     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
67
68     private final CacheProvider cacheProvider;
69     private final ParticipantMessagePublisher publisher;
70     private final ThreadHandler listener;
71     private final AcInstanceStateResolver acInstanceStateResolver;
72
73     /**
74      * Constructor, set the participant ID and messageSender.
75      *
76      * @param cacheProvider the Cache Provider
77      * @param publisher the ParticipantMessage Publisher
78      * @param listener the ThreadHandler Listener
79      */
80     public AutomationCompositionHandler(CacheProvider cacheProvider, ParticipantMessagePublisher publisher,
81             ThreadHandler listener) {
82         this.cacheProvider = cacheProvider;
83         this.publisher = publisher;
84         this.listener = listener;
85         this.acInstanceStateResolver = new AcInstanceStateResolver();
86     }
87
88     /**
89      * Handle a automation composition state change message.
90      *
91      * @param stateChangeMsg the state change message
92      */
93     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
94         if (stateChangeMsg.getAutomationCompositionId() == null) {
95             return;
96         }
97
98         var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
99
100         if (automationComposition == null) {
101             if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
102                 var automationCompositionAck = new AutomationCompositionDeployAck(
103                         ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
104                 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
105                 automationCompositionAck.setMessage("Already deleted or never used");
106                 automationCompositionAck.setResult(true);
107                 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
108                 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
109                 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
110                 publisher.sendAutomationCompositionAck(automationCompositionAck);
111             } else {
112                 LOGGER.debug("Automation composition {} does not use this participant",
113                         stateChangeMsg.getAutomationCompositionId());
114             }
115             return;
116         }
117
118         if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
119                 stateChangeMsg.getLockOrderedState())) {
120             LOGGER.warn("Not Consistant OrderState Automation composition {}",
121                     stateChangeMsg.getAutomationCompositionId());
122             return;
123         }
124
125         if (DeployOrder.NONE.equals(stateChangeMsg.getDeployOrderedState())) {
126             handleLockOrderState(stateChangeMsg.getMessageId(), automationComposition,
127                     stateChangeMsg.getLockOrderedState(), stateChangeMsg.getStartPhase());
128         } else {
129             handleDeployOrderState(stateChangeMsg.getMessageId(), automationComposition,
130                     stateChangeMsg.getDeployOrderedState(), stateChangeMsg.getStartPhase());
131         }
132     }
133
134     private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder,
135             LockOrder lockOrder) {
136         if (DeployOrder.UPDATE.equals(deployOrder)) {
137             return true;
138         }
139         return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
140                 automationComposition.getLockState(), automationComposition.getStateChangeResult()) != null;
141     }
142
143     /**
144      * Method to handle state changes.
145      *
146      * @param messageId the messageId
147      * @param automationComposition participant response
148      * @param orderedState automation composition ordered state
149      * @param startPhaseMsg startPhase from message
150      */
151     private void handleDeployOrderState(UUID messageId, final AutomationComposition automationComposition,
152             DeployOrder orderedState, Integer startPhaseMsg) {
153
154         switch (orderedState) {
155             case UNDEPLOY:
156                 handleUndeployState(messageId, automationComposition, startPhaseMsg);
157                 break;
158             case DELETE:
159                 handleDeleteState(messageId, automationComposition, startPhaseMsg);
160                 break;
161
162             default:
163                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
164                 break;
165         }
166     }
167
168     /**
169      * Method to handle state changes.
170      *
171      * @param messageId the messageId
172      * @param automationComposition participant response
173      * @param orderedState automation composition ordered state
174      * @param startPhaseMsg startPhase from message
175      */
176     private void handleLockOrderState(UUID messageId, final AutomationComposition automationComposition,
177             LockOrder orderedState, Integer startPhaseMsg) {
178
179         switch (orderedState) {
180             case LOCK:
181                 handleLockState(messageId, automationComposition, startPhaseMsg);
182                 break;
183             case UNLOCK:
184                 handleUnlockState(messageId, automationComposition, startPhaseMsg);
185                 break;
186             default:
187                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
188                 break;
189         }
190     }
191
192     /**
193      * Handle a automation composition properties update message.
194      *
195      * @param updateMsg the properties update message
196      */
197     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
198
199         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
200             LOGGER.warn("No AutomationCompositionElement updates in message {}",
201                     updateMsg.getAutomationCompositionId());
202             return;
203         }
204
205         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
206             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
207
208                 var acCopy = new AutomationComposition(cacheProvider.getAutomationComposition(
209                     updateMsg.getAutomationCompositionId()));
210                 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy,
211                         DeployState.UPDATING);
212
213                 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(), acCopy);
214             }
215         }
216     }
217
218     /**
219      * Handle a automation composition Deploy message.
220      *
221      * @param deployMsg the Deploy message
222      */
223     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
224
225         if (deployMsg.getParticipantUpdatesList().isEmpty()) {
226             LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
227             return;
228         }
229
230         for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
231             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
232                 if (deployMsg.isFirstStartPhase()) {
233                     cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
234                             deployMsg.getAutomationCompositionId(), participantDeploy);
235                 }
236                 callParticipanDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
237                         deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
238             }
239         }
240     }
241
242     private void callParticipanDeploy(UUID messageId, List<AcElementDeploy> acElementDeployList,
243             Integer startPhaseMsg, UUID instanceId) {
244         var automationComposition = cacheProvider.getAutomationComposition(instanceId);
245         for (var elementDeploy : acElementDeployList) {
246             var element = automationComposition.getElements().get(elementDeploy.getId());
247             var compositionInProperties = cacheProvider
248                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
249             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
250             if (startPhaseMsg.equals(startPhase)) {
251                 var compositionElement = createCompositionElementDto(automationComposition.getCompositionId(),
252                     element, compositionInProperties);
253                 var instanceElement = new InstanceElementDto(instanceId, elementDeploy.getId(),
254                     elementDeploy.getToscaServiceTemplateFragment(),
255                     elementDeploy.getProperties(), element.getOutProperties());
256                 listener.deploy(messageId, compositionElement, instanceElement);
257             }
258         }
259     }
260
261     private CompositionElementDto createCompositionElementDto(UUID compositionId, AutomationCompositionElement element,
262         Map<String, Object> compositionInProperties) {
263         var compositionOutProperties = cacheProvider.getAcElementsDefinitions()
264             .get(compositionId).get(element.getDefinition()).getOutProperties();
265         return new CompositionElementDto(compositionId,
266             element.getDefinition(), compositionInProperties, compositionOutProperties);
267     }
268
269     private Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition,
270         UUID compositionId) {
271         Map<UUID, CompositionElementDto> map = new HashMap<>();
272         for (var element : automationComposition.getElements().values()) {
273             var compositionInProperties = cacheProvider.getCommonProperties(compositionId, element.getDefinition());
274             var compositionElement = createCompositionElementDto(compositionId, element, compositionInProperties);
275             map.put(element.getId(), compositionElement);
276         }
277         return map;
278     }
279
280     private Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition) {
281         return getCompositionElementDtoMap(automationComposition, automationComposition.getCompositionId());
282     }
283
284     private Map<UUID, InstanceElementDto> getInstanceElementDtoMap(AutomationComposition automationComposition) {
285         Map<UUID, InstanceElementDto> map = new HashMap<>();
286         for (var element : automationComposition.getElements().values()) {
287             var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
288                 null, element.getProperties(), element.getOutProperties());
289             map.put(element.getId(), instanceElement);
290         }
291         return map;
292     }
293
294     private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements,
295         AutomationComposition acCopy) {
296         var instanceElementDtoMap = getInstanceElementDtoMap(acCopy);
297         var instanceElementDtoMapUpdated = getInstanceElementDtoMap(
298             cacheProvider.getAutomationComposition(acCopy.getInstanceId()));
299         var compositionElementDtoMap = getCompositionElementDtoMap(acCopy);
300         for (var acElement : acElements) {
301             listener.update(messageId, compositionElementDtoMap.get(acElement.getId()),
302                 instanceElementDtoMap.get(acElement.getId()), instanceElementDtoMapUpdated.get(acElement.getId()));
303         }
304     }
305
306     private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy,
307         DeployState deployState) {
308         var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
309         for (var element : participantDeploy.getAcElementList()) {
310             var acElement = acElementList.get(element.getId());
311             AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
312             acElement.setDeployState(deployState);
313             acElement.setDefinition(element.getDefinition());
314         }
315     }
316
317     /**
318      * Method to handle when the new state from participant is UNINITIALISED state.
319      *
320      * @param messageId the messageId
321      * @param automationComposition participant response
322      * @param startPhaseMsg startPhase from message
323      */
324     private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
325             Integer startPhaseMsg) {
326         automationComposition.setCompositionTargetId(null);
327         for (var element : automationComposition.getElements().values()) {
328             var compositionInProperties = cacheProvider
329                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
330             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
331             if (startPhaseMsg.equals(startPhase)) {
332                 element.setDeployState(DeployState.UNDEPLOYING);
333                 var compositionElement = createCompositionElementDto(automationComposition.getCompositionId(),
334                     element, compositionInProperties);
335                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
336                     null, element.getProperties(), element.getOutProperties());
337                 listener.undeploy(messageId, compositionElement, instanceElement);
338             }
339         }
340     }
341
342     private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
343             Integer startPhaseMsg) {
344         for (var element : automationComposition.getElements().values()) {
345             var compositionInProperties = cacheProvider
346                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
347             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
348             if (startPhaseMsg.equals(startPhase)) {
349                 element.setDeployState(DeployState.DELETING);
350                 var compositionElement = createCompositionElementDto(automationComposition.getCompositionId(),
351                     element, compositionInProperties);
352                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
353                     null, element.getProperties(), element.getOutProperties());
354                 listener.delete(messageId, compositionElement, instanceElement);
355             }
356         }
357     }
358
359     /**
360      * Method to handle when the new state from participant is PASSIVE state.
361      *
362      * @param messageId the messageId
363      * @param automationComposition participant response
364      * @param startPhaseMsg startPhase from message
365      */
366     private void handleLockState(UUID messageId, final AutomationComposition automationComposition,
367             Integer startPhaseMsg) {
368         for (var element : automationComposition.getElements().values()) {
369             var compositionInProperties = cacheProvider
370                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
371             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
372             if (startPhaseMsg.equals(startPhase)) {
373                 element.setLockState(LockState.LOCKING);
374                 var compositionElement = createCompositionElementDto(automationComposition.getCompositionId(),
375                     element, compositionInProperties);
376                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
377                     null, element.getProperties(), element.getOutProperties());
378                 listener.lock(messageId, compositionElement, instanceElement);
379             }
380         }
381     }
382
383     /**
384      * Method to handle when the new state from participant is RUNNING state.
385      *
386      * @param messageId the messageId
387      * @param automationComposition participant response
388      * @param startPhaseMsg startPhase from message
389      */
390     private void handleUnlockState(UUID messageId, final AutomationComposition automationComposition,
391             Integer startPhaseMsg) {
392         for (var element : automationComposition.getElements().values()) {
393             var compositionInProperties = cacheProvider
394                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
395             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
396             if (startPhaseMsg.equals(startPhase)) {
397                 element.setLockState(LockState.UNLOCKING);
398                 var compositionElement = createCompositionElementDto(automationComposition.getCompositionId(),
399                     element, compositionInProperties);
400                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
401                     null, element.getProperties(), element.getOutProperties());
402                 listener.unlock(messageId, compositionElement, instanceElement);
403             }
404         }
405     }
406
407     /**
408      * Handles prime a Composition Definition.
409      *
410      * @param messageId the messageId
411      * @param compositionId the compositionId
412      * @param list the list of AutomationCompositionElementDefinition
413      */
414     public void prime(UUID messageId, UUID compositionId, List<AutomationCompositionElementDefinition> list) {
415         var inPropertiesMap = list.stream().collect(Collectors.toMap(
416             AutomationCompositionElementDefinition::getAcElementDefinitionId,
417             el -> el.getAutomationCompositionElementToscaNodeTemplate().getProperties()));
418         var outPropertiesMap = list.stream().collect(Collectors.toMap(
419             AutomationCompositionElementDefinition::getAcElementDefinitionId,
420             AutomationCompositionElementDefinition::getOutProperties));
421         listener.prime(messageId, new CompositionDto(compositionId, inPropertiesMap, outPropertiesMap));
422     }
423
424     /**
425      * Handles deprime a Composition Definition.
426      *
427      * @param messageId the messageId
428      * @param compositionId the compositionId
429      */
430     public void deprime(UUID messageId, UUID compositionId) {
431         var acElementsDefinitions = cacheProvider.getAcElementsDefinitions().get(compositionId);
432         if (acElementsDefinitions == null) {
433             // this participant does not handle this composition
434             var participantPrimeAck = new ParticipantPrimeAck();
435             participantPrimeAck.setCompositionId(compositionId);
436             participantPrimeAck.setMessage("Already deprimed or never primed");
437             participantPrimeAck.setResult(true);
438             participantPrimeAck.setResponseTo(messageId);
439             participantPrimeAck.setCompositionState(AcTypeState.COMMISSIONED);
440             participantPrimeAck.setStateChangeResult(StateChangeResult.NO_ERROR);
441             participantPrimeAck.setParticipantId(cacheProvider.getParticipantId());
442             participantPrimeAck.setState(ParticipantState.ON_LINE);
443             publisher.sendParticipantPrimeAck(participantPrimeAck);
444             return;
445         }
446         var list = new ArrayList<>(acElementsDefinitions.values());
447         var inPropertiesMap = list.stream().collect(Collectors.toMap(
448             AutomationCompositionElementDefinition::getAcElementDefinitionId,
449             el -> el.getAutomationCompositionElementToscaNodeTemplate().getProperties()));
450         var outPropertiesMap = list.stream().collect(Collectors.toMap(
451             AutomationCompositionElementDefinition::getAcElementDefinitionId,
452             AutomationCompositionElementDefinition::getOutProperties));
453         listener.deprime(messageId, new CompositionDto(compositionId, inPropertiesMap, outPropertiesMap));
454     }
455
456     /**
457      * Handles restarted scenario.
458      *
459      * @param messageId the messageId
460      * @param compositionId the compositionId
461      * @param list the list of AutomationCompositionElementDefinition
462      * @param state the state of the composition
463      * @param automationCompositionList list of ParticipantRestartAc
464      */
465     public void restarted(UUID messageId, UUID compositionId, List<AutomationCompositionElementDefinition> list,
466             AcTypeState state, List<ParticipantRestartAc> automationCompositionList) {
467
468         for (var automationcomposition : automationCompositionList) {
469             cacheProvider.initializeAutomationComposition(compositionId, automationcomposition);
470         }
471         var inPropertiesMap = list.stream().collect(Collectors.toMap(
472             AutomationCompositionElementDefinition::getAcElementDefinitionId,
473             el -> el.getAutomationCompositionElementToscaNodeTemplate().getProperties()));
474         var outPropertiesMap = list.stream().collect(Collectors.toMap(
475             AutomationCompositionElementDefinition::getAcElementDefinitionId,
476             AutomationCompositionElementDefinition::getOutProperties));
477         var composition = new CompositionDto(compositionId, inPropertiesMap, outPropertiesMap);
478         listener.restarted(messageId, composition, state, automationCompositionList);
479     }
480
481     /**
482      * Handles AutomationComposition Migration.
483      *
484      * @param migrationMsg the AutomationCompositionMigration
485      */
486     public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
487         if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
488             return;
489         }
490
491         var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
492         if (automationComposition == null) {
493             LOGGER.debug("Automation composition {} does not use this participant",
494                     migrationMsg.getAutomationCompositionId());
495             return;
496         }
497         var acCopy = new AutomationComposition(automationComposition);
498         automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
499         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
500             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
501
502                 updateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), participantDeploy,
503                         DeployState.MIGRATING);
504
505                 callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
506                     acCopy, migrationMsg.getCompositionTargetId());
507             }
508         }
509     }
510
511     private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements,
512             AutomationComposition acCopy, UUID compositionTargetId) {
513         var compositionElementMap = getCompositionElementDtoMap(acCopy);
514         var instanceElementMap = getInstanceElementDtoMap(acCopy);
515         var automationComposition = cacheProvider.getAutomationComposition(acCopy.getInstanceId());
516         var compositionElementTargetMap = getCompositionElementDtoMap(automationComposition, compositionTargetId);
517         var instanceElementMigrateMap = getInstanceElementDtoMap(automationComposition);
518
519         for (var acElement : acElements) {
520             listener.migrate(messageId, compositionElementMap.get(acElement.getId()),
521                 compositionElementTargetMap.get(acElement.getId()),
522                 instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId()));
523         }
524     }
525 }