a8913c1f0002ebfc68dd1836f4af30340ecc21dc
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.controlloop.participant.intermediary.handler;
22
23 import java.io.Closeable;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26 import java.util.Objects;
27 import java.util.UUID;
28 import lombok.Getter;
29 import lombok.Setter;
30 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition;
31 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
32 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus;
33 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantState;
34 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics;
35 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange;
36 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate;
37 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister;
38 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregisterAck;
39 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantHealthCheck;
40 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessage;
41 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister;
42 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegisterAck;
43 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseDetails;
44 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseStatus;
45 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStateChange;
46 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate;
47 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck;
48 import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender;
49 import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantMessagePublisher;
50 import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters;
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 @Getter
60 @Component
61 public class ParticipantHandler implements Closeable {
62     private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantHandler.class);
63
64     private final ToscaConceptIdentifier participantType;
65     private final ToscaConceptIdentifier participantId;
66     private final MessageSender sender;
67     private final ControlLoopHandler controlLoopHandler;
68     private final ParticipantStatistics participantStatistics;
69
70     @Setter
71     private ParticipantState state = ParticipantState.UNKNOWN;
72
73     @Setter
74     private ParticipantHealthStatus healthStatus = ParticipantHealthStatus.UNKNOWN;
75
76     private final Map<UUID, ControlLoopElementDefinition> clElementDefsOnThisParticipant = new LinkedHashMap<>();
77
78     /**
79      * Constructor, set the participant ID and sender.
80      *
81      * @param parameters the parameters of the participant
82      * @param publisher the publisher for sending responses to messages
83      */
84     public ParticipantHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) {
85         this.participantType = parameters.getIntermediaryParameters().getParticipantType();
86         this.participantId = parameters.getIntermediaryParameters().getParticipantId();
87         this.sender =
88                 new MessageSender(this, publisher, parameters.getIntermediaryParameters().getReportingTimeInterval());
89         this.controlLoopHandler = new ControlLoopHandler(parameters.getIntermediaryParameters(), sender);
90         this.participantStatistics = new ParticipantStatistics();
91     }
92
93     @Override
94     public void close() {
95         sender.close();
96     }
97
98     /**
99      * Method which handles a participant state change event from clamp.
100      *
101      * @param stateChangeMsg participant state change message
102      */
103     public void handleParticipantStateChange(final ParticipantStateChange stateChangeMsg) {
104
105         if (!stateChangeMsg.appliesTo(participantType, participantId)) {
106             return;
107         }
108
109         var response = new ParticipantResponseDetails(stateChangeMsg);
110
111         switch (stateChangeMsg.getState()) {
112             case PASSIVE:
113                 handlePassiveState(response);
114                 break;
115             case ACTIVE:
116                 handleActiveState(response);
117                 break;
118             case SAFE:
119                 handleSafeState(response);
120                 break;
121             case TEST:
122                 handleTestState(response);
123                 break;
124             case TERMINATED:
125                 handleTerminatedState(response);
126                 break;
127             default:
128                 LOGGER.debug("StateChange message has no state, state is null {}", stateChangeMsg.getParticipantId());
129                 response.setResponseStatus(ParticipantResponseStatus.FAIL);
130                 response.setResponseMessage(
131                         "StateChange message has invalid state for participantId " + stateChangeMsg.getParticipantId());
132                 break;
133         }
134
135         sender.sendResponse(response);
136     }
137
138     /**
139      * Method which handles a participant health check event from clamp.
140      *
141      * @param healthCheckMsg participant health check message
142      */
143     public void handleParticipantHealthCheck(final ParticipantHealthCheck healthCheckMsg) {
144         var response = new ParticipantResponseDetails(healthCheckMsg);
145         response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
146         response.setResponseMessage(healthStatus.toString());
147
148         sender.sendResponse(response);
149     }
150
151     /**
152      * Handle a control loop update message.
153      *
154      * @param updateMsg the update message
155      */
156     public void handleControlLoopUpdate(ParticipantControlLoopUpdate updateMsg) {
157         controlLoopHandler.handleControlLoopUpdate(updateMsg);
158     }
159
160     /**
161      * Handle a control loop state change message.
162      *
163      * @param stateChangeMsg the state change message
164      */
165     public void handleControlLoopStateChange(ParticipantControlLoopStateChange stateChangeMsg) {
166         controlLoopHandler.handleControlLoopStateChange(stateChangeMsg);
167     }
168
169     /**
170      * Method to handle when the new state from participant is active.
171      *
172      * @param response participant response
173      */
174     private void handleActiveState(final ParticipantResponseDetails response) {
175         handleStateChange(ParticipantState.ACTIVE, response);
176     }
177
178     /**
179      * Method to handle when the new state from participant is passive.
180      *
181      * @param response participant response
182      */
183     private void handlePassiveState(final ParticipantResponseDetails response) {
184         handleStateChange(ParticipantState.PASSIVE, response);
185     }
186
187     /**
188      * Method to handle when the new state from participant is safe.
189      *
190      * @param response participant response
191      */
192     private void handleSafeState(final ParticipantResponseDetails response) {
193         handleStateChange(ParticipantState.SAFE, response);
194     }
195
196     /**
197      * Method to handle when the new state from participant is TEST.
198      *
199      * @param response participant response
200      */
201     private void handleTestState(final ParticipantResponseDetails response) {
202         handleStateChange(ParticipantState.TEST, response);
203     }
204
205     /**
206      * Method to handle when the new state from participant is Terminated.
207      *
208      * @param response participant response
209      */
210     private void handleTerminatedState(final ParticipantResponseDetails response) {
211         handleStateChange(ParticipantState.TERMINATED, response);
212     }
213
214     private void handleStateChange(ParticipantState newParticipantState, ParticipantResponseDetails response) {
215         if (state.equals(newParticipantState)) {
216             response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
217             response.setResponseMessage("Participant already in state " + newParticipantState);
218         } else {
219             response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
220             response.setResponseMessage("Participant state changed from " + state + " to " + newParticipantState);
221             state = newParticipantState;
222         }
223     }
224
225     /**
226      * Method to update participant state.
227      *
228      * @param definition participant definition
229      * @param participantState participant state
230      * @return the participant
231      */
232     public Participant updateParticipantState(ToscaConceptIdentifier definition, ParticipantState participantState) {
233         if (!Objects.equals(definition, participantId)) {
234             LOGGER.debug("No participant with this ID {}", definition.getName());
235             return null;
236         }
237         var response = new ParticipantResponseDetails();
238         handleStateChange(participantState, response);
239         sender.sendResponse(response);
240         return getParticipant(definition.getName(), definition.getVersion());
241     }
242
243     /**
244      * Get participants as a {@link Participant} class.
245      *
246      * @param name the participant name to get
247      * @param version the version of the participant to get
248      * @return the participant
249      */
250     public Participant getParticipant(String name, String version) {
251         if (participantId.getName().equals(name)) {
252             var participant = new Participant();
253             participant.setDefinition(participantId);
254             participant.setParticipantState(state);
255             participant.setHealthStatus(healthStatus);
256             return participant;
257         }
258         return null;
259     }
260
261     /**
262      * Check if a participant message applies to this participant handler.
263      *
264      * @param participantMsg the message to check
265      * @return true if it applies, false otherwise
266      */
267     public boolean appliesTo(ParticipantMessage participantMsg) {
268         return participantMsg.appliesTo(participantType, participantId);
269     }
270
271     /**
272      * Method to send ParticipantRegister message to controlloop runtime.
273      */
274     public void sendParticipantRegister() {
275         var participantRegister = new ParticipantRegister();
276         participantRegister.setParticipantId(participantId);
277         participantRegister.setParticipantType(participantType);
278
279         sender.sendParticipantRegister(participantRegister);
280     }
281
282     /**
283      * Handle a participantRegister Ack message.
284      *
285      * @param participantRegisterAckMsg the participantRegisterAck message
286      */
287     public void handleParticipantRegisterAck(ParticipantRegisterAck participantRegisterAckMsg) {
288         LOGGER.debug("ParticipantRegisterAck message received as responseTo {}",
289             participantRegisterAckMsg.getResponseTo());
290     }
291
292     /**
293      * Method to send ParticipantDeregister message to controlloop runtime.
294      */
295     public void sendParticipantDeregister() {
296         var participantDeregister = new ParticipantDeregister();
297         participantDeregister.setParticipantId(participantId);
298         participantDeregister.setParticipantType(participantType);
299
300         sender.sendParticipantDeregister(participantDeregister);
301     }
302
303     /**
304      * Handle a participantDeregister Ack message.
305      *
306      * @param participantDeregisterAckMsg the participantDeregisterAck message
307      */
308     public void handleParticipantDeregisterAck(ParticipantDeregisterAck participantDeregisterAckMsg) {
309         LOGGER.debug("ParticipantDeregisterAck message received as responseTo {}",
310             participantDeregisterAckMsg.getResponseTo());
311     }
312
313     /**
314      * Handle a ParticipantUpdate message.
315      *
316      * @param participantUpdateMsg the ParticipantUpdate message
317      */
318     public void handleParticipantUpdate(ParticipantUpdate participantUpdateMsg) {
319         LOGGER.debug("ParticipantUpdate message received for participantId {}",
320             participantUpdateMsg.getParticipantId());
321
322         if (!participantUpdateMsg.appliesTo(participantType, participantId)) {
323             return;
324         }
325
326         Map<UUID, ControlLoopElementDefinition> clDefinitionMap =
327                 participantUpdateMsg.getParticipantDefinitionUpdateMap().get(participantUpdateMsg.getParticipantId());
328
329         for (ControlLoopElementDefinition element : clDefinitionMap.values()) {
330             clElementDefsOnThisParticipant.put(element.getId(), element);
331         }
332
333         sendParticipantUpdateAck(participantUpdateMsg.getMessageId());
334     }
335
336     /**
337      * Method to send ParticipantUpdateAck message to controlloop runtime.
338      */
339     public void sendParticipantUpdateAck(UUID messageId) {
340         var participantUpdateAck = new ParticipantUpdateAck();
341         participantUpdateAck.setResponseTo(messageId);
342         participantUpdateAck.setMessage("Participant Update Ack message");
343         participantUpdateAck.setResult(true);
344
345         sender.sendParticipantUpdateAck(participantUpdateAck);
346     }
347 }