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");