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);
 
  58     private final ParticipantMessagePublisher publisher;
 
  59     private final CacheProvider cacheProvider;
 
  62      * Handle a automation composition element stage change message.
 
  64      * @param instance the automationComposition Id
 
  65      * @param elementId the automationComposition Element Id
 
  66      * @param stage the next stage
 
  67      * @param message the message
 
  68      * @param stateChangeResult the indicator if error occurs
 
  70     public void updateAutomationCompositionElementStage(UUID instance, UUID elementId,
 
  71         StateChangeResult stateChangeResult, int stage, String message) {
 
  72         if (!validateData(instance, elementId, stateChangeResult)) {
 
  76         var automationComposition = cacheProvider.getAutomationComposition(instance);
 
  77         if (automationComposition == null) {
 
  78             LOGGER.error("Cannot update Automation composition element stage, Automation composition id {} not present",
 
  83         var element = automationComposition.getElements().get(elementId);
 
  84         if (element == null) {
 
  85             var msg = "Cannot update Automation composition element stage, AC Element id {} not present";
 
  86             LOGGER.error(msg, elementId);
 
  90         var automationCompositionStateChangeAck =
 
  91             new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
 
  92         automationCompositionStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
 
  93         automationCompositionStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
 
  94         automationCompositionStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
 
  95         automationCompositionStateChangeAck.setStateChangeResult(stateChangeResult);
 
  96         automationCompositionStateChangeAck.setStage(stage);
 
  97         automationCompositionStateChangeAck.setAutomationCompositionId(instance);
 
  98         automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
 
  99             new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
 
 100                 element.getUseState(), element.getOutProperties(), true, message));
 
 101         LOGGER.debug("Automation composition element {} stage changed to {}", elementId, stage);
 
 102         automationCompositionStateChangeAck.setResult(true);
 
 103         publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
 
 104         cacheProvider.getMsgIdentification().remove(element.getId());
 
 107     private boolean validateData(UUID instance, UUID elementId, StateChangeResult stateChangeResult) {
 
 108         if (instance == null || elementId == null) {
 
 109             LOGGER.error("Not valid Ac instance, id is null");
 
 112         if (stateChangeResult == null) {
 
 113             LOGGER.error("Not valid Ac instance, stateChangeResult is null");
 
 116         if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
 
 117                 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
 
 118             LOGGER.error("Not valid Ac instance, stateChangeResult is not valid");
 
 125      * Handle a automation composition element state change message.
 
 127      * @param instance the automationComposition Id
 
 128      * @param elementId the automationComposition Element Id
 
 129      * @param deployState the DeployState state
 
 130      * @param lockState the LockState state
 
 131      * @param message the message
 
 132      * @param stateChangeResult the indicator if error occurs
 
 134     public void updateAutomationCompositionElementState(UUID instance, UUID elementId,
 
 135             DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message) {
 
 136         if (!validateData(instance, elementId, stateChangeResult)) {
 
 140         if ((deployState != null && lockState != null) || (deployState == null && lockState == null)
 
 141                 || AcmUtils.isInTransitionalState(deployState, lockState, SubState.NONE)) {
 
 142             LOGGER.error("state error {} and {} cannot be handled", deployState, lockState);
 
 146         var automationComposition = cacheProvider.getAutomationComposition(instance);
 
 147         if (automationComposition == null) {
 
 148             LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
 
 153         var element = automationComposition.getElements().get(elementId);
 
 154         if (element == null) {
 
 155             var msg = "Cannot update Automation composition element state, AC Element id {} not present";
 
 156             LOGGER.error(msg, elementId);
 
 160         if (!SubState.NONE.equals(element.getSubState())) {
 
 161             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 acDefinition = acElementDefsMap.get(compositionId);
 
 365         if (acDefinition == null) {
 
 366             LOGGER.error("Cannot send Composition outProperties, id {} is null", compositionId);
 
 369         var acElementDefinition = getAutomationCompositionElementDefinition(acDefinition, 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             AcDefinition acElementsDefinition,
 
 384             ToscaConceptIdentifier elementId) {
 
 386         if (elementId == null) {
 
 387             if (acElementsDefinition.getElements().size() == 1) {
 
 388                 return acElementsDefinition.getElements().values().iterator().next();
 
 392         return acElementsDefinition.getElements().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());