c7cb54893fad6ae81bc08f78695e33b0764b9e05
[policy/clamp.git] /
1 /*-
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.clamp.acm.participant.intermediary.handler;
23
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.UUID;
27 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
28 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
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.AutomationCompositionElementDefinition;
32 import org.onap.policy.clamp.models.acm.concepts.DeployState;
33 import org.onap.policy.clamp.models.acm.concepts.LockState;
34 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
35 import org.onap.policy.clamp.models.acm.concepts.ParticipantRestartAc;
36 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
37 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
38 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
39 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck;
40 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
41 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
42 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
43 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
44 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
45 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.stereotype.Component;
49
50 /*
51  * This class is responsible for managing the state of all automation compositions in the participant.
52  */
53 @Component
54 public class AutomationCompositionHandler {
55     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
56
57     private final CacheProvider cacheProvider;
58     private final ParticipantMessagePublisher publisher;
59     private final ThreadHandler listener;
60     private final AcInstanceStateResolver acInstanceStateResolver;
61
62     /**
63      * Constructor, set the participant ID and messageSender.
64      *
65      * @param cacheProvider the Cache Provider
66      * @param publisher the ParticipantMessage Publisher
67      * @param listener the ThreadHandler Listener
68      */
69     public AutomationCompositionHandler(CacheProvider cacheProvider, ParticipantMessagePublisher publisher,
70             ThreadHandler listener) {
71         this.cacheProvider = cacheProvider;
72         this.publisher = publisher;
73         this.listener = listener;
74         this.acInstanceStateResolver = new AcInstanceStateResolver();
75     }
76
77     /**
78      * Handle a automation composition state change message.
79      *
80      * @param stateChangeMsg the state change message
81      */
82     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
83         if (stateChangeMsg.getAutomationCompositionId() == null) {
84             return;
85         }
86
87         var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
88
89         if (automationComposition == null) {
90             if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
91                 var automationCompositionAck = new AutomationCompositionDeployAck(
92                         ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
93                 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
94                 automationCompositionAck.setMessage("Already deleted or never used");
95                 automationCompositionAck.setResult(true);
96                 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
97                 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
98                 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
99                 publisher.sendAutomationCompositionAck(automationCompositionAck);
100             } else {
101                 LOGGER.debug("Automation composition {} does not use this participant",
102                         stateChangeMsg.getAutomationCompositionId());
103             }
104             return;
105         }
106
107         if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
108                 stateChangeMsg.getLockOrderedState())) {
109             LOGGER.warn("Not Consistant OrderState Automation composition {}",
110                     stateChangeMsg.getAutomationCompositionId());
111             return;
112         }
113
114         if (DeployOrder.NONE.equals(stateChangeMsg.getDeployOrderedState())) {
115             handleLockOrderState(stateChangeMsg.getMessageId(), automationComposition,
116                     stateChangeMsg.getLockOrderedState(), stateChangeMsg.getStartPhase());
117         } else {
118             handleDeployOrderState(stateChangeMsg.getMessageId(), automationComposition,
119                     stateChangeMsg.getDeployOrderedState(), stateChangeMsg.getStartPhase());
120         }
121     }
122
123     private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder,
124             LockOrder lockOrder) {
125         if (DeployOrder.UPDATE.equals(deployOrder)) {
126             return true;
127         }
128         return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
129                 automationComposition.getLockState(), automationComposition.getStateChangeResult()) != null;
130     }
131
132     /**
133      * Method to handle state changes.
134      *
135      * @param messageId the messageId
136      * @param automationComposition participant response
137      * @param orderedState automation composition ordered state
138      * @param startPhaseMsg startPhase from message
139      */
140     private void handleDeployOrderState(UUID messageId, final AutomationComposition automationComposition,
141             DeployOrder orderedState, Integer startPhaseMsg) {
142
143         switch (orderedState) {
144             case UNDEPLOY:
145                 handleUndeployState(messageId, automationComposition, startPhaseMsg);
146                 break;
147             case DELETE:
148                 handleDeleteState(messageId, automationComposition, startPhaseMsg);
149                 break;
150
151             default:
152                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
153                 break;
154         }
155     }
156
157     /**
158      * Method to handle state changes.
159      *
160      * @param messageId the messageId
161      * @param automationComposition participant response
162      * @param orderedState automation composition ordered state
163      * @param startPhaseMsg startPhase from message
164      */
165     private void handleLockOrderState(UUID messageId, final AutomationComposition automationComposition,
166             LockOrder orderedState, Integer startPhaseMsg) {
167
168         switch (orderedState) {
169             case LOCK:
170                 handleLockState(messageId, automationComposition, startPhaseMsg);
171                 break;
172             case UNLOCK:
173                 handleUnlockState(messageId, automationComposition, startPhaseMsg);
174                 break;
175             default:
176                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
177                 break;
178         }
179     }
180
181     /**
182      * Handle a automation composition properties update message.
183      *
184      * @param updateMsg the properties update message
185      */
186     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
187
188         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
189             LOGGER.warn("No AutomationCompositionElement updates in message {}",
190                     updateMsg.getAutomationCompositionId());
191             return;
192         }
193
194         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
195             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
196
197                 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy);
198
199                 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(),
200                         updateMsg.getAutomationCompositionId());
201             }
202         }
203     }
204
205     /**
206      * Handle a automation composition Deploy message.
207      *
208      * @param deployMsg the Deploy message
209      */
210     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
211
212         if (deployMsg.getParticipantUpdatesList().isEmpty()) {
213             LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
214             return;
215         }
216
217         for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
218             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
219                 if (deployMsg.isFirstStartPhase()) {
220                     cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
221                             deployMsg.getAutomationCompositionId(), participantDeploy);
222                 }
223                 callParticipanDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
224                         deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
225             }
226         }
227     }
228
229     private void callParticipanDeploy(UUID messageId, List<AcElementDeploy> acElements, Integer startPhaseMsg,
230             UUID instanceId) {
231         for (var element : acElements) {
232             var commonProperties = cacheProvider.getCommonProperties(instanceId, element.getId());
233             int startPhase = ParticipantUtils.findStartPhase(commonProperties);
234             if (startPhaseMsg.equals(startPhase)) {
235                 var map = new HashMap<>(commonProperties);
236                 map.putAll(element.getProperties());
237                 listener.deploy(messageId, instanceId, element, map);
238             }
239         }
240     }
241
242     private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements, UUID instanceId) {
243         for (var element : acElements) {
244             listener.update(messageId, instanceId, element, element.getProperties());
245         }
246     }
247
248     private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy) {
249         var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
250         for (var element : participantDeploy.getAcElementList()) {
251             var acElement = acElementList.get(element.getId());
252             acElement.getProperties().putAll(element.getProperties());
253         }
254     }
255
256     /**
257      * Method to handle when the new state from participant is UNINITIALISED state.
258      *
259      * @param messageId the messageId
260      * @param automationComposition participant response
261      * @param startPhaseMsg startPhase from message
262      */
263     private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
264             Integer startPhaseMsg) {
265         for (var acElement : automationComposition.getElements().values()) {
266             int startPhase = ParticipantUtils.findStartPhase(
267                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
268             if (startPhaseMsg.equals(startPhase)) {
269                 acElement.setDeployState(DeployState.UNDEPLOYING);
270                 listener.undeploy(messageId, automationComposition.getInstanceId(), acElement.getId());
271             }
272         }
273     }
274
275     private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
276             Integer startPhaseMsg) {
277         for (var acElement : automationComposition.getElements().values()) {
278             int startPhase = ParticipantUtils.findStartPhase(
279                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
280             if (startPhaseMsg.equals(startPhase)) {
281                 acElement.setDeployState(DeployState.DELETING);
282                 listener.delete(messageId, automationComposition.getInstanceId(), acElement.getId());
283             }
284         }
285     }
286
287     /**
288      * Method to handle when the new state from participant is PASSIVE state.
289      *
290      * @param messageId the messageId
291      * @param automationComposition participant response
292      * @param startPhaseMsg startPhase from message
293      */
294     private void handleLockState(UUID messageId, final AutomationComposition automationComposition,
295             Integer startPhaseMsg) {
296         for (var acElement : automationComposition.getElements().values()) {
297             int startPhase = ParticipantUtils.findStartPhase(
298                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
299             if (startPhaseMsg.equals(startPhase)) {
300                 acElement.setLockState(LockState.LOCKING);
301                 listener.lock(messageId, automationComposition.getInstanceId(), acElement.getId());
302             }
303         }
304     }
305
306     /**
307      * Method to handle when the new state from participant is RUNNING state.
308      *
309      * @param messageId the messageId
310      * @param automationComposition participant response
311      * @param startPhaseMsg startPhase from message
312      */
313     private void handleUnlockState(UUID messageId, final AutomationComposition automationComposition,
314             Integer startPhaseMsg) {
315         for (var acElement : automationComposition.getElements().values()) {
316             int startPhase = ParticipantUtils.findStartPhase(
317                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
318             if (startPhaseMsg.equals(startPhase)) {
319                 acElement.setLockState(LockState.UNLOCKING);
320                 listener.unlock(messageId, automationComposition.getInstanceId(), acElement.getId());
321             }
322         }
323     }
324
325     /**
326      * Handles prime a Composition Definition.
327      *
328      * @param messageId the messageId
329      * @param compositionId the compositionId
330      * @param list the list of AutomationCompositionElementDefinition
331      */
332     public void prime(UUID messageId, UUID compositionId, List<AutomationCompositionElementDefinition> list) {
333         listener.prime(messageId, compositionId, list);
334     }
335
336     /**
337      * Handles deprime a Composition Definition.
338      *
339      * @param messageId the messageId
340      * @param compositionId the compositionId
341      */
342     public void deprime(UUID messageId, UUID compositionId) {
343         listener.deprime(messageId, compositionId);
344     }
345
346     /**
347      * Handles restarted scenario.
348      *
349      * @param messageId the messageId
350      * @param compositionId the compositionId
351      * @param list the list of AutomationCompositionElementDefinition
352      * @param state the state of the composition
353      * @param automationCompositionList list of ParticipantRestartAc
354      */
355     public void restarted(UUID messageId, UUID compositionId, List<AutomationCompositionElementDefinition> list,
356             AcTypeState state, List<ParticipantRestartAc> automationCompositionList) {
357
358         for (var automationcomposition : automationCompositionList) {
359             cacheProvider.initializeAutomationComposition(compositionId, automationcomposition);
360         }
361         listener.restarted(messageId, compositionId, list, state, automationCompositionList);
362     }
363 }