2  * ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2024-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.sim.main.handler;
 
  23 import java.util.ArrayList;
 
  24 import java.util.List;
 
  26 import java.util.UUID;
 
  27 import java.util.concurrent.locks.LockSupport;
 
  29 import lombok.RequiredArgsConstructor;
 
  31 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto;
 
  32 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
 
  33 import org.onap.policy.clamp.acm.participant.sim.model.InternalData;
 
  34 import org.onap.policy.clamp.acm.participant.sim.model.InternalDatas;
 
  35 import org.onap.policy.clamp.acm.participant.sim.model.SimConfig;
 
  36 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 
  37 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
 
  38 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
 
  39 import org.onap.policy.clamp.models.acm.concepts.DeployState;
 
  40 import org.onap.policy.clamp.models.acm.concepts.LockState;
 
  41 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
 
  42 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 
  43 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
 
  44 import org.slf4j.Logger;
 
  45 import org.slf4j.LoggerFactory;
 
  46 import org.springframework.stereotype.Service;
 
  49  * This class handles implementation of Simulator Service.
 
  52 @RequiredArgsConstructor
 
  53 public class SimulatorService {
 
  55     private final ParticipantIntermediaryApi intermediaryApi;
 
  57     private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorService.class);
 
  58     private static final String INTERNAL_STATE = "InternalState";
 
  59     private static final String MIGRATION_PROPERTY = "stage";
 
  60     private static final String PREPARE_PROPERTY = "prepareStage";
 
  64     private SimConfig config = new SimConfig();
 
  67      * Get AutomationComposition.
 
  69      * @return the AutomationCompositions
 
  71     public AutomationCompositions getAutomationCompositions() {
 
  72         var result = new AutomationCompositions();
 
  73         result.setAutomationCompositionList(new ArrayList<>(intermediaryApi.getAutomationCompositions().values()));
 
  77     public AutomationComposition getAutomationComposition(UUID instanceId) {
 
  78         return intermediaryApi.getAutomationComposition(instanceId);
 
  84      * @param instanceId       the automationComposition Id
 
  85      * @param elementId        the automationComposition Element Id
 
  86      * @param useState         the useState
 
  87      * @param operationalState the operationalState
 
  88      * @param outProperties    the outProperties
 
  90     public void setOutProperties(UUID instanceId, UUID elementId, String useState, String operationalState,
 
  91                                  Map<String, Object> outProperties) {
 
  92         intermediaryApi.sendAcElementInfo(instanceId, elementId, useState, operationalState,
 
  97      * Get Instance Data List.
 
  99      * @return the InternalDatas
 
 101     public InternalDatas getDataList() {
 
 102         var result = new InternalDatas();
 
 103         var map = intermediaryApi.getAutomationCompositions();
 
 104         for (var instance : map.values()) {
 
 105             for (var element : instance.getElements().values()) {
 
 106                 var data = new InternalData();
 
 107                 data.setCompositionId(instance.getCompositionId());
 
 108                 data.setAutomationCompositionId(instance.getInstanceId());
 
 109                 data.setAutomationCompositionElementId(element.getId());
 
 110                 data.setIntProperties(element.getProperties());
 
 111                 data.setOperationalState(element.getOperationalState());
 
 112                 data.setUseState(element.getUseState());
 
 113                 data.setOutProperties(element.getOutProperties());
 
 114                 result.getList().add(data);
 
 121      * Get Composition Data List.
 
 123      * @return the InternalDatas
 
 125     public InternalDatas getCompositionDataList() {
 
 126         var acElementsDefinitions = intermediaryApi.getAcElementsDefinitions();
 
 127         var internalDatas = new InternalDatas();
 
 128         for (var entry : acElementsDefinitions.entrySet()) {
 
 129             for (var acElementsDefinition : entry.getValue().values()) {
 
 130                 var internalData = new InternalData();
 
 131                 internalData.setCompositionId(entry.getKey());
 
 132                 internalData.setCompositionDefinitionElementId(acElementsDefinition.getAcElementDefinitionId());
 
 133                 internalData.setIntProperties(
 
 134                     acElementsDefinition.getAutomationCompositionElementToscaNodeTemplate().getProperties());
 
 135                 internalData.setOutProperties(acElementsDefinition.getOutProperties());
 
 136                 internalDatas.getList().add(internalData);
 
 139         return internalDatas;
 
 142     public void setCompositionOutProperties(UUID compositionId, ToscaConceptIdentifier compositionDefinitionElementId,
 
 143                                             Map<String, Object> outProperties) {
 
 144         intermediaryApi.sendAcDefinitionInfo(compositionId, compositionDefinitionElementId, outProperties);
 
 148     protected boolean isInterrupted(int timeMs, String msg, UUID elementId) {
 
 149         long endTime = System.nanoTime() + (timeMs * 1_000_000L);
 
 150         while (System.nanoTime() < endTime) {
 
 151             if (Thread.interrupted()) {
 
 152                 LOGGER.debug(msg, elementId);
 
 155             LockSupport.parkNanos(10_000_000L);
 
 160     private void sendAcInternalState(UUID instanceId, UUID elementId, Map<String, Object> outProperties,
 
 161             DeployState deployState) {
 
 162         outProperties.put(INTERNAL_STATE, deployState.name());
 
 163         intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
 
 167      * Handle deploying an automation composition element.
 
 169      * @param instanceId    the instanceId
 
 170      * @param elementId     the elementId
 
 171      * @param outProperties the outProperties
 
 173     public void deploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
 
 174         sendAcInternalState(instanceId, elementId, outProperties, DeployState.DEPLOYING);
 
 176         if (isInterrupted(getConfig().getDeployTimerMs(),
 
 177             "Current Thread deploy is Interrupted during execution {}", elementId)) {
 
 181         if (getConfig().isDeploySuccess()) {
 
 182             sendAcInternalState(instanceId, elementId, outProperties, DeployState.DEPLOYED);
 
 184             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 185                 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
 
 187             sendAcInternalState(instanceId, elementId, outProperties, DeployState.UNDEPLOYED);
 
 189             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 190                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
 
 195      * Handle undeploying an automation composition element.
 
 197      * @param instanceId    the instanceId
 
 198      * @param elementId     the elementId
 
 199      * @param outProperties the outProperties
 
 201     public void undeploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
 
 202         sendAcInternalState(instanceId, elementId, outProperties, DeployState.UNDEPLOYING);
 
 204         if (isInterrupted(getConfig().getUndeployTimerMs(),
 
 205             "Current Thread undeploy is Interrupted during execution {}", elementId)) {
 
 209         if (getConfig().isUndeploySuccess()) {
 
 210             sendAcInternalState(instanceId, elementId, outProperties, DeployState.UNDEPLOYED);
 
 212             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 213                 DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
 
 215             sendAcInternalState(instanceId, elementId, outProperties, DeployState.DEPLOYED);
 
 217             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 218                 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Undeploy failed!");
 
 223      * Handle locking an automation composition element.
 
 225      * @param instanceId the instanceId
 
 226      * @param elementId  the elementId
 
 228     public void lock(UUID instanceId, UUID elementId) {
 
 229         if (isInterrupted(getConfig().getLockTimerMs(),
 
 230             "Current Thread lock is Interrupted during execution {}", elementId)) {
 
 234         if (getConfig().isLockSuccess()) {
 
 235             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 236                 null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
 
 238             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 239                 null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
 
 244      * Handle unlocking an automation composition element.
 
 246      * @param instanceId the instanceId
 
 247      * @param elementId  the elementId
 
 249     public void unlock(UUID instanceId, UUID elementId) {
 
 250         if (isInterrupted(getConfig().getUnlockTimerMs(),
 
 251             "Current Thread unlock is Interrupted during execution {}", elementId)) {
 
 255         if (getConfig().isUnlockSuccess()) {
 
 256             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 257                 null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
 
 259             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 260                 null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
 
 265      * Handle deleting an automation composition element.
 
 267      * @param instanceId the instanceId
 
 268      * @param elementId  the elementId
 
 270     public void delete(UUID instanceId, UUID elementId) {
 
 271         if (isInterrupted(getConfig().getDeleteTimerMs(),
 
 272             "Current Thread delete is Interrupted during execution {}", elementId)) {
 
 276         if (getConfig().isDeleteSuccess()) {
 
 277             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 278                 DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
 
 280             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 281                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Delete failed!");
 
 286      * Handle an update on an automation composition element.
 
 288      * @param instanceId the instanceId
 
 289      * @param elementId  the elementId
 
 291     public void update(UUID instanceId, UUID elementId) {
 
 292         if (isInterrupted(getConfig().getUpdateTimerMs(),
 
 293             "Current Thread update is Interrupted during execution {}", elementId)) {
 
 297         if (getConfig().isUpdateSuccess()) {
 
 298             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 299                 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
 
 301             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 302                 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
 
 307      * Handle a prime on an automation composition definition.
 
 309      * @param composition the information of the Automation Composition Definition
 
 311     public void prime(CompositionDto composition) {
 
 312         if (isInterrupted(getConfig().getPrimeTimerMs(),
 
 313             "Current Thread prime is Interrupted during execution {}", composition.compositionId())) {
 
 317         if (getConfig().isPrimeSuccess()) {
 
 318             sendOutProperties(composition, AcTypeState.PRIMED.name());
 
 319             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
 
 320                 StateChangeResult.NO_ERROR, "Primed");
 
 322             sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
 
 323             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
 
 324                 StateChangeResult.FAILED, "Prime failed!");
 
 328     private void sendOutProperties(CompositionDto composition, String data) {
 
 329         for (var elementEntry : composition.outPropertiesMap().entrySet()) {
 
 330             elementEntry.getValue().put(INTERNAL_STATE, data);
 
 331             intermediaryApi.sendAcDefinitionInfo(
 
 332                 composition.compositionId(), elementEntry.getKey(), elementEntry.getValue());
 
 337      * Handle a deprime on an automation composition definition.
 
 339      * @param composition the information of the Automation Composition Definition
 
 341     public void deprime(CompositionDto composition) {
 
 342         if (isInterrupted(getConfig().getDeprimeTimerMs(),
 
 343             "Current Thread deprime is Interrupted during execution {}", composition.compositionId())) {
 
 347         if (getConfig().isDeprimeSuccess()) {
 
 348             sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
 
 349             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
 
 350                 StateChangeResult.NO_ERROR, "Deprimed");
 
 352             sendOutProperties(composition, AcTypeState.PRIMED.name());
 
 353             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
 
 354                 StateChangeResult.FAILED, "Deprime failed!");
 
 359      * Handle a migration on an automation composition element.
 
 361      * @param instanceId              the instanceId
 
 362      * @param elementId               the elementId
 
 363      * @param stage                   the stage
 
 364      * @param compositionInProperties in Properties from composition definition element
 
 365      * @param instanceOutProperties   in Properties from instance element
 
 367     public void migrate(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
 
 368                         Map<String, Object> instanceOutProperties) {
 
 369         if (isInterrupted(getConfig().getMigrateTimerMs(),
 
 370             "Current Thread migrate is Interrupted during execution {}", elementId)) {
 
 374         if (config.isMigrateSuccess()) {
 
 375             var stageSet = ParticipantUtils.findStageSetMigrate(compositionInProperties);
 
 376             var nextStage = 1000;
 
 377             for (var s : stageSet) {
 
 379                     nextStage = Math.min(s, nextStage);
 
 382             instanceOutProperties.putIfAbsent(MIGRATION_PROPERTY, new ArrayList<>());
 
 383             @SuppressWarnings("unchecked")
 
 384             var stageList = (List<Integer>) instanceOutProperties.get(MIGRATION_PROPERTY);
 
 385             stageList.add(stage);
 
 386             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
 
 387             if (nextStage == 1000) {
 
 388                 intermediaryApi.updateAutomationCompositionElementState(
 
 389                     instanceId, elementId,
 
 390                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
 
 392                 intermediaryApi.updateAutomationCompositionElementStage(
 
 393                     instanceId, elementId,
 
 394                     StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Migrated");
 
 397             intermediaryApi.updateAutomationCompositionElementState(
 
 398                 instanceId, elementId,
 
 399                 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migrate failed!");
 
 404      * Handle a Migrate Precheck on an automation composition element.
 
 406      * @param instanceId the instanceId
 
 407      * @param elementId  the elementId
 
 409     public void migratePrecheck(UUID instanceId, UUID elementId) {
 
 410         if (isInterrupted(config.getMigratePrecheckTimerMs(),
 
 411             "Current Thread migrate precheck is Interrupted during execution {}", elementId)) {
 
 415         if (config.isMigratePrecheck()) {
 
 416             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 417                 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migration precheck completed");
 
 419             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 420                 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration precheck failed");
 
 425      * Handle a Prepare on an automation composition element.
 
 427      * @param instanceId              the instanceId
 
 428      * @param elementId               the elementId
 
 429      * @param stage                   the stage
 
 430      * @param compositionInProperties in Properties from composition definition element
 
 431      * @param instanceOutProperties   in Properties from instance element
 
 433     public void prepare(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
 
 434                         Map<String, Object> instanceOutProperties) {
 
 435         if (isInterrupted(config.getPrepareTimerMs(),
 
 436             "Current Thread prepare is Interrupted during execution {}", elementId)) {
 
 440         if (config.isPrepare()) {
 
 441             var stageSet = ParticipantUtils.findStageSetPrepare(compositionInProperties);
 
 442             var nextStage = 1000;
 
 443             for (var s : stageSet) {
 
 445                     nextStage = Math.min(s, nextStage);
 
 448             instanceOutProperties.putIfAbsent(PREPARE_PROPERTY, new ArrayList<>());
 
 449             @SuppressWarnings("unchecked")
 
 450             var stageList = (List<Integer>) instanceOutProperties.get(PREPARE_PROPERTY);
 
 451             stageList.add(stage);
 
 452             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
 
 453             if (nextStage == 1000) {
 
 454                 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 455                     DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Prepare completed");
 
 457                 intermediaryApi.updateAutomationCompositionElementStage(
 
 458                     instanceId, elementId,
 
 459                     StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Prepared");
 
 462             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 463                 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Prepare failed");
 
 468      * Handle a Review on an automation composition element.
 
 470      * @param instanceId the instanceId
 
 471      * @param elementId  the elementId
 
 473     public void review(UUID instanceId, UUID elementId) {
 
 474         if (isInterrupted(config.getReviewTimerMs(),
 
 475             "Current Thread review is Interrupted during execution {}", elementId)) {
 
 479         if (config.isReview()) {
 
 480             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 481                 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Review completed");
 
 483             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
 
 484                 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Review failed");
 
 489      * Handle rollback of an automation composition.
 
 491      * @param instanceId AC instance ID
 
 492      * @param elementId  AC element ID
 
 494     public void rollback(UUID instanceId, UUID elementId) {
 
 495         if (isInterrupted(getConfig().getRollbackTimerMs(),
 
 496             "Current Thread for rollback was Interrupted during execution {}", instanceId)) {
 
 497             LOGGER.debug("Rollback interrupted");
 
 501         if (config.isRollback()) {
 
 502             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, DeployState.DEPLOYED, null,
 
 503                 StateChangeResult.NO_ERROR, "Migration rollback done");
 
 505             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, DeployState.DEPLOYED, null,
 
 506                 StateChangeResult.FAILED, "Migration rollback failed");