2  * ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
 
   4  * ================================================================================
 
   5  * Licensed under the Apache License, Version 2.0 (the "License");
 
   6  * you may not use this file except in compliance with the License.
 
   7  * You may obtain a copy of the License at
 
   9  *      http://www.apache.org/licenses/LICENSE-2.0
 
  11  * Unless required by applicable law or agreed to in writing, software
 
  12  * distributed under the License is distributed on an "AS IS" BASIS,
 
  13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14  * See the License for the specific language governing permissions and
 
  15  * limitations under the License.
 
  17  * SPDX-License-Identifier: Apache-2.0
 
  18  * ============LICENSE_END=========================================================
 
  21 package org.onap.policy.clamp.acm.participant.intermediary.handler;
 
  23 import java.util.List;
 
  25 import java.util.UUID;
 
  26 import lombok.RequiredArgsConstructor;
 
  27 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
 
  28 import org.onap.policy.clamp.acm.participant.intermediary.api.ElementState;
 
  29 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
 
  30 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.CacheProvider;
 
  31 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
 
  32 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
 
  33 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
 
  34 import org.onap.policy.clamp.models.acm.concepts.DeployState;
 
  35 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
 
  36 import org.onap.policy.clamp.models.acm.concepts.SubState;
 
  37 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
 
  38 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare;
 
  39 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
 
  40 import org.slf4j.Logger;
 
  41 import org.slf4j.LoggerFactory;
 
  42 import org.springframework.stereotype.Component;
 
  45 @RequiredArgsConstructor
 
  46 public class AcSubStateHandler {
 
  48     private static final Logger LOGGER = LoggerFactory.getLogger(AcSubStateHandler.class);
 
  50     private final CacheProvider cacheProvider;
 
  51     private final ThreadHandler listener;
 
  54      * Handles AutomationComposition Migration Precheck.
 
  56      * @param migrationMsg the AutomationCompositionMigration
 
  58     public void handleAcMigrationPrecheck(AutomationCompositionMigration migrationMsg) {
 
  59         if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
 
  62         var acTargetDefinition = cacheProvider.getAcElementsDefinitions().get(migrationMsg.getCompositionTargetId());
 
  63         var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
 
  64         if (automationComposition == null) {
 
  65             if (acTargetDefinition == null) {
 
  66                 LOGGER.warn("Automation composition {} does not use this participant",
 
  67                         migrationMsg.getAutomationCompositionId());
 
  71             LOGGER.info("Migration Precheck invoked on an existing participant for the instance {}",
 
  72                     migrationMsg.getAutomationCompositionId());
 
  74         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
 
  75             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
 
  76                 if (automationComposition == null) { // New element with new participant
 
  77                     automationComposition = cacheProvider.createAcInstance(migrationMsg.getCompositionId(),
 
  78                             migrationMsg.getCompositionTargetId(), migrationMsg.getAutomationCompositionId(),
 
  79                             participantDeploy, DeployState.MIGRATING, SubState.MIGRATION_PRECHECKING,
 
  80                             migrationMsg.getRevisionIdInstance());
 
  81                     LOGGER.info("New participant with new element type added for Migration Precheck");
 
  84                 callParticipantMigratePrecheck(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
 
  85                     automationComposition, migrationMsg.getCompositionTargetId());
 
  90     private void callParticipantMigratePrecheck(UUID messageId, List<AcElementDeploy> acElements,
 
  91             AutomationComposition automationComposition, UUID compositionTargetId) {
 
  92         var compositionElementMap = cacheProvider.getCompositionElementDtoMap(automationComposition);
 
  93         var instanceElementMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
 
  94         var acElementList = automationComposition.getElements();
 
  95         for (var acElement : acElements) {
 
  96             var element = acElementList.get(acElement.getId());
 
  97             if (element != null) {
 
  98                 element.setSubState(SubState.MIGRATION_PRECHECKING);
 
 101         var acCopyMigrateTo = new AutomationComposition(automationComposition);
 
 102         var acElementCopyList = acCopyMigrateTo.getElements();
 
 103         for (var acElement : acElements) {
 
 104             var element = acElementCopyList.get(acElement.getId());
 
 105             if (element != null) {
 
 106                 AcmUtils.recursiveMerge(element.getProperties(), acElement.getProperties());
 
 107                 element.setDefinition(acElement.getDefinition());
 
 109                 element = CacheProvider.createAutomationCompositionElement(acElement);
 
 110                 element.setSubState(SubState.MIGRATION_PRECHECKING);
 
 111                 acElementCopyList.put(element.getId(), element);
 
 114         var toDelete = acElementCopyList.values().stream()
 
 115                 .filter(el -> !SubState.MIGRATION_PRECHECKING.equals(el.getSubState()))
 
 116                 .map(AutomationCompositionElement::getId)
 
 118         toDelete.forEach(acElementCopyList::remove);
 
 120         var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(acCopyMigrateTo,
 
 121             compositionTargetId);
 
 122         var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(acCopyMigrateTo);
 
 124         for (var acElement : acElements) {
 
 125             var compositionElement = compositionElementMap.get(acElement.getId());
 
 126             var compositionElementTarget = compositionElementTargetMap.get(acElement.getId());
 
 127             var instanceElement = instanceElementMap.get(acElement.getId());
 
 128             var instanceElementMigrate = instanceElementMigrateMap.get(acElement.getId());
 
 130             if (instanceElement == null) {
 
 131                 // new element scenario
 
 132                 compositionElement = new CompositionElementDto(automationComposition.getCompositionId(),
 
 133                         acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
 
 134                 instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), acElement.getId(),
 
 135                         Map.of(), Map.of(), ElementState.NOT_PRESENT);
 
 136                 compositionElementTarget = CacheProvider.changeStateToNew(compositionElementTarget);
 
 137                 instanceElementMigrate = CacheProvider.changeStateToNew(instanceElementMigrate);
 
 140             listener.migratePrecheck(messageId, compositionElement, compositionElementTarget,
 
 141                     instanceElement, instanceElementMigrate);
 
 144         for (var elementId : toDelete) {
 
 145             var compositionDtoTarget =
 
 146                     new CompositionElementDto(compositionTargetId,
 
 147                             automationComposition.getElements().get(elementId).getDefinition(),
 
 148                             Map.of(), Map.of(), ElementState.REMOVED);
 
 149             var instanceDtoTarget =
 
 150                     new InstanceElementDto(automationComposition.getInstanceId(), elementId,
 
 151                             Map.of(), Map.of(), ElementState.REMOVED);
 
 153             listener.migratePrecheck(messageId, compositionElementMap.get(elementId), compositionDtoTarget,
 
 154                     instanceElementMap.get(elementId), instanceDtoTarget);
 
 159      * Handle AutomationComposition Prepare message.
 
 161      * @param acPrepareMsg the AutomationCompositionPrepare message
 
 163     public void handleAcPrepare(AutomationCompositionPrepare acPrepareMsg) {
 
 164         if (acPrepareMsg.isPreDeploy()) {
 
 165             for (var participantPrepare : acPrepareMsg.getParticipantList()) {
 
 166                 if (cacheProvider.getParticipantId().equals(participantPrepare.getParticipantId())) {
 
 167                     cacheProvider.initializeAutomationComposition(acPrepareMsg.getCompositionId(), null,
 
 168                         acPrepareMsg.getAutomationCompositionId(), participantPrepare, DeployState.UNDEPLOYED,
 
 169                         SubState.PREPARING, acPrepareMsg.getRevisionIdInstance());
 
 170                     callParticipanPrepare(acPrepareMsg.getMessageId(), participantPrepare.getAcElementList(),
 
 171                         acPrepareMsg.getStage(), acPrepareMsg.getAutomationCompositionId());
 
 175             var automationComposition =
 
 176                 cacheProvider.getAutomationComposition(acPrepareMsg.getAutomationCompositionId());
 
 177             automationComposition.setSubState(SubState.REVIEWING);
 
 178             callParticipanReview(acPrepareMsg.getMessageId(), automationComposition);
 
 182     private void callParticipanPrepare(UUID messageId, List<AcElementDeploy> acElementList, Integer stageMsg,
 
 184         var automationComposition = cacheProvider.getAutomationComposition(instanceId);
 
 185         for (var elementDeploy : acElementList) {
 
 186             var element = automationComposition.getElements().get(elementDeploy.getId());
 
 187             var compositionInProperties = cacheProvider
 
 188                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
 
 189             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
 
 191             var stageSet = ParticipantUtils.findStageSetPrepare(compositionInProperties);
 
 192             if (stageSet.contains(stageMsg)) {
 
 193                 var instanceElement =
 
 194                         new InstanceElementDto(instanceId, elementDeploy.getId(), elementDeploy.getProperties(),
 
 195                                 element.getOutProperties());
 
 196                 listener.prepare(messageId, compositionElement, instanceElement, stageMsg);
 
 201     private void callParticipanReview(UUID messageId, AutomationComposition automationComposition) {
 
 202         for (var element : automationComposition.getElements().values()) {
 
 203             element.setSubState(SubState.REVIEWING);
 
 204             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
 
 206             var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
 
 207                 element.getProperties(), element.getOutProperties());
 
 208             listener.review(messageId, compositionElement, instanceElement);