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);