50048ffc275fefc441aead8880de16dd1b3b6f76
[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.util.ArrayList;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.UUID;
28 import lombok.Getter;
29 import lombok.NoArgsConstructor;
30 import org.apache.commons.collections4.CollectionUtils;
31 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics;
32 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
33 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
34 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
35 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
36 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
37 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopStateChange;
38 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantControlLoopUpdate;
39 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseDetails;
40 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantResponseStatus;
41 import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
42 import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender;
43 import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters;
44 import org.onap.policy.models.base.PfModelException;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /*
50  * This class is responsible for managing the state of all control loops in the participant.
51  */
52 @NoArgsConstructor
53 public class ControlLoopHandler {
54     private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopHandler.class);
55
56     private ToscaConceptIdentifier participantType = null;
57     private ToscaConceptIdentifier participantId = null;
58     private MessageSender messageSender = null;
59
60     private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>();
61
62     private final Map<UUID, ControlLoopElement> elementsOnThisParticipant = new LinkedHashMap<>();
63
64     @Getter
65     private List<ControlLoopElementListener> listeners = new ArrayList<>();
66
67     /**
68      * Constructor, set the participant ID and messageSender.
69      *
70      * @param parameters the parameters of the participant
71      * @param messageSender the messageSender for sending responses to messages
72      */
73     public ControlLoopHandler(ParticipantIntermediaryParameters parameters, MessageSender messageSender) {
74         this.participantType = parameters.getParticipantType();
75         this.participantId = parameters.getParticipantId();
76         this.messageSender = messageSender;
77     }
78
79     public void registerControlLoopElementListener(ControlLoopElementListener listener) {
80         listeners.add(listener);
81     }
82
83     /**
84      * Handle a control loop element state change message.
85      *
86      * @param id controlloop element id
87      * @param orderedState the current state
88      * @param newState the ordered state
89      * @return controlLoopElement the updated controlloop element
90      */
91     public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState orderedState,
92             ControlLoopState newState) {
93
94         if (id == null) {
95             return null;
96         }
97
98         ControlLoopElement clElement = elementsOnThisParticipant.get(id);
99         if (clElement != null) {
100             clElement.setOrderedState(orderedState);
101             clElement.setState(newState);
102             LOGGER.debug("Control loop element {} state changed to {}", id, newState);
103             var response = new ParticipantResponseDetails();
104             response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
105             response.setResponseMessage("ControlLoopElement state changed to {} " + newState);
106             messageSender.sendResponse(response);
107             return clElement;
108         }
109
110         return null;
111     }
112
113     /**
114      * Handle a control loop element statistics.
115      *
116      * @param id controlloop element id
117      * @param elementStatistics control loop element Statistics
118      */
119     public void updateControlLoopElementStatistics(UUID id, ClElementStatistics elementStatistics) {
120         ControlLoopElement clElement = elementsOnThisParticipant.get(id);
121         if (clElement != null) {
122             elementStatistics.setParticipantId(participantId);
123             elementStatistics.setId(id);
124             clElement.setClElementStatistics(elementStatistics);
125         }
126     }
127
128     /**
129      * Handle a control loop state change message.
130      *
131      * @param stateChangeMsg the state change message
132      */
133     public void handleControlLoopStateChange(ParticipantControlLoopStateChange stateChangeMsg) {
134         if (stateChangeMsg.getControlLoopId() == null) {
135             return;
136         }
137
138         var controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId());
139
140         if (controlLoop == null) {
141             LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId());
142             return;
143         }
144
145         var response = new ParticipantResponseDetails(stateChangeMsg);
146         handleState(controlLoop, response, stateChangeMsg.getOrderedState());
147         messageSender.sendResponse(response);
148     }
149
150     /**
151      * Method to handle state changes.
152      *
153      * @param controlLoop participant response
154      * @param response participant response
155      * @param orderedState controlloop ordered state
156      */
157     private void handleState(final ControlLoop controlLoop, final ParticipantResponseDetails response,
158             ControlLoopOrderedState orderedState) {
159         switch (orderedState) {
160             case UNINITIALISED:
161                 handleUninitialisedState(controlLoop, orderedState, response);
162                 break;
163             case PASSIVE:
164                 handlePassiveState(controlLoop, orderedState, response);
165                 break;
166             case RUNNING:
167                 handleRunningState(controlLoop, orderedState, response);
168                 break;
169             default:
170                 LOGGER.debug("StateChange message has no state, state is null {}", controlLoop.getDefinition());
171                 break;
172         }
173     }
174
175     /**
176      * Handle a control loop update message.
177      *
178      * @param updateMsg the update message
179      */
180     public void handleControlLoopUpdate(ParticipantControlLoopUpdate updateMsg) {
181
182         if (!updateMsg.appliesTo(participantType, participantId)) {
183             return;
184         }
185
186         var controlLoop = controlLoopMap.get(updateMsg.getControlLoopId());
187
188         var response = new ParticipantResponseDetails(updateMsg);
189
190         // TODO: Updates to existing ControlLoops are not supported yet (Addition/Removal of ControlLoop
191         // elements to existing ControlLoop has to be supported).
192         if (controlLoop != null) {
193             response.setResponseStatus(ParticipantResponseStatus.FAIL);
194             response.setResponseMessage("Control loop " + updateMsg.getControlLoopId()
195                     + " already defined on participant " + participantId);
196
197             messageSender.sendResponse(response);
198             return;
199         }
200
201         controlLoop = updateMsg.getControlLoop();
202         controlLoop.getElements().values().removeIf(element -> !participantType.equals(element.getParticipantType()));
203
204         controlLoopMap.put(updateMsg.getControlLoopId(), controlLoop);
205         for (ControlLoopElement element : updateMsg.getControlLoop().getElements().values()) {
206             element.setState(element.getOrderedState().asState());
207             element.setParticipantId(participantId);
208             elementsOnThisParticipant.put(element.getId(), element);
209         }
210
211         for (ControlLoopElementListener clElementListener : listeners) {
212             try {
213                 for (ControlLoopElement element : updateMsg.getControlLoop().getElements().values()) {
214                     clElementListener.controlLoopElementUpdate(element, updateMsg.getControlLoopDefinition());
215                 }
216             } catch (PfModelException e) {
217                 LOGGER.debug("Control loop element update failed {}", updateMsg.getControlLoopId());
218             }
219         }
220
221         response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
222         response.setResponseMessage(
223                 "Control loop " + updateMsg.getControlLoopId() + " defined on participant " + participantId);
224
225         messageSender.sendResponse(response);
226     }
227
228     /**
229      * Method to handle when the new state from participant is UNINITIALISED state.
230      *
231      * @param controlLoop participant response
232      * @param orderedState orderedState
233      * @param response participant response
234      */
235     private void handleUninitialisedState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
236             final ParticipantResponseDetails response) {
237         handleStateChange(controlLoop, orderedState, ControlLoopState.UNINITIALISED, response);
238         controlLoopMap.remove(controlLoop.getKey().asIdentifier());
239
240         for (ControlLoopElementListener clElementListener : listeners) {
241             try {
242                 for (ControlLoopElement element : controlLoop.getElements().values()) {
243                     clElementListener.controlLoopElementStateChange(element.getId(), element.getState(), orderedState);
244                 }
245             } catch (PfModelException e) {
246                 LOGGER.debug("Control loop element update failed {}", controlLoop.getDefinition());
247             }
248         }
249     }
250
251     /**
252      * Method to handle when the new state from participant is PASSIVE state.
253      *
254      * @param controlLoop participant response
255      * @param orderedState orderedState
256      * @param response participant response
257      */
258     private void handlePassiveState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
259             final ParticipantResponseDetails response) {
260         handleStateChange(controlLoop, orderedState, ControlLoopState.PASSIVE, response);
261     }
262
263     /**
264      * Method to handle when the new state from participant is RUNNING state.
265      *
266      * @param controlLoop participant response
267      * @param orderedState orderedState
268      * @param response participant response
269      */
270     private void handleRunningState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
271             final ParticipantResponseDetails response) {
272         handleStateChange(controlLoop, orderedState, ControlLoopState.RUNNING, response);
273     }
274
275     /**
276      * Method to update the state of control loop elements.
277      *
278      * @param controlLoop participant status in memory
279      * @param orderedState orderedState the new ordered state the participant should have
280      * @param newState new state of the control loop elements
281      * @param response the response to the state change request
282      */
283     private void handleStateChange(ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
284             ControlLoopState newState, ParticipantResponseDetails response) {
285
286         if (orderedState.equals(controlLoop.getOrderedState())) {
287             response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
288             response.setResponseMessage("Control loop is already in state " + orderedState);
289             return;
290         }
291
292         if (!CollectionUtils.isEmpty(controlLoop.getElements().values())) {
293             controlLoop.getElements().values().forEach(element -> {
294                 element.setState(newState);
295                 element.setOrderedState(orderedState);
296             });
297         }
298
299         response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
300         response.setResponseMessage(
301                 "ControlLoop state changed from " + controlLoop.getOrderedState() + " to " + orderedState);
302         controlLoop.setOrderedState(orderedState);
303     }
304
305     /**
306      * Get control loops as a {@link ConrolLoops} class.
307      *
308      * @return the control loops
309      */
310     public ControlLoops getControlLoops() {
311         var controlLoops = new ControlLoops();
312         controlLoops.setControlLoopList(new ArrayList<>(controlLoopMap.values()));
313         return controlLoops;
314     }
315 }