7e713654d4034c0d8e21e170f6395eecad63730d
[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.AutomationCompositionElementDefinition;
32 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
33 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
34 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
35 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck;
36 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
37 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
38 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
39 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
40 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
41 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
42 import org.onap.policy.models.base.PfModelException;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.stereotype.Component;
46
47 /*
48  * This class is responsible for managing the state of all automation compositions in the participant.
49  */
50 @Component
51 public class AutomationCompositionHandler {
52     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
53
54     private final CacheProvider cacheProvider;
55     private final ParticipantMessagePublisher publisher;
56     private final AutomationCompositionElementListener listener;
57     private final AcInstanceStateResolver acInstanceStateResolver;
58
59     /**
60      * Constructor, set the participant ID and messageSender.
61      *
62      * @param cacheProvider the Cache Provider
63      * @param publisher the ParticipantMessage Publisher
64      * @param listener the ThreadHandler Listener
65      */
66     public AutomationCompositionHandler(CacheProvider cacheProvider, ParticipantMessagePublisher publisher,
67             AutomationCompositionElementListener listener) {
68         this.cacheProvider = cacheProvider;
69         this.publisher = publisher;
70         this.listener = listener;
71         this.acInstanceStateResolver = new AcInstanceStateResolver();
72     }
73
74     /**
75      * Handle a automation composition state change message.
76      *
77      * @param stateChangeMsg the state change message
78      */
79     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
80         if (stateChangeMsg.getAutomationCompositionId() == null) {
81             return;
82         }
83
84         var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
85
86         if (automationComposition == null) {
87             var automationCompositionAck =
88                     new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
89             automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
90             automationCompositionAck.setMessage("Automation composition " + stateChangeMsg.getAutomationCompositionId()
91                     + " does not use this participant " + cacheProvider.getParticipantId());
92             automationCompositionAck.setResult(false);
93             automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
94             automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
95             publisher.sendAutomationCompositionAck(automationCompositionAck);
96             LOGGER.debug("Automation composition {} does not use this participant",
97                     stateChangeMsg.getAutomationCompositionId());
98             return;
99         }
100
101         if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
102                 stateChangeMsg.getLockOrderedState())) {
103             LOGGER.warn("Not Consistant OrderState Automation composition {}",
104                     stateChangeMsg.getAutomationCompositionId());
105             return;
106         }
107
108         if (DeployOrder.NONE.equals(stateChangeMsg.getDeployOrderedState())) {
109             handleLockOrderState(automationComposition, stateChangeMsg.getLockOrderedState(),
110                     stateChangeMsg.getStartPhase());
111         } else {
112             handleDeployOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
113                     stateChangeMsg.getStartPhase());
114         }
115     }
116
117     private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder,
118             LockOrder lockOrder) {
119         if (DeployOrder.UPDATE.equals(deployOrder)) {
120             return false;
121         }
122         return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
123                 automationComposition.getLockState(), automationComposition.getStateChangeResult()) != null;
124     }
125
126     /**
127      * Method to handle state changes.
128      *
129      * @param automationComposition participant response
130      * @param orderedState automation composition ordered state
131      * @param startPhaseMsg startPhase from message
132      */
133     private void handleDeployOrderState(final AutomationComposition automationComposition, DeployOrder orderedState,
134             Integer startPhaseMsg) {
135
136         switch (orderedState) {
137             case UNDEPLOY:
138                 handleUndeployState(automationComposition, startPhaseMsg);
139                 break;
140             case DELETE:
141                 handleDeleteState(automationComposition, startPhaseMsg);
142                 break;
143
144             default:
145                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
146                 break;
147         }
148     }
149
150     /**
151      * Method to handle state changes.
152      *
153      * @param automationComposition participant response
154      * @param orderedState automation composition ordered state
155      * @param startPhaseMsg startPhase from message
156      */
157     private void handleLockOrderState(final AutomationComposition automationComposition, LockOrder orderedState,
158             Integer startPhaseMsg) {
159
160         switch (orderedState) {
161             case LOCK:
162                 handleLockState(automationComposition, startPhaseMsg);
163                 break;
164             case UNLOCK:
165                 handleUnlockState(automationComposition, startPhaseMsg);
166                 break;
167             default:
168                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
169                 break;
170         }
171     }
172
173     /**
174      * Handle a automation composition properties update message.
175      *
176      * @param updateMsg the properties update message
177      */
178     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
179
180         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
181             LOGGER.warn("No AutomationCompositionElement updates in message {}",
182                     updateMsg.getAutomationCompositionId());
183             return;
184         }
185
186         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
187             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
188
189                 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy);
190
191                 callParticipantUpdateProperty(participantDeploy.getAcElementList(),
192                         updateMsg.getAutomationCompositionId());
193             }
194         }
195     }
196
197     /**
198      * Handle a automation composition Deploy message.
199      *
200      * @param deployMsg the Deploy message
201      */
202     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
203
204         if (deployMsg.getParticipantUpdatesList().isEmpty()) {
205             LOGGER.warn("No AutomationCompositionElement deploy in message {}", 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
329     /**
330      * Handles prime a Composition Definition.
331      *
332      * @param compositionId the compositionId
333      * @param list the list of AutomationCompositionElementDefinition
334      */
335     public void prime(UUID compositionId, List<AutomationCompositionElementDefinition> list) {
336         try {
337             listener.prime(compositionId, list);
338         } catch (PfModelException e) {
339             LOGGER.debug("Composition prime failed {}", compositionId);
340         }
341     }
342
343     /**
344      * Handles deprime a Composition Definition.
345      *
346      * @param compositionId the compositionId
347      */
348     public void deprime(UUID compositionId) {
349         try {
350             listener.deprime(compositionId);
351         } catch (PfModelException e) {
352             LOGGER.debug("Composition deprime failed {}", compositionId);
353         }
354     }
355 }