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