ff967791d2314f4851d2520451c9570f0b72be26
[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         publisher.sendParticipantDeregister(participantDeregister);
176         undeployInstancesOnParticipant();
177     }
178
179     private void undeployInstancesOnParticipant() {
180         automationCompositionHandler.getAutomationCompositionMap().values().forEach(ac ->
181             undeployInstanceOnParticipant(ac)
182         );
183     }
184
185     private void undeployInstanceOnParticipant(AutomationComposition automationComposition) {
186         automationComposition.getElements().values().forEach(element -> {
187             if (element.getParticipantId().equals(participantId)) {
188                 undeployInstanceElementsOnParticipant(automationComposition.getInstanceId(), element.getId());
189             }
190         });
191     }
192
193     private void undeployInstanceElementsOnParticipant(UUID instanceId, UUID elementId) {
194         var acElementListeners = automationCompositionHandler.getListeners();
195         for (var acElementListener : acElementListeners) {
196             try {
197                 acElementListener.undeploy(instanceId, elementId);
198             } catch (PfModelException e) {
199                 LOGGER.debug("Automation composition element update failed {}", instanceId);
200             }
201         }
202     }
203
204     /**
205      * Handle a participantDeregister Ack message.
206      *
207      * @param participantDeregisterAckMsg the participantDeregisterAck message
208      */
209     @Timed(value = "listener.participant_deregister_ack", description = "PARTICIPANT_DEREGISTER_ACK messages received")
210     public void handleParticipantDeregisterAck(ParticipantDeregisterAck participantDeregisterAckMsg) {
211         LOGGER.debug("ParticipantDeregisterAck message received as responseTo {}",
212                 participantDeregisterAckMsg.getResponseTo());
213     }
214
215     /**
216      * Handle a ParticipantPrime message.
217      *
218      * @param participantPrimeMsg the ParticipantPrime message
219      */
220     @Timed(value = "listener.participant_prime", description = "PARTICIPANT_PRIME messages received")
221     public void handleParticipantPrime(ParticipantPrime participantPrimeMsg) {
222         LOGGER.debug("ParticipantPrime message received for participantId {}",
223                 participantPrimeMsg.getParticipantId());
224
225         acElementDefsMap.putIfAbsent(participantPrimeMsg.getCompositionId(), new ArrayList<>());
226         if (!participantPrimeMsg.getParticipantDefinitionUpdates().isEmpty()) {
227             // This message is to commission the automation composition
228             for (var participantDefinition : participantPrimeMsg.getParticipantDefinitionUpdates()) {
229                 if (participantDefinition.getParticipantId().equals(participantId)) {
230                     acElementDefsMap.get(participantPrimeMsg.getCompositionId())
231                             .addAll(participantDefinition.getAutomationCompositionElementDefinitionList());
232                     break;
233                 }
234             }
235         } else {
236             // This message is to decommission the automation composition
237             acElementDefsMap.get(participantPrimeMsg.getCompositionId()).clear();
238         }
239         sendParticipantPrimeAck(participantPrimeMsg.getMessageId(), participantPrimeMsg.getCompositionId());
240     }
241
242     /**
243      * Method to send ParticipantPrimeAck message to automation composition runtime.
244      */
245     public void sendParticipantPrimeAck(UUID messageId, UUID compositionId) {
246         var participantPrimeAck = new ParticipantPrimeAck();
247         participantPrimeAck.setResponseTo(messageId);
248         participantPrimeAck.setCompositionId(compositionId);
249         participantPrimeAck.setMessage("Participant Prime Ack message");
250         participantPrimeAck.setResult(true);
251         participantPrimeAck.setParticipantId(participantId);
252         participantPrimeAck.setState(ParticipantState.ON_LINE);
253         publisher.sendParticipantPrimeAck(participantPrimeAck);
254     }
255
256     /**
257      * Dispatch a heartbeat for this participant.
258      */
259     public void sendHeartbeat() {
260         publisher.sendHeartbeat(makeHeartbeat(false));
261     }
262
263     /**
264      * Method to send heartbeat to automation composition runtime.
265      */
266     public ParticipantStatus makeHeartbeat(boolean responseToParticipantStatusReq) {
267         var heartbeat = new ParticipantStatus();
268         heartbeat.setParticipantId(participantId);
269         heartbeat.setState(ParticipantState.ON_LINE);
270         heartbeat.setAutomationCompositionInfoList(getAutomationCompositionInfoList());
271
272         if (responseToParticipantStatusReq) {
273             List<ParticipantDefinition> participantDefinitionList = new ArrayList<>(acElementDefsMap.size());
274             for (var acElementDefsOnThisParticipant : acElementDefsMap.values()) {
275                 var participantDefinition = new ParticipantDefinition();
276                 participantDefinition.setParticipantId(participantId);
277                 participantDefinition.setAutomationCompositionElementDefinitionList(acElementDefsOnThisParticipant);
278                 participantDefinitionList.add(participantDefinition);
279             }
280             heartbeat.setParticipantDefinitionUpdates(participantDefinitionList);
281         }
282
283         return heartbeat;
284     }
285
286     private List<AutomationCompositionInfo> getAutomationCompositionInfoList() {
287         List<AutomationCompositionInfo> automationCompositionInfoList = new ArrayList<>();
288         for (var entry : automationCompositionHandler.getAutomationCompositionMap().entrySet()) {
289             var acInfo = new AutomationCompositionInfo();
290             acInfo.setAutomationCompositionId(entry.getKey());
291             acInfo.setDeployState(entry.getValue().getDeployState());
292             acInfo.setLockState(entry.getValue().getLockState());
293             automationCompositionInfoList.add(acInfo);
294         }
295         return automationCompositionInfoList;
296     }
297 }