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