84a7738e5aa3e58e7ab4cc3af2bd0bc332bdbf4b
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
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.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.UUID;
28 import lombok.RequiredArgsConstructor;
29 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
30 import org.onap.policy.clamp.acm.participant.intermediary.api.ElementState;
31 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
32 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
33 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.CacheProvider;
34 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
36 import org.onap.policy.clamp.models.acm.concepts.DeployState;
37 import org.onap.policy.clamp.models.acm.concepts.LockState;
38 import org.onap.policy.clamp.models.acm.concepts.MigrationState;
39 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
40 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
41 import org.onap.policy.clamp.models.acm.concepts.SubState;
42 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
43 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
44 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
45 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange;
46 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
47 import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate;
48 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
49 import org.onap.policy.clamp.models.acm.utils.AcmStageUtils;
50 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53 import org.springframework.stereotype.Component;
54
55 /*
56  * This class is responsible for managing the state of all automation compositions in the participant.
57  */
58 @Component
59 @RequiredArgsConstructor
60 public class AutomationCompositionHandler {
61     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
62     private static final String AC_NOT_USED = "Automation composition {} does not use this participant";
63
64     private final CacheProvider cacheProvider;
65     private final ParticipantMessagePublisher publisher;
66     private final ThreadHandler listener;
67
68     /**
69      * Handle a automation composition state change message.
70      *
71      * @param stateChangeMsg the state change message
72      */
73     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
74         var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
75
76         if (automationComposition == null) {
77             if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
78                 var automationCompositionAck = new AutomationCompositionDeployAck(
79                         ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
80                 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
81                 automationCompositionAck.setReplicaId(cacheProvider.getReplicaId());
82                 automationCompositionAck.setMessage("Already deleted or never used");
83                 automationCompositionAck.setResult(true);
84                 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
85                 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
86                 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
87                 publisher.sendAutomationCompositionAck(automationCompositionAck);
88             } else {
89                 LOGGER.warn(AC_NOT_USED, stateChangeMsg.getAutomationCompositionId());
90             }
91             return;
92         }
93
94         switch (stateChangeMsg.getDeployOrderedState()) {
95             case UNDEPLOY -> handleUndeployState(stateChangeMsg.getMessageId(), automationComposition,
96                     stateChangeMsg.getStartPhase());
97             case DELETE -> handleDeleteState(stateChangeMsg.getMessageId(), automationComposition,
98                     stateChangeMsg.getStartPhase());
99             default ->
100                     LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
101         }
102     }
103
104     /**
105      * Handle a automation composition properties update message.
106      *
107      * @param updateMsg the properties update message
108      */
109     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
110
111         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
112             LOGGER.warn("No AutomationCompositionElement updates in message {}",
113                     updateMsg.getAutomationCompositionId());
114             return;
115         }
116
117         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
118             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
119                 var automationComposition =
120                         cacheProvider.getAutomationComposition(updateMsg.getAutomationCompositionId());
121                 automationComposition.setDeployState(DeployState.UPDATING);
122                 var acCopy = new AutomationComposition(automationComposition);
123                 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy);
124
125                 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(), acCopy);
126             }
127         }
128     }
129
130     /**
131      * Handle a automation composition Deploy message.
132      *
133      * @param deployMsg the Deploy message
134      */
135     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
136
137         if (deployMsg.getParticipantUpdatesList().isEmpty()) {
138             LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
139             return;
140         }
141
142         for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
143             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
144                 if (deployMsg.isFirstStartPhase()) {
145                     cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
146                             deployMsg.getAutomationCompositionId(), participantDeploy,
147                             deployMsg.getRevisionIdInstance());
148                 }
149                 callParticipantDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
150                         deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
151             }
152         }
153     }
154
155     private void callParticipantDeploy(UUID messageId, List<AcElementDeploy> acElementDeployList, Integer startPhaseMsg,
156             UUID instanceId) {
157         var automationComposition = cacheProvider.getAutomationComposition(instanceId);
158         automationComposition.setDeployState(DeployState.DEPLOYING);
159         for (var elementDeploy : acElementDeployList) {
160             var element = automationComposition.getElements().get(elementDeploy.getId());
161             var compositionInProperties = cacheProvider.getCommonProperties(automationComposition.getCompositionId(),
162                     element.getDefinition());
163             int startPhase = AcmStageUtils.findStartPhase(compositionInProperties);
164             if (startPhaseMsg.equals(startPhase)) {
165                 var compositionElement =
166                         cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(), element);
167                 var instanceElement =
168                         new InstanceElementDto(instanceId, elementDeploy.getId(), elementDeploy.getProperties(),
169                                 element.getOutProperties());
170                 listener.deploy(messageId, compositionElement, instanceElement);
171             }
172         }
173     }
174
175     private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements,
176             AutomationComposition acCopy) {
177         var instanceElementDtoMap = cacheProvider.getInstanceElementDtoMap(acCopy);
178         var instanceElementDtoMapUpdated =
179                 cacheProvider.getInstanceElementDtoMap(cacheProvider.getAutomationComposition(acCopy.getInstanceId()));
180         var compositionElementDtoMap = cacheProvider.getCompositionElementDtoMap(acCopy);
181         for (var acElement : acElements) {
182             listener.update(messageId, compositionElementDtoMap.get(acElement.getId()),
183                     instanceElementDtoMap.get(acElement.getId()), instanceElementDtoMapUpdated.get(acElement.getId()));
184         }
185     }
186
187     private void migrateAutomationComposition(AutomationComposition automationComposition,
188             ParticipantDeploy participantDeploy, int stage) {
189         for (var element : participantDeploy.getAcElementList()) {
190             var stageSet = getMigrationStageSet(element, automationComposition.getCompositionTargetId());
191             if (stageSet.contains(stage)) {
192                 migrateElement(element, automationComposition, stage, participantDeploy);
193             }
194         }
195     }
196
197     private void rollbackAutomationComposition(AutomationComposition automationComposition,
198             ParticipantDeploy participantDeploy, int stage) {
199         for (var element : participantDeploy.getAcElementList()) {
200             var stageSet = getRollbackStageSet(element, automationComposition.getCompositionId());
201             if (stageSet.contains(stage)) {
202                 migrateElement(element, automationComposition, stage, participantDeploy);
203             }
204         }
205     }
206
207     private void migrateElement(AcElementDeploy element, AutomationComposition automationComposition,
208             int stage, ParticipantDeploy participantDeploy) {
209         var acElementList = automationComposition.getElements();
210         var acElement = acElementList.get(element.getId());
211         if (acElement == null) {  // NEW element with existing participant
212             var newElement = CacheProvider.createAutomationCompositionElement(element);
213             newElement.setParticipantId(participantDeploy.getParticipantId());
214             newElement.setDeployState(automationComposition.getDeployState());
215             newElement.setLockState(LockState.LOCKED);
216             newElement.setStage(stage);
217             newElement.setMigrationState(MigrationState.NEW);
218
219             acElementList.put(element.getId(), newElement);
220             LOGGER.info("New Ac Element with id {} is added in Migration", element.getId());
221         } else {
222             acElement.setStage(stage);
223             acElement.setMigrationState(element.getMigrationState());
224             acElement.setDeployState(automationComposition.getDeployState());
225             acElement.setDefinition(element.getDefinition());
226             if (MigrationState.DEFAULT.equals(element.getMigrationState())) { //DEFAULT element
227                 AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
228             }
229             LOGGER.info("Cache updated for the migration of element with id {}", element.getId());
230         }
231     }
232
233     private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy) {
234         var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
235         for (var element : participantDeploy.getAcElementList()) {
236             var acElement = acElementList.get(element.getId());
237             AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
238             acElement.setDeployState(DeployState.UPDATING);
239             acElement.setSubState(SubState.NONE);
240             acElement.setDefinition(element.getDefinition());
241         }
242     }
243
244     /**
245      * Method to handle when the new state from participant is UNINITIALISED state.
246      *
247      * @param messageId             the messageId
248      * @param automationComposition participant response
249      * @param startPhaseMsg         startPhase from message
250      */
251     private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
252             Integer startPhaseMsg) {
253         automationComposition.setDeployState(DeployState.UNDEPLOYING);
254         for (var element : automationComposition.getElements().values()) {
255             var compositionId = MigrationState.NEW.equals(element.getMigrationState())
256                     ? automationComposition.getCompositionTargetId() : automationComposition.getCompositionId();
257             var compositionInProperties = cacheProvider.getCommonProperties(compositionId, element.getDefinition());
258             var startPhase = AcmStageUtils.findStartPhase(compositionInProperties);
259             if (MigrationState.NEW.equals(element.getMigrationState())) {
260                 // Undeploy newly added element on a Failed Migration
261                 startPhase = 0;
262             }
263             if (startPhaseMsg.equals(startPhase)) {
264                 element.setDeployState(DeployState.UNDEPLOYING);
265                 var compositionElement =
266                         cacheProvider.createCompositionElementDto(compositionId, element);
267                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
268                         element.getProperties(), element.getOutProperties());
269                 listener.undeploy(messageId, compositionElement, instanceElement);
270             }
271         }
272     }
273
274     private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
275             Integer startPhaseMsg) {
276         automationComposition.setDeployState(DeployState.DELETING);
277         for (var element : automationComposition.getElements().values()) {
278             var compositionInProperties = cacheProvider.getCommonProperties(automationComposition.getCompositionId(),
279                     element.getDefinition());
280             int startPhase = AcmStageUtils.findStartPhase(compositionInProperties);
281             if (startPhaseMsg.equals(startPhase)) {
282                 element.setDeployState(DeployState.DELETING);
283                 element.setSubState(SubState.NONE);
284                 var compositionElement =
285                         cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(), element);
286                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
287                         element.getProperties(), element.getOutProperties());
288                 listener.delete(messageId, compositionElement, instanceElement);
289             }
290         }
291     }
292
293     /**
294      * Handles AutomationComposition Migration.
295      *
296      * @param migrationMsg the AutomationCompositionMigration
297      */
298     public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
299         var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
300         if (Boolean.FALSE.equals(migrationMsg.getRollback())) {
301             handleMigration(automationComposition, migrationMsg);
302         } else {
303             handleRollback(automationComposition, migrationMsg);
304         }
305     }
306
307     private void handleRollback(AutomationComposition automationComposition,
308                                 AutomationCompositionMigration migrationMsg) {
309         LOGGER.info("Rollback operation invoked for the instance {}", migrationMsg.getAutomationCompositionId());
310         automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
311         automationComposition.setDeployState(DeployState.MIGRATION_REVERTING);
312         var automationCompositionCopy = new AutomationComposition(automationComposition);
313         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
314             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
315                 rollbackAutomationComposition(automationComposition, participantDeploy, migrationMsg.getStage());
316                 callParticipantRollback(migrationMsg, participantDeploy.getAcElementList(), automationCompositionCopy);
317             }
318
319         }
320     }
321
322     private void handleMigration(AutomationComposition automationComposition,
323             AutomationCompositionMigration migrationMsg) {
324         LOGGER.info("Migration invoked for the instance {}", migrationMsg.getAutomationCompositionId());
325         automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
326         automationComposition.setDeployState(DeployState.MIGRATING);
327         var automationCompositionCopy = new AutomationComposition(automationComposition);
328         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
329             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
330                 migrateAutomationComposition(automationComposition, participantDeploy, migrationMsg.getStage());
331                 callParticipantMigrate(migrationMsg, participantDeploy.getAcElementList(), automationCompositionCopy);
332             }
333         }
334     }
335
336     private void callParticipantMigrate(AutomationCompositionMigration migrationMsg, List<AcElementDeploy> acElements,
337             AutomationComposition automationCompositionCopy) {
338         var automationComposition = cacheProvider.getAutomationComposition(automationCompositionCopy.getInstanceId());
339         var instanceElementTargetMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
340         var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(automationComposition,
341                 automationCompositionCopy.getCompositionTargetId());
342         var compositionElementMap = cacheProvider.getCompositionElementDtoMap(automationCompositionCopy);
343         var instanceElementMap = cacheProvider.getInstanceElementDtoMap(automationCompositionCopy);
344         for (var acElement : acElements) {
345             var stageSet = getMigrationStageSet(acElement, automationComposition.getCompositionTargetId());
346             var newElement = MigrationState.NEW.equals(acElement.getMigrationState());
347             if (stageSet.contains(migrationMsg.getStage())) {
348                 if (newElement) {
349                     var compositionElementDto = new CompositionElementDto(automationCompositionCopy.getCompositionId(),
350                             acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
351                     var instanceElementDto = new InstanceElementDto(automationCompositionCopy.getInstanceId(),
352                             acElement.getId(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
353                     var compositionElementTargetDto =
354                             CacheProvider.changeStateToNew(compositionElementTargetMap.get(acElement.getId()));
355                     var instanceElementTargetDto =
356                             CacheProvider.changeStateToNew(instanceElementTargetMap.get(acElement.getId()));
357
358                     listenerMigrate(migrationMsg.getMessageId(), compositionElementDto, compositionElementTargetDto,
359                             instanceElementDto, instanceElementTargetDto, migrationMsg.getStage());
360
361                 } else if (MigrationState.REMOVED.equals(acElement.getMigrationState())) {
362                     var compositionDtoTarget = new CompositionElementDto(migrationMsg.getCompositionTargetId(),
363                             acElement.getDefinition(), Map.of(), Map.of(), ElementState.REMOVED);
364                     var instanceElementDtoTarget = new InstanceElementDto(migrationMsg.getAutomationCompositionId(),
365                             acElement.getId(), Map.of(), Map.of(), ElementState.REMOVED);
366                     listenerMigrate(migrationMsg.getMessageId(), compositionElementMap.get(acElement.getId()),
367                             compositionDtoTarget, instanceElementMap.get(acElement.getId()), instanceElementDtoTarget,
368                             migrationMsg.getStage());
369
370                 } else { // DEFAULT case
371                     listenerMigrate(migrationMsg.getMessageId(), compositionElementMap.get(acElement.getId()),
372                             compositionElementTargetMap.get(acElement.getId()),
373                             instanceElementMap.get(acElement.getId()), instanceElementTargetMap.get(acElement.getId()),
374                             migrationMsg.getStage());
375                 }
376             }
377         }
378     }
379
380     private Set<Integer> getMigrationStageSet(AcElementDeploy acElement, UUID compositionTargetId) {
381         if (MigrationState.REMOVED.equals(acElement.getMigrationState())) {
382             return Set.of(0);
383         } else {
384             var commonProperties = cacheProvider.getCommonProperties(compositionTargetId, acElement.getDefinition());
385             return AcmStageUtils.findStageSetMigrate(commonProperties);
386         }
387     }
388
389     private void callParticipantRollback(AutomationCompositionMigration migrationMsg, List<AcElementDeploy> acElements,
390             AutomationComposition automationCompositionCopy) {
391         var automationComposition = cacheProvider.getAutomationComposition(automationCompositionCopy.getInstanceId());
392         var instanceElementTargetMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
393         var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(automationComposition);
394         var compositionElementMap = cacheProvider.getCompositionElementDtoMap(automationCompositionCopy,
395                 automationCompositionCopy.getCompositionTargetId());
396         var instanceElementMap = cacheProvider.getInstanceElementDtoMap(automationCompositionCopy);
397         for (var acElement : acElements) {
398             var stageSet = getRollbackStageSet(acElement, automationComposition.getCompositionId());
399             var removed = MigrationState.NEW.equals(acElement.getMigrationState());
400             if (!removed) {
401                 var commonProperties = cacheProvider
402                         .getCommonProperties(automationComposition.getCompositionId(), acElement.getDefinition());
403                 stageSet = AcmStageUtils.findStageSetMigrate(commonProperties);
404             }
405             var newElement = MigrationState.REMOVED.equals(acElement.getMigrationState());
406             if (stageSet.contains(migrationMsg.getStage())) {
407                 if (newElement) {
408                     var compositionElementDto =
409                             new CompositionElementDto(automationCompositionCopy.getCompositionTargetId(),
410                             acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
411                     var instanceElementDto = new InstanceElementDto(automationCompositionCopy.getInstanceId(),
412                             acElement.getId(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
413                     var compositionElementTargetDto =
414                             CacheProvider.changeStateToNew(compositionElementTargetMap.get(acElement.getId()));
415                     var instanceElementTargetDto =
416                             CacheProvider.changeStateToNew(instanceElementTargetMap.get(acElement.getId()));
417
418                     listenerRollback(migrationMsg.getMessageId(), compositionElementDto, compositionElementTargetDto,
419                             instanceElementDto, instanceElementTargetDto, migrationMsg.getStage());
420
421                 } else if (removed) {
422                     var compositionDtoTarget = new CompositionElementDto(
423                             automationCompositionCopy.getCompositionId(), acElement.getDefinition(),
424                             Map.of(), Map.of(), ElementState.REMOVED);
425                     var instanceElementDtoTarget = new InstanceElementDto(automationCompositionCopy.getInstanceId(),
426                             acElement.getId(), Map.of(), Map.of(), ElementState.REMOVED);
427                     listenerRollback(migrationMsg.getMessageId(), compositionElementMap.get(acElement.getId()),
428                             compositionDtoTarget, instanceElementMap.get(acElement.getId()), instanceElementDtoTarget,
429                             migrationMsg.getStage());
430
431                 } else { // DEFAULT case
432                     listenerRollback(migrationMsg.getMessageId(), compositionElementMap.get(acElement.getId()),
433                             compositionElementTargetMap.get(acElement.getId()),
434                             instanceElementMap.get(acElement.getId()), instanceElementTargetMap.get(acElement.getId()),
435                             migrationMsg.getStage());
436                 }
437             }
438         }
439     }
440
441     private Set<Integer> getRollbackStageSet(AcElementDeploy acElement, UUID compositionId) {
442         if (MigrationState.NEW.equals(acElement.getMigrationState())) {
443             return Set.of(0);
444         } else {
445             var commonProperties = cacheProvider.getCommonProperties(compositionId, acElement.getDefinition());
446             return AcmStageUtils.findStageSetMigrate(commonProperties);
447         }
448     }
449
450     private void listenerMigrate(UUID messageId, CompositionElementDto compositionElement,
451             CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
452             InstanceElementDto instanceElementMigrate, int stage) {
453         LOGGER.info("Invoking migration of element on the participant for {}", instanceElement.elementId());
454         listener.migrate(messageId, compositionElement, compositionElementTarget, instanceElement,
455                     instanceElementMigrate, stage);
456     }
457
458     private void listenerRollback(UUID messageId, CompositionElementDto compositionElement,
459             CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
460             InstanceElementDto instanceElementMigrate, int stage) {
461         LOGGER.info("Invoking rollback of element on the participant for {}", instanceElement.elementId());
462         listener.rollback(messageId, compositionElement, compositionElementTarget, instanceElement,
463                 instanceElementMigrate, stage);
464     }
465 }