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.ArrayList;
25 import java.util.HashMap;
26 import java.util.LinkedHashMap;
27 import java.util.List;
29 import java.util.UUID;
31 import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
32 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
33 import org.onap.policy.clamp.acm.participant.intermediary.parameters.ParticipantParameters;
34 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
35 import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
37 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
38 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
39 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo;
40 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo;
41 import org.onap.policy.clamp.models.acm.concepts.DeployState;
42 import org.onap.policy.clamp.models.acm.concepts.LockState;
43 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
44 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
45 import org.onap.policy.clamp.models.acm.concepts.ParticipantSupportedElementType;
46 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
47 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
48 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck;
49 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
50 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
51 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
52 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
53 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
54 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
55 import org.onap.policy.models.base.PfModelException;
56 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
57 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.springframework.stereotype.Component;
63 * This class is responsible for managing the state of all automation compositions in the participant.
66 public class AutomationCompositionHandler {
67 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
69 private final UUID participantId;
70 private final ParticipantMessagePublisher publisher;
71 private final AcInstanceStateResolver acInstanceStateResolver;
72 private final List<ParticipantSupportedElementType> supportedAcElementTypes;
73 private final List<AutomationCompositionElementListener> listeners = new ArrayList<>();
76 private final Map<UUID, AutomationComposition> automationCompositionMap = new LinkedHashMap<>();
79 * Constructor, set the participant ID and messageSender.
81 * @param parameters the parameters of the participant
82 * @param publisher the ParticipantMessage Publisher
84 public AutomationCompositionHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) {
85 this.participantId = parameters.getIntermediaryParameters().getParticipantId();
86 this.publisher = publisher;
87 this.acInstanceStateResolver = new AcInstanceStateResolver();
88 this.supportedAcElementTypes = parameters.getIntermediaryParameters().getParticipantSupportedElementTypes();
91 public void registerAutomationCompositionElementListener(AutomationCompositionElementListener listener) {
92 listeners.add(listener);
96 * Handle a automation composition element state change message.
98 * @param automationCompositionId the automationComposition Id
99 * @param id the automationComposition UUID
100 * @param deployState the DeployState state
101 * @param lockState the LockState state
103 public void updateAutomationCompositionElementState(UUID automationCompositionId, UUID id, DeployState deployState,
104 LockState lockState, String message) {
106 if (automationCompositionId == null || id == null) {
107 LOGGER.error("Cannot update Automation composition element state, id is null");
111 if ((deployState != null && lockState != null) || (deployState == null && lockState == null)) {
112 LOGGER.error("state error {} and {} cannot be handled", deployState, lockState);
116 var automationComposition = automationCompositionMap.get(automationCompositionId);
117 if (automationComposition == null) {
118 LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
119 automationComposition);
123 var element = automationComposition.getElements().get(id);
124 if (element == null) {
125 var msg = "Cannot update Automation composition element state, AC Element id {} not present";
126 LOGGER.error(msg, automationComposition);
130 if (deployState != null) {
131 element.setDeployState(deployState);
132 var checkOpt = automationComposition.getElements().values().stream()
133 .filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
134 if (checkOpt.isEmpty()) {
135 automationComposition.setDeployState(deployState);
137 element.setLockState(
138 DeployState.DEPLOYED.equals(element.getDeployState()) ? LockState.LOCKED : LockState.NONE);
140 if (lockState != null) {
141 element.setLockState(lockState);
142 var checkOpt = automationComposition.getElements().values().stream()
143 .filter(acElement -> !lockState.equals(acElement.getLockState())).findAny();
144 if (checkOpt.isEmpty()) {
145 automationComposition.setLockState(lockState);
149 var automationCompositionStateChangeAck =
150 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
151 automationCompositionStateChangeAck.setParticipantId(participantId);
152 automationCompositionStateChangeAck.setMessage(message);
153 automationCompositionStateChangeAck.setAutomationCompositionId(automationCompositionId);
154 automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
155 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
156 element.getUseState(), element.getStatusProperties(), true,
157 "Automation composition element {} state changed to {}\", id, newState)"));
158 LOGGER.debug("Automation composition element {} state changed to {}", id, deployState);
159 automationCompositionStateChangeAck.setResult(true);
160 publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
164 * Handle a automation composition state change message.
166 * @param stateChangeMsg the state change message
167 * @param acElementDefinitions the list of AutomationCompositionElementDefinition
169 public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg,
170 List<AutomationCompositionElementDefinition> acElementDefinitions) {
171 if (stateChangeMsg.getAutomationCompositionId() == null) {
175 var automationComposition = automationCompositionMap.get(stateChangeMsg.getAutomationCompositionId());
177 if (automationComposition == null) {
178 var automationCompositionAck =
179 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
180 automationCompositionAck.setParticipantId(participantId);
181 automationCompositionAck.setMessage("Automation composition " + stateChangeMsg.getAutomationCompositionId()
182 + " does not use this participant " + participantId);
183 automationCompositionAck.setResult(false);
184 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
185 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
186 publisher.sendAutomationCompositionAck(automationCompositionAck);
187 LOGGER.debug("Automation composition {} does not use this participant",
188 stateChangeMsg.getAutomationCompositionId());
192 if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
193 stateChangeMsg.getLockOrderedState())) {
194 var automationCompositionAck =
195 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
196 automationCompositionAck.setParticipantId(participantId);
197 automationCompositionAck.setMessage("Automation composition is already in state "
198 + stateChangeMsg.getDeployOrderedState() + " and " + stateChangeMsg.getLockOrderedState());
199 automationCompositionAck.setResult(false);
200 automationCompositionAck.setAutomationCompositionId(automationComposition.getInstanceId());
201 publisher.sendAutomationCompositionAck(automationCompositionAck);
205 if (DeployOrder.NONE.equals(stateChangeMsg.getDeployOrderedState())) {
206 handleLockOrderState(automationComposition, stateChangeMsg.getLockOrderedState(),
207 stateChangeMsg.getStartPhase(), acElementDefinitions);
209 handleDeployOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
210 stateChangeMsg.getStartPhase(), acElementDefinitions);
214 private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder,
215 LockOrder lockOrder) {
216 return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
217 automationComposition.getLockState()) != null;
221 * Method to handle state changes.
223 * @param automationComposition participant response
224 * @param orderedState automation composition ordered state
225 * @param startPhaseMsg startPhase from message
226 * @param acElementDefinitions the list of AutomationCompositionElementDefinition
228 private void handleDeployOrderState(final AutomationComposition automationComposition, DeployOrder orderedState,
229 Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
231 if (DeployOrder.UNDEPLOY.equals(orderedState)) {
232 handleUndeployState(automationComposition, startPhaseMsg, acElementDefinitions);
234 LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
239 * Method to handle state changes.
241 * @param automationComposition participant response
242 * @param orderedState automation composition ordered state
243 * @param startPhaseMsg startPhase from message
244 * @param acElementDefinitions the list of AutomationCompositionElementDefinition
246 private void handleLockOrderState(final AutomationComposition automationComposition, LockOrder orderedState,
247 Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
249 switch (orderedState) {
251 handleLockState(automationComposition, startPhaseMsg, acElementDefinitions);
254 handleUnlockState(automationComposition, startPhaseMsg, acElementDefinitions);
257 LOGGER.debug("StateChange message has no state, state is null {}", automationComposition.getKey());
263 * Handle a automation composition Deploy message.
265 * @param updateMsg the Deploy message
266 * @param acElementDefinitions the list of AutomationCompositionElementDefinition
268 public void handleAutomationCompositionDeploy(AutomationCompositionDeploy updateMsg,
269 List<AutomationCompositionElementDefinition> acElementDefinitions) {
271 if (updateMsg.getParticipantUpdatesList().isEmpty()) {
272 LOGGER.warn("No AutomationCompositionElement updates in message {}",
273 updateMsg.getAutomationCompositionId());
277 for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
278 if (participantId.equals(participantDeploy.getParticipantId())) {
279 if (updateMsg.isFirstStartPhase()) {
280 initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
283 callParticipanDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
284 updateMsg.getStartPhase(), updateMsg.getAutomationCompositionId());
289 private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy) {
290 var automationComposition = automationCompositionMap.get(instanceId);
292 if (automationComposition != null) {
293 var automationCompositionUpdateAck =
294 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY_ACK);
295 automationCompositionUpdateAck.setParticipantId(participantId);
297 automationCompositionUpdateAck.setMessage(
298 "Automation composition " + instanceId + " already defined on participant " + participantId);
299 automationCompositionUpdateAck.setResult(false);
300 automationCompositionUpdateAck.setResponseTo(messageId);
301 automationCompositionUpdateAck.setAutomationCompositionId(instanceId);
302 publisher.sendAutomationCompositionAck(automationCompositionUpdateAck);
306 automationComposition = new AutomationComposition();
307 automationComposition.setInstanceId(instanceId);
308 var acElements = storeElementsOnThisParticipant(participantDeploy);
309 automationComposition.setElements(prepareAcElementMap(acElements));
310 automationCompositionMap.put(instanceId, automationComposition);
313 private void callParticipanDeploy(List<AcElementDeploy> acElements,
314 List<AutomationCompositionElementDefinition> acElementDefinitions, Integer startPhaseMsg,
315 UUID automationCompositionId) {
317 for (var element : acElements) {
318 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, element.getDefinition());
319 if (acElementNodeTemplate != null) {
320 int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
321 if (startPhaseMsg.equals(startPhase)) {
322 for (var acElementListener : listeners) {
323 var map = new HashMap<>(acElementNodeTemplate.getProperties());
324 map.putAll(element.getProperties());
325 acElementListener.deploy(automationCompositionId, element, map);
330 } catch (PfModelException e) {
331 LOGGER.debug("Automation composition element update failed {}", automationCompositionId);
336 private ToscaNodeTemplate getAcElementNodeTemplate(
337 List<AutomationCompositionElementDefinition> acElementDefinitions, ToscaConceptIdentifier acElementDefId) {
339 for (var acElementDefinition : acElementDefinitions) {
340 if (acElementDefId.getName().contains(acElementDefinition.getAcElementDefinitionId().getName())) {
341 return acElementDefinition.getAutomationCompositionElementToscaNodeTemplate();
347 private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy) {
348 List<AutomationCompositionElement> acElementList = new ArrayList<>();
349 for (var element : participantDeploy.getAcElementList()) {
350 var acElement = new AutomationCompositionElement();
351 acElement.setId(element.getId());
352 acElement.setParticipantId(participantDeploy.getParticipantId());
353 acElement.setDefinition(element.getDefinition());
354 acElement.setDeployState(DeployState.DEPLOYING);
355 acElement.setLockState(LockState.NONE);
356 acElementList.add(acElement);
358 return acElementList;
361 private Map<UUID, AutomationCompositionElement> prepareAcElementMap(List<AutomationCompositionElement> acElements) {
362 Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
363 for (var element : acElements) {
364 acElementMap.put(element.getId(), element);
370 * Method to handle when the new state from participant is UNINITIALISED state.
372 * @param automationComposition participant response
373 * @param startPhaseMsg startPhase from message
374 * @param acElementDefinitions the list of AutomationCompositionElementDefinition
376 private void handleUndeployState(final AutomationComposition automationComposition, Integer startPhaseMsg,
377 List<AutomationCompositionElementDefinition> acElementDefinitions) {
379 automationComposition.getElements().values().stream()
380 .forEach(acElement -> automationCompositionElementUndeploy(automationComposition.getInstanceId(),
381 acElement, startPhaseMsg, acElementDefinitions));
383 boolean isAllUninitialised = automationComposition.getElements().values().stream()
384 .filter(element -> !DeployState.UNDEPLOYED.equals(element.getDeployState())).findAny().isEmpty();
385 if (isAllUninitialised) {
386 automationCompositionMap.remove(automationComposition.getInstanceId());
391 * Method to handle when the new state from participant is PASSIVE state.
393 * @param automationComposition participant response
394 * @param startPhaseMsg startPhase from message
395 * @param acElementDefinitions the list of AutomationCompositionElementDefinition
397 private void handleLockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
398 List<AutomationCompositionElementDefinition> acElementDefinitions) {
399 automationComposition.getElements().values().stream()
400 .forEach(acElement -> automationCompositionElementLock(automationComposition.getInstanceId(), acElement,
401 startPhaseMsg, acElementDefinitions));
405 * Method to handle when the new state from participant is RUNNING state.
407 * @param automationComposition participant response
408 * @param startPhaseMsg startPhase from message
409 * @param acElementDefinitions the list of AutomationCompositionElementDefinition
411 private void handleUnlockState(final AutomationComposition automationComposition, Integer startPhaseMsg,
412 List<AutomationCompositionElementDefinition> acElementDefinitions) {
413 automationComposition.getElements().values().stream()
414 .forEach(acElement -> automationCompositionElementUnlock(automationComposition.getInstanceId(),
415 acElement, startPhaseMsg, acElementDefinitions));
418 private void automationCompositionElementLock(UUID instanceId, AutomationCompositionElement acElement,
419 Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
420 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
421 if (acElementNodeTemplate != null) {
422 int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
423 if (startPhaseMsg.equals(startPhase)) {
424 for (var acElementListener : listeners) {
426 acElementListener.lock(instanceId, acElement.getId());
427 updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.LOCKED,
429 } catch (PfModelException e) {
430 LOGGER.error("Automation composition element lock failed {}", instanceId);
437 private void automationCompositionElementUnlock(UUID instanceId, AutomationCompositionElement acElement,
438 Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
439 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
440 if (acElementNodeTemplate != null) {
441 int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
442 if (startPhaseMsg.equals(startPhase)) {
443 for (var acElementListener : listeners) {
445 acElementListener.unlock(instanceId, acElement.getId());
446 updateAutomationCompositionElementState(instanceId, acElement.getId(), null, LockState.UNLOCKED,
448 } catch (PfModelException e) {
449 LOGGER.error("Automation composition element unlock failed {}", instanceId);
456 private void automationCompositionElementUndeploy(UUID instanceId, AutomationCompositionElement acElement,
457 Integer startPhaseMsg, List<AutomationCompositionElementDefinition> acElementDefinitions) {
458 var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, acElement.getDefinition());
459 if (acElementNodeTemplate != null) {
460 int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
461 if (startPhaseMsg.equals(startPhase)) {
462 undeployInstanceElements(instanceId, acElement.getId());
469 * Undeploy Instance Elements On Participant.
471 public void undeployInstances() {
472 automationCompositionMap.values().forEach(this::undeployInstance);
475 private void undeployInstance(AutomationComposition automationComposition) {
476 automationComposition.getElements().values().forEach(element -> {
477 if (element.getParticipantId().equals(participantId)) {
478 undeployInstanceElements(automationComposition.getInstanceId(), element.getId());
483 private void undeployInstanceElements(UUID instanceId, UUID elementId) {
484 for (var acElementListener : listeners) {
486 acElementListener.undeploy(instanceId, elementId);
487 } catch (PfModelException e) {
488 LOGGER.error("Automation composition element update failed {}", instanceId);
494 * Send Ac Element Info.
496 * @param automationCompositionId the automationComposition Id
497 * @param elementId the automationComposition Element id
498 * @param useState the use State
499 * @param operationalState the operational State
500 * @param statusProperties the status Properties Map
502 public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
503 String operationalState, Map<String, Object> statusProperties) {
505 if (automationCompositionId == null || elementId == null) {
506 LOGGER.error("Cannot update Automation composition element state, id is null");
510 var automationComposition = automationCompositionMap.get(automationCompositionId);
511 if (automationComposition == null) {
512 LOGGER.error("Cannot update Automation composition element state, Automation composition id {} not present",
513 automationComposition);
517 var element = automationComposition.getElements().get(elementId);
518 if (element == null) {
519 var msg = "Cannot update Automation composition element state, AC Element id {} not present";
520 LOGGER.error(msg, automationComposition);
523 element.setOperationalState(operationalState);
524 element.setUseState(useState);
525 element.setStatusProperties(statusProperties);
527 var statusMsg = new ParticipantStatus();
528 statusMsg.setParticipantId(participantId);
529 statusMsg.setState(ParticipantState.ON_LINE);
530 statusMsg.setParticipantSupportedElementType(new ArrayList<>(supportedAcElementTypes));
531 var acInfo = new AutomationCompositionInfo();
532 acInfo.setAutomationCompositionId(automationCompositionId);
533 acInfo.setDeployState(automationComposition.getDeployState());
534 acInfo.setLockState(automationComposition.getLockState());
535 acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
536 statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
537 publisher.sendParticipantStatus(statusMsg);
541 * get AutomationComposition Info List.
543 * @return list of AutomationCompositionInfo
545 public List<AutomationCompositionInfo> getAutomationCompositionInfoList() {
546 List<AutomationCompositionInfo> automationCompositionInfoList = new ArrayList<>();
547 for (var entry : automationCompositionMap.entrySet()) {
548 var acInfo = new AutomationCompositionInfo();
549 acInfo.setAutomationCompositionId(entry.getKey());
550 acInfo.setDeployState(entry.getValue().getDeployState());
551 acInfo.setLockState(entry.getValue().getLockState());
552 for (var element : entry.getValue().getElements().values()) {
553 acInfo.getElements().add(getAutomationCompositionElementInfo(element));
555 automationCompositionInfoList.add(acInfo);
557 return automationCompositionInfoList;
560 private AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
561 var elementInfo = new AutomationCompositionElementInfo();
562 elementInfo.setAutomationCompositionElementId(element.getId());
563 elementInfo.setDeployState(element.getDeployState());
564 elementInfo.setLockState(element.getLockState());
565 elementInfo.setOperationalState(element.getOperationalState());
566 elementInfo.setUseState(element.getUseState());
567 elementInfo.setStatusProperties(element.getStatusProperties());