2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 Nordix Foundation.
4 * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.clamp.controlloop.participant.intermediary.handler;
24 import java.util.ArrayList;
25 import java.util.LinkedHashMap;
26 import java.util.List;
28 import java.util.UUID;
29 import java.util.stream.Collectors;
31 import org.apache.commons.collections4.CollectionUtils;
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.ControlLoopElementAck;
36 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition;
37 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
38 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
39 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
40 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantUpdates;
41 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopAck;
42 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopStateChange;
43 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopUpdate;
44 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType;
45 import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
46 import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantMessagePublisher;
47 import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters;
48 import org.onap.policy.models.base.PfModelException;
49 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53 import org.springframework.stereotype.Component;
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 final ToscaConceptIdentifier participantType;
63 private final ToscaConceptIdentifier participantId;
64 private final ParticipantMessagePublisher publisher;
67 private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>();
70 private final Map<UUID, ControlLoopElement> elementsOnThisParticipant = new LinkedHashMap<>();
73 private List<ControlLoopElementListener> listeners = new ArrayList<>();
76 * Constructor, set the participant ID and messageSender.
78 * @param parameters the parameters of the participant
79 * @param publisher the ParticipantMessage Publisher
81 public ControlLoopHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) {
82 this.participantType = parameters.getIntermediaryParameters().getParticipantType();
83 this.participantId = parameters.getIntermediaryParameters().getParticipantId();
84 this.publisher = publisher;
87 public void registerControlLoopElementListener(ControlLoopElementListener listener) {
88 listeners.add(listener);
92 * Handle a control loop element state change message.
94 * @param id controlloop element id
95 * @param orderedState the current state
96 * @param newState the ordered state
97 * @return controlLoopElement the updated controlloop element
99 public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState orderedState,
100 ControlLoopState newState) {
103 LOGGER.warn("Cannot update Control loop element state, id is null");
106 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
107 if (clElement != null) {
108 var controlLoopStateChangeAck =
109 new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
110 controlLoopStateChangeAck.setParticipantId(participantId);
111 controlLoopStateChangeAck.setParticipantType(participantType);
112 clElement.setOrderedState(orderedState);
113 clElement.setState(newState);
114 controlLoopStateChangeAck.getControlLoopResultMap().put(clElement.getId(),
115 new ControlLoopElementAck(true, "Control loop element {} state changed to {}\", id, newState)"));
116 LOGGER.debug("Control loop element {} state changed to {}", id, newState);
117 controlLoopStateChangeAck.setMessage("ControlLoopElement state changed to {} " + newState);
118 controlLoopStateChangeAck.setResult(true);
119 publisher.sendControlLoopAck(controlLoopStateChangeAck);
126 * Handle a control loop element statistics.
128 * @param id controlloop element id
129 * @param elementStatistics control loop element Statistics
131 public void updateControlLoopElementStatistics(UUID id, ClElementStatistics elementStatistics) {
132 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
133 if (clElement != null) {
134 elementStatistics.setParticipantId(participantId);
135 elementStatistics.setId(id);
136 clElement.setClElementStatistics(elementStatistics);
141 * Handle a control loop state change message.
143 * @param stateChangeMsg the state change message
145 public void handleControlLoopStateChange(ControlLoopStateChange stateChangeMsg) {
146 if (stateChangeMsg.getControlLoopId() == null) {
150 var controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId());
152 if (controlLoop == null) {
153 var controlLoopAck = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_STATE_CHANGE);
154 controlLoopAck.setParticipantId(participantId);
155 controlLoopAck.setParticipantType(participantType);
156 controlLoopAck.setMessage("Control loop " + stateChangeMsg.getControlLoopId()
157 + " does not use this participant " + participantId);
158 controlLoopAck.setResult(false);
159 controlLoopAck.setResponseTo(stateChangeMsg.getMessageId());
160 controlLoopAck.setControlLoopId(stateChangeMsg.getControlLoopId());
161 publisher.sendControlLoopAck(controlLoopAck);
162 LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId());
166 handleState(controlLoop, stateChangeMsg.getOrderedState());
170 * Method to handle state changes.
172 * @param controlLoop participant response
173 * @param orderedState controlloop ordered state
175 private void handleState(final ControlLoop controlLoop, ControlLoopOrderedState orderedState) {
176 switch (orderedState) {
178 handleUninitialisedState(controlLoop, orderedState);
181 handlePassiveState(controlLoop, orderedState);
184 handleRunningState(controlLoop, orderedState);
187 LOGGER.debug("StateChange message has no state, state is null {}", controlLoop.getDefinition());
193 * Handle a control loop update message.
195 * @param updateMsg the update message
197 public void handleControlLoopUpdate(ControlLoopUpdate updateMsg,
198 List<ControlLoopElementDefinition> clElementDefinitions) {
200 if (!updateMsg.appliesTo(participantType, participantId)) {
204 var controlLoop = controlLoopMap.get(updateMsg.getControlLoopId());
206 // TODO: Updates to existing ControlLoops are not supported yet (Addition/Removal of ControlLoop
207 // elements to existing ControlLoop has to be supported).
208 if (controlLoop != null) {
209 var controlLoopUpdateAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_UPDATE_ACK);
210 controlLoopUpdateAck.setParticipantId(participantId);
211 controlLoopUpdateAck.setParticipantType(participantType);
213 controlLoopUpdateAck.setMessage("Control loop " + updateMsg.getControlLoopId()
214 + " already defined on participant " + participantId);
215 controlLoopUpdateAck.setResult(false);
216 controlLoopUpdateAck.setResponseTo(updateMsg.getMessageId());
217 controlLoopUpdateAck.setControlLoopId(updateMsg.getControlLoopId());
218 publisher.sendControlLoopAck(controlLoopUpdateAck);
222 List<ControlLoopElement> clElements = storeElementsOnThisParticipant(updateMsg.getParticipantUpdatesList());
225 for (ControlLoopElement element : clElements) {
226 ToscaNodeTemplate clElementNodeTemplate = getClElementNodeTemplate(
227 clElementDefinitions, element.getDefinition());
228 for (ControlLoopElementListener clElementListener : listeners) {
229 clElementListener.controlLoopElementUpdate(element, clElementNodeTemplate);
232 } catch (PfModelException e) {
233 LOGGER.debug("Control loop element update failed {}", updateMsg.getControlLoopId());
236 Map<UUID, ControlLoopElement> clElementMap = prepareClElementMap(clElements);
237 controlLoop = new ControlLoop();
238 controlLoop.setDefinition(updateMsg.getControlLoopId());
239 controlLoop.setElements(clElementMap);
240 controlLoopMap.put(updateMsg.getControlLoopId(), controlLoop);
243 private ToscaNodeTemplate getClElementNodeTemplate(List<ControlLoopElementDefinition> clElementDefinitions,
244 ToscaConceptIdentifier clElementDefId) {
245 for (ControlLoopElementDefinition clElementDefinition : clElementDefinitions) {
246 if (clElementDefinition.getClElementDefinitionId().equals(clElementDefId)) {
247 return clElementDefinition.getControlLoopElementToscaNodeTemplate();
253 private List<ControlLoopElement> storeElementsOnThisParticipant(List<ParticipantUpdates> participantUpdates) {
255 participantUpdates.stream()
256 .flatMap(participantUpdate -> participantUpdate.getControlLoopElementList().stream())
257 .filter(element -> participantType.equals(element.getParticipantType()))
258 .collect(Collectors.toList());
260 for (var element : clElementMap) {
261 elementsOnThisParticipant.put(element.getId(), element);
266 private Map<UUID, ControlLoopElement> prepareClElementMap(List<ControlLoopElement> clElements) {
267 Map<UUID, ControlLoopElement> clElementMap = new LinkedHashMap<>();
268 for (ControlLoopElement element : clElements) {
269 clElementMap.put(element.getId(), element);
275 * Method to handle when the new state from participant is UNINITIALISED state.
277 * @param controlLoop participant response
278 * @param orderedState orderedState
280 private void handleUninitialisedState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState) {
281 handleStateChange(controlLoop, orderedState, ControlLoopState.UNINITIALISED);
282 controlLoopMap.remove(controlLoop.getKey().asIdentifier());
284 for (ControlLoopElementListener clElementListener : listeners) {
286 for (ControlLoopElement element : controlLoop.getElements().values()) {
287 clElementListener.controlLoopElementStateChange(element.getId(), element.getState(), orderedState);
289 } catch (PfModelException e) {
290 LOGGER.debug("Control loop element update failed {}", controlLoop.getDefinition());
296 * Method to handle when the new state from participant is PASSIVE state.
298 * @param controlLoop participant response
299 * @param orderedState orderedState
301 private void handlePassiveState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState) {
302 handleStateChange(controlLoop, orderedState, ControlLoopState.PASSIVE);
306 * Method to handle when the new state from participant is RUNNING state.
308 * @param controlLoop participant response
309 * @param orderedState orderedState
311 private void handleRunningState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState) {
312 handleStateChange(controlLoop, orderedState, ControlLoopState.RUNNING);
316 * Method to update the state of control loop elements.
318 * @param controlLoop participant status in memory
319 * @param orderedState orderedState the new ordered state the participant should have
320 * @param newState new state of the control loop elements
322 private void handleStateChange(ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
323 ControlLoopState newState) {
325 if (orderedState.equals(controlLoop.getOrderedState())) {
326 var controlLoopAck = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_STATE_CHANGE);
327 controlLoopAck.setParticipantId(participantId);
328 controlLoopAck.setParticipantType(participantType);
329 controlLoopAck.setMessage("Control loop is already in state" + orderedState);
330 controlLoopAck.setResult(false);
331 controlLoopAck.setControlLoopId(controlLoop.getDefinition());
332 publisher.sendControlLoopAck(controlLoopAck);
336 if (!CollectionUtils.isEmpty(controlLoop.getElements().values())) {
337 controlLoop.getElements().values().forEach(element -> {
338 element.setState(newState);
339 element.setOrderedState(orderedState);
343 controlLoop.setOrderedState(orderedState);
347 * Get control loops as a {@link ConrolLoops} class.
349 * @return the control loops
351 public ControlLoops getControlLoops() {
352 var controlLoops = new ControlLoops();
353 controlLoops.setControlLoopList(new ArrayList<>(controlLoopMap.values()));