b442b9967022d7262329337f2275aff5da6b1402
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2022 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 lombok.Setter;
33 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
34 import org.onap.policy.clamp.acm.participant.intermediary.parameters.ParticipantParameters;
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.ParticipantHealthStatus;
39 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
40 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
41 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionUpdate;
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.ParticipantRegister;
47 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegisterAck;
48 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
49 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatusReq;
50 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantUpdate;
51 import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantUpdateAck;
52 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
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 ToscaConceptIdentifier participantType;
66
67     @Getter
68     private final ToscaConceptIdentifier participantId;
69
70     private final AutomationCompositionHandler automationCompositionHandler;
71     private final ParticipantMessagePublisher publisher;
72
73     @Setter
74     private ParticipantState state = ParticipantState.UNKNOWN;
75
76     @Setter
77     private ParticipantHealthStatus healthStatus = ParticipantHealthStatus.UNKNOWN;
78
79     private final Map<UUID, List<AutomationCompositionElementDefinition>> acElementDefsMap = new HashMap<>();
80
81     /**
82      * Constructor, set the participant ID and sender.
83      *
84      * @param parameters the parameters of the participant
85      * @param publisher the publisher for sending responses to messages
86      */
87     public ParticipantHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher,
88             AutomationCompositionHandler automationCompositionHandler) {
89         this.participantType = parameters.getIntermediaryParameters().getParticipantType();
90         this.participantId = parameters.getIntermediaryParameters().getParticipantId();
91         this.publisher = publisher;
92         this.automationCompositionHandler = automationCompositionHandler;
93     }
94
95     /**
96      * Method which handles a participant health check event from clamp.
97      *
98      * @param participantStatusReqMsg participant participantStatusReq message
99      */
100     @Timed(value = "listener.participant_status_req", description = "PARTICIPANT_STATUS_REQ messages received")
101     public void handleParticipantStatusReq(final ParticipantStatusReq participantStatusReqMsg) {
102         var participantStatus = makeHeartbeat(true);
103         publisher.sendParticipantStatus(participantStatus);
104     }
105
106     /**
107      * Handle a automation composition update message.
108      *
109      * @param updateMsg the update message
110      */
111     @Timed(
112             value = "listener.automation_composition_update",
113             description = "AUTOMATION_COMPOSITION_UPDATE messages received")
114     public void handleAutomationCompositionUpdate(AutomationCompositionUpdate updateMsg) {
115         automationCompositionHandler.handleAutomationCompositionUpdate(updateMsg,
116                 acElementDefsMap.get(updateMsg.getCompositionId()));
117     }
118
119     /**
120      * Handle a automation composition state change message.
121      *
122      * @param stateChangeMsg the state change message
123      */
124     @Timed(
125             value = "listener.automation_composition_state_change",
126             description = "AUTOMATION_COMPOSITION_STATE_CHANGE messages received")
127     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
128         automationCompositionHandler.handleAutomationCompositionStateChange(stateChangeMsg,
129                 acElementDefsMap.get(stateChangeMsg.getCompositionId()));
130     }
131
132     /**
133      * Check if a participant message applies to this participant handler.
134      *
135      * @param participantMsg the message to check
136      * @return true if it applies, false otherwise
137      */
138     public boolean appliesTo(ParticipantMessage participantMsg) {
139         return participantMsg.appliesTo(participantType, participantId);
140     }
141
142     /**
143      * Check if a participant message applies to this participant handler.
144      *
145      * @param participantMsg the message to check
146      * @return true if it applies, false otherwise
147      */
148     public boolean appliesTo(ParticipantAckMessage participantMsg) {
149         return participantMsg.appliesTo(participantType, participantId);
150     }
151
152     /**
153      * Method to send ParticipantRegister message to automation composition runtime.
154      */
155     public void sendParticipantRegister() {
156         var participantRegister = new ParticipantRegister();
157         participantRegister.setParticipantId(participantId);
158         participantRegister.setParticipantType(participantType);
159
160         publisher.sendParticipantRegister(participantRegister);
161     }
162
163     /**
164      * Handle a participantRegister Ack message.
165      *
166      * @param participantRegisterAckMsg the participantRegisterAck message
167      */
168     @Timed(value = "listener.participant_register_ack", description = "PARTICIPANT_REGISTER_ACK messages received")
169     public void handleParticipantRegisterAck(ParticipantRegisterAck participantRegisterAckMsg) {
170         LOGGER.debug("ParticipantRegisterAck message received as responseTo {}",
171                 participantRegisterAckMsg.getResponseTo());
172         statusToPassive();
173         publisher.sendParticipantStatus(makeHeartbeat(false));
174     }
175
176     private void statusToPassive() {
177         if (ParticipantHealthStatus.UNKNOWN.equals(this.healthStatus)) {
178             this.healthStatus = ParticipantHealthStatus.HEALTHY;
179         }
180
181         if (ParticipantState.UNKNOWN.equals(this.state) || ParticipantState.TERMINATED.equals(this.state)) {
182             this.state = ParticipantState.PASSIVE;
183         }
184
185     }
186
187     /**
188      * Method to send ParticipantDeregister message to automation composition runtime.
189      */
190     public void sendParticipantDeregister() {
191         var participantDeregister = new ParticipantDeregister();
192         participantDeregister.setParticipantId(participantId);
193         participantDeregister.setParticipantType(participantType);
194
195         publisher.sendParticipantDeregister(participantDeregister);
196     }
197
198     /**
199      * Handle a participantDeregister Ack message.
200      *
201      * @param participantDeregisterAckMsg the participantDeregisterAck message
202      */
203     @Timed(value = "listener.participant_deregister_ack", description = "PARTICIPANT_DEREGISTER_ACK messages received")
204     public void handleParticipantDeregisterAck(ParticipantDeregisterAck participantDeregisterAckMsg) {
205         LOGGER.debug("ParticipantDeregisterAck message received as responseTo {}",
206                 participantDeregisterAckMsg.getResponseTo());
207     }
208
209     /**
210      * Handle a ParticipantUpdate message.
211      *
212      * @param participantUpdateMsg the ParticipantUpdate message
213      */
214     @Timed(value = "listener.participant_update", description = "PARTICIPANT_UPDATE messages received")
215     public void handleParticipantUpdate(ParticipantUpdate participantUpdateMsg) {
216         LOGGER.debug("ParticipantUpdate message received for participantId {}",
217                 participantUpdateMsg.getParticipantId());
218
219         acElementDefsMap.putIfAbsent(participantUpdateMsg.getCompositionId(), new ArrayList<>());
220         if (!participantUpdateMsg.getParticipantDefinitionUpdates().isEmpty()) {
221             statusToPassive();
222             // This message is to commission the automation composition
223             for (var participantDefinition : participantUpdateMsg.getParticipantDefinitionUpdates()) {
224                 if (participantDefinition.getParticipantType().equals(participantType)) {
225                     acElementDefsMap.get(participantUpdateMsg.getCompositionId())
226                             .addAll(participantDefinition.getAutomationCompositionElementDefinitionList());
227                     break;
228                 }
229             }
230         } else {
231             // This message is to decommission the automation composition
232             acElementDefsMap.get(participantUpdateMsg.getCompositionId()).clear();
233             this.state = ParticipantState.TERMINATED;
234         }
235         sendParticipantUpdateAck(participantUpdateMsg.getMessageId());
236     }
237
238     /**
239      * Method to send ParticipantUpdateAck message to automation composition runtime.
240      */
241     public void sendParticipantUpdateAck(UUID messageId) {
242         var participantUpdateAck = new ParticipantUpdateAck();
243         participantUpdateAck.setResponseTo(messageId);
244         participantUpdateAck.setMessage("Participant Update Ack message");
245         participantUpdateAck.setResult(true);
246         participantUpdateAck.setParticipantId(participantId);
247         participantUpdateAck.setParticipantType(participantType);
248         participantUpdateAck.setState(state);
249         publisher.sendParticipantUpdateAck(participantUpdateAck);
250     }
251
252     /**
253      * Dispatch a heartbeat for this participant.
254      */
255     public void sendHeartbeat() {
256         publisher.sendHeartbeat(makeHeartbeat(false));
257     }
258
259     /**
260      * Method to send heartbeat to automation composition runtime.
261      */
262     public ParticipantStatus makeHeartbeat(boolean responseToParticipantStatusReq) {
263         var heartbeat = new ParticipantStatus();
264         heartbeat.setParticipantId(participantId);
265         heartbeat.setParticipantType(participantType);
266         heartbeat.setHealthStatus(healthStatus);
267         heartbeat.setState(state);
268         heartbeat.setAutomationCompositionInfoList(getAutomationCompositionInfoList());
269
270         if (responseToParticipantStatusReq) {
271             List<ParticipantDefinition> participantDefinitionList = new ArrayList<>(acElementDefsMap.size());
272             for (var acElementDefsOnThisParticipant : acElementDefsMap.values()) {
273                 var participantDefinition = new ParticipantDefinition();
274                 participantDefinition.setParticipantId(participantId);
275                 participantDefinition.setParticipantType(participantType);
276                 participantDefinition.setAutomationCompositionElementDefinitionList(acElementDefsOnThisParticipant);
277                 participantDefinitionList.add(participantDefinition);
278             }
279             heartbeat.setParticipantDefinitionUpdates(participantDefinitionList);
280         }
281
282         return heartbeat;
283     }
284
285     private List<AutomationCompositionInfo> getAutomationCompositionInfoList() {
286         List<AutomationCompositionInfo> automationCompositionInfoList = new ArrayList<>();
287         for (var entry : automationCompositionHandler.getAutomationCompositionMap().entrySet()) {
288             var acInfo = new AutomationCompositionInfo();
289             acInfo.setAutomationCompositionId(entry.getKey());
290             acInfo.setState(entry.getValue().getState());
291             automationCompositionInfoList.add(acInfo);
292         }
293         return automationCompositionInfoList;
294     }
295 }