37e0e22d27acf59daf5c01fb74586db23ebdebeb
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2023-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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.acm.participant.intermediary.handler;
22
23 import java.util.List;
24 import java.util.Map;
25 import java.util.UUID;
26 import lombok.RequiredArgsConstructor;
27 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
28 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.AcDefinition;
29 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.CacheProvider;
30 import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck;
31 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
32 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
33 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo;
37 import org.onap.policy.clamp.models.acm.concepts.DeployState;
38 import org.onap.policy.clamp.models.acm.concepts.LockState;
39 import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
40 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
41 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
42 import org.onap.policy.clamp.models.acm.concepts.SubState;
43 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
44 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
45 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck;
46 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantStatus;
47 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.springframework.stereotype.Component;
52
53 @Component
54 @RequiredArgsConstructor
55 public class AutomationCompositionOutHandler {
56     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionOutHandler.class);
57     private static final String MSG_NOT_PRESENT
58             = "Cannot update Automation composition element {}, {} id {} not present";
59     private static final String MSG_STATE_CHANGE = "Automation composition element {} state changed to {}";
60     private static final String MSG_AC = "Automation composition";
61     private static final String MSG_AC_ELEMENT = "AC Element";
62     private static final String MSG_STAGE = "stage";
63
64     private final ParticipantMessagePublisher publisher;
65     private final CacheProvider cacheProvider;
66
67     /**
68      * Handle a automation composition element stage change message.
69      *
70      * @param instance the automationComposition Id
71      * @param elementId the automationComposition Element Id
72      * @param stage the next stage
73      * @param message the message
74      * @param stateChangeResult the indicator if error occurs
75      */
76     public void updateAutomationCompositionElementStage(UUID instance, UUID elementId,
77         StateChangeResult stateChangeResult, int stage, String message) {
78         if (!validateData(instance, elementId, stateChangeResult)) {
79             return;
80         }
81
82         var automationComposition = cacheProvider.getAutomationComposition(instance);
83         if (automationComposition == null) {
84             LOGGER.error(MSG_NOT_PRESENT, MSG_STAGE, MSG_AC, instance);
85             return;
86         }
87
88         var element = automationComposition.getElements().get(elementId);
89         if (element == null) {
90             LOGGER.error(MSG_NOT_PRESENT, MSG_STAGE, MSG_AC_ELEMENT, elementId);
91             return;
92         }
93
94         var automationCompositionStateChangeAck =
95             new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
96         automationCompositionStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
97         automationCompositionStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
98         automationCompositionStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
99         automationCompositionStateChangeAck.setStateChangeResult(stateChangeResult);
100         automationCompositionStateChangeAck.setStage(stage);
101         automationCompositionStateChangeAck.setAutomationCompositionId(instance);
102         automationCompositionStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
103             new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
104                 element.getUseState(), element.getOutProperties(), true, message));
105         LOGGER.debug("Automation composition element {} stage changed to {}", elementId, stage);
106         automationCompositionStateChangeAck.setResult(true);
107         publisher.sendAutomationCompositionAck(automationCompositionStateChangeAck);
108         cacheProvider.getMsgIdentification().remove(element.getId());
109     }
110
111     private boolean validateData(UUID instance, UUID elementId, StateChangeResult stateChangeResult) {
112         if (instance == null || elementId == null) {
113             LOGGER.error("Not valid Ac instance, id is null");
114             return false;
115         }
116         if (stateChangeResult == null) {
117             LOGGER.error("Not valid Ac instance, stateChangeResult is null");
118             return false;
119         }
120         if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
121                 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
122             LOGGER.error("Not valid Ac instance, stateChangeResult is not valid");
123             return false;
124         }
125         return true;
126     }
127
128     /**
129      * Handle a automation composition element state change message.
130      *
131      * @param instance the automationComposition Id
132      * @param elementId the automationComposition Element Id
133      * @param deployState the DeployState state
134      * @param lockState the LockState state
135      * @param message the message
136      * @param stateChangeResult the indicator if error occurs
137      */
138     public void updateAutomationCompositionElementState(UUID instance, UUID elementId,
139             DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message) {
140         if (!validateData(instance, elementId, stateChangeResult)) {
141             return;
142         }
143
144         if ((deployState != null && lockState != null) || (deployState == null && lockState == null)
145                 || AcmUtils.isInTransitionalState(deployState, lockState, SubState.NONE)) {
146             LOGGER.error("state error {} and {} cannot be handled", deployState, lockState);
147             return;
148         }
149
150         var automationComposition = cacheProvider.getAutomationComposition(instance);
151         if (automationComposition == null) {
152             LOGGER.error(MSG_NOT_PRESENT, "state", MSG_AC, instance);
153             return;
154         }
155
156         var element = automationComposition.getElements().get(elementId);
157         if (element == null) {
158             checkElement(automationComposition, instance, elementId, deployState, stateChangeResult, message);
159             return;
160         }
161
162         if (!SubState.NONE.equals(element.getSubState())) {
163             handleSubState(automationComposition, element, stateChangeResult);
164         } else if (deployState != null) {
165             handleDeployState(automationComposition, element, deployState, stateChangeResult);
166         }
167         if (lockState != null) {
168             handleLockState(automationComposition, element, lockState, stateChangeResult);
169         }
170
171         var acStateChangeAck = createAutomationCompositionDeployAck();
172         acStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
173         acStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(element.getId()));
174         acStateChangeAck.setStateChangeResult(stateChangeResult);
175         acStateChangeAck.setAutomationCompositionId(instance);
176         acStateChangeAck.getAutomationCompositionResultMap().put(element.getId(),
177                 new AcElementDeployAck(element.getDeployState(), element.getLockState(), element.getOperationalState(),
178                         element.getUseState(), element.getOutProperties(), true, message));
179         LOGGER.debug(MSG_STATE_CHANGE, elementId, deployState);
180         publisher.sendAutomationCompositionAck(acStateChangeAck);
181         cacheProvider.getMsgIdentification().remove(element.getId());
182     }
183
184     private void checkElement(AutomationComposition automationComposition, UUID instance, UUID elementId,
185             DeployState deployState, StateChangeResult stateChangeResult, String message) {
186         if ((DeployState.MIGRATING.equals(automationComposition.getDeployState())
187                 || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState()))) {
188             var acStateChangeAck = createAutomationCompositionDeployAck();
189             acStateChangeAck.setMessage(AcmUtils.validatedMessage(message));
190             acStateChangeAck.setResponseTo(cacheProvider.getMsgIdentification().get(elementId));
191             acStateChangeAck.setStateChangeResult(stateChangeResult);
192             acStateChangeAck.setAutomationCompositionId(instance);
193             acStateChangeAck.getAutomationCompositionResultMap().put(elementId,
194                     new AcElementDeployAck(deployState, null, null,
195                             null, Map.of(), true, message));
196             LOGGER.debug(MSG_STATE_CHANGE, elementId, deployState);
197             publisher.sendAutomationCompositionAck(acStateChangeAck);
198             cacheProvider.getMsgIdentification().remove(elementId);
199         } else {
200             LOGGER.error(MSG_NOT_PRESENT, "state", MSG_AC_ELEMENT, elementId);
201         }
202     }
203
204     private AutomationCompositionDeployAck createAutomationCompositionDeployAck() {
205         var acStateChangeAck =
206                 new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
207         acStateChangeAck.setParticipantId(cacheProvider.getParticipantId());
208         acStateChangeAck.setReplicaId(cacheProvider.getReplicaId());
209         acStateChangeAck.setResult(true);
210         return acStateChangeAck;
211     }
212
213     private void handleDeployState(AutomationComposition automationComposition, AutomationCompositionElement element,
214             DeployState deployState, StateChangeResult stateChangeResult) {
215         element.setDeployState(deployState);
216         element.setLockState(DeployState.DEPLOYED.equals(element.getDeployState()) ? LockState.LOCKED : LockState.NONE);
217         if (StateChangeResult.FAILED.equals(stateChangeResult)) {
218             return;
219         }
220         var checkOpt = automationComposition.getElements().values().stream()
221                 .filter(acElement -> !deployState.equals(acElement.getDeployState())).findAny();
222         if (checkOpt.isEmpty()) {
223             if (DeployState.DEPLOYED.equals(automationComposition.getDeployState())
224                     && automationComposition.getCompositionTargetId() != null) {
225                 // migration scenario
226                 automationComposition.setCompositionId(automationComposition.getCompositionTargetId());
227                 automationComposition.setCompositionTargetId(null);
228             }
229             automationComposition.setDeployState(deployState);
230             automationComposition.setLockState(element.getLockState());
231             automationComposition.setSubState(SubState.NONE);
232
233             if (DeployState.DELETED.equals(deployState)) {
234                 cacheProvider.removeAutomationComposition(automationComposition.getInstanceId());
235             }
236         }
237     }
238
239     private void handleLockState(AutomationComposition automationComposition, AutomationCompositionElement element,
240             LockState lockState, StateChangeResult stateChangeResult) {
241         element.setLockState(lockState);
242         if (StateChangeResult.FAILED.equals(stateChangeResult)) {
243             return;
244         }
245         var checkOpt = automationComposition.getElements().values().stream()
246                 .filter(acElement -> !lockState.equals(acElement.getLockState())).findAny();
247         if (checkOpt.isEmpty()) {
248             automationComposition.setLockState(lockState);
249             automationComposition.setSubState(SubState.NONE);
250         }
251     }
252
253     private void handleSubState(AutomationComposition automationComposition, AutomationCompositionElement element,
254             StateChangeResult stateChangeResult) {
255         if (StateChangeResult.FAILED.equals(stateChangeResult)) {
256             return;
257         }
258         element.setSubState(SubState.NONE);
259         var checkOpt = automationComposition.getElements().values().stream()
260                 .filter(acElement -> !SubState.NONE.equals(acElement.getSubState())).findAny();
261         if (checkOpt.isEmpty()) {
262             automationComposition.setSubState(SubState.NONE);
263         }
264     }
265
266     /**
267      * Send Ac Element Info.
268      *
269      * @param automationCompositionId the automationComposition Id
270      * @param elementId the automationComposition Element id
271      * @param useState the use State
272      * @param operationalState the operational State
273      * @param outProperties the output Properties Map
274      */
275     public void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState,
276             String operationalState, Map<String, Object> outProperties) {
277
278         if (automationCompositionId == null || elementId == null) {
279             LOGGER.error("Cannot update Automation composition element state, id is null");
280             return;
281         }
282
283         var automationComposition = cacheProvider.getAutomationComposition(automationCompositionId);
284         if (automationComposition == null) {
285             LOGGER.error(MSG_NOT_PRESENT, "outProperites", MSG_AC, automationCompositionId);
286             return;
287         }
288
289         var element = automationComposition.getElements().get(elementId);
290         if (element == null) {
291             LOGGER.error(MSG_NOT_PRESENT, "outProperites", MSG_AC_ELEMENT, elementId);
292             return;
293         }
294         element.setOperationalState(operationalState);
295         element.setUseState(useState);
296         element.setOutProperties(outProperties);
297
298         var acInfo = new AutomationCompositionInfo();
299         acInfo.setAutomationCompositionId(automationCompositionId);
300         acInfo.setDeployState(automationComposition.getDeployState());
301         acInfo.setLockState(automationComposition.getLockState());
302         acInfo.setElements(List.of(getAutomationCompositionElementInfo(element)));
303         var statusMsg = createParticipantStatus();
304         statusMsg.setCompositionId(automationComposition.getCompositionId());
305         statusMsg.setAutomationCompositionInfoList(List.of(acInfo));
306         publisher.sendParticipantStatus(statusMsg);
307     }
308
309     /**
310      * Get AutomationCompositionElementInfo from AutomationCompositionElement.
311      *
312      * @param element the AutomationCompositionElement
313      * @return the AutomationCompositionElementInfo
314      */
315     public AutomationCompositionElementInfo getAutomationCompositionElementInfo(AutomationCompositionElement element) {
316         var elementInfo = new AutomationCompositionElementInfo();
317         elementInfo.setAutomationCompositionElementId(element.getId());
318         elementInfo.setDeployState(element.getDeployState());
319         elementInfo.setLockState(element.getLockState());
320         elementInfo.setOperationalState(element.getOperationalState());
321         elementInfo.setUseState(element.getUseState());
322         elementInfo.setOutProperties(element.getOutProperties());
323         return elementInfo;
324     }
325
326     /**
327      * Update Composition State for prime and deprime.
328      *
329      * @param compositionId the composition id
330      * @param state the Composition State
331      * @param stateChangeResult the indicator if error occurs
332      * @param message the message
333      */
334     public void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult,
335             String message) {
336         if (compositionId == null) {
337             LOGGER.error("Cannot update Automation composition definition state, id is null");
338             return;
339         }
340
341         if (stateChangeResult == null) {
342             LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is null");
343             return;
344         }
345         if (!StateChangeResult.NO_ERROR.equals(stateChangeResult)
346                 && !StateChangeResult.FAILED.equals(stateChangeResult)) {
347             LOGGER.error("Cannot update Automation composition definition state, stateChangeResult is not valid");
348             return;
349         }
350
351         if ((state == null) || AcTypeState.PRIMING.equals(state) || AcTypeState.DEPRIMING.equals(state)) {
352             LOGGER.error("state invalid {} cannot be handled", state);
353             return;
354         }
355
356         var participantPrimeAck = new ParticipantPrimeAck();
357         participantPrimeAck.setCompositionId(compositionId);
358         participantPrimeAck.setMessage(AcmUtils.validatedMessage(message));
359         participantPrimeAck.setResult(true);
360         participantPrimeAck.setResponseTo(cacheProvider.getMsgIdentification().get(compositionId));
361         participantPrimeAck.setCompositionState(state);
362         participantPrimeAck.setStateChangeResult(stateChangeResult);
363         participantPrimeAck.setParticipantId(cacheProvider.getParticipantId());
364         participantPrimeAck.setReplicaId(cacheProvider.getReplicaId());
365         participantPrimeAck.setState(ParticipantState.ON_LINE);
366         publisher.sendParticipantPrimeAck(participantPrimeAck);
367         cacheProvider.getMsgIdentification().remove(compositionId);
368         if (AcTypeState.COMMISSIONED.equals(state) && StateChangeResult.NO_ERROR.equals(stateChangeResult)) {
369             cacheProvider.removeElementDefinition(compositionId);
370         }
371     }
372
373     /**
374      * Send Composition Definition Info.
375      *
376      * @param compositionId the composition id
377      * @param elementId the Composition Definition Element id
378      * @param outProperties the output Properties Map
379      */
380     public void sendAcDefinitionInfo(UUID compositionId, ToscaConceptIdentifier elementId,
381             Map<String, Object> outProperties) {
382         if (compositionId == null) {
383             LOGGER.error("Cannot send Composition outProperties, id is null");
384             return;
385         }
386         var statusMsg = createParticipantStatus();
387         statusMsg.setCompositionId(compositionId);
388         var acElementDefsMap = cacheProvider.getAcElementsDefinitions();
389         var acDefinition = acElementDefsMap.get(compositionId);
390         if (acDefinition == null) {
391             LOGGER.error("Cannot send Composition outProperties, id {} is null", compositionId);
392             return;
393         }
394         var acElementDefinition = getAutomationCompositionElementDefinition(acDefinition, elementId);
395         if (acElementDefinition == null) {
396             LOGGER.error("Cannot send Composition outProperties, elementId {} not present", elementId);
397             return;
398         }
399         acElementDefinition.setOutProperties(outProperties);
400         var participantDefinition = new ParticipantDefinition();
401         participantDefinition.setParticipantId(cacheProvider.getParticipantId());
402         participantDefinition.setAutomationCompositionElementDefinitionList(List.of(acElementDefinition));
403         statusMsg.setParticipantDefinitionUpdates(List.of(participantDefinition));
404         publisher.sendParticipantStatus(statusMsg);
405     }
406
407     private AutomationCompositionElementDefinition getAutomationCompositionElementDefinition(
408             AcDefinition acElementsDefinition,
409             ToscaConceptIdentifier elementId) {
410
411         if (elementId == null) {
412             if (acElementsDefinition.getElements().size() == 1) {
413                 return acElementsDefinition.getElements().values().iterator().next();
414             }
415             return null;
416         }
417         return acElementsDefinition.getElements().get(elementId);
418     }
419
420     private ParticipantStatus createParticipantStatus() {
421         var statusMsg = new ParticipantStatus();
422         statusMsg.setParticipantId(cacheProvider.getParticipantId());
423         statusMsg.setReplicaId(cacheProvider.getReplicaId());
424         statusMsg.setState(ParticipantState.ON_LINE);
425         statusMsg.setParticipantSupportedElementType(cacheProvider.getSupportedAcElementTypes());
426         return statusMsg;
427     }
428 }