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 ROLLBACK_PROPERTY = "rollbackStage";
61 private static final String PREPARE_PROPERTY = "prepareStage";
62 private static final String STAGE_MSG = "stage %d %s";
66 private SimConfig config = new SimConfig();
69 * Get AutomationComposition.
71 * @return the AutomationCompositions
73 public AutomationCompositions getAutomationCompositions() {
74 var result = new AutomationCompositions();
75 result.setAutomationCompositionList(new ArrayList<>(intermediaryApi.getAutomationCompositions().values()));
79 public AutomationComposition getAutomationComposition(UUID instanceId) {
80 return intermediaryApi.getAutomationComposition(instanceId);
86 * @param instanceId the automationComposition Id
87 * @param elementId the automationComposition Element Id
88 * @param useState the useState
89 * @param operationalState the operationalState
90 * @param outProperties the outProperties
92 public void setOutProperties(UUID instanceId, UUID elementId, String useState, String operationalState,
93 Map<String, Object> outProperties) {
94 intermediaryApi.sendAcElementInfo(instanceId, elementId, useState, operationalState,
99 * Get Instance Data List.
101 * @return the InternalDatas
103 public InternalDatas getDataList() {
104 var result = new InternalDatas();
105 var map = intermediaryApi.getAutomationCompositions();
106 for (var instance : map.values()) {
107 for (var element : instance.getElements().values()) {
108 var data = new InternalData();
109 data.setCompositionId(instance.getCompositionId());
110 data.setAutomationCompositionId(instance.getInstanceId());
111 data.setAutomationCompositionElementId(element.getId());
112 data.setIntProperties(element.getProperties());
113 data.setOperationalState(element.getOperationalState());
114 data.setUseState(element.getUseState());
115 data.setOutProperties(element.getOutProperties());
116 result.getList().add(data);
123 * Get Composition Data List.
125 * @return the InternalDatas
127 public InternalDatas getCompositionDataList() {
128 var acElementsDefinitions = intermediaryApi.getAcElementsDefinitions();
129 var internalDatas = new InternalDatas();
130 for (var entry : acElementsDefinitions.entrySet()) {
131 for (var acElementsDefinition : entry.getValue().values()) {
132 var internalData = new InternalData();
133 internalData.setCompositionId(entry.getKey());
134 internalData.setCompositionDefinitionElementId(acElementsDefinition.getAcElementDefinitionId());
135 internalData.setIntProperties(
136 acElementsDefinition.getAutomationCompositionElementToscaNodeTemplate().getProperties());
137 internalData.setOutProperties(acElementsDefinition.getOutProperties());
138 internalDatas.getList().add(internalData);
141 return internalDatas;
144 public void setCompositionOutProperties(UUID compositionId, ToscaConceptIdentifier compositionDefinitionElementId,
145 Map<String, Object> outProperties) {
146 intermediaryApi.sendAcDefinitionInfo(compositionId, compositionDefinitionElementId, outProperties);
150 protected boolean isInterrupted(int timeMs, String msg, UUID elementId) {
151 long endTime = System.nanoTime() + (timeMs * 1_000_000L);
152 while (System.nanoTime() < endTime) {
153 if (Thread.interrupted()) {
154 LOGGER.debug(msg, elementId);
157 LockSupport.parkNanos(10_000_000L);
162 private void sendAcInternalState(UUID instanceId, UUID elementId, Map<String, Object> outProperties,
163 DeployState deployState) {
164 outProperties.put(INTERNAL_STATE, deployState.name());
165 intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
169 * Handle deploying an automation composition element.
171 * @param instanceId the instanceId
172 * @param elementId the elementId
173 * @param outProperties the outProperties
175 public void deploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
176 sendAcInternalState(instanceId, elementId, outProperties, DeployState.DEPLOYING);
178 if (isInterrupted(getConfig().getDeployTimerMs(),
179 "Current Thread deploy is Interrupted during execution {}", elementId)) {
183 if (getConfig().isDeploySuccess()) {
184 sendAcInternalState(instanceId, elementId, outProperties, DeployState.DEPLOYED);
186 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
187 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
189 sendAcInternalState(instanceId, elementId, outProperties, DeployState.UNDEPLOYED);
191 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
192 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
197 * Handle undeploying an automation composition element.
199 * @param instanceId the instanceId
200 * @param elementId the elementId
201 * @param outProperties the outProperties
203 public void undeploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
204 sendAcInternalState(instanceId, elementId, outProperties, DeployState.UNDEPLOYING);
206 if (isInterrupted(getConfig().getUndeployTimerMs(),
207 "Current Thread undeploy is Interrupted during execution {}", elementId)) {
211 if (getConfig().isUndeploySuccess()) {
212 sendAcInternalState(instanceId, elementId, outProperties, DeployState.UNDEPLOYED);
214 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
215 DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
217 sendAcInternalState(instanceId, elementId, outProperties, DeployState.DEPLOYED);
219 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
220 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Undeploy failed!");
225 * Handle locking an automation composition element.
227 * @param instanceId the instanceId
228 * @param elementId the elementId
230 public void lock(UUID instanceId, UUID elementId) {
231 if (isInterrupted(getConfig().getLockTimerMs(),
232 "Current Thread lock is Interrupted during execution {}", elementId)) {
236 if (getConfig().isLockSuccess()) {
237 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
238 null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
240 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
241 null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
246 * Handle unlocking an automation composition element.
248 * @param instanceId the instanceId
249 * @param elementId the elementId
251 public void unlock(UUID instanceId, UUID elementId) {
252 if (isInterrupted(getConfig().getUnlockTimerMs(),
253 "Current Thread unlock is Interrupted during execution {}", elementId)) {
257 if (getConfig().isUnlockSuccess()) {
258 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
259 null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
261 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
262 null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
267 * Handle deleting an automation composition element.
269 * @param instanceId the instanceId
270 * @param elementId the elementId
272 public void delete(UUID instanceId, UUID elementId) {
273 if (isInterrupted(getConfig().getDeleteTimerMs(),
274 "Current Thread delete is Interrupted during execution {}", elementId)) {
278 if (getConfig().isDeleteSuccess()) {
279 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
280 DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
282 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
283 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Delete failed!");
288 * Handle deleting an automation composition element in migration.
290 * @param instanceId the instanceId
291 * @param elementId the elementId
293 public void deleteInMigration(UUID instanceId, UUID elementId) {
294 if (getConfig().isMigrateSuccess()) {
295 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
296 DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Migration - Deleted");
298 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
299 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Migration - Delete failed!");
304 * Handle deleting an automation composition element in rollback.
306 * @param instanceId the instanceId
307 * @param elementId the elementId
309 public void deleteInRollback(UUID instanceId, UUID elementId) {
310 if (getConfig().isRollback()) {
311 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
312 DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Rollback - Deleted");
314 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
315 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Rollback - Delete failed!");
320 * Handle an update on an automation composition element.
322 * @param instanceId the instanceId
323 * @param elementId the elementId
325 public void update(UUID instanceId, UUID elementId) {
326 if (isInterrupted(getConfig().getUpdateTimerMs(),
327 "Current Thread update is Interrupted during execution {}", elementId)) {
331 if (getConfig().isUpdateSuccess()) {
332 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
333 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
335 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
336 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
341 * Handle a prime on an automation composition definition.
343 * @param composition the information of the Automation Composition Definition
345 public void prime(CompositionDto composition) {
346 if (isInterrupted(getConfig().getPrimeTimerMs(),
347 "Current Thread prime is Interrupted during execution {}", composition.compositionId())) {
351 if (getConfig().isPrimeSuccess()) {
352 sendOutProperties(composition, AcTypeState.PRIMED.name());
353 intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
354 StateChangeResult.NO_ERROR, "Primed");
356 sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
357 intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
358 StateChangeResult.FAILED, "Prime failed!");
362 private void sendOutProperties(CompositionDto composition, String data) {
363 for (var elementEntry : composition.outPropertiesMap().entrySet()) {
364 elementEntry.getValue().put(INTERNAL_STATE, data);
365 intermediaryApi.sendAcDefinitionInfo(
366 composition.compositionId(), elementEntry.getKey(), elementEntry.getValue());
371 * Handle a deprime on an automation composition definition.
373 * @param composition the information of the Automation Composition Definition
375 public void deprime(CompositionDto composition) {
376 if (isInterrupted(getConfig().getDeprimeTimerMs(),
377 "Current Thread deprime is Interrupted during execution {}", composition.compositionId())) {
381 if (getConfig().isDeprimeSuccess()) {
382 sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
383 intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
384 StateChangeResult.NO_ERROR, "Deprimed");
386 sendOutProperties(composition, AcTypeState.PRIMED.name());
387 intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
388 StateChangeResult.FAILED, "Deprime failed!");
393 * Handle a migration on an automation composition element.
395 * @param instanceId the instanceId
396 * @param elementId the elementId
397 * @param stage the stage
398 * @param compositionInProperties in Properties from composition definition element
399 * @param instanceOutProperties in Properties from instance element
401 public void migrate(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
402 Map<String, Object> instanceOutProperties) {
403 if (isInterrupted(getConfig().getMigrateTimerMs(),
404 "Current Thread migrate is Interrupted during execution {}", elementId)) {
408 if (config.isMigrateSuccess()) {
409 var stageSet = ParticipantUtils.findStageSetMigrate(compositionInProperties);
410 var nextStage = 1000;
411 for (var s : stageSet) {
413 nextStage = Math.min(s, nextStage);
416 instanceOutProperties.putIfAbsent(MIGRATION_PROPERTY, new ArrayList<>());
417 @SuppressWarnings("unchecked")
418 var stageList = (List<Integer>) instanceOutProperties.get(MIGRATION_PROPERTY);
419 stageList.add(stage);
420 intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
421 if (nextStage == 1000) {
422 intermediaryApi.updateAutomationCompositionElementState(
423 instanceId, elementId,
424 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
426 intermediaryApi.updateAutomationCompositionElementStage(
427 instanceId, elementId,
428 StateChangeResult.NO_ERROR, nextStage, String.format(STAGE_MSG, stage, "Migrated"));
431 intermediaryApi.updateAutomationCompositionElementState(
432 instanceId, elementId,
433 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migrate failed!");
438 * Handle a Migrate Precheck on an automation composition element.
440 * @param instanceId the instanceId
441 * @param elementId the elementId
443 public void migratePrecheck(UUID instanceId, UUID elementId) {
444 if (isInterrupted(config.getMigratePrecheckTimerMs(),
445 "Current Thread migrate precheck is Interrupted during execution {}", elementId)) {
449 if (config.isMigratePrecheck()) {
450 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
451 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migration precheck completed");
453 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
454 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration precheck failed");
459 * Handle a Prepare on an automation composition element.
461 * @param instanceId the instanceId
462 * @param elementId the elementId
463 * @param stage the stage
464 * @param compositionInProperties in Properties from composition definition element
465 * @param instanceOutProperties in Properties from instance element
467 public void prepare(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
468 Map<String, Object> instanceOutProperties) {
469 if (isInterrupted(config.getPrepareTimerMs(),
470 "Current Thread prepare is Interrupted during execution {}", elementId)) {
474 if (config.isPrepare()) {
475 var stageSet = ParticipantUtils.findStageSetPrepare(compositionInProperties);
476 var nextStage = 1000;
477 for (var s : stageSet) {
479 nextStage = Math.min(s, nextStage);
482 instanceOutProperties.putIfAbsent(PREPARE_PROPERTY, new ArrayList<>());
483 @SuppressWarnings("unchecked")
484 var stageList = (List<Integer>) instanceOutProperties.get(PREPARE_PROPERTY);
485 stageList.add(stage);
486 intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
487 if (nextStage == 1000) {
488 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
489 DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Prepare completed");
491 intermediaryApi.updateAutomationCompositionElementStage(
492 instanceId, elementId,
493 StateChangeResult.NO_ERROR, nextStage, String.format(STAGE_MSG, stage, "Prepared"));
496 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
497 DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Prepare failed");
502 * Handle a Review on an automation composition element.
504 * @param instanceId the instanceId
505 * @param elementId the elementId
507 public void review(UUID instanceId, UUID elementId) {
508 if (isInterrupted(config.getReviewTimerMs(),
509 "Current Thread review is Interrupted during execution {}", elementId)) {
513 if (config.isReview()) {
514 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
515 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Review completed");
517 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
518 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Review failed");
523 * Handle rollback of an automation composition.
525 * @param instanceId the instanceId
526 * @param elementId the elementId
527 * @param stage the stage
528 * @param compositionInProperties in Properties from composition definition element
529 * @param instanceOutProperties in Properties from instance element
531 public void rollback(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
532 Map<String, Object> instanceOutProperties) {
533 if (isInterrupted(getConfig().getRollbackTimerMs(),
534 "Current Thread for rollback was Interrupted during execution {}", instanceId)) {
535 LOGGER.debug("Rollback interrupted");
539 if (config.isRollback()) {
540 var stageSet = ParticipantUtils.findStageSetMigrate(compositionInProperties);
541 var nextStage = 1000;
542 for (var s : stageSet) {
544 nextStage = Math.min(s, nextStage);
547 instanceOutProperties.putIfAbsent(ROLLBACK_PROPERTY, new ArrayList<>());
548 @SuppressWarnings("unchecked")
549 var stageList = (List<Integer>) instanceOutProperties.get(ROLLBACK_PROPERTY);
550 stageList.add(stage);
551 intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
552 if (nextStage == 1000) {
553 intermediaryApi.updateAutomationCompositionElementState(
554 instanceId, elementId,
555 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migration rollback done");
557 intermediaryApi.updateAutomationCompositionElementStage(
558 instanceId, elementId,
559 StateChangeResult.NO_ERROR, nextStage, String.format(STAGE_MSG, stage, "Migration rollback"));
562 intermediaryApi.updateAutomationCompositionElementState(
563 instanceId, elementId,
564 DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration rollback failed");