2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021-2023 Nordix Foundation.
4 * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.clamp.acm.participant.intermediary.handler;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.UUID;
27 import lombok.NonNull;
28 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
29 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
30 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
31 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
32 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
33 import org.onap.policy.clamp.models.acm.concepts.DeployState;
34 import org.onap.policy.clamp.models.acm.concepts.LockState;
35 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
36 import org.onap.policy.clamp.models.acm.concepts.ParticipantRestartAc;
37 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
38 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
39 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
40 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck;
41 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionMigration;
42 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
43 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
44 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
45 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
46 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
47 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 import org.springframework.stereotype.Component;
53 * This class is responsible for managing the state of all automation compositions in the participant.
56 public class AutomationCompositionHandler {
57 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
59 private final CacheProvider cacheProvider;
60 private final ParticipantMessagePublisher publisher;
61 private final ThreadHandler listener;
62 private final AcInstanceStateResolver acInstanceStateResolver;
65 * Constructor, set the participant ID and messageSender.
67 * @param cacheProvider the Cache Provider
68 * @param publisher the ParticipantMessage Publisher
69 * @param listener the ThreadHandler Listener
71 public AutomationCompositionHandler(CacheProvider cacheProvider, ParticipantMessagePublisher publisher,
72 ThreadHandler listener) {
73 this.cacheProvider = cacheProvider;
74 this.publisher = publisher;
75 this.listener = listener;
76 this.acInstanceStateResolver = new AcInstanceStateResolver();
80 * Handle a automation composition state change message.
82 * @param stateChangeMsg the state change message
84 public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
85 if (stateChangeMsg.getAutomationCompositionId() == null) {
89 var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
91 if (automationComposition == null) {
92 if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
93 var automationCompositionAck = new AutomationCompositionDeployAck(
94 ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
95 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
96 automationCompositionAck.setMessage("Already deleted or never used");
97 automationCompositionAck.setResult(true);
98 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
99 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
100 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
101 publisher.sendAutomationCompositionAck(automationCompositionAck);
103 LOGGER.debug("Automation composition {} does not use this participant",
104 stateChangeMsg.getAutomationCompositionId());
109 if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
110 stateChangeMsg.getLockOrderedState())) {
111 LOGGER.warn("Not Consistant OrderState Automation composition {}",
112 stateChangeMsg.getAutomationCompositionId());
116 if (DeployOrder.NONE.equals(stateChangeMsg.getDeployOrderedState())) {
117 handleLockOrderState(stateChangeMsg.getMessageId(), automationComposition,
118 stateChangeMsg.getLockOrderedState(), stateChangeMsg.getStartPhase());
120 handleDeployOrderState(stateChangeMsg.getMessageId(), automationComposition,
121 stateChangeMsg.getDeployOrderedState(), stateChangeMsg.getStartPhase());
125 private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder,
126 LockOrder lockOrder) {
127 if (DeployOrder.UPDATE.equals(deployOrder)) {
130 return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
131 automationComposition.getLockState(), automationComposition.getStateChangeResult()) != null;
135 * Method to handle state changes.
137 * @param messageId the messageId
138 * @param automationComposition participant response
139 * @param orderedState automation composition ordered state
140 * @param startPhaseMsg startPhase from message
142 private void handleDeployOrderState(UUID messageId, final AutomationComposition automationComposition,
143 DeployOrder orderedState, Integer startPhaseMsg) {
145 switch (orderedState) {
147 handleUndeployState(messageId, automationComposition, startPhaseMsg);
150 handleDeleteState(messageId, automationComposition, startPhaseMsg);
154 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
160 * Method to handle state changes.
162 * @param messageId the messageId
163 * @param automationComposition participant response
164 * @param orderedState automation composition ordered state
165 * @param startPhaseMsg startPhase from message
167 private void handleLockOrderState(UUID messageId, final AutomationComposition automationComposition,
168 LockOrder orderedState, Integer startPhaseMsg) {
170 switch (orderedState) {
172 handleLockState(messageId, automationComposition, startPhaseMsg);
175 handleUnlockState(messageId, automationComposition, startPhaseMsg);
178 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
184 * Handle a automation composition properties update message.
186 * @param updateMsg the properties update message
188 public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
190 if (updateMsg.getParticipantUpdatesList().isEmpty()) {
191 LOGGER.warn("No AutomationCompositionElement updates in message {}",
192 updateMsg.getAutomationCompositionId());
196 for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
197 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
199 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy,
200 DeployState.UPDATING);
202 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(),
203 updateMsg.getAutomationCompositionId());
209 * Handle a automation composition Deploy message.
211 * @param deployMsg the Deploy message
213 public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
215 if (deployMsg.getParticipantUpdatesList().isEmpty()) {
216 LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
220 for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
221 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
222 if (deployMsg.isFirstStartPhase()) {
223 cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
224 deployMsg.getAutomationCompositionId(), participantDeploy);
226 callParticipanDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
227 deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
232 private void callParticipanDeploy(UUID messageId, List<AcElementDeploy> acElements, Integer startPhaseMsg,
234 for (var element : acElements) {
235 var commonProperties = cacheProvider.getCommonProperties(instanceId, element.getId());
236 int startPhase = ParticipantUtils.findStartPhase(commonProperties);
237 if (startPhaseMsg.equals(startPhase)) {
238 var map = new HashMap<>(commonProperties);
239 map.putAll(element.getProperties());
240 listener.deploy(messageId, instanceId, element, map);
245 private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements, UUID instanceId) {
246 for (var element : acElements) {
247 listener.update(messageId, instanceId, element, element.getProperties());
251 private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy,
252 DeployState deployState) {
253 var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
254 for (var element : participantDeploy.getAcElementList()) {
255 var acElement = acElementList.get(element.getId());
256 acElement.getProperties().putAll(element.getProperties());
257 acElement.setDeployState(deployState);
262 * Method to handle when the new state from participant is UNINITIALISED state.
264 * @param messageId the messageId
265 * @param automationComposition participant response
266 * @param startPhaseMsg startPhase from message
268 private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
269 Integer startPhaseMsg) {
270 for (var acElement : automationComposition.getElements().values()) {
271 int startPhase = ParticipantUtils.findStartPhase(
272 cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
273 if (startPhaseMsg.equals(startPhase)) {
274 acElement.setDeployState(DeployState.UNDEPLOYING);
275 listener.undeploy(messageId, automationComposition.getInstanceId(), acElement.getId());
280 private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
281 Integer startPhaseMsg) {
282 for (var acElement : automationComposition.getElements().values()) {
283 int startPhase = ParticipantUtils.findStartPhase(
284 cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
285 if (startPhaseMsg.equals(startPhase)) {
286 acElement.setDeployState(DeployState.DELETING);
287 listener.delete(messageId, automationComposition.getInstanceId(), acElement.getId());
293 * Method to handle when the new state from participant is PASSIVE state.
295 * @param messageId the messageId
296 * @param automationComposition participant response
297 * @param startPhaseMsg startPhase from message
299 private void handleLockState(UUID messageId, final AutomationComposition automationComposition,
300 Integer startPhaseMsg) {
301 for (var acElement : automationComposition.getElements().values()) {
302 int startPhase = ParticipantUtils.findStartPhase(
303 cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
304 if (startPhaseMsg.equals(startPhase)) {
305 acElement.setLockState(LockState.LOCKING);
306 listener.lock(messageId, automationComposition.getInstanceId(), acElement.getId());
312 * Method to handle when the new state from participant is RUNNING state.
314 * @param messageId the messageId
315 * @param automationComposition participant response
316 * @param startPhaseMsg startPhase from message
318 private void handleUnlockState(UUID messageId, final AutomationComposition automationComposition,
319 Integer startPhaseMsg) {
320 for (var acElement : automationComposition.getElements().values()) {
321 int startPhase = ParticipantUtils.findStartPhase(
322 cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
323 if (startPhaseMsg.equals(startPhase)) {
324 acElement.setLockState(LockState.UNLOCKING);
325 listener.unlock(messageId, automationComposition.getInstanceId(), acElement.getId());
331 * Handles prime a Composition Definition.
333 * @param messageId the messageId
334 * @param compositionId the compositionId
335 * @param list the list of AutomationCompositionElementDefinition
337 public void prime(UUID messageId, UUID compositionId, List<AutomationCompositionElementDefinition> list) {
338 listener.prime(messageId, compositionId, list);
342 * Handles deprime a Composition Definition.
344 * @param messageId the messageId
345 * @param compositionId the compositionId
347 public void deprime(UUID messageId, UUID compositionId) {
348 listener.deprime(messageId, compositionId);
352 * Handles restarted scenario.
354 * @param messageId the messageId
355 * @param compositionId the compositionId
356 * @param list the list of AutomationCompositionElementDefinition
357 * @param state the state of the composition
358 * @param automationCompositionList list of ParticipantRestartAc
360 public void restarted(UUID messageId, UUID compositionId, List<AutomationCompositionElementDefinition> list,
361 AcTypeState state, List<ParticipantRestartAc> automationCompositionList) {
363 for (var automationcomposition : automationCompositionList) {
364 cacheProvider.initializeAutomationComposition(compositionId, automationcomposition);
366 listener.restarted(messageId, compositionId, list, state, automationCompositionList);
370 * Handles AutomationComposition Migration.
372 * @param migrationMsg the AutomationCompositionMigration
374 public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
375 if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
379 var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
380 if (automationComposition == null) {
381 LOGGER.debug("Automation composition {} does not use this participant",
382 migrationMsg.getAutomationCompositionId());
385 automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
386 for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
387 if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
389 updateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), participantDeploy,
390 DeployState.MIGRATING);
392 callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
393 migrationMsg.getAutomationCompositionId(), migrationMsg.getCompositionTargetId());
398 private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements, UUID instanceId,
399 UUID compositionTargetId) {
400 for (var element : acElements) {
401 listener.migrate(messageId, instanceId, element, compositionTargetId, element.getProperties());