2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021-2024 Nordix Foundation.
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.participant.intermediary.handler;
24 import java.util.List;
25 import java.util.UUID;
26 import lombok.RequiredArgsConstructor;
27 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
28 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
29 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
30 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
31 import org.onap.policy.clamp.models.acm.concepts.DeployState;
32 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
33 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
34 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
35 import org.onap.policy.clamp.models.acm.concepts.SubState;
36 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
37 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
38 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
39 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange;
40 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
41 import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate;
42 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
43 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.stereotype.Component;
49 * This class is responsible for managing the state of all automation compositions in the participant.
52 @RequiredArgsConstructor
53 public class AutomationCompositionHandler {
54 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
56 private final CacheProvider cacheProvider;
57 private final ParticipantMessagePublisher publisher;
58 private final ThreadHandler listener;
61 * Handle a automation composition state change message.
63 * @param stateChangeMsg the state change message
65 public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
66 if (stateChangeMsg.getAutomationCompositionId() == null) {
70 var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
72 if (automationComposition == null) {
73 if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
74 var automationCompositionAck = new AutomationCompositionDeployAck(
75 ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
76 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
77 automationCompositionAck.setReplicaId(cacheProvider.getReplicaId());
78 automationCompositionAck.setMessage("Already deleted or never used");
79 automationCompositionAck.setResult(true);
80 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
81 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
82 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
83 publisher.sendAutomationCompositionAck(automationCompositionAck);
85 LOGGER.debug("Automation composition {} does not use this participant",
86 stateChangeMsg.getAutomationCompositionId());
91 switch (stateChangeMsg.getDeployOrderedState()) {
92 case UNDEPLOY -> handleUndeployState(stateChangeMsg.getMessageId(), automationComposition,
93 stateChangeMsg.getStartPhase());
94 case DELETE -> handleDeleteState(stateChangeMsg.getMessageId(), automationComposition,
95 stateChangeMsg.getStartPhase());
97 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
102 * Handle a automation composition properties update message.
104 * @param updateMsg the properties update message
106 public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
108 if (updateMsg.getParticipantUpdatesList().isEmpty()) {
109 LOGGER.warn("No AutomationCompositionElement updates in message {}",
110 updateMsg.getAutomationCompositionId());
114 for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
115 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
116 var automationComposition = cacheProvider.getAutomationComposition(
117 updateMsg.getAutomationCompositionId());
118 automationComposition.setDeployState(DeployState.UPDATING);
119 var acCopy = new AutomationComposition(automationComposition);
120 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy,
121 DeployState.UPDATING);
123 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(), acCopy);
129 * Handle a automation composition Deploy message.
131 * @param deployMsg the Deploy message
133 public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
135 if (deployMsg.getParticipantUpdatesList().isEmpty()) {
136 LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
140 for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
141 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
142 if (deployMsg.isFirstStartPhase()) {
143 cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
144 deployMsg.getAutomationCompositionId(), participantDeploy);
146 callParticipanDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
147 deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
152 private void callParticipanDeploy(UUID messageId, List<AcElementDeploy> acElementDeployList,
153 Integer startPhaseMsg, UUID instanceId) {
154 var automationComposition = cacheProvider.getAutomationComposition(instanceId);
155 automationComposition.setDeployState(DeployState.DEPLOYING);
156 for (var elementDeploy : acElementDeployList) {
157 var element = automationComposition.getElements().get(elementDeploy.getId());
158 var compositionInProperties = cacheProvider
159 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
160 int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
161 if (startPhaseMsg.equals(startPhase)) {
162 var compositionElement = cacheProvider.createCompositionElementDto(
163 automationComposition.getCompositionId(), element, compositionInProperties);
164 var instanceElement = new InstanceElementDto(instanceId, elementDeploy.getId(),
165 elementDeploy.getToscaServiceTemplateFragment(),
166 elementDeploy.getProperties(), element.getOutProperties());
167 listener.deploy(messageId, compositionElement, instanceElement);
172 private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements,
173 AutomationComposition acCopy) {
174 var instanceElementDtoMap = cacheProvider.getInstanceElementDtoMap(acCopy);
175 var instanceElementDtoMapUpdated = cacheProvider.getInstanceElementDtoMap(
176 cacheProvider.getAutomationComposition(acCopy.getInstanceId()));
177 var compositionElementDtoMap = cacheProvider.getCompositionElementDtoMap(acCopy);
178 for (var acElement : acElements) {
179 listener.update(messageId, compositionElementDtoMap.get(acElement.getId()),
180 instanceElementDtoMap.get(acElement.getId()), instanceElementDtoMapUpdated.get(acElement.getId()));
184 private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy,
185 DeployState deployState) {
186 var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
187 for (var element : participantDeploy.getAcElementList()) {
188 var acElement = acElementList.get(element.getId());
189 AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
190 acElement.setDeployState(deployState);
191 acElement.setSubState(SubState.NONE);
192 acElement.setDefinition(element.getDefinition());
197 * Method to handle when the new state from participant is UNINITIALISED state.
199 * @param messageId the messageId
200 * @param automationComposition participant response
201 * @param startPhaseMsg startPhase from message
203 private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
204 Integer startPhaseMsg) {
205 automationComposition.setCompositionTargetId(null);
206 automationComposition.setDeployState(DeployState.UNDEPLOYING);
207 var serviceTemplateFragment = cacheProvider
208 .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId());
209 for (var element : automationComposition.getElements().values()) {
210 var compositionInProperties = cacheProvider
211 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
212 int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
213 if (startPhaseMsg.equals(startPhase)) {
214 element.setDeployState(DeployState.UNDEPLOYING);
215 var compositionElement = cacheProvider.createCompositionElementDto(
216 automationComposition.getCompositionId(), element, compositionInProperties);
217 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
218 serviceTemplateFragment, element.getProperties(), element.getOutProperties());
219 listener.undeploy(messageId, compositionElement, instanceElement);
224 private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
225 Integer startPhaseMsg) {
226 automationComposition.setDeployState(DeployState.DELETING);
227 var serviceTemplateFragment = cacheProvider
228 .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId());
229 for (var element : automationComposition.getElements().values()) {
230 var compositionInProperties = cacheProvider
231 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
232 int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
233 if (startPhaseMsg.equals(startPhase)) {
234 element.setDeployState(DeployState.DELETING);
235 element.setSubState(SubState.NONE);
236 var compositionElement = cacheProvider.createCompositionElementDto(
237 automationComposition.getCompositionId(), element, compositionInProperties);
238 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
239 serviceTemplateFragment, element.getProperties(), element.getOutProperties());
240 listener.delete(messageId, compositionElement, instanceElement);
246 * Handles AutomationComposition Migration.
248 * @param migrationMsg the AutomationCompositionMigration
250 public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
251 if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
255 var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
256 if (automationComposition == null) {
257 LOGGER.debug("Automation composition {} does not use this participant",
258 migrationMsg.getAutomationCompositionId());
261 var acCopy = new AutomationComposition(automationComposition);
262 automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
263 automationComposition.setDeployState(DeployState.MIGRATING);
264 for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
265 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
267 updateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), participantDeploy,
268 DeployState.MIGRATING);
270 callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
271 acCopy, migrationMsg.getCompositionTargetId());
276 private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements,
277 AutomationComposition acCopy, UUID compositionTargetId) {
278 var compositionElementMap = cacheProvider.getCompositionElementDtoMap(acCopy);
279 var instanceElementMap = cacheProvider.getInstanceElementDtoMap(acCopy);
280 var automationComposition = cacheProvider.getAutomationComposition(acCopy.getInstanceId());
281 var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(automationComposition,
282 compositionTargetId);
283 var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
285 for (var acElement : acElements) {
286 listener.migrate(messageId, compositionElementMap.get(acElement.getId()),
287 compositionElementTargetMap.get(acElement.getId()),
288 instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId()));