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