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.HashMap;
25 import java.util.List;
27 import java.util.UUID;
28 import lombok.RequiredArgsConstructor;
29 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
30 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
31 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
32 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
33 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
34 import org.onap.policy.clamp.models.acm.concepts.DeployState;
35 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
36 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
37 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
38 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
39 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
40 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
41 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange;
42 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
43 import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate;
44 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
45 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.stereotype.Component;
51 * This class is responsible for managing the state of all automation compositions in the participant.
54 @RequiredArgsConstructor
55 public class AutomationCompositionHandler {
56 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
58 private final CacheProvider cacheProvider;
59 private final ParticipantMessagePublisher publisher;
60 private final ThreadHandler listener;
63 * Handle a automation composition state change message.
65 * @param stateChangeMsg the state change message
67 public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
68 if (stateChangeMsg.getAutomationCompositionId() == null) {
72 var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
74 if (automationComposition == null) {
75 if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
76 var automationCompositionAck = new AutomationCompositionDeployAck(
77 ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
78 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
79 automationCompositionAck.setReplicaId(cacheProvider.getReplicaId());
80 automationCompositionAck.setMessage("Already deleted or never used");
81 automationCompositionAck.setResult(true);
82 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
83 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
84 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
85 publisher.sendAutomationCompositionAck(automationCompositionAck);
87 LOGGER.debug("Automation composition {} does not use this participant",
88 stateChangeMsg.getAutomationCompositionId());
93 switch (stateChangeMsg.getDeployOrderedState()) {
94 case UNDEPLOY -> handleUndeployState(stateChangeMsg.getMessageId(), automationComposition,
95 stateChangeMsg.getStartPhase());
96 case DELETE -> handleDeleteState(stateChangeMsg.getMessageId(), automationComposition,
97 stateChangeMsg.getStartPhase());
99 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
104 * Handle a automation composition properties update message.
106 * @param updateMsg the properties update message
108 public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
110 if (updateMsg.getParticipantUpdatesList().isEmpty()) {
111 LOGGER.warn("No AutomationCompositionElement updates in message {}",
112 updateMsg.getAutomationCompositionId());
116 for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
117 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
118 var automationComposition = cacheProvider.getAutomationComposition(
119 updateMsg.getAutomationCompositionId());
120 automationComposition.setDeployState(DeployState.UPDATING);
121 var acCopy = new AutomationComposition(automationComposition);
122 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy,
123 DeployState.UPDATING);
125 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(), acCopy);
131 * Handle a automation composition Deploy message.
133 * @param deployMsg the Deploy message
135 public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
137 if (deployMsg.getParticipantUpdatesList().isEmpty()) {
138 LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
142 for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
143 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
144 if (deployMsg.isFirstStartPhase()) {
145 cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
146 deployMsg.getAutomationCompositionId(), participantDeploy);
148 callParticipanDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
149 deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
154 private void callParticipanDeploy(UUID messageId, List<AcElementDeploy> acElementDeployList,
155 Integer startPhaseMsg, UUID instanceId) {
156 var automationComposition = cacheProvider.getAutomationComposition(instanceId);
157 automationComposition.setDeployState(DeployState.DEPLOYING);
158 for (var elementDeploy : acElementDeployList) {
159 var element = automationComposition.getElements().get(elementDeploy.getId());
160 var compositionInProperties = cacheProvider
161 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
162 int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
163 if (startPhaseMsg.equals(startPhase)) {
164 var compositionElement = cacheProvider.createCompositionElementDto(
165 automationComposition.getCompositionId(), element, compositionInProperties);
166 var instanceElement = new InstanceElementDto(instanceId, elementDeploy.getId(),
167 elementDeploy.getToscaServiceTemplateFragment(),
168 elementDeploy.getProperties(), element.getOutProperties());
169 listener.deploy(messageId, compositionElement, instanceElement);
174 private Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition,
175 UUID compositionId) {
176 Map<UUID, CompositionElementDto> map = new HashMap<>();
177 for (var element : automationComposition.getElements().values()) {
178 var compositionInProperties = cacheProvider.getCommonProperties(compositionId, element.getDefinition());
179 var compositionElement = cacheProvider
180 .createCompositionElementDto(compositionId, element, compositionInProperties);
181 map.put(element.getId(), compositionElement);
186 private Map<UUID, CompositionElementDto> getCompositionElementDtoMap(AutomationComposition automationComposition) {
187 return getCompositionElementDtoMap(automationComposition, automationComposition.getCompositionId());
190 private Map<UUID, InstanceElementDto> getInstanceElementDtoMap(AutomationComposition automationComposition) {
191 Map<UUID, InstanceElementDto> map = new HashMap<>();
192 var serviceTemplateFragment = cacheProvider
193 .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId());
194 for (var element : automationComposition.getElements().values()) {
195 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
196 serviceTemplateFragment, element.getProperties(), element.getOutProperties());
197 map.put(element.getId(), instanceElement);
202 private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements,
203 AutomationComposition acCopy) {
204 var instanceElementDtoMap = getInstanceElementDtoMap(acCopy);
205 var instanceElementDtoMapUpdated = getInstanceElementDtoMap(
206 cacheProvider.getAutomationComposition(acCopy.getInstanceId()));
207 var compositionElementDtoMap = getCompositionElementDtoMap(acCopy);
208 for (var acElement : acElements) {
209 listener.update(messageId, compositionElementDtoMap.get(acElement.getId()),
210 instanceElementDtoMap.get(acElement.getId()), instanceElementDtoMapUpdated.get(acElement.getId()));
214 private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy,
215 DeployState deployState) {
216 var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
217 for (var element : participantDeploy.getAcElementList()) {
218 var acElement = acElementList.get(element.getId());
219 AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
220 acElement.setDeployState(deployState);
221 acElement.setDefinition(element.getDefinition());
226 * Method to handle when the new state from participant is UNINITIALISED state.
228 * @param messageId the messageId
229 * @param automationComposition participant response
230 * @param startPhaseMsg startPhase from message
232 private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
233 Integer startPhaseMsg) {
234 automationComposition.setCompositionTargetId(null);
235 automationComposition.setDeployState(DeployState.UNDEPLOYING);
236 var serviceTemplateFragment = cacheProvider
237 .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId());
238 for (var element : automationComposition.getElements().values()) {
239 var compositionInProperties = cacheProvider
240 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
241 int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
242 if (startPhaseMsg.equals(startPhase)) {
243 element.setDeployState(DeployState.UNDEPLOYING);
244 var compositionElement = cacheProvider.createCompositionElementDto(
245 automationComposition.getCompositionId(), element, compositionInProperties);
246 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
247 serviceTemplateFragment, element.getProperties(), element.getOutProperties());
248 listener.undeploy(messageId, compositionElement, instanceElement);
253 private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
254 Integer startPhaseMsg) {
255 automationComposition.setDeployState(DeployState.DELETING);
256 var serviceTemplateFragment = cacheProvider
257 .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId());
258 for (var element : automationComposition.getElements().values()) {
259 var compositionInProperties = cacheProvider
260 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
261 int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
262 if (startPhaseMsg.equals(startPhase)) {
263 element.setDeployState(DeployState.DELETING);
264 var compositionElement = cacheProvider.createCompositionElementDto(
265 automationComposition.getCompositionId(), element, compositionInProperties);
266 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
267 serviceTemplateFragment, element.getProperties(), element.getOutProperties());
268 listener.delete(messageId, compositionElement, instanceElement);
274 * Handles AutomationComposition Migration.
276 * @param migrationMsg the AutomationCompositionMigration
278 public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
279 if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
283 var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
284 if (automationComposition == null) {
285 LOGGER.debug("Automation composition {} does not use this participant",
286 migrationMsg.getAutomationCompositionId());
289 var acCopy = new AutomationComposition(automationComposition);
290 automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
291 automationComposition.setDeployState(DeployState.MIGRATING);
292 for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
293 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
295 updateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), participantDeploy,
296 DeployState.MIGRATING);
298 callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
299 acCopy, migrationMsg.getCompositionTargetId());
304 private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements,
305 AutomationComposition acCopy, UUID compositionTargetId) {
306 var compositionElementMap = getCompositionElementDtoMap(acCopy);
307 var instanceElementMap = getInstanceElementDtoMap(acCopy);
308 var automationComposition = cacheProvider.getAutomationComposition(acCopy.getInstanceId());
309 var compositionElementTargetMap = getCompositionElementDtoMap(automationComposition, compositionTargetId);
310 var instanceElementMigrateMap = getInstanceElementDtoMap(automationComposition);
312 for (var acElement : acElements) {
313 listener.migrate(messageId, compositionElementMap.get(acElement.getId()),
314 compositionElementTargetMap.get(acElement.getId()),
315 instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId()));