71c9d9abce3efa488cab9f89dddeedd8aeb7c887
[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.AutomationComposition;
30 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
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.concepts.StateChangeResult;
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.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 ThreadHandler 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             ThreadHandler 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             if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
87                 var automationCompositionAck = new AutomationCompositionDeployAck(
88                         ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
89                 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
90                 automationCompositionAck.setMessage("Already deleted or never used");
91                 automationCompositionAck.setResult(true);
92                 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
93                 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
94                 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
95                 publisher.sendAutomationCompositionAck(automationCompositionAck);
96             } else {
97                 LOGGER.debug("Automation composition {} does not use this participant",
98                         stateChangeMsg.getAutomationCompositionId());
99             }
100             return;
101         }
102
103         if (!checkConsistantOrderState(automationComposition, stateChangeMsg.getDeployOrderedState(),
104                 stateChangeMsg.getLockOrderedState())) {
105             LOGGER.warn("Not Consistant OrderState Automation composition {}",
106                     stateChangeMsg.getAutomationCompositionId());
107             return;
108         }
109
110         if (DeployOrder.NONE.equals(stateChangeMsg.getDeployOrderedState())) {
111             handleLockOrderState(stateChangeMsg.getMessageId(), automationComposition,
112                     stateChangeMsg.getLockOrderedState(), stateChangeMsg.getStartPhase());
113         } else {
114             handleDeployOrderState(stateChangeMsg.getMessageId(), automationComposition,
115                     stateChangeMsg.getDeployOrderedState(), stateChangeMsg.getStartPhase());
116         }
117     }
118
119     private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder,
120             LockOrder lockOrder) {
121         if (DeployOrder.UPDATE.equals(deployOrder)) {
122             return true;
123         }
124         return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(),
125                 automationComposition.getLockState(), automationComposition.getStateChangeResult()) != null;
126     }
127
128     /**
129      * Method to handle state changes.
130      *
131      * @param messageId the messageId
132      * @param automationComposition participant response
133      * @param orderedState automation composition ordered state
134      * @param startPhaseMsg startPhase from message
135      */
136     private void handleDeployOrderState(UUID messageId, final AutomationComposition automationComposition,
137             DeployOrder orderedState, Integer startPhaseMsg) {
138
139         switch (orderedState) {
140             case UNDEPLOY:
141                 handleUndeployState(messageId, automationComposition, startPhaseMsg);
142                 break;
143             case DELETE:
144                 handleDeleteState(messageId, automationComposition, startPhaseMsg);
145                 break;
146
147             default:
148                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
149                 break;
150         }
151     }
152
153     /**
154      * Method to handle state changes.
155      *
156      * @param messageId the messageId
157      * @param automationComposition participant response
158      * @param orderedState automation composition ordered state
159      * @param startPhaseMsg startPhase from message
160      */
161     private void handleLockOrderState(UUID messageId, final AutomationComposition automationComposition,
162             LockOrder orderedState, Integer startPhaseMsg) {
163
164         switch (orderedState) {
165             case LOCK:
166                 handleLockState(messageId, automationComposition, startPhaseMsg);
167                 break;
168             case UNLOCK:
169                 handleUnlockState(messageId, automationComposition, startPhaseMsg);
170                 break;
171             default:
172                 LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
173                 break;
174         }
175     }
176
177     /**
178      * Handle a automation composition properties update message.
179      *
180      * @param updateMsg the properties update message
181      */
182     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
183
184         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
185             LOGGER.warn("No AutomationCompositionElement updates in message {}",
186                     updateMsg.getAutomationCompositionId());
187             return;
188         }
189
190         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
191             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
192
193                 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy);
194
195                 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(),
196                         updateMsg.getAutomationCompositionId());
197             }
198         }
199     }
200
201     /**
202      * Handle a automation composition Deploy message.
203      *
204      * @param deployMsg the Deploy message
205      */
206     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
207
208         if (deployMsg.getParticipantUpdatesList().isEmpty()) {
209             LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
210             return;
211         }
212
213         for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
214             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
215                 if (deployMsg.isFirstStartPhase()) {
216                     cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
217                             deployMsg.getAutomationCompositionId(), participantDeploy);
218                 }
219                 callParticipanDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
220                         deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
221             }
222         }
223     }
224
225     private void callParticipanDeploy(UUID messageId, List<AcElementDeploy> acElements, Integer startPhaseMsg,
226             UUID instanceId) {
227         for (var element : acElements) {
228             var commonProperties = cacheProvider.getCommonProperties(instanceId, element.getId());
229             int startPhase = ParticipantUtils.findStartPhase(commonProperties);
230             if (startPhaseMsg.equals(startPhase)) {
231                 var map = new HashMap<>(commonProperties);
232                 map.putAll(element.getProperties());
233                 listener.deploy(messageId, instanceId, element, map);
234             }
235         }
236     }
237
238     private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements, UUID instanceId) {
239         for (var element : acElements) {
240             listener.update(messageId, instanceId, element, element.getProperties());
241         }
242     }
243
244     private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy) {
245         var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
246         for (var element : participantDeploy.getAcElementList()) {
247             var acElement = acElementList.get(element.getId());
248             acElement.getProperties().putAll(element.getProperties());
249         }
250     }
251
252     /**
253      * Method to handle when the new state from participant is UNINITIALISED state.
254      *
255      * @param messageId the messageId
256      * @param automationComposition participant response
257      * @param startPhaseMsg startPhase from message
258      */
259     private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
260             Integer startPhaseMsg) {
261         for (var acElement : automationComposition.getElements().values()) {
262             int startPhase = ParticipantUtils.findStartPhase(
263                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
264             if (startPhaseMsg.equals(startPhase)) {
265                 listener.undeploy(messageId, automationComposition.getInstanceId(), acElement.getId());
266             }
267         }
268     }
269
270     private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
271             Integer startPhaseMsg) {
272         for (var acElement : automationComposition.getElements().values()) {
273             int startPhase = ParticipantUtils.findStartPhase(
274                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
275             if (startPhaseMsg.equals(startPhase)) {
276                 listener.delete(messageId, automationComposition.getInstanceId(), acElement.getId());
277             }
278         }
279     }
280
281     /**
282      * Method to handle when the new state from participant is PASSIVE state.
283      *
284      * @param messageId the messageId
285      * @param automationComposition participant response
286      * @param startPhaseMsg startPhase from message
287      */
288     private void handleLockState(UUID messageId, final AutomationComposition automationComposition,
289             Integer startPhaseMsg) {
290         for (var acElement : automationComposition.getElements().values()) {
291             int startPhase = ParticipantUtils.findStartPhase(
292                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
293             if (startPhaseMsg.equals(startPhase)) {
294                 listener.lock(messageId, automationComposition.getInstanceId(), acElement.getId());
295             }
296         }
297     }
298
299     /**
300      * Method to handle when the new state from participant is RUNNING state.
301      *
302      * @param messageId the messageId
303      * @param automationComposition participant response
304      * @param startPhaseMsg startPhase from message
305      */
306     private void handleUnlockState(UUID messageId, final AutomationComposition automationComposition,
307             Integer startPhaseMsg) {
308         for (var acElement : automationComposition.getElements().values()) {
309             int startPhase = ParticipantUtils.findStartPhase(
310                     cacheProvider.getCommonProperties(automationComposition.getInstanceId(), acElement.getId()));
311             if (startPhaseMsg.equals(startPhase)) {
312                 listener.unlock(messageId, automationComposition.getInstanceId(), acElement.getId());
313             }
314         }
315     }
316
317     /**
318      * Handles prime a Composition Definition.
319      *
320      * @param messageId the messageId
321      * @param compositionId the compositionId
322      * @param list the list of AutomationCompositionElementDefinition
323      */
324     public void prime(UUID messageId, UUID compositionId, List<AutomationCompositionElementDefinition> list) {
325         listener.prime(messageId, compositionId, list);
326     }
327
328     /**
329      * Handles deprime a Composition Definition.
330      *
331      * @param messageId the messageId
332      * @param compositionId the compositionId
333      */
334     public void deprime(UUID messageId, UUID compositionId) {
335         listener.deprime(messageId, compositionId);
336     }
337 }