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             if (!StateChangeResult.FAILED.equals(stateChangeResult)) {
 
 164                 element.setSubState(SubState.NONE);
 
 166         } else if (deployState != null) {
 
 167             element.setDeployState(deployState);
 
 168             element.setLockState(
 
 169                     DeployState.DEPLOYED.equals(element.getDeployState()) ? LockState.LOCKED : LockState.NONE);
 
 171         if (lockState != null) {
 
 172             element.setLockState(lockState);
 
 175         var acStateChangeAck = createAutomationCompositionDeployAck();
 
 176         acStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
 
 177         acStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
 
 178         acStateChangeAck.setStateChangeResult(stateChangeResult);
 
 179         acStateChangeAck.setAutomationCompositionId(instance);
 
 180         acStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
 
 181                 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
 
 182                         element.getUseState(), element.getOutProperties(), true, message));
 
 183         LOGGER.debug(MSG_STATE_CHANGE, elementId, deployState);
 
 184         publisher.sendAutomationCompositionAck(acStateChangeAck);
 
 185         cacheProvider.getMsgIdentification().remove(element.getId());
 
 188     private void checkElement(AutomationComposition automationComposition, UUID instance, UUID elementId,
 
 189             DeployState deployState, StateChangeResult stateChangeResult, String message) {
 
 190         if ((DeployState.MIGRATING.equals(automationComposition.getDeployState())
 
 191                 || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState()))) {
 
 192             var acStateChangeAck = createAutomationCompositionDeployAck();
 
 193             acStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
 
 194             acStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(elementId));
 
 195             acStateChangeAck.setStateChangeResult(stateChangeResult);
 
 196             acStateChangeAck.setAutomationCompositionId(instance);
 
 197             acStateChangeAck.getAutomationCompositionResultMap().put(elementId,
 
 198                     new AcElementDeployAck(deployState, LockState.NONE, null,
 
 199                             null, Map.of(), true, message));
 
 200             LOGGER.debug(MSG_STATE_CHANGE, elementId, deployState);
 
 201             publisher.sendAutomationCompositionAck(acStateChangeAck);
 
 202             cacheProvider.getMsgIdentification().remove(elementId);
 
 204             LOGGER.error(MSG_NOT_PRESENT, "state", MSG_AC_ELEMENT, elementId);
 
 208     private AutomationCompositionDeployAck createAutomationCompositionDeployAck() {
 
 209         var acStateChangeAck =
 
 210                 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
 
 211         acStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
 
 212         acStateChangeAck.setReplicaId(cacheProvider.getReplicaId());
 
 213         acStateChangeAck.setResult(true);
 
 214         return acStateChangeAck;
 
 218      * Send Ac Element Info.
 
 220      * @param automationCompositionId the automationComposition Id
 
 221      * @param elementId the automationComposition Element id
 
 222      * @param useState the use State
 
 223      * @param operationalState the operational State
 
 224      * @param outProperties the output Properties Map
 
 226     public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
 
 227             String operationalState, Map<String, Object> outProperties) {
 
 229         if (automationCompositionId == null || elementId == null) {
 
 230             LOGGER.error("Cannot update Automation composition element state, id is null");
 
 234         var automationComposition = cacheProvider.getAutomationComposition(automationCompositionId);
 
 235         if (automationComposition == null) {
 
 236             LOGGER.error(MSG_NOT_PRESENT, "outProperites", MSG_AC, automationCompositionId);
 
 240         var element = automationComposition.getElements().get(elementId);
 
 241         if (element == null) {
 
 242             LOGGER.error(MSG_NOT_PRESENT, "outProperites", MSG_AC_ELEMENT, elementId);
 
 245         element.setOperationalState(operationalState);
 
 246         element.setUseState(useState);
 
 247         element.setOutProperties(outProperties);
 
 249         var acInfo = new AutomationCompositionInfo();
 
 250         acInfo.setAutomationCompositionId(automationCompositionId);
 
 251         acInfo.setDeployState(automationComposition.getDeployState());
 
 252         acInfo.setLockState(automationComposition.getLockState());
 
 253         acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
 
 254         var statusMsg = createParticipantStatus();
 
 255         statusMsg.setCompositionId(automationComposition.getCompositionId());
 
 256         statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
 
 257         publisher.sendParticipantStatus(statusMsg);
 
 261      * Get AutomationCompositionElementInfo from AutomationCompositionElement.
 
 263      * @param element the AutomationCompositionElement
 
 264      * @return the AutomationCompositionElementInfo
 
 266     public AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
 
 267         var elementInfo = new AutomationCompositionElementInfo();
 
 268         elementInfo.setAutomationCompositionElementId(element.getId());
 
 269         elementInfo.setDeployState(element.getDeployState());
 
 270         elementInfo.setLockState(element.getLockState());
 
 271         elementInfo.setOperationalState(element.getOperationalState());
 
 272         elementInfo.setUseState(element.getUseState());
 
 273         elementInfo.setOutProperties(element.getOutProperties());
 
 278      * Update Composition State for prime and deprime.
 
 280      * @param compositionId the composition id
 
 281      * @param state the Composition State
 
 282      * @param stateChangeResult the indicator if error occurs
 
 283      * @param message the message
 
 285     public void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult,
 
 287         if (compositionId == null) {
 
 288             LOGGER.error("Cannot update Automation composition definition state, id is null");
 
 292         if (stateChangeResult == null) {
 
 293             LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is null");
 
 296         if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
 
 297                 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
 
 298             LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is not valid");
 
 302         if ((state == null) || AcTypeState.PRIMING.equals(state) || AcTypeState.DEPRIMING.equals(state)) {
 
 303             LOGGER.error("state invalid {} cannot be handled", state);
 
 307         var participantPrimeAck = new ParticipantPrimeAck();
 
 308         participantPrimeAck.setCompositionId(compositionId);
 
 309         participantPrimeAck.setMessage(AcmUtils.validatedMessage(message));
 
 310         participantPrimeAck.setResult(true);
 
 311         participantPrimeAck.setResponseTo(cacheProvider.getMsgIdentification().get(compositionId));
 
 312         participantPrimeAck.setCompositionState(state);
 
 313         participantPrimeAck.setStateChangeResult(stateChangeResult);
 
 314         participantPrimeAck.setParticipantId(cacheProvider.getParticipantId());
 
 315         participantPrimeAck.setReplicaId(cacheProvider.getReplicaId());
 
 316         participantPrimeAck.setState(ParticipantState.ON_LINE);
 
 317         publisher.sendParticipantPrimeAck(participantPrimeAck);
 
 318         cacheProvider.getMsgIdentification().remove(compositionId);
 
 319         if (AcTypeState.COMMISSIONED.equals(state) && StateChangeResult.NO_ERROR.equals(stateChangeResult)) {
 
 320             cacheProvider.removeElementDefinition(compositionId);
 
 325      * Send Composition Definition Info.
 
 327      * @param compositionId the composition id
 
 328      * @param elementId the Composition Definition Element id
 
 329      * @param outProperties the output Properties Map
 
 331     public void sendAcDefinitionInfo(UUID compositionId, ToscaConceptIdentifier elementId,
 
 332             Map<String, Object> outProperties) {
 
 333         if (compositionId == null) {
 
 334             LOGGER.error("Cannot send Composition outProperties, id is null");
 
 337         var statusMsg = createParticipantStatus();
 
 338         statusMsg.setCompositionId(compositionId);
 
 339         var acElementDefsMap = cacheProvider.getAcElementsDefinitions();
 
 340         var acDefinition = acElementDefsMap.get(compositionId);
 
 341         if (acDefinition == null) {
 
 342             LOGGER.error("Cannot send Composition outProperties, id {} is null", compositionId);
 
 345         var acElementDefinition = getAutomationCompositionElementDefinition(acDefinition, elementId);
 
 346         if (acElementDefinition == null) {
 
 347             LOGGER.error("Cannot send Composition outProperties, elementId {} not present", elementId);
 
 350         acElementDefinition.setOutProperties(outProperties);
 
 351         var participantDefinition = new ParticipantDefinition();
 
 352         participantDefinition.setParticipantId(cacheProvider.getParticipantId());
 
 353         participantDefinition.setAutomationCompositionElementDefinitionList(List.of(acElementDefinition));
 
 354         statusMsg.setParticipantDefinitionUpdates(List.of(participantDefinition));
 
 355         publisher.sendParticipantStatus(statusMsg);
 
 358     private AutomationCompositionElementDefinition getAutomationCompositionElementDefinition(
 
 359             AcDefinition acElementsDefinition,
 
 360             ToscaConceptIdentifier elementId) {
 
 362         if (elementId == null) {
 
 363             if (acElementsDefinition.getElements().size() == 1) {
 
 364                 return acElementsDefinition.getElements().values().iterator().next();
 
 368         return acElementsDefinition.getElements().get(elementId);
 
 371     private ParticipantStatus createParticipantStatus() {
 
 372         var statusMsg = new ParticipantStatus();
 
 373         statusMsg.setParticipantId(cacheProvider.getParticipantId());
 
 374         statusMsg.setReplicaId(cacheProvider.getReplicaId());
 
 375         statusMsg.setState(ParticipantState.ON_LINE);
 
 376         statusMsg.setParticipantSupportedElementType(cacheProvider.getSupportedAcElementTypes());