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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.clamp.controlloop.participant.intermediary.handler;
23 import java.util.ArrayList;
24 import java.util.LinkedHashMap;
25 import java.util.List;
27 import java.util.UUID;
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;
50 * This class is responsible for managing the state of all control loops in the participant.
53 public class ControlLoopHandler {
54 private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopHandler.class);
56 private ToscaConceptIdentifier participantType = null;
57 private ToscaConceptIdentifier participantId = null;
58 private MessageSender messageSender = null;
60 private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>();
62 private final Map<UUID, ControlLoopElement> elementsOnThisParticipant = new LinkedHashMap<>();
65 private List<ControlLoopElementListener> listeners = new ArrayList<>();
68 * Constructor, set the participant ID and messageSender.
70 * @param parameters the parameters of the participant
71 * @param messageSender the messageSender for sending responses to messages
73 public ControlLoopHandler(ParticipantIntermediaryParameters parameters, MessageSender messageSender) {
74 this.participantType = parameters.getParticipantType();
75 this.participantId = parameters.getParticipantId();
76 this.messageSender = messageSender;
79 public void registerControlLoopElementListener(ControlLoopElementListener listener) {
80 listeners.add(listener);
84 * Handle a control loop element state change message.
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
91 public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState orderedState,
92 ControlLoopState newState) {
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);
114 * Handle a control loop element statistics.
116 * @param id controlloop element id
117 * @param elementStatistics control loop element Statistics
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);
129 * Handle a control loop state change message.
131 * @param stateChangeMsg the state change message
133 public void handleControlLoopStateChange(ParticipantControlLoopStateChange stateChangeMsg) {
134 if (stateChangeMsg.getControlLoopId() == null) {
138 var controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId());
140 if (controlLoop == null) {
141 LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId());
145 var response = new ParticipantResponseDetails(stateChangeMsg);
146 handleState(controlLoop, response, stateChangeMsg.getOrderedState());
147 messageSender.sendResponse(response);
151 * Method to handle state changes.
153 * @param controlLoop participant response
154 * @param response participant response
155 * @param orderedState controlloop ordered state
157 private void handleState(final ControlLoop controlLoop, final ParticipantResponseDetails response,
158 ControlLoopOrderedState orderedState) {
159 switch (orderedState) {
161 handleUninitialisedState(controlLoop, orderedState, response);
164 handlePassiveState(controlLoop, orderedState, response);
167 handleRunningState(controlLoop, orderedState, response);
170 LOGGER.debug("StateChange message has no state, state is null {}", controlLoop.getDefinition());
176 * Handle a control loop update message.
178 * @param updateMsg the update message
180 public void handleControlLoopUpdate(ParticipantControlLoopUpdate updateMsg) {
182 if (!updateMsg.appliesTo(participantType, participantId)) {
186 var controlLoop = controlLoopMap.get(updateMsg.getControlLoopId());
188 var response = new ParticipantResponseDetails(updateMsg);
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);
197 messageSender.sendResponse(response);
201 controlLoop = updateMsg.getControlLoop();
202 controlLoop.getElements().values().removeIf(element -> !participantType.equals(element.getParticipantType()));
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);
211 for (ControlLoopElementListener clElementListener : listeners) {
213 for (ControlLoopElement element : updateMsg.getControlLoop().getElements().values()) {
214 clElementListener.controlLoopElementUpdate(element, updateMsg.getControlLoopDefinition());
216 } catch (PfModelException e) {
217 LOGGER.debug("Control loop element update failed {}", updateMsg.getControlLoopId());
221 response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
222 response.setResponseMessage(
223 "Control loop " + updateMsg.getControlLoopId() + " defined on participant " + participantId);
225 messageSender.sendResponse(response);
229 * Method to handle when the new state from participant is UNINITIALISED state.
231 * @param controlLoop participant response
232 * @param orderedState orderedState
233 * @param response participant response
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());
240 for (ControlLoopElementListener clElementListener : listeners) {
242 for (ControlLoopElement element : controlLoop.getElements().values()) {
243 clElementListener.controlLoopElementStateChange(element.getId(), element.getState(), orderedState);
245 } catch (PfModelException e) {
246 LOGGER.debug("Control loop element update failed {}", controlLoop.getDefinition());
252 * Method to handle when the new state from participant is PASSIVE state.
254 * @param controlLoop participant response
255 * @param orderedState orderedState
256 * @param response participant response
258 private void handlePassiveState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
259 final ParticipantResponseDetails response) {
260 handleStateChange(controlLoop, orderedState, ControlLoopState.PASSIVE, response);
264 * Method to handle when the new state from participant is RUNNING state.
266 * @param controlLoop participant response
267 * @param orderedState orderedState
268 * @param response participant response
270 private void handleRunningState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
271 final ParticipantResponseDetails response) {
272 handleStateChange(controlLoop, orderedState, ControlLoopState.RUNNING, response);
276 * Method to update the state of control loop elements.
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
283 private void handleStateChange(ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
284 ControlLoopState newState, ParticipantResponseDetails response) {
286 if (orderedState.equals(controlLoop.getOrderedState())) {
287 response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
288 response.setResponseMessage("Control loop is already in state " + orderedState);
292 if (!CollectionUtils.isEmpty(controlLoop.getElements().values())) {
293 controlLoop.getElements().values().forEach(element -> {
294 element.setState(newState);
295 element.setOrderedState(orderedState);
299 response.setResponseStatus(ParticipantResponseStatus.SUCCESS);
300 response.setResponseMessage(
301 "ControlLoop state changed from " + controlLoop.getOrderedState() + " to " + orderedState);
302 controlLoop.setOrderedState(orderedState);
306 * Get control loops as a {@link ConrolLoops} class.
308 * @return the control loops
310 public ControlLoops getControlLoops() {
311 var controlLoops = new ControlLoops();
312 controlLoops.setControlLoopList(new ArrayList<>(controlLoopMap.values()));