2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2023-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.comm.ParticipantMessagePublisher;
28 import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck;
29 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
30 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
31 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
32 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
33 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo;
35 import org.onap.policy.clamp.models.acm.concepts.DeployState;
36 import org.onap.policy.clamp.models.acm.concepts.LockState;
37 import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
38 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
39 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
40 import org.onap.policy.clamp.models.acm.concepts.SubState;
41 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
42 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
43 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck;
44 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus;
45 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import org.springframework.stereotype.Component;
52 @RequiredArgsConstructor
53 public class AutomationCompositionOutHandler {
54 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionOutHandler.class);
56 private final ParticipantMessagePublisher publisher;
57 private final CacheProvider cacheProvider;
60 * Handle a automation composition element stage change message.
62 * @param instance the automationComposition Id
63 * @param elementId the automationComposition Element Id
64 * @param stage the next stage
65 * @param message the message
66 * @param stateChangeResult the indicator if error occurs
68 public void updateAutomationCompositionElementStage(UUID instance, UUID elementId,
69 StateChangeResult stateChangeResult, int stage, String message) {
70 if (!validateData(instance, elementId, stateChangeResult)) {
74 var automationComposition = cacheProvider.getAutomationComposition(instance);
75 if (automationComposition == null) {
76 LOGGER.error("Cannot update Automation composition element stage, Automation composition id {} not present",
81 var element = automationComposition.getElements().get(elementId);
82 if (element == null) {
83 var msg = "Cannot update Automation composition element stage, AC Element id {} not present";
84 LOGGER.error(msg, elementId);
88 var automationCompositionStateChangeAck =
89 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
90 automationCompositionStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
91 automationCompositionStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
92 automationCompositionStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
93 automationCompositionStateChangeAck.setStateChangeResult(stateChangeResult);
94 automationCompositionStateChangeAck.setStage(stage);
95 automationCompositionStateChangeAck.setAutomationCompositionId(instance);
96 automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
97 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
98 element.getUseState(), element.getOutProperties(), true, message));
99 LOGGER.debug("Automation composition element {} stage changed to {}", elementId, stage);
100 automationCompositionStateChangeAck.setResult(true);
101 publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
102 cacheProvider.getMsgIdentification().remove(element.getId());
105 private boolean validateData(UUID instance, UUID elementId, StateChangeResult stateChangeResult) {
106 if (instance == null || elementId == null) {
107 LOGGER.error("Not valid Ac instance, id is null");
110 if (stateChangeResult == null) {
111 LOGGER.error("Not valid Ac instance, stateChangeResult is null");
114 if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
115 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
116 LOGGER.error("Not valid Ac instance, stateChangeResult is not valid");
123 * Handle a automation composition element state change message.
125 * @param instance the automationComposition Id
126 * @param elementId the automationComposition Element Id
127 * @param deployState the DeployState state
128 * @param lockState the LockState state
129 * @param message the message
130 * @param stateChangeResult the indicator if error occurs
132 public void updateAutomationCompositionElementState(UUID instance, UUID elementId,
133 DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message) {
134 if (!validateData(instance, elementId, stateChangeResult)) {
138 if ((deployState != null && lockState != null) || (deployState == null && lockState == null)
139 || AcmUtils.isInTransitionalState(deployState, lockState, SubState.NONE)) {
140 LOGGER.error("state error {} and {} cannot be handled", deployState, lockState);
144 var automationComposition = cacheProvider.getAutomationComposition(instance);
145 if (automationComposition == null) {
146 LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
151 var element = automationComposition.getElements().get(elementId);
152 if (element == null) {
153 var msg = "Cannot update Automation composition element state, AC Element id {} not present";
154 LOGGER.error(msg, elementId);
158 if (!SubState.NONE.equals(element.getSubState())) {
159 if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)) {
160 handleSubState(automationComposition, element, stateChangeResult);
162 } else if (deployState != null) {
163 handleDeployState(automationComposition, element, deployState, stateChangeResult);
165 if (lockState != null) {
166 handleLockState(automationComposition, element, lockState, stateChangeResult);
169 var automationCompositionStateChangeAck =
170 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
171 automationCompositionStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
172 automationCompositionStateChangeAck.setReplicaId(cacheProvider.getReplicaId());
173 automationCompositionStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
174 automationCompositionStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
175 automationCompositionStateChangeAck.setStateChangeResult(stateChangeResult);
176 automationCompositionStateChangeAck.setAutomationCompositionId(instance);
177 automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
178 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
179 element.getUseState(), element.getOutProperties(), true, message));
180 LOGGER.debug("Automation composition element {} state changed to {}", elementId, deployState);
181 automationCompositionStateChangeAck.setResult(true);
182 publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
183 cacheProvider.getMsgIdentification().remove(element.getId());
186 private void handleDeployState(AutomationComposition automationComposition, AutomationCompositionElement element,
187 DeployState deployState, StateChangeResult stateChangeResult) {
188 element.setDeployState(deployState);
189 element.setLockState(DeployState.DEPLOYED.equals(element.getDeployState()) ? LockState.LOCKED : LockState.NONE);
190 if (StateChangeResult.FAILED.equals(stateChangeResult)) {
193 var checkOpt = automationComposition.getElements().values().stream()
194 .filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
195 if (checkOpt.isEmpty()) {
196 if (DeployState.DEPLOYED.equals(automationComposition.getDeployState())
197 && automationComposition.getCompositionTargetId() != null) {
198 // migration scenario
199 automationComposition.setCompositionId(automationComposition.getCompositionTargetId());
200 automationComposition.setCompositionTargetId(null);
202 automationComposition.setDeployState(deployState);
203 automationComposition.setLockState(element.getLockState());
204 automationComposition.setSubState(SubState.NONE);
206 if (DeployState.DELETED.equals(deployState)) {
207 cacheProvider.removeAutomationComposition(automationComposition.getInstanceId());
212 private void handleLockState(AutomationComposition automationComposition, AutomationCompositionElement element,
213 LockState lockState, StateChangeResult stateChangeResult) {
214 element.setLockState(lockState);
215 if (StateChangeResult.FAILED.equals(stateChangeResult)) {
218 var checkOpt = automationComposition.getElements().values().stream()
219 .filter(acElement -> !lockState.equals(acElement.getLockState())).findAny();
220 if (checkOpt.isEmpty()) {
221 automationComposition.setLockState(lockState);
222 automationComposition.setSubState(SubState.NONE);
226 private void handleSubState(AutomationComposition automationComposition, AutomationCompositionElement element,
227 StateChangeResult stateChangeResult) {
228 if (StateChangeResult.FAILED.equals(stateChangeResult)) {
231 element.setSubState(SubState.NONE);
232 var checkOpt = automationComposition.getElements().values().stream()
233 .filter(acElement -> !SubState.NONE.equals(acElement.getSubState())).findAny();
234 if (checkOpt.isEmpty()) {
235 automationComposition.setSubState(SubState.NONE);
240 * Send Ac Element Info.
242 * @param automationCompositionId the automationComposition Id
243 * @param elementId the automationComposition Element id
244 * @param useState the use State
245 * @param operationalState the operational State
246 * @param outProperties the output Properties Map
248 public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
249 String operationalState, Map<String, Object> outProperties) {
251 if (automationCompositionId == null || elementId == null) {
252 LOGGER.error("Cannot update Automation composition element state, id is null");
256 var automationComposition = cacheProvider.getAutomationComposition(automationCompositionId);
257 if (automationComposition == null) {
258 LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
259 automationCompositionId);
263 var element = automationComposition.getElements().get(elementId);
264 if (element == null) {
265 var msg = "Cannot update Automation composition element state, AC Element id {} not present";
266 LOGGER.error(msg, elementId);
269 element.setOperationalState(operationalState);
270 element.setUseState(useState);
271 element.setOutProperties(outProperties);
273 var acInfo = new AutomationCompositionInfo();
274 acInfo.setAutomationCompositionId(automationCompositionId);
275 acInfo.setDeployState(automationComposition.getDeployState());
276 acInfo.setLockState(automationComposition.getLockState());
277 acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
278 var statusMsg = createParticipantStatus();
279 statusMsg.setCompositionId(automationComposition.getCompositionId());
280 statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
281 publisher.sendParticipantStatus(statusMsg);
285 * Get AutomationCompositionElementInfo from AutomationCompositionElement.
287 * @param element the AutomationCompositionElement
288 * @return the AutomationCompositionElementInfo
290 public AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
291 var elementInfo = new AutomationCompositionElementInfo();
292 elementInfo.setAutomationCompositionElementId(element.getId());
293 elementInfo.setDeployState(element.getDeployState());
294 elementInfo.setLockState(element.getLockState());
295 elementInfo.setOperationalState(element.getOperationalState());
296 elementInfo.setUseState(element.getUseState());
297 elementInfo.setOutProperties(element.getOutProperties());
302 * Update Composition State for prime and deprime.
304 * @param compositionId the composition id
305 * @param state the Composition State
306 * @param stateChangeResult the indicator if error occurs
307 * @param message the message
309 public void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult,
311 if (compositionId == null) {
312 LOGGER.error("Cannot update Automation composition definition state, id is null");
316 if (stateChangeResult == null) {
317 LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is null");
320 if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
321 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
322 LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is not valid");
326 if ((state == null) || AcTypeState.PRIMING.equals(state) || AcTypeState.DEPRIMING.equals(state)) {
327 LOGGER.error("state invalid {} cannot be handled", state);
331 var participantPrimeAck = new ParticipantPrimeAck();
332 participantPrimeAck.setCompositionId(compositionId);
333 participantPrimeAck.setMessage(AcmUtils.validatedMessage(message));
334 participantPrimeAck.setResult(true);
335 participantPrimeAck.setResponseTo(cacheProvider.getMsgIdentification().get(compositionId));
336 participantPrimeAck.setCompositionState(state);
337 participantPrimeAck.setStateChangeResult(stateChangeResult);
338 participantPrimeAck.setParticipantId(cacheProvider.getParticipantId());
339 participantPrimeAck.setReplicaId(cacheProvider.getReplicaId());
340 participantPrimeAck.setState(ParticipantState.ON_LINE);
341 publisher.sendParticipantPrimeAck(participantPrimeAck);
342 cacheProvider.getMsgIdentification().remove(compositionId);
343 if (AcTypeState.COMMISSIONED.equals(state) && StateChangeResult.NO_ERROR.equals(stateChangeResult)) {
344 cacheProvider.removeElementDefinition(compositionId);
349 * Send Composition Definition Info.
351 * @param compositionId the composition id
352 * @param elementId the Composition Definition Element id
353 * @param outProperties the output Properties Map
355 public void sendAcDefinitionInfo(UUID compositionId, ToscaConceptIdentifier elementId,
356 Map<String, Object> outProperties) {
357 if (compositionId == null) {
358 LOGGER.error("Cannot send Composition outProperties, id is null");
361 var statusMsg = createParticipantStatus();
362 statusMsg.setCompositionId(compositionId);
363 var acElementDefsMap = cacheProvider.getAcElementsDefinitions();
364 var acElementsDefinitions = acElementDefsMap.get(compositionId);
365 if (acElementsDefinitions == null) {
366 LOGGER.error("Cannot send Composition outProperties, id {} is null", compositionId);
369 var acElementDefinition = getAutomationCompositionElementDefinition(acElementsDefinitions, elementId);
370 if (acElementDefinition == null) {
371 LOGGER.error("Cannot send Composition outProperties, elementId {} not present", elementId);
374 acElementDefinition.setOutProperties(outProperties);
375 var participantDefinition = new ParticipantDefinition();
376 participantDefinition.setParticipantId(cacheProvider.getParticipantId());
377 participantDefinition.setAutomationCompositionElementDefinitionList(List.of(acElementDefinition));
378 statusMsg.setParticipantDefinitionUpdates(List.of(participantDefinition));
379 publisher.sendParticipantStatus(statusMsg);
382 private AutomationCompositionElementDefinition getAutomationCompositionElementDefinition(
383 Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> acElementsDefinition,
384 ToscaConceptIdentifier elementId) {
386 if (elementId == null) {
387 if (acElementsDefinition.size() == 1) {
388 return acElementsDefinition.values().iterator().next();
392 return acElementsDefinition.get(elementId);
395 private ParticipantStatus createParticipantStatus() {
396 var statusMsg = new ParticipantStatus();
397 statusMsg.setParticipantId(cacheProvider.getParticipantId());
398 statusMsg.setReplicaId(cacheProvider.getReplicaId());
399 statusMsg.setState(ParticipantState.ON_LINE);
400 statusMsg.setParticipantSupportedElementType(cacheProvider.getSupportedAcElementTypes());