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