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.acm.participant.intermediary.handler.cache.AcDefinition;
29 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.CacheProvider;
30 import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck;
31 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
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.AutomationCompositionElementDefinition;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo;
37 import org.onap.policy.clamp.models.acm.concepts.DeployState;
38 import org.onap.policy.clamp.models.acm.concepts.LockState;
39 import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
40 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
41 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
42 import org.onap.policy.clamp.models.acm.concepts.SubState;
43 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
44 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
45 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck;
46 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus;
47 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.springframework.stereotype.Component;
54 @RequiredArgsConstructor
55 public class AutomationCompositionOutHandler {
56 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionOutHandler.class);
57 private static final String MSG_NOT_PRESENT
58 = "Cannot update Automation composition element {}, {} id {} not present";
59 private static final String MSG_STATE_CHANGE = "Automation composition element {} state changed to {}";
60 private static final String MSG_AC = "Automation composition";
61 private static final String MSG_AC_ELEMENT = "AC Element";
62 private static final String MSG_STAGE = "stage";
64 private final ParticipantMessagePublisher publisher;
65 private final CacheProvider cacheProvider;
68 * Handle a automation composition element stage change message.
70 * @param instance the automationComposition Id
71 * @param elementId the automationComposition Element Id
72 * @param stage the next stage
73 * @param message the message
74 * @param stateChangeResult the indicator if error occurs
76 public void updateAutomationCompositionElementStage(UUID instance, UUID elementId,
77 StateChangeResult stateChangeResult, int stage, String message) {
78 if (!validateData(instance, elementId, stateChangeResult)) {
82 var automationComposition = cacheProvider.getAutomationComposition(instance);
83 if (automationComposition == null) {
84 LOGGER.error(MSG_NOT_PRESENT, MSG_STAGE, MSG_AC, instance);
88 var element = automationComposition.getElements().get(elementId);
89 if (element == null) {
90 LOGGER.error(MSG_NOT_PRESENT, MSG_STAGE, MSG_AC_ELEMENT, elementId);
94 var automationCompositionStateChangeAck =
95 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
96 automationCompositionStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
97 automationCompositionStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
98 automationCompositionStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
99 automationCompositionStateChangeAck.setStateChangeResult(stateChangeResult);
100 automationCompositionStateChangeAck.setStage(stage);
101 automationCompositionStateChangeAck.setAutomationCompositionId(instance);
102 automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
103 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
104 element.getUseState(), element.getOutProperties(), true, message));
105 LOGGER.debug("Automation composition element {} stage changed to {}", elementId, stage);
106 automationCompositionStateChangeAck.setResult(true);
107 publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
108 cacheProvider.getMsgIdentification().remove(element.getId());
111 private boolean validateData(UUID instance, UUID elementId, StateChangeResult stateChangeResult) {
112 if (instance == null || elementId == null) {
113 LOGGER.error("Not valid Ac instance, id is null");
116 if (stateChangeResult == null) {
117 LOGGER.error("Not valid Ac instance, stateChangeResult is null");
120 if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
121 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
122 LOGGER.error("Not valid Ac instance, stateChangeResult is not valid");
129 * Handle a automation composition element state change message.
131 * @param instance the automationComposition Id
132 * @param elementId the automationComposition Element Id
133 * @param deployState the DeployState state
134 * @param lockState the LockState state
135 * @param message the message
136 * @param stateChangeResult the indicator if error occurs
138 public void updateAutomationCompositionElementState(UUID instance, UUID elementId,
139 DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message) {
140 if (!validateData(instance, elementId, stateChangeResult)) {
144 if ((deployState != null && lockState != null) || (deployState == null && lockState == null)
145 || AcmUtils.isInTransitionalState(deployState, lockState, SubState.NONE)) {
146 LOGGER.error("state error {} and {} cannot be handled", deployState, lockState);
150 var automationComposition = cacheProvider.getAutomationComposition(instance);
151 if (automationComposition == null) {
152 LOGGER.error(MSG_NOT_PRESENT, "state", MSG_AC, instance);
156 var element = automationComposition.getElements().get(elementId);
157 if (element == null) {
158 checkElement(automationComposition, instance, elementId, deployState, stateChangeResult, message);
162 if (!SubState.NONE.equals(element.getSubState())) {
163 handleSubState(automationComposition, element, stateChangeResult);
164 } else if (deployState != null) {
165 handleDeployState(automationComposition, element, deployState, stateChangeResult);
167 if (lockState != null) {
168 handleLockState(automationComposition, element, lockState, stateChangeResult);
171 var acStateChangeAck = createAutomationCompositionDeployAck();
172 acStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
173 acStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
174 acStateChangeAck.setStateChangeResult(stateChangeResult);
175 acStateChangeAck.setAutomationCompositionId(instance);
176 acStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
177 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
178 element.getUseState(), element.getOutProperties(), true, message));
179 LOGGER.debug(MSG_STATE_CHANGE, elementId, deployState);
180 publisher.sendAutomationCompositionAck(acStateChangeAck);
181 cacheProvider.getMsgIdentification().remove(element.getId());
184 private void checkElement(AutomationComposition automationComposition, UUID instance, UUID elementId,
185 DeployState deployState, StateChangeResult stateChangeResult, String message) {
186 if ((DeployState.MIGRATING.equals(automationComposition.getDeployState())
187 || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState()))) {
188 var acStateChangeAck = createAutomationCompositionDeployAck();
189 acStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
190 acStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(elementId));
191 acStateChangeAck.setStateChangeResult(stateChangeResult);
192 acStateChangeAck.setAutomationCompositionId(instance);
193 acStateChangeAck.getAutomationCompositionResultMap().put(elementId,
194 new AcElementDeployAck(deployState, null, null,
195 null, Map.of(), true, message));
196 LOGGER.debug(MSG_STATE_CHANGE, elementId, deployState);
197 publisher.sendAutomationCompositionAck(acStateChangeAck);
198 cacheProvider.getMsgIdentification().remove(elementId);
200 LOGGER.error(MSG_NOT_PRESENT, "state", MSG_AC_ELEMENT, elementId);
204 private AutomationCompositionDeployAck createAutomationCompositionDeployAck() {
205 var acStateChangeAck =
206 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
207 acStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
208 acStateChangeAck.setReplicaId(cacheProvider.getReplicaId());
209 acStateChangeAck.setResult(true);
210 return acStateChangeAck;
213 private void handleDeployState(AutomationComposition automationComposition, AutomationCompositionElement element,
214 DeployState deployState, StateChangeResult stateChangeResult) {
215 element.setDeployState(deployState);
216 element.setLockState(DeployState.DEPLOYED.equals(element.getDeployState()) ? LockState.LOCKED : LockState.NONE);
217 if (StateChangeResult.FAILED.equals(stateChangeResult)) {
220 var checkOpt = automationComposition.getElements().values().stream()
221 .filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
222 if (checkOpt.isEmpty()) {
223 if (DeployState.DEPLOYED.equals(automationComposition.getDeployState())
224 && automationComposition.getCompositionTargetId() != null) {
225 // migration scenario
226 automationComposition.setCompositionId(automationComposition.getCompositionTargetId());
227 automationComposition.setCompositionTargetId(null);
229 automationComposition.setDeployState(deployState);
230 automationComposition.setLockState(element.getLockState());
231 automationComposition.setSubState(SubState.NONE);
233 if (DeployState.DELETED.equals(deployState)) {
234 cacheProvider.removeAutomationComposition(automationComposition.getInstanceId());
239 private void handleLockState(AutomationComposition automationComposition, AutomationCompositionElement element,
240 LockState lockState, StateChangeResult stateChangeResult) {
241 element.setLockState(lockState);
242 if (StateChangeResult.FAILED.equals(stateChangeResult)) {
245 var checkOpt = automationComposition.getElements().values().stream()
246 .filter(acElement -> !lockState.equals(acElement.getLockState())).findAny();
247 if (checkOpt.isEmpty()) {
248 automationComposition.setLockState(lockState);
249 automationComposition.setSubState(SubState.NONE);
253 private void handleSubState(AutomationComposition automationComposition, AutomationCompositionElement element,
254 StateChangeResult stateChangeResult) {
255 if (StateChangeResult.FAILED.equals(stateChangeResult)) {
258 element.setSubState(SubState.NONE);
259 var checkOpt = automationComposition.getElements().values().stream()
260 .filter(acElement -> !SubState.NONE.equals(acElement.getSubState())).findAny();
261 if (checkOpt.isEmpty()) {
262 automationComposition.setSubState(SubState.NONE);
267 * Send Ac Element Info.
269 * @param automationCompositionId the automationComposition Id
270 * @param elementId the automationComposition Element id
271 * @param useState the use State
272 * @param operationalState the operational State
273 * @param outProperties the output Properties Map
275 public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
276 String operationalState, Map<String, Object> outProperties) {
278 if (automationCompositionId == null || elementId == null) {
279 LOGGER.error("Cannot update Automation composition element state, id is null");
283 var automationComposition = cacheProvider.getAutomationComposition(automationCompositionId);
284 if (automationComposition == null) {
285 LOGGER.error(MSG_NOT_PRESENT, "outProperites", MSG_AC, automationCompositionId);
289 var element = automationComposition.getElements().get(elementId);
290 if (element == null) {
291 LOGGER.error(MSG_NOT_PRESENT, "outProperites", MSG_AC_ELEMENT, elementId);
294 element.setOperationalState(operationalState);
295 element.setUseState(useState);
296 element.setOutProperties(outProperties);
298 var acInfo = new AutomationCompositionInfo();
299 acInfo.setAutomationCompositionId(automationCompositionId);
300 acInfo.setDeployState(automationComposition.getDeployState());
301 acInfo.setLockState(automationComposition.getLockState());
302 acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
303 var statusMsg = createParticipantStatus();
304 statusMsg.setCompositionId(automationComposition.getCompositionId());
305 statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
306 publisher.sendParticipantStatus(statusMsg);
310 * Get AutomationCompositionElementInfo from AutomationCompositionElement.
312 * @param element the AutomationCompositionElement
313 * @return the AutomationCompositionElementInfo
315 public AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
316 var elementInfo = new AutomationCompositionElementInfo();
317 elementInfo.setAutomationCompositionElementId(element.getId());
318 elementInfo.setDeployState(element.getDeployState());
319 elementInfo.setLockState(element.getLockState());
320 elementInfo.setOperationalState(element.getOperationalState());
321 elementInfo.setUseState(element.getUseState());
322 elementInfo.setOutProperties(element.getOutProperties());
327 * Update Composition State for prime and deprime.
329 * @param compositionId the composition id
330 * @param state the Composition State
331 * @param stateChangeResult the indicator if error occurs
332 * @param message the message
334 public void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult,
336 if (compositionId == null) {
337 LOGGER.error("Cannot update Automation composition definition state, id is null");
341 if (stateChangeResult == null) {
342 LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is null");
345 if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
346 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
347 LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is not valid");
351 if ((state == null) || AcTypeState.PRIMING.equals(state) || AcTypeState.DEPRIMING.equals(state)) {
352 LOGGER.error("state invalid {} cannot be handled", state);
356 var participantPrimeAck = new ParticipantPrimeAck();
357 participantPrimeAck.setCompositionId(compositionId);
358 participantPrimeAck.setMessage(AcmUtils.validatedMessage(message));
359 participantPrimeAck.setResult(true);
360 participantPrimeAck.setResponseTo(cacheProvider.getMsgIdentification().get(compositionId));
361 participantPrimeAck.setCompositionState(state);
362 participantPrimeAck.setStateChangeResult(stateChangeResult);
363 participantPrimeAck.setParticipantId(cacheProvider.getParticipantId());
364 participantPrimeAck.setReplicaId(cacheProvider.getReplicaId());
365 participantPrimeAck.setState(ParticipantState.ON_LINE);
366 publisher.sendParticipantPrimeAck(participantPrimeAck);
367 cacheProvider.getMsgIdentification().remove(compositionId);
368 if (AcTypeState.COMMISSIONED.equals(state) && StateChangeResult.NO_ERROR.equals(stateChangeResult)) {
369 cacheProvider.removeElementDefinition(compositionId);
374 * Send Composition Definition Info.
376 * @param compositionId the composition id
377 * @param elementId the Composition Definition Element id
378 * @param outProperties the output Properties Map
380 public void sendAcDefinitionInfo(UUID compositionId, ToscaConceptIdentifier elementId,
381 Map<String, Object> outProperties) {
382 if (compositionId == null) {
383 LOGGER.error("Cannot send Composition outProperties, id is null");
386 var statusMsg = createParticipantStatus();
387 statusMsg.setCompositionId(compositionId);
388 var acElementDefsMap = cacheProvider.getAcElementsDefinitions();
389 var acDefinition = acElementDefsMap.get(compositionId);
390 if (acDefinition == null) {
391 LOGGER.error("Cannot send Composition outProperties, id {} is null", compositionId);
394 var acElementDefinition = getAutomationCompositionElementDefinition(acDefinition, elementId);
395 if (acElementDefinition == null) {
396 LOGGER.error("Cannot send Composition outProperties, elementId {} not present", elementId);
399 acElementDefinition.setOutProperties(outProperties);
400 var participantDefinition = new ParticipantDefinition();
401 participantDefinition.setParticipantId(cacheProvider.getParticipantId());
402 participantDefinition.setAutomationCompositionElementDefinitionList(List.of(acElementDefinition));
403 statusMsg.setParticipantDefinitionUpdates(List.of(participantDefinition));
404 publisher.sendParticipantStatus(statusMsg);
407 private AutomationCompositionElementDefinition getAutomationCompositionElementDefinition(
408 AcDefinition acElementsDefinition,
409 ToscaConceptIdentifier elementId) {
411 if (elementId == null) {
412 if (acElementsDefinition.getElements().size() == 1) {
413 return acElementsDefinition.getElements().values().iterator().next();
417 return acElementsDefinition.getElements().get(elementId);
420 private ParticipantStatus createParticipantStatus() {
421 var statusMsg = new ParticipantStatus();
422 statusMsg.setParticipantId(cacheProvider.getParticipantId());
423 statusMsg.setReplicaId(cacheProvider.getReplicaId());
424 statusMsg.setState(ParticipantState.ON_LINE);
425 statusMsg.setParticipantSupportedElementType(cacheProvider.getSupportedAcElementTypes());