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