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