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