14660a8128c05a14e39c17d9fe05bea724d775bc
[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.runtime.instantiation;
23
24 import jakarta.validation.Valid;
25 import jakarta.ws.rs.core.Response.Status;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.UUID;
30 import java.util.stream.Collectors;
31 import lombok.NonNull;
32 import lombok.RequiredArgsConstructor;
33 import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
34 import org.onap.policy.clamp.acm.runtime.main.utils.EncryptionUtils;
35 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
36 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
37 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
38 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
39 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
40 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
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.NodeTemplateState;
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.concepts.SubState;
47 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
48 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
49 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
50 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
51 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
52 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
53 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
54 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
55 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
56 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
57 import org.onap.policy.common.parameters.BeanValidationResult;
58 import org.onap.policy.common.parameters.ObjectValidationResult;
59 import org.onap.policy.common.parameters.ValidationStatus;
60 import org.onap.policy.models.base.PfConceptKey;
61 import org.onap.policy.models.base.PfKey;
62 import org.onap.policy.models.base.PfModelRuntimeException;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65 import org.springframework.data.domain.Pageable;
66 import org.springframework.stereotype.Service;
67 import org.springframework.transaction.annotation.Transactional;
68
69 /**
70  * This class is dedicated to the Instantiation of Commissioned automation composition.
71  */
72 @Service
73 @Transactional
74 @RequiredArgsConstructor
75 public class AutomationCompositionInstantiationProvider {
76     private static final String DO_NOT_MATCH = " do not match with ";
77     private static final String ELEMENT_ID_NOT_PRESENT = "Element id not present ";
78     private static final String NOT_VALID_ORDER =
79         "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
80
81     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
82
83     private final AutomationCompositionProvider automationCompositionProvider;
84     private final AcDefinitionProvider acDefinitionProvider;
85     private final AcInstanceStateResolver acInstanceStateResolver;
86     private final SupervisionAcHandler supervisionAcHandler;
87     private final ParticipantProvider participantProvider;
88     private final AcRuntimeParameterGroup acRuntimeParameterGroup;
89     private final EncryptionUtils encryptionUtils;
90
91     /**
92      * Create automation composition.
93      *
94      * @param compositionId         The UUID of the automation composition definition
95      * @param automationComposition the automation composition
96      * @return the result of the instantiation operation
97      */
98     public InstantiationResponse createAutomationComposition(UUID compositionId,
99                                                              AutomationComposition automationComposition) {
100         validateCompositionRequested(compositionId, automationComposition);
101         var checkAutomationCompositionOpt =
102             automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
103         if (checkAutomationCompositionOpt.isPresent()) {
104             throw new PfModelRuntimeException(Status.BAD_REQUEST,
105                 automationComposition.getKey().asIdentifier() + " already defined");
106         }
107
108         var validationResult = validateAutomationComposition(automationComposition);
109         if (!validationResult.isValid()) {
110             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
111         }
112         encryptInstanceProperties(automationComposition, compositionId);
113         automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
114
115         return createInstantiationResponse(automationComposition);
116     }
117
118     private InstantiationResponse createInstantiationResponse(AutomationComposition automationComposition) {
119         var response = new InstantiationResponse();
120         response.setInstanceId(automationComposition.getInstanceId());
121         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
122         return response;
123     }
124
125     /**
126      * Update automation composition.
127      *
128      * @param compositionId         The UUID of the automation composition definition
129      * @param automationComposition the automation composition
130      * @return the result of the update
131      */
132     public InstantiationResponse updateAutomationComposition(UUID compositionId,
133                                                              AutomationComposition automationComposition) {
134         var instanceId = automationComposition.getInstanceId();
135         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
136         validateCompositionRequested(compositionId, acToUpdate);
137         if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
138             acToUpdate.setElements(automationComposition.getElements());
139             acToUpdate.setName(automationComposition.getName());
140             acToUpdate.setVersion(automationComposition.getVersion());
141             acToUpdate.setDescription(automationComposition.getDescription());
142             acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
143             var validationResult = validateAutomationComposition(acToUpdate);
144             if (!validationResult.isValid()) {
145                 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
146             }
147             encryptInstanceProperties(acToUpdate, compositionId);
148             automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
149             return createInstantiationResponse(automationComposition);
150
151         }
152
153         var deployOrder = DeployOrder.UPDATE;
154         var subOrder = SubOrder.NONE;
155
156         if (automationComposition.getCompositionTargetId() != null) {
157
158             if (Boolean.TRUE.equals(automationComposition.getPrecheck())) {
159                 subOrder = SubOrder.MIGRATE_PRECHECK;
160                 deployOrder = DeployOrder.NONE;
161             } else {
162                 deployOrder = DeployOrder.MIGRATE;
163             }
164         }
165         var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
166             acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
167             acToUpdate.getStateChangeResult());
168         return switch (result) {
169             case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate);
170
171             case "MIGRATE" -> migrateAutomationComposition(automationComposition, acToUpdate);
172
173             case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate);
174
175             default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
176                 "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
177         };
178     }
179
180     /**
181      * Update deployed AC Element properties.
182      *
183      * @param automationComposition the automation composition
184      * @param acToBeUpdated         the composition to be updated
185      * @return the result of the update
186      */
187     private InstantiationResponse updateDeployedAutomationComposition(
188         AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
189         // save copy in case of a rollback
190         automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
191
192         // Iterate and update the element property values
193         for (var element : automationComposition.getElements().entrySet()) {
194             var elementId = element.getKey();
195             var dbAcElement = acToBeUpdated.getElements().get(elementId);
196             if (dbAcElement == null) {
197                 throw new PfModelRuntimeException(Status.BAD_REQUEST, ELEMENT_ID_NOT_PRESENT + elementId);
198             }
199             AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
200         }
201
202         var validationResult = validateAutomationComposition(acToBeUpdated);
203         if (!validationResult.isValid()) {
204             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
205         }
206         updateAcForProperties(acToBeUpdated);
207
208         var acToPublish = new AutomationComposition(acToBeUpdated);
209
210         encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionId());
211
212         automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
213         // Publish property update event to the participants
214         supervisionAcHandler.update(acToPublish);
215         return createInstantiationResponse(automationComposition);
216     }
217
218     private InstantiationResponse migrateAutomationComposition(
219         AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
220
221         if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
222             throw new PfModelRuntimeException(Status.BAD_REQUEST,
223                 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
224         }
225         // make copy for rollback
226         automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
227
228         // Iterate and update the element property values
229         var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated);
230         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
231
232         updateAcForMigration(acToBeUpdated, acDefinition);
233
234         var acToPublish = new AutomationComposition(acToBeUpdated);
235
236         encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionTargetId());
237
238         var ac = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
239         elementsRemoved.forEach(automationCompositionProvider::deleteAutomationCompositionElement);
240
241         // Publish migrate event to the participants
242         supervisionAcHandler.migrate(acToPublish);
243         return createInstantiationResponse(ac);
244     }
245
246     private void updateAcForMigration(AutomationComposition acToBeUpdated,
247                                       AutomationCompositionDefinition acDefinition) {
248         AcmUtils.setCascadedState(acToBeUpdated, DeployState.MIGRATING, LockState.LOCKED);
249         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
250         var stage = ParticipantUtils.getFirstStage(acToBeUpdated, acDefinition.getServiceTemplate());
251         acToBeUpdated.setPhase(stage);
252     }
253
254     private void updateAcForProperties(AutomationComposition acToBeUpdated) {
255         AcmUtils.setCascadedState(acToBeUpdated, DeployState.UPDATING, acToBeUpdated.getLockState());
256         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
257     }
258
259     private List<UUID> getElementRemoved(AutomationComposition acFromDb, AutomationComposition acFromMigration) {
260         return acFromDb.getElements().keySet().stream()
261             .filter(id -> acFromMigration.getElements().get(id) == null).toList();
262     }
263
264     void checkCompatibility(PfConceptKey newDefinition, PfConceptKey dbElementDefinition,
265                             UUID instanceId) {
266         var compatibility = newDefinition.getCompatibility(dbElementDefinition);
267         if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
268             throw new PfModelRuntimeException(Status.BAD_REQUEST,
269                 dbElementDefinition + " is not compatible with " + newDefinition);
270         }
271         if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR
272             .equals(compatibility)) {
273             LOGGER.warn("Migrate {}: Version {} has {} compatibility with {} ", instanceId, newDefinition,
274                 compatibility, dbElementDefinition);
275         }
276     }
277
278     private InstantiationResponse migratePrecheckAc(
279         AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
280
281         acToBeUpdated.setPrecheck(true);
282         var copyAc = new AutomationComposition(acToBeUpdated);
283         // Iterate and update the element property values
284         updateElementsProperties(automationComposition, copyAc);
285
286         // Publish migrate event to the participants
287         supervisionAcHandler.migratePrecheck(copyAc);
288
289         AcmUtils.setCascadedState(acToBeUpdated, DeployState.DEPLOYED, LockState.LOCKED,
290             SubState.MIGRATION_PRECHECKING);
291         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
292
293         return createInstantiationResponse(automationCompositionProvider.updateAutomationComposition(acToBeUpdated));
294     }
295
296     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
297         return validateAutomationComposition(automationComposition, automationComposition.getCompositionId());
298     }
299
300     /**
301      * Validate AutomationComposition.
302      *
303      * @param automationComposition AutomationComposition to validate
304      * @param compositionId         the composition id
305      * @return the result of validation
306      */
307     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
308                                                                UUID compositionId) {
309
310         var result = new BeanValidationResult("AutomationComposition", automationComposition);
311         var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
312         if (acDefinitionOpt.isEmpty()) {
313             result.addResult(new ObjectValidationResult("ServiceTemplate", compositionId, ValidationStatus.INVALID,
314                 "Commissioned automation composition definition not found"));
315             return result;
316         }
317         if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
318             result.addResult(new ObjectValidationResult("ServiceTemplate.state", acDefinitionOpt.get().getState(),
319                 ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
320             return result;
321         }
322         var participantIds = acDefinitionOpt.get().getElementStateMap().values().stream()
323             .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
324
325         participantProvider.verifyParticipantState(participantIds);
326
327         result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
328             acDefinitionOpt.get().getServiceTemplate(),
329             acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
330
331         result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
332
333         if (result.isValid()) {
334             for (var element : automationComposition.getElements().values()) {
335                 var name = element.getDefinition().getName();
336                 var participantId = acDefinitionOpt.get().getElementStateMap().get(name).getParticipantId();
337                 element.setParticipantId(participantId);
338             }
339         }
340
341         return result;
342     }
343
344
345     private void encryptInstanceProperties(AutomationComposition automationComposition, UUID compositionId) {
346         if (encryptionUtils.encryptionEnabled()) {
347             var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
348             acDefinitionOpt.ifPresent(acDefinition
349                 -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
350         }
351     }
352
353     /**
354      * Get Automation Composition.
355      *
356      * @param compositionId The UUID of the automation composition definition
357      * @param instanceId    The UUID of the automation composition instance
358      * @return the Automation Composition
359      */
360     @Transactional(readOnly = true)
361     public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
362         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
363         if (!compositionId.equals(automationComposition.getCompositionId())
364             && !compositionId.equals(automationComposition.getCompositionTargetId())) {
365             throw new PfModelRuntimeException(Status.BAD_REQUEST,
366                 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
367         }
368         return automationComposition;
369     }
370
371     /**
372      * Delete the automation composition with the given name and version.
373      *
374      * @param compositionId The UUID of the automation composition definition
375      * @param instanceId    The UUID of the automation composition instance
376      * @return the result of the deletion
377      */
378     public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
379         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
380         var acDefinition = getAcDefinition(compositionId, automationComposition);
381         var result = acInstanceStateResolver.resolve(DeployOrder.DELETE,
382             null, null,
383             automationComposition.getDeployState(), automationComposition.getLockState(),
384             automationComposition.getSubState(), automationComposition.getStateChangeResult());
385         if (!DeployOrder.DELETE.name().equals(result)) {
386             var msg = String.format(NOT_VALID_ORDER, DeployOrder.DELETE,
387                 automationComposition.getDeployState(), automationComposition.getLockState(),
388                 automationComposition.getSubState(), automationComposition.getStateChangeResult());
389             throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
390         }
391         supervisionAcHandler.delete(automationComposition, acDefinition);
392         return createInstantiationResponse(automationComposition);
393     }
394
395     /**
396      * Get the requested automation compositions.
397      *
398      * @param name     the name of the automation composition to get, null for all automation compositions
399      * @param version  the version of the automation composition to get, null for all automation compositions
400      * @param pageable the Pageable
401      * @return the automation compositions
402      */
403     @Transactional(readOnly = true)
404     public AutomationCompositions getAutomationCompositions(@NonNull final UUID compositionId,
405                                                             final String name, final String version,
406                                                             @NonNull final Pageable pageable) {
407         var automationCompositions = new AutomationCompositions();
408         automationCompositions.setAutomationCompositionList(
409             automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
410
411         return automationCompositions;
412     }
413
414     /**
415      * Handle Composition Instance State.
416      *
417      * @param compositionId         the compositionId
418      * @param instanceId            the instanceId
419      * @param acInstanceStateUpdate the AcInstanceStateUpdate
420      */
421     public void compositionInstanceState(UUID compositionId, UUID instanceId,
422                                          @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
423         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
424         var acDefinition = getAcDefinition(compositionId, automationComposition);
425         var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
426             acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
427             automationComposition.getDeployState(), automationComposition.getLockState(),
428             automationComposition.getSubState(), automationComposition.getStateChangeResult());
429         switch (result) {
430             case "DEPLOY":
431                 supervisionAcHandler.deploy(automationComposition, acDefinition);
432                 break;
433
434             case "UNDEPLOY":
435                 supervisionAcHandler.undeploy(automationComposition, acDefinition);
436                 break;
437
438             case "LOCK":
439                 supervisionAcHandler.lock(automationComposition, acDefinition);
440                 break;
441
442             case "UNLOCK":
443                 supervisionAcHandler.unlock(automationComposition, acDefinition);
444                 break;
445
446             case "PREPARE":
447                 supervisionAcHandler.prepare(automationComposition, acDefinition);
448                 break;
449
450             case "REVIEW":
451                 supervisionAcHandler.review(automationComposition);
452                 break;
453
454             default:
455                 var msg = String.format(NOT_VALID_ORDER, acInstanceStateUpdate,
456                     automationComposition.getDeployState(), automationComposition.getLockState(),
457                     automationComposition.getSubState(), automationComposition.getStateChangeResult());
458                 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
459         }
460     }
461
462     /**
463      * Rollback AC Instance.
464      *
465      * @param instanceId the instanceId
466      * @return the instantiation response
467      */
468     public InstantiationResponse rollback(UUID instanceId) {
469         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
470         var automationCompositionToRollback =
471             automationCompositionProvider.getAutomationCompositionRollback(instanceId.toString());
472
473         if (DeployState.DEPLOYED.equals(automationComposition.getDeployState())
474               && SubState.NONE.equals(automationComposition.getSubState())
475               && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
476             automationComposition.setCompositionId(UUID.fromString(automationCompositionToRollback.getCompositionId()));
477             Map<UUID, AutomationCompositionElement> elements = new HashMap<>();
478             automationCompositionToRollback.getElements().forEach((String uuid, Object acElement) ->
479                 elements.put(UUID.fromString(uuid), (AutomationCompositionElement) acElement));
480             automationComposition.setElements(elements);
481             automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
482             AcmUtils.setCascadedState(automationComposition, DeployState.MIGRATION_REVERTING, LockState.LOCKED);
483             automationCompositionProvider.updateAutomationComposition(automationComposition);
484             return createInstantiationResponse(automationComposition);
485         } else {
486             throw new PfModelRuntimeException(Status.BAD_REQUEST, "Invalid state for rollback");
487         }
488     }
489
490     private List<UUID> updateElementsProperties(AutomationComposition automationComposition,
491                                                 AutomationComposition acToBeUpdated) {
492         for (var element : automationComposition.getElements().entrySet()) {
493             var elementId = element.getKey();
494             var dbAcElement = acToBeUpdated.getElements().get(elementId);
495             // Add additional elements if present for migration
496             if (dbAcElement == null) {
497                 LOGGER.info("New Ac element {} added in Migration", elementId);
498                 acToBeUpdated.getElements().put(elementId, element.getValue());
499             } else {
500                 AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
501                 var newDefinition = element.getValue().getDefinition().asConceptKey();
502                 var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
503                 checkCompatibility(newDefinition, dbElementDefinition, automationComposition.getInstanceId());
504                 dbAcElement.setDefinition(element.getValue().getDefinition());
505             }
506         }
507         // Remove element which is not present in the new Ac instance
508         var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
509         elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
510
511         var validationResult =
512             validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
513         if (!validationResult.isValid()) {
514             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
515         }
516         acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
517         return elementsRemoved;
518     }
519
520     private static void validateCompositionRequested(UUID compositionId,
521                                                      AutomationComposition automationComposition) {
522         if (!compositionId.equals(automationComposition.getCompositionId())) {
523             throw new PfModelRuntimeException(Status.BAD_REQUEST,
524                 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
525         }
526     }
527
528     private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
529                                                             AutomationComposition automationComposition) {
530         validateCompositionRequested(compositionId, automationComposition);
531         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
532
533         var participantIds = acDefinition.getElementStateMap().values().stream()
534             .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
535
536         participantProvider.verifyParticipantState(participantIds);
537         return acDefinition;
538     }
539 }