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
 
  10  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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.
 
  18  * SPDX-License-Identifier: Apache-2.0
 
  19  * ============LICENSE_END=========================================================
 
  22 package org.onap.policy.clamp.acm.runtime.instantiation;
 
  24 import jakarta.validation.Valid;
 
  25 import jakarta.ws.rs.core.Response.Status;
 
  26 import java.util.List;
 
  27 import java.util.UUID;
 
  28 import java.util.function.UnaryOperator;
 
  29 import java.util.stream.Collectors;
 
  30 import lombok.NonNull;
 
  31 import lombok.RequiredArgsConstructor;
 
  32 import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
 
  33 import org.onap.policy.clamp.acm.runtime.main.utils.EncryptionUtils;
 
  34 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
 
  35 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 
  36 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
 
  37 import org.onap.policy.clamp.models.acm.concepts.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.NodeTemplateState;
 
  43 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
 
  44 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 
  45 import org.onap.policy.clamp.models.acm.concepts.SubState;
 
  46 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
 
  47 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
 
  48 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
 
  49 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
 
  50 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
 
  51 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
 
  52 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
 
  53 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
 
  54 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
 
  55 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
 
  56 import org.onap.policy.common.parameters.BeanValidationResult;
 
  57 import org.onap.policy.common.parameters.ObjectValidationResult;
 
  58 import org.onap.policy.common.parameters.ValidationStatus;
 
  59 import org.onap.policy.models.base.PfConceptKey;
 
  60 import org.onap.policy.models.base.PfKey;
 
  61 import org.onap.policy.models.base.PfModelRuntimeException;
 
  62 import org.slf4j.Logger;
 
  63 import org.slf4j.LoggerFactory;
 
  64 import org.springframework.data.domain.Pageable;
 
  65 import org.springframework.stereotype.Service;
 
  66 import org.springframework.transaction.annotation.Transactional;
 
  69  * This class is dedicated to the Instantiation of Commissioned automation composition.
 
  73 @RequiredArgsConstructor
 
  74 public class AutomationCompositionInstantiationProvider {
 
  75     private static final String DO_NOT_MATCH = " do not match with ";
 
  76     private static final String ELEMENT_ID_NOT_PRESENT = "Element id not present ";
 
  77     private static final String NOT_VALID_ORDER =
 
  78         "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
 
  80     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
 
  82     private final AutomationCompositionProvider automationCompositionProvider;
 
  83     private final AcDefinitionProvider acDefinitionProvider;
 
  84     private final AcInstanceStateResolver acInstanceStateResolver;
 
  85     private final SupervisionAcHandler supervisionAcHandler;
 
  86     private final ParticipantProvider participantProvider;
 
  87     private final AcRuntimeParameterGroup acRuntimeParameterGroup;
 
  88     private final EncryptionUtils encryptionUtils;
 
  91      * Create automation composition.
 
  93      * @param compositionId         The UUID of the automation composition definition
 
  94      * @param automationComposition the automation composition
 
  95      * @return the result of the instantiation operation
 
  97     public InstantiationResponse createAutomationComposition(UUID compositionId,
 
  98                                                              AutomationComposition automationComposition) {
 
  99         validateCompositionRequested(compositionId, automationComposition);
 
 100         var checkAutomationCompositionOpt =
 
 101             automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
 
 102         if (checkAutomationCompositionOpt.isPresent()) {
 
 103             throw new PfModelRuntimeException(Status.BAD_REQUEST,
 
 104                 automationComposition.getKey().asIdentifier() + " already defined");
 
 107         var validationResult = validateAutomationComposition(automationComposition);
 
 108         if (!validationResult.isValid()) {
 
 109             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
 
 111         encryptInstanceProperties(automationComposition, compositionId);
 
 112         automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
 
 114         return createInstantiationResponse(automationComposition);
 
 117     private InstantiationResponse createInstantiationResponse(AutomationComposition automationComposition) {
 
 118         var response = new InstantiationResponse();
 
 119         response.setInstanceId(automationComposition.getInstanceId());
 
 120         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
 
 125      * Update automation composition.
 
 127      * @param compositionId         The UUID of the automation composition definition
 
 128      * @param automationComposition the automation composition
 
 129      * @return the result of the update
 
 131     public InstantiationResponse updateAutomationComposition(UUID compositionId,
 
 132                                                              AutomationComposition automationComposition) {
 
 133         var instanceId = automationComposition.getInstanceId();
 
 134         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
 
 135         validateCompositionRequested(compositionId, acToUpdate);
 
 136         if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
 
 137             acToUpdate.setElements(automationComposition.getElements());
 
 138             acToUpdate.setName(automationComposition.getName());
 
 139             acToUpdate.setVersion(automationComposition.getVersion());
 
 140             acToUpdate.setDescription(automationComposition.getDescription());
 
 141             acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
 
 142             var validationResult = validateAutomationComposition(acToUpdate);
 
 143             if (!validationResult.isValid()) {
 
 144                 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
 
 146             encryptInstanceProperties(acToUpdate, compositionId);
 
 147             automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
 
 148             return createInstantiationResponse(automationComposition);
 
 152         var deployOrder = DeployOrder.UPDATE;
 
 153         var subOrder = SubOrder.NONE;
 
 155         if (automationComposition.getCompositionTargetId() != null) {
 
 157             if (Boolean.TRUE.equals(automationComposition.getPrecheck())) {
 
 158                 subOrder = SubOrder.MIGRATE_PRECHECK;
 
 159                 deployOrder = DeployOrder.NONE;
 
 161                 deployOrder = DeployOrder.MIGRATE;
 
 164         var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
 
 165             acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
 
 166             acToUpdate.getStateChangeResult());
 
 167         return switch (result) {
 
 168             case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate);
 
 170             case "MIGRATE" -> migrateAutomationComposition(automationComposition, acToUpdate);
 
 172             case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate);
 
 174             default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
 
 175                 "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
 
 180      * Update deployed AC Element properties.
 
 182      * @param automationComposition the automation composition
 
 183      * @param acToBeUpdated         the composition to be updated
 
 184      * @return the result of the update
 
 186     private InstantiationResponse updateDeployedAutomationComposition(
 
 187         AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
 
 188         // save copy in case of a rollback
 
 189         automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
 
 191         // Iterate and update the element property values
 
 192         for (var element : automationComposition.getElements().entrySet()) {
 
 193             var elementId = element.getKey();
 
 194             var dbAcElement = acToBeUpdated.getElements().get(elementId);
 
 195             if (dbAcElement == null) {
 
 196                 throw new PfModelRuntimeException(Status.BAD_REQUEST, ELEMENT_ID_NOT_PRESENT + elementId);
 
 198             AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
 
 201         var validationResult = validateAutomationComposition(acToBeUpdated);
 
 202         if (!validationResult.isValid()) {
 
 203             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
 
 205         updateAcForProperties(acToBeUpdated);
 
 207         var acToPublish = new AutomationComposition(acToBeUpdated);
 
 209         encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionId());
 
 211         automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
 
 212         // Publish property update event to the participants
 
 213         supervisionAcHandler.update(acToPublish);
 
 214         return createInstantiationResponse(automationComposition);
 
 217     private InstantiationResponse migrateAutomationComposition(
 
 218         AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
 
 220         if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
 
 221             throw new PfModelRuntimeException(Status.BAD_REQUEST,
 
 222                 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
 
 224         // make copy for rollback
 
 225         automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
 
 227         // Iterate and update the element property values
 
 228         var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated);
 
 229         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
 
 231         updateAcForMigration(acToBeUpdated, acDefinition);
 
 233         var acToPublish = new AutomationComposition(acToBeUpdated);
 
 235         encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionTargetId());
 
 237         var ac = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
 
 238         elementsRemoved.forEach(automationCompositionProvider::deleteAutomationCompositionElement);
 
 240         // Publish migrate event to the participants
 
 241         supervisionAcHandler.migrate(acToPublish);
 
 242         return createInstantiationResponse(ac);
 
 245     private void updateAcForMigration(AutomationComposition acToBeUpdated,
 
 246                                       AutomationCompositionDefinition acDefinition) {
 
 247         AcmUtils.setCascadedState(acToBeUpdated, DeployState.MIGRATING, LockState.LOCKED);
 
 248         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
 
 249         var stage = ParticipantUtils.getFirstStage(acToBeUpdated, acDefinition.getServiceTemplate());
 
 250         acToBeUpdated.setPhase(stage);
 
 253     private void updateAcForProperties(AutomationComposition acToBeUpdated) {
 
 254         AcmUtils.setCascadedState(acToBeUpdated, DeployState.UPDATING, acToBeUpdated.getLockState());
 
 255         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
 
 258     private List<UUID> getElementRemoved(AutomationComposition acFromDb, AutomationComposition acFromMigration) {
 
 259         return acFromDb.getElements().keySet().stream()
 
 260             .filter(id -> acFromMigration.getElements().get(id) == null).toList();
 
 263     void checkCompatibility(PfConceptKey newDefinition, PfConceptKey dbElementDefinition,
 
 265         var compatibility = newDefinition.getCompatibility(dbElementDefinition);
 
 266         if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
 
 267             throw new PfModelRuntimeException(Status.BAD_REQUEST,
 
 268                 dbElementDefinition + " is not compatible with " + newDefinition);
 
 270         if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR
 
 271             .equals(compatibility)) {
 
 272             LOGGER.warn("Migrate {}: Version {} has {} compatibility with {} ", instanceId, newDefinition,
 
 273                 compatibility, dbElementDefinition);
 
 277     private InstantiationResponse migratePrecheckAc(
 
 278         AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
 
 280         acToBeUpdated.setPrecheck(true);
 
 281         var copyAc = new AutomationComposition(acToBeUpdated);
 
 282         // Iterate and update the element property values
 
 283         updateElementsProperties(automationComposition, copyAc);
 
 285         // Publish migrate event to the participants
 
 286         supervisionAcHandler.migratePrecheck(copyAc);
 
 288         AcmUtils.setCascadedState(acToBeUpdated, DeployState.DEPLOYED, LockState.LOCKED,
 
 289             SubState.MIGRATION_PRECHECKING);
 
 290         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
 
 292         return createInstantiationResponse(automationCompositionProvider.updateAutomationComposition(acToBeUpdated));
 
 295     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
 
 296         return validateAutomationComposition(automationComposition, automationComposition.getCompositionId());
 
 300      * Validate AutomationComposition.
 
 302      * @param automationComposition AutomationComposition to validate
 
 303      * @param compositionId         the composition id
 
 304      * @return the result of validation
 
 306     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
 
 307                                                                UUID compositionId) {
 
 309         var result = new BeanValidationResult("AutomationComposition", automationComposition);
 
 310         var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
 
 311         if (acDefinitionOpt.isEmpty()) {
 
 312             result.addResult(new ObjectValidationResult("ServiceTemplate", compositionId, ValidationStatus.INVALID,
 
 313                 "Commissioned automation composition definition not found"));
 
 316         if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
 
 317             result.addResult(new ObjectValidationResult("ServiceTemplate.state", acDefinitionOpt.get().getState(),
 
 318                 ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
 
 321         var participantIds = acDefinitionOpt.get().getElementStateMap().values().stream()
 
 322             .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
 
 324         participantProvider.verifyParticipantState(participantIds);
 
 326         result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
 
 327             acDefinitionOpt.get().getServiceTemplate(),
 
 328             acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
 
 330         result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
 
 332         if (result.isValid()) {
 
 333             for (var element : automationComposition.getElements().values()) {
 
 334                 var name = element.getDefinition().getName();
 
 335                 var participantId = acDefinitionOpt.get().getElementStateMap().get(name).getParticipantId();
 
 336                 element.setParticipantId(participantId);
 
 344     private void encryptInstanceProperties(AutomationComposition automationComposition, UUID compositionId) {
 
 345         if (encryptionUtils.encryptionEnabled()) {
 
 346             var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
 
 347             acDefinitionOpt.ifPresent(acDefinition
 
 348                 -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
 
 353      * Get Automation Composition.
 
 355      * @param compositionId The UUID of the automation composition definition
 
 356      * @param instanceId    The UUID of the automation composition instance
 
 357      * @return the Automation Composition
 
 359     @Transactional(readOnly = true)
 
 360     public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
 
 361         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
 
 362         if (!compositionId.equals(automationComposition.getCompositionId())
 
 363             && !compositionId.equals(automationComposition.getCompositionTargetId())) {
 
 364             throw new PfModelRuntimeException(Status.BAD_REQUEST,
 
 365                 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
 
 367         return automationComposition;
 
 371      * Delete the automation composition with the given name and version.
 
 373      * @param compositionId The UUID of the automation composition definition
 
 374      * @param instanceId    The UUID of the automation composition instance
 
 375      * @return the result of the deletion
 
 377     public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
 
 378         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
 
 379         var acDefinition = getAcDefinition(compositionId, automationComposition);
 
 380         var result = acInstanceStateResolver.resolve(DeployOrder.DELETE,
 
 382             automationComposition.getDeployState(), automationComposition.getLockState(),
 
 383             automationComposition.getSubState(), automationComposition.getStateChangeResult());
 
 384         if (!DeployOrder.DELETE.name().equals(result)) {
 
 385             var msg = String.format(NOT_VALID_ORDER, DeployOrder.DELETE,
 
 386                 automationComposition.getDeployState(), automationComposition.getLockState(),
 
 387                 automationComposition.getSubState(), automationComposition.getStateChangeResult());
 
 388             throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
 
 390         supervisionAcHandler.delete(automationComposition, acDefinition);
 
 391         return createInstantiationResponse(automationComposition);
 
 395      * Get the requested automation compositions.
 
 397      * @param name     the name of the automation composition to get, null for all automation compositions
 
 398      * @param version  the version of the automation composition to get, null for all automation compositions
 
 399      * @param pageable the Pageable
 
 400      * @return the automation compositions
 
 402     @Transactional(readOnly = true)
 
 403     public AutomationCompositions getAutomationCompositions(@NonNull final UUID compositionId,
 
 404                                                             final String name, final String version,
 
 405                                                             @NonNull final Pageable pageable) {
 
 406         var automationCompositions = new AutomationCompositions();
 
 407         automationCompositions.setAutomationCompositionList(
 
 408             automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
 
 410         return automationCompositions;
 
 414      * Handle Composition Instance State.
 
 416      * @param compositionId         the compositionId
 
 417      * @param instanceId            the instanceId
 
 418      * @param acInstanceStateUpdate the AcInstanceStateUpdate
 
 420     public void compositionInstanceState(UUID compositionId, UUID instanceId,
 
 421                                          @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
 
 422         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
 
 423         var acDefinition = getAcDefinition(compositionId, automationComposition);
 
 424         var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
 
 425             acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
 
 426             automationComposition.getDeployState(), automationComposition.getLockState(),
 
 427             automationComposition.getSubState(), automationComposition.getStateChangeResult());
 
 430                 supervisionAcHandler.deploy(automationComposition, acDefinition);
 
 434                 supervisionAcHandler.undeploy(automationComposition, acDefinition);
 
 438                 supervisionAcHandler.lock(automationComposition, acDefinition);
 
 442                 supervisionAcHandler.unlock(automationComposition, acDefinition);
 
 446                 supervisionAcHandler.prepare(automationComposition, acDefinition);
 
 450                 supervisionAcHandler.review(automationComposition);
 
 454                 var msg = String.format(NOT_VALID_ORDER, acInstanceStateUpdate,
 
 455                     automationComposition.getDeployState(), automationComposition.getLockState(),
 
 456                     automationComposition.getSubState(), automationComposition.getStateChangeResult());
 
 457                 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
 
 462      * Rollback AC Instance.
 
 464      * @param instanceId the instanceId
 
 466     public void rollback(UUID compositionId, UUID instanceId) {
 
 467         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
 
 468         validateCompositionRequested(compositionId, automationComposition);
 
 469         var automationCompositionToRollback =
 
 470             automationCompositionProvider.getAutomationCompositionRollback(instanceId);
 
 472         if (DeployState.DEPLOYED.equals(automationComposition.getDeployState())
 
 473               && SubState.NONE.equals(automationComposition.getSubState())
 
 474               && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
 
 475             automationComposition.setCompositionId(automationCompositionToRollback.getCompositionId());
 
 476             automationComposition.setElements(automationCompositionToRollback.getElements().values().stream()
 
 477                     .collect(Collectors.toMap(AutomationCompositionElement::getId, UnaryOperator.identity())));
 
 478             automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
 
 479             AcmUtils.setCascadedState(automationComposition, DeployState.MIGRATION_REVERTING, LockState.LOCKED);
 
 480             automationCompositionProvider.updateAutomationComposition(automationComposition);
 
 482             throw new PfModelRuntimeException(Status.BAD_REQUEST, "Invalid state for rollback");
 
 486     private List<UUID> updateElementsProperties(AutomationComposition automationComposition,
 
 487                                                 AutomationComposition acToBeUpdated) {
 
 488         for (var element : automationComposition.getElements().entrySet()) {
 
 489             var elementId = element.getKey();
 
 490             var dbAcElement = acToBeUpdated.getElements().get(elementId);
 
 491             // Add additional elements if present for migration
 
 492             if (dbAcElement == null) {
 
 493                 LOGGER.info("New Ac element {} added in Migration", elementId);
 
 494                 acToBeUpdated.getElements().put(elementId, element.getValue());
 
 496                 AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
 
 497                 var newDefinition = element.getValue().getDefinition().asConceptKey();
 
 498                 var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
 
 499                 checkCompatibility(newDefinition, dbElementDefinition, automationComposition.getInstanceId());
 
 500                 dbAcElement.setDefinition(element.getValue().getDefinition());
 
 503         // Remove element which is not present in the new Ac instance
 
 504         var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
 
 505         elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
 
 507         var validationResult =
 
 508             validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
 
 509         if (!validationResult.isValid()) {
 
 510             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
 
 512         acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
 
 513         return elementsRemoved;
 
 516     private static void validateCompositionRequested(UUID compositionId,
 
 517                                                      AutomationComposition automationComposition) {
 
 518         if (!compositionId.equals(automationComposition.getCompositionId())) {
 
 519             throw new PfModelRuntimeException(Status.BAD_REQUEST,
 
 520                 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
 
 524     private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
 
 525                                                             AutomationComposition automationComposition) {
 
 526         validateCompositionRequested(compositionId, automationComposition);
 
 527         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
 
 529         var participantIds = acDefinition.getElementStateMap().values().stream()
 
 530             .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
 
 532         participantProvider.verifyParticipantState(participantIds);