bf9fbbcd2cfe2b51cc1191bddc3b52249fec6623
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2023 Nordix Foundation.
4  * ================================================================================
5  * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.clamp.acm.participant.intermediary.handler;
24
25 import io.micrometer.core.annotation.Timed;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.UUID;
31 import lombok.Getter;
32 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
33 import org.onap.policy.clamp.acm.participant.intermediary.parameters.ParticipantParameters;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo;
37 import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
38 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
39 import org.onap.policy.clamp.models.acm.concepts.ParticipantSupportedElementType;
40 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
41 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
42 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantAckMessage;
43 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantDeregister;
44 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantDeregisterAck;
45 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessage;
46 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantPrime;
47 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantPrimeAck;
48 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegister;
49 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegisterAck;
50 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
51 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatusReq;
52 import org.onap.policy.models.base.PfModelException;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.stereotype.Component;
56
57 /**
58  * This class is responsible for managing the state of a participant.
59  */
60 @Component
61 public class ParticipantHandler {
62     private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantHandler.class);
63
64     @Getter
65     private final UUID participantId;
66
67     private final AutomationCompositionHandler automationCompositionHandler;
68     private final ParticipantMessagePublisher publisher;
69
70     private final Map<UUID, List<AutomationCompositionElementDefinition>> acElementDefsMap = new HashMap<>();
71
72     private final List<ParticipantSupportedElementType> supportedAcElementTypes;
73
74     /**
75      * Constructor, set the participant ID and sender.
76      *
77      * @param parameters the parameters of the participant
78      * @param publisher the publisher for sending responses to messages
79      */
80     public ParticipantHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher,
81             AutomationCompositionHandler automationCompositionHandler) {
82         this.participantId = parameters.getIntermediaryParameters().getParticipantId();
83         this.publisher = publisher;
84         this.automationCompositionHandler = automationCompositionHandler;
85         this.supportedAcElementTypes = parameters.getIntermediaryParameters().getParticipantSupportedElementTypes();
86     }
87
88     /**
89      * Method which handles a participant health check event from clamp.
90      *
91      * @param participantStatusReqMsg participant participantStatusReq message
92      */
93     @Timed(value = "listener.participant_status_req", description = "PARTICIPANT_STATUS_REQ messages received")
94     public void handleParticipantStatusReq(final ParticipantStatusReq participantStatusReqMsg) {
95         var participantStatus = makeHeartbeat(true);
96         participantStatus.setParticipantSupportedElementType(this.supportedAcElementTypes);
97         publisher.sendParticipantStatus(participantStatus);
98     }
99
100     /**
101      * Handle a automation composition update message.
102      *
103      * @param updateMsg the update message
104      */
105     @Timed(
106             value = "listener.automation_composition_update",
107             description = "AUTOMATION_COMPOSITION_UPDATE messages received")
108     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy updateMsg) {
109         automationCompositionHandler.handleAutomationCompositionDeploy(updateMsg,
110                 acElementDefsMap.get(updateMsg.getCompositionId()));
111     }
112
113     /**
114      * Handle a automation composition state change message.
115      *
116      * @param stateChangeMsg the state change message
117      */
118     @Timed(
119             value = "listener.automation_composition_state_change",
120             description = "AUTOMATION_COMPOSITION_STATE_CHANGE messages received")
121     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
122         automationCompositionHandler.handleAutomationCompositionStateChange(stateChangeMsg,
123                 acElementDefsMap.get(stateChangeMsg.getCompositionId()));
124     }
125
126     /**
127      * Check if a participant message applies to this participant handler.
128      *
129      * @param participantMsg the message to check
130      * @return true if it applies, false otherwise
131      */
132     public boolean appliesTo(ParticipantMessage participantMsg) {
133         return participantMsg.appliesTo(participantId);
134     }
135
136     /**
137      * Check if a participant message applies to this participant handler.
138      *
139      * @param participantMsg the message to check
140      * @return true if it applies, false otherwise
141      */
142     public boolean appliesTo(ParticipantAckMessage participantMsg) {
143         return participantMsg.appliesTo(participantId);
144     }
145
146     /**
147      * Method to send ParticipantRegister message to automation composition runtime.
148      */
149     public void sendParticipantRegister() {
150         var participantRegister = new ParticipantRegister();
151         participantRegister.setParticipantId(participantId);
152         participantRegister.setParticipantSupportedElementType(supportedAcElementTypes);
153
154         publisher.sendParticipantRegister(participantRegister);
155     }
156
157     /**
158      * Handle a participantRegister Ack message.
159      *
160      * @param participantRegisterAckMsg the participantRegisterAck message
161      */
162     @Timed(value = "listener.participant_register_ack", description = "PARTICIPANT_REGISTER_ACK messages received")
163     public void handleParticipantRegisterAck(ParticipantRegisterAck participantRegisterAckMsg) {
164         LOGGER.debug("ParticipantRegisterAck message received as responseTo {}",
165                 participantRegisterAckMsg.getResponseTo());
166         publisher.sendParticipantStatus(makeHeartbeat(false));
167     }
168
169     /**
170      * Method to send ParticipantDeregister message to automation composition runtime.
171      */
172     public void sendParticipantDeregister() {
173         var participantDeregister = new ParticipantDeregister();
174         participantDeregister.setParticipantId(participantId);
175
176         undeployInstancesOnParticipant();
177         publisher.sendParticipantDeregister(participantDeregister);
178     }
179
180     private void undeployInstancesOnParticipant() {
181         automationCompositionHandler.getAutomationCompositionMap().values().forEach(ac ->
182             undeployInstanceOnParticipant(ac)
183         );
184     }
185
186     private void undeployInstanceOnParticipant(AutomationComposition automationComposition) {
187         automationComposition.getElements().values().forEach(element -> {
188             if (element.getParticipantId().equals(participantId)) {
189                 undeployInstanceElementsOnParticipant(automationComposition.getInstanceId(), element.getId());
190             }
191         });
192     }
193
194     private void undeployInstanceElementsOnParticipant(UUID instanceId, UUID elementId) {
195         var acElementListeners = automationCompositionHandler.getListeners();
196         for (var acElementListener : acElementListeners) {
197             try {
198                 acElementListener.undeploy(instanceId, elementId);
199             } catch (PfModelException e) {
200                 LOGGER.debug("Automation composition element update failed {}", instanceId);
201             }
202         }
203     }
204
205     /**
206      * Handle a participantDeregister Ack message.
207      *
208      * @param participantDeregisterAckMsg the participantDeregisterAck message
209      */
210     @Timed(value = "listener.participant_deregister_ack", description = "PARTICIPANT_DEREGISTER_ACK messages received")
211     public void handleParticipantDeregisterAck(ParticipantDeregisterAck participantDeregisterAckMsg) {
212         LOGGER.debug("ParticipantDeregisterAck message received as responseTo {}",
213                 participantDeregisterAckMsg.getResponseTo());
214     }
215
216     /**
217      * Handle a ParticipantPrime message.
218      *
219      * @param participantPrimeMsg the ParticipantPrime message
220      */
221     @Timed(value = "listener.participant_prime", description = "PARTICIPANT_PRIME messages received")
222     public void handleParticipantPrime(ParticipantPrime participantPrimeMsg) {
223         LOGGER.debug("ParticipantPrime message received for participantId {}",
224                 participantPrimeMsg.getParticipantId());
225
226         acElementDefsMap.putIfAbsent(participantPrimeMsg.getCompositionId(), new ArrayList<>());
227         if (!participantPrimeMsg.getParticipantDefinitionUpdates().isEmpty()) {
228             // This message is to commission the automation composition
229             for (var participantDefinition : participantPrimeMsg.getParticipantDefinitionUpdates()) {
230                 if (participantDefinition.getParticipantId().equals(participantId)) {
231                     acElementDefsMap.get(participantPrimeMsg.getCompositionId())
232                             .addAll(participantDefinition.getAutomationCompositionElementDefinitionList());
233                     break;
234                 }
235             }
236         } else {
237             // This message is to decommission the automation composition
238             acElementDefsMap.get(participantPrimeMsg.getCompositionId()).clear();
239         }
240         sendParticipantPrimeAck(participantPrimeMsg.getMessageId(), participantPrimeMsg.getCompositionId());
241     }
242
243     /**
244      * Method to send ParticipantPrimeAck message to automation composition runtime.
245      */
246     public void sendParticipantPrimeAck(UUID messageId, UUID compositionId) {
247         var participantPrimeAck = new ParticipantPrimeAck();
248         participantPrimeAck.setResponseTo(messageId);
249         participantPrimeAck.setCompositionId(compositionId);
250         participantPrimeAck.setMessage("Participant Prime Ack message");
251         participantPrimeAck.setResult(true);
252         participantPrimeAck.setParticipantId(participantId);
253         participantPrimeAck.setState(ParticipantState.ON_LINE);
254         publisher.sendParticipantPrimeAck(participantPrimeAck);
255     }
256
257     /**
258      * Dispatch a heartbeat for this participant.
259      */
260     public void sendHeartbeat() {
261         publisher.sendHeartbeat(makeHeartbeat(false));
262     }
263
264     /**
265      * Method to send heartbeat to automation composition runtime.
266      */
267     public ParticipantStatus makeHeartbeat(boolean responseToParticipantStatusReq) {
268         var heartbeat = new ParticipantStatus();
269         heartbeat.setParticipantId(participantId);
270         heartbeat.setState(ParticipantState.ON_LINE);
271         heartbeat.setAutomationCompositionInfoList(getAutomationCompositionInfoList());
272
273         if (responseToParticipantStatusReq) {
274             List<ParticipantDefinition> participantDefinitionList = new ArrayList<>(acElementDefsMap.size());
275             for (var acElementDefsOnThisParticipant : acElementDefsMap.values()) {
276                 var participantDefinition = new ParticipantDefinition();
277                 participantDefinition.setParticipantId(participantId);
278                 participantDefinition.setAutomationCompositionElementDefinitionList(acElementDefsOnThisParticipant);
279                 participantDefinitionList.add(participantDefinition);
280             }
281             heartbeat.setParticipantDefinitionUpdates(participantDefinitionList);
282         }
283
284         return heartbeat;
285     }
286
287     private List<AutomationCompositionInfo> getAutomationCompositionInfoList() {
288         List<AutomationCompositionInfo> automationCompositionInfoList = new ArrayList<>();
289         for (var entry : automationCompositionHandler.getAutomationCompositionMap().entrySet()) {
290             var acInfo = new AutomationCompositionInfo();
291             acInfo.setAutomationCompositionId(entry.getKey());
292             acInfo.setDeployState(entry.getValue().getDeployState());
293             acInfo.setLockState(entry.getValue().getLockState());
294             automationCompositionInfoList.add(acInfo);
295         }
296         return automationCompositionInfoList;
297     }
298 }