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