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.apache.commons.lang3.tuple.Pair;
32 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics;
33 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
34 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
35 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition;
36 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
37 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
38 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
39 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopAck;
40 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopStateChange;
41 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopUpdate;
42 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType;
43 import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
44 import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender;
45 import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters;
46 import org.onap.policy.models.base.PfModelException;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 * This class is responsible for managing the state of all control loops in the participant.
55 public class ControlLoopHandler {
56 private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopHandler.class);
58 private ToscaConceptIdentifier participantType = null;
59 private ToscaConceptIdentifier participantId = null;
60 private MessageSender messageSender = null;
62 private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>();
65 private final Map<UUID, ControlLoopElement> elementsOnThisParticipant = new LinkedHashMap<>();
68 private List<ControlLoopElementListener> listeners = new ArrayList<>();
71 * Constructor, set the participant ID and messageSender.
73 * @param parameters the parameters of the participant
74 * @param messageSender the messageSender for sending responses to messages
76 public ControlLoopHandler(ParticipantIntermediaryParameters parameters, MessageSender messageSender) {
77 this.participantType = parameters.getParticipantType();
78 this.participantId = parameters.getParticipantId();
79 this.messageSender = messageSender;
82 public void registerControlLoopElementListener(ControlLoopElementListener listener) {
83 listeners.add(listener);
87 * Handle a control loop element state change message.
89 * @param id controlloop element id
90 * @param orderedState the current state
91 * @param newState the ordered state
92 * @return controlLoopElement the updated controlloop element
94 public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState orderedState,
95 ControlLoopState newState) {
98 LOGGER.warn("Cannot update Control loop element state, id is null");
101 ControlLoopAck controlLoopStateChangeAck =
102 new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
103 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
104 if (clElement != null) {
105 clElement.setOrderedState(orderedState);
106 clElement.setState(newState);
107 controlLoopStateChangeAck.getControlLoopResultMap().put(clElement.getId(),
108 Pair.of(true, "Control loop element {} state changed to {}\", id, newState)"));
109 LOGGER.debug("Control loop element {} state changed to {}", id, newState);
110 controlLoopStateChangeAck.setMessage("ControlLoopElement state changed to {} " + newState);
111 controlLoopStateChangeAck.setResult(true);
112 messageSender.sendAckResponse(controlLoopStateChangeAck);
119 * Handle a control loop element statistics.
121 * @param id controlloop element id
122 * @param elementStatistics control loop element Statistics
124 public void updateControlLoopElementStatistics(UUID id, ClElementStatistics elementStatistics) {
125 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
126 if (clElement != null) {
127 elementStatistics.setParticipantId(participantId);
128 elementStatistics.setId(id);
129 clElement.setClElementStatistics(elementStatistics);
134 * Handle a control loop state change message.
136 * @param stateChangeMsg the state change message
138 public void handleControlLoopStateChange(ControlLoopStateChange stateChangeMsg) {
139 if (stateChangeMsg.getControlLoopId() == null) {
143 var controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId());
145 if (controlLoop == null) {
146 LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId());
150 var controlLoopStateChangeAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
151 controlLoopStateChangeAck.setResponseTo(stateChangeMsg.getMessageId());
152 controlLoopStateChangeAck.setControlLoopId(stateChangeMsg.getControlLoopId());
153 handleState(controlLoop, controlLoopStateChangeAck, stateChangeMsg.getOrderedState());
154 messageSender.sendAckResponse(controlLoopStateChangeAck);
158 * Method to handle state changes.
160 * @param controlLoop participant response
161 * @param response participant response
162 * @param orderedState controlloop ordered state
164 private void handleState(final ControlLoop controlLoop, final ControlLoopAck response,
165 ControlLoopOrderedState orderedState) {
166 switch (orderedState) {
168 handleUninitialisedState(controlLoop, orderedState, response);
171 handlePassiveState(controlLoop, orderedState, response);
174 handleRunningState(controlLoop, orderedState, response);
177 LOGGER.debug("StateChange message has no state, state is null {}", controlLoop.getDefinition());
183 * Handle a control loop update message.
185 * @param updateMsg the update message
187 public void handleControlLoopUpdate(ControlLoopUpdate updateMsg,
188 Map<UUID, ControlLoopElementDefinition> clElementDefinitions) {
190 if (!updateMsg.appliesTo(participantType, participantId)) {
194 var controlLoop = controlLoopMap.get(updateMsg.getControlLoopId());
196 var controlLoopUpdateAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_UPDATE_ACK);
198 // TODO: Updates to existing ControlLoops are not supported yet (Addition/Removal of ControlLoop
199 // elements to existing ControlLoop has to be supported).
200 if (controlLoop != null) {
201 controlLoopUpdateAck.setResponseTo(updateMsg.getMessageId());
202 controlLoopUpdateAck.setControlLoopId(updateMsg.getControlLoopId());
203 controlLoopUpdateAck.setMessage("Control loop " + updateMsg.getControlLoopId()
204 + " already defined on participant " + participantId);
205 controlLoopUpdateAck.setResult(false);
206 messageSender.sendAckResponse(controlLoopUpdateAck);
210 controlLoop = updateMsg.getControlLoop();
211 controlLoop.getElements().values().removeIf(element -> !participantType.equals(element.getParticipantType()));
213 controlLoopMap.put(updateMsg.getControlLoopId(), controlLoop);
214 for (ControlLoopElement element : updateMsg.getControlLoop().getElements().values()) {
215 element.setState(element.getOrderedState().asState());
216 element.setParticipantId(participantId);
217 elementsOnThisParticipant.put(element.getId(), element);
220 for (ControlLoopElementListener clElementListener : listeners) {
222 for (ControlLoopElement element : updateMsg.getControlLoop().getElements().values()) {
223 clElementListener.controlLoopElementUpdate(element,
224 clElementDefinitions.get(element.getId()).getControlLoopElementToscaServiceTemplate());
226 } catch (PfModelException e) {
227 LOGGER.debug("Control loop element update failed {}", updateMsg.getControlLoopId());
231 controlLoopUpdateAck.setResponseTo(updateMsg.getMessageId());
232 controlLoopUpdateAck.setControlLoopId(updateMsg.getControlLoopId());
233 controlLoopUpdateAck.setMessage("Control loop " + updateMsg.getControlLoopId()
234 + " defined on participant " + participantId);
235 controlLoopUpdateAck.setResult(true);
236 messageSender.sendAckResponse(controlLoopUpdateAck);
240 * Method to handle when the new state from participant is UNINITIALISED state.
242 * @param controlLoop participant response
243 * @param orderedState orderedState
244 * @param response participant response
246 private void handleUninitialisedState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
247 final ControlLoopAck response) {
248 handleStateChange(controlLoop, orderedState, ControlLoopState.UNINITIALISED, response);
249 controlLoopMap.remove(controlLoop.getKey().asIdentifier());
251 for (ControlLoopElementListener clElementListener : listeners) {
253 for (ControlLoopElement element : controlLoop.getElements().values()) {
254 clElementListener.controlLoopElementStateChange(element.getId(), element.getState(), orderedState);
256 } catch (PfModelException e) {
257 LOGGER.debug("Control loop element update failed {}", controlLoop.getDefinition());
263 * Method to handle when the new state from participant is PASSIVE state.
265 * @param controlLoop participant response
266 * @param orderedState orderedState
267 * @param response participant response
269 private void handlePassiveState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
270 final ControlLoopAck response) {
271 handleStateChange(controlLoop, orderedState, ControlLoopState.PASSIVE, response);
275 * Method to handle when the new state from participant is RUNNING state.
277 * @param controlLoop participant response
278 * @param orderedState orderedState
279 * @param response participant response
281 private void handleRunningState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
282 final ControlLoopAck response) {
283 handleStateChange(controlLoop, orderedState, ControlLoopState.RUNNING, response);
287 * Method to update the state of control loop elements.
289 * @param controlLoop participant status in memory
290 * @param orderedState orderedState the new ordered state the participant should have
291 * @param newState new state of the control loop elements
292 * @param response the response to the state change request
294 private void handleStateChange(ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
295 ControlLoopState newState, ControlLoopAck response) {
297 if (orderedState.equals(controlLoop.getOrderedState())) {
298 response.setMessage("Control loop is already in state " + orderedState);
299 response.setResult(false);
303 if (!CollectionUtils.isEmpty(controlLoop.getElements().values())) {
304 controlLoop.getElements().values().forEach(element -> {
305 element.setState(newState);
306 element.setOrderedState(orderedState);
310 response.setMessage("ControlLoop state changed from " + controlLoop.getOrderedState() + " to " + orderedState);
311 response.setResult(true);
312 controlLoop.setOrderedState(orderedState);
316 * Get control loops as a {@link ConrolLoops} class.
318 * @return the control loops
320 public ControlLoops getControlLoops() {
321 var controlLoops = new ControlLoops();
322 controlLoops.setControlLoopList(new ArrayList<>(controlLoopMap.values()));