2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 Nordix Foundation.
4 * ================================================================================
5 * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.policy.clamp.controlloop.participant.intermediary.handler;
25 import java.util.ArrayList;
26 import java.util.LinkedHashMap;
27 import java.util.List;
29 import java.util.UUID;
31 import lombok.NoArgsConstructor;
32 import org.apache.commons.collections4.CollectionUtils;
33 import org.apache.commons.lang3.tuple.Pair;
34 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics;
35 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
36 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
37 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition;
38 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
39 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
40 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
41 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantUpdates;
42 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopAck;
43 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopStateChange;
44 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopUpdate;
45 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType;
46 import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
47 import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender;
48 import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters;
49 import org.onap.policy.models.base.PfModelException;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
56 * This class is responsible for managing the state of all control loops in the participant.
59 public class ControlLoopHandler {
60 private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopHandler.class);
62 private ToscaConceptIdentifier participantType = null;
63 private ToscaConceptIdentifier participantId = null;
64 private MessageSender messageSender = null;
66 private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>();
69 private final Map<UUID, ControlLoopElement> elementsOnThisParticipant = new LinkedHashMap<>();
72 private List<ControlLoopElementListener> listeners = new ArrayList<>();
75 * Constructor, set the participant ID and messageSender.
77 * @param parameters the parameters of the participant
78 * @param messageSender the messageSender for sending responses to messages
80 public ControlLoopHandler(ParticipantIntermediaryParameters parameters, MessageSender messageSender) {
81 this.participantType = parameters.getParticipantType();
82 this.participantId = parameters.getParticipantId();
83 this.messageSender = messageSender;
86 public void registerControlLoopElementListener(ControlLoopElementListener listener) {
87 listeners.add(listener);
91 * Handle a control loop element state change message.
93 * @param id controlloop element id
94 * @param orderedState the current state
95 * @param newState the ordered state
96 * @return controlLoopElement the updated controlloop element
98 public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState orderedState,
99 ControlLoopState newState) {
102 LOGGER.warn("Cannot update Control loop element state, id is null");
105 var controlLoopStateChangeAck =
106 new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
107 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
108 if (clElement != null) {
109 clElement.setOrderedState(orderedState);
110 clElement.setState(newState);
111 controlLoopStateChangeAck.getControlLoopResultMap().put(clElement.getId(),
112 Pair.of(true, "Control loop element {} state changed to {}\", id, newState)"));
113 LOGGER.debug("Control loop element {} state changed to {}", id, newState);
114 controlLoopStateChangeAck.setMessage("ControlLoopElement state changed to {} " + newState);
115 controlLoopStateChangeAck.setResult(true);
116 messageSender.sendAckResponse(controlLoopStateChangeAck);
123 * Handle a control loop element statistics.
125 * @param id controlloop element id
126 * @param elementStatistics control loop element Statistics
128 public void updateControlLoopElementStatistics(UUID id, ClElementStatistics elementStatistics) {
129 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
130 if (clElement != null) {
131 elementStatistics.setParticipantId(participantId);
132 elementStatistics.setId(id);
133 clElement.setClElementStatistics(elementStatistics);
138 * Handle a control loop state change message.
140 * @param stateChangeMsg the state change message
142 public void handleControlLoopStateChange(ControlLoopStateChange stateChangeMsg) {
143 if (stateChangeMsg.getControlLoopId() == null) {
147 var controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId());
149 if (controlLoop == null) {
150 LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId());
154 var controlLoopStateChangeAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
155 controlLoopStateChangeAck.setResponseTo(stateChangeMsg.getMessageId());
156 controlLoopStateChangeAck.setControlLoopId(stateChangeMsg.getControlLoopId());
157 handleState(controlLoop, controlLoopStateChangeAck, stateChangeMsg.getOrderedState());
158 messageSender.sendAckResponse(controlLoopStateChangeAck);
162 * Method to handle state changes.
164 * @param controlLoop participant response
165 * @param response participant response
166 * @param orderedState controlloop ordered state
168 private void handleState(final ControlLoop controlLoop, final ControlLoopAck response,
169 ControlLoopOrderedState orderedState) {
170 switch (orderedState) {
172 handleUninitialisedState(controlLoop, orderedState, response);
175 handlePassiveState(controlLoop, orderedState, response);
178 handleRunningState(controlLoop, orderedState, response);
181 LOGGER.debug("StateChange message has no state, state is null {}", controlLoop.getDefinition());
187 * Handle a control loop update message.
189 * @param updateMsg the update message
191 public void handleControlLoopUpdate(ControlLoopUpdate updateMsg,
192 List<ControlLoopElementDefinition> clElementDefinitions) {
194 if (!updateMsg.appliesTo(participantType, participantId)) {
198 var controlLoop = controlLoopMap.get(updateMsg.getControlLoopId());
200 var controlLoopUpdateAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_UPDATE_ACK);
202 // TODO: Updates to existing ControlLoops are not supported yet (Addition/Removal of ControlLoop
203 // elements to existing ControlLoop has to be supported).
204 if (controlLoop != null) {
205 controlLoopUpdateAck.setResponseTo(updateMsg.getMessageId());
206 controlLoopUpdateAck.setControlLoopId(updateMsg.getControlLoopId());
207 controlLoopUpdateAck.setMessage("Control loop " + updateMsg.getControlLoopId()
208 + " already defined on participant " + participantId);
209 controlLoopUpdateAck.setResult(false);
210 messageSender.sendAckResponse(controlLoopUpdateAck);
214 List<ControlLoopElement> clElements = storeElementsOnThisParticipant(updateMsg.getParticipantUpdatesList());
217 for (ControlLoopElement element : clElements) {
218 ToscaNodeTemplate clElementNodeTemplate = getClElementNodeTemplate(
219 clElementDefinitions, element.getDefinition());
220 for (ControlLoopElementListener clElementListener : listeners) {
221 clElementListener.controlLoopElementUpdate(element, clElementNodeTemplate);
224 } catch (PfModelException e) {
225 LOGGER.debug("Control loop element update failed {}", updateMsg.getControlLoopId());
228 Map<UUID, ControlLoopElement> clElementMap = prepareClElementMap(clElements);
229 controlLoop = new ControlLoop();
230 controlLoop.setDefinition(updateMsg.getControlLoopId());
231 controlLoop.setElements(clElementMap);
232 controlLoopMap.put(updateMsg.getControlLoopId(), controlLoop);
234 controlLoopUpdateAck.setResponseTo(updateMsg.getMessageId());
235 controlLoopUpdateAck.setControlLoopId(updateMsg.getControlLoopId());
236 controlLoopUpdateAck.setMessage("Control loop " + updateMsg.getControlLoopId()
237 + " defined on participant " + participantId);
238 controlLoopUpdateAck.setResult(true);
239 messageSender.sendAckResponse(controlLoopUpdateAck);
242 private ToscaNodeTemplate getClElementNodeTemplate(List<ControlLoopElementDefinition> clElementDefinitions,
243 ToscaConceptIdentifier clElementDefId) {
244 for (ControlLoopElementDefinition clElementDefinition : clElementDefinitions) {
245 if (clElementDefinition.getClElementDefinitionId().equals(clElementDefId)) {
246 return clElementDefinition.getControlLoopElementToscaNodeTemplate();
252 private List<ControlLoopElement> storeElementsOnThisParticipant(List<ParticipantUpdates> participantUpdates) {
253 List<ControlLoopElement> clElementMap = new ArrayList<>();
254 for (ParticipantUpdates participantUpdate : participantUpdates) {
255 if (participantUpdate.getParticipantId().equals(participantType)) {
256 clElementMap = participantUpdate.getControlLoopElementList();
259 for (ControlLoopElement element : clElementMap) {
260 elementsOnThisParticipant.put(element.getId(), element);
265 private Map<UUID, ControlLoopElement> prepareClElementMap(List<ControlLoopElement> clElements) {
266 Map<UUID, ControlLoopElement> clElementMap = new LinkedHashMap<>();
267 for (ControlLoopElement element : clElements) {
268 clElementMap.put(element.getId(), element);
274 * Method to handle when the new state from participant is UNINITIALISED state.
276 * @param controlLoop participant response
277 * @param orderedState orderedState
278 * @param response participant response
280 private void handleUninitialisedState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
281 final ControlLoopAck response) {
282 handleStateChange(controlLoop, orderedState, ControlLoopState.UNINITIALISED, response);
283 controlLoopMap.remove(controlLoop.getKey().asIdentifier());
285 for (ControlLoopElementListener clElementListener : listeners) {
287 for (ControlLoopElement element : controlLoop.getElements().values()) {
288 clElementListener.controlLoopElementStateChange(element.getId(), element.getState(), orderedState);
290 } catch (PfModelException e) {
291 LOGGER.debug("Control loop element update failed {}", controlLoop.getDefinition());
297 * Method to handle when the new state from participant is PASSIVE state.
299 * @param controlLoop participant response
300 * @param orderedState orderedState
301 * @param response participant response
303 private void handlePassiveState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
304 final ControlLoopAck response) {
305 handleStateChange(controlLoop, orderedState, ControlLoopState.PASSIVE, response);
309 * Method to handle when the new state from participant is RUNNING state.
311 * @param controlLoop participant response
312 * @param orderedState orderedState
313 * @param response participant response
315 private void handleRunningState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
316 final ControlLoopAck response) {
317 handleStateChange(controlLoop, orderedState, ControlLoopState.RUNNING, response);
321 * Method to update the state of control loop elements.
323 * @param controlLoop participant status in memory
324 * @param orderedState orderedState the new ordered state the participant should have
325 * @param newState new state of the control loop elements
326 * @param response the response to the state change request
328 private void handleStateChange(ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
329 ControlLoopState newState, ControlLoopAck response) {
331 if (orderedState.equals(controlLoop.getOrderedState())) {
332 response.setMessage("Control loop is already in state " + orderedState);
333 response.setResult(false);
337 if (!CollectionUtils.isEmpty(controlLoop.getElements().values())) {
338 controlLoop.getElements().values().forEach(element -> {
339 element.setState(newState);
340 element.setOrderedState(orderedState);
344 response.setMessage("ControlLoop state changed from " + controlLoop.getOrderedState() + " to " + orderedState);
345 response.setResult(true);
346 controlLoop.setOrderedState(orderedState);
350 * Get control loops as a {@link ConrolLoops} class.
352 * @return the control loops
354 public ControlLoops getControlLoops() {
355 var controlLoops = new ControlLoops();
356 controlLoops.setControlLoopList(new ArrayList<>(controlLoopMap.values()));