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