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