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;
30 import java.util.stream.Collectors;
32 import lombok.NoArgsConstructor;
33 import org.apache.commons.collections4.CollectionUtils;
34 import org.apache.commons.lang3.tuple.Pair;
35 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics;
36 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
37 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
38 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition;
39 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
40 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
41 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
42 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantUpdates;
43 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopAck;
44 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopStateChange;
45 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopUpdate;
46 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType;
47 import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
48 import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender;
49 import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters;
50 import org.onap.policy.models.base.PfModelException;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
52 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
57 * This class is responsible for managing the state of all control loops in the participant.
60 public class ControlLoopHandler {
61 private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopHandler.class);
63 private ToscaConceptIdentifier participantType = null;
64 private ToscaConceptIdentifier participantId = null;
65 private MessageSender messageSender = null;
68 private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>();
71 private final Map<UUID, ControlLoopElement> elementsOnThisParticipant = new LinkedHashMap<>();
74 private List<ControlLoopElementListener> listeners = new ArrayList<>();
77 * Constructor, set the participant ID and messageSender.
79 * @param parameters the parameters of the participant
80 * @param messageSender the messageSender for sending responses to messages
82 public ControlLoopHandler(ParticipantIntermediaryParameters parameters, MessageSender messageSender) {
83 this.participantType = parameters.getParticipantType();
84 this.participantId = parameters.getParticipantId();
85 this.messageSender = messageSender;
88 public void registerControlLoopElementListener(ControlLoopElementListener listener) {
89 listeners.add(listener);
93 * Handle a control loop element state change message.
95 * @param id controlloop element id
96 * @param orderedState the current state
97 * @param newState the ordered state
98 * @return controlLoopElement the updated controlloop element
100 public ControlLoopElement updateControlLoopElementState(UUID id, ControlLoopOrderedState orderedState,
101 ControlLoopState newState, ParticipantMessageType messageType) {
104 LOGGER.warn("Cannot update Control loop element state, id is null");
107 var controlLoopStateChangeAck =
108 new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
109 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
110 if (clElement != null) {
111 clElement.setOrderedState(orderedState);
112 clElement.setState(newState);
113 controlLoopStateChangeAck.getControlLoopResultMap().put(clElement.getId(),
114 Pair.of(true, "Control loop element {} state changed to {}\", id, newState)"));
115 LOGGER.debug("Control loop element {} state changed to {}", id, newState);
116 controlLoopStateChangeAck.setMessage("ControlLoopElement state changed to {} " + newState);
117 controlLoopStateChangeAck.setResult(true);
118 messageSender.sendAckResponse(controlLoopStateChangeAck);
125 * Handle a control loop element statistics.
127 * @param id controlloop element id
128 * @param elementStatistics control loop element Statistics
130 public void updateControlLoopElementStatistics(UUID id, ClElementStatistics elementStatistics) {
131 ControlLoopElement clElement = elementsOnThisParticipant.get(id);
132 if (clElement != null) {
133 elementStatistics.setParticipantId(participantId);
134 elementStatistics.setId(id);
135 clElement.setClElementStatistics(elementStatistics);
140 * Handle a control loop state change message.
142 * @param stateChangeMsg the state change message
144 public void handleControlLoopStateChange(ControlLoopStateChange stateChangeMsg) {
145 if (stateChangeMsg.getControlLoopId() == null) {
149 var controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId());
150 var controlLoopAck = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_STATE_CHANGE);
152 if (controlLoop == null) {
153 controlLoopAck.setMessage("Control loop " + stateChangeMsg.getControlLoopId()
154 + " does not use this participant " + participantId);
155 controlLoopAck.setResult(false);
156 controlLoopAck.setResponseTo(stateChangeMsg.getMessageId());
157 controlLoopAck.setControlLoopId(stateChangeMsg.getControlLoopId());
158 messageSender.sendAckResponse(controlLoopAck);
159 LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId());
163 handleState(controlLoop, stateChangeMsg.getOrderedState());
167 * Method to handle state changes.
169 * @param controlLoop participant response
170 * @param orderedState controlloop ordered state
172 private void handleState(final ControlLoop controlLoop, ControlLoopOrderedState orderedState) {
173 switch (orderedState) {
175 handleUninitialisedState(controlLoop, orderedState);
178 handlePassiveState(controlLoop, orderedState);
181 handleRunningState(controlLoop, orderedState);
184 LOGGER.debug("StateChange message has no state, state is null {}", controlLoop.getDefinition());
190 * Handle a control loop update message.
192 * @param updateMsg the update message
194 public void handleControlLoopUpdate(ControlLoopUpdate updateMsg,
195 List<ControlLoopElementDefinition> clElementDefinitions) {
197 if (!updateMsg.appliesTo(participantType, participantId)) {
201 var controlLoop = controlLoopMap.get(updateMsg.getControlLoopId());
203 var controlLoopUpdateAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_UPDATE_ACK);
205 // TODO: Updates to existing ControlLoops are not supported yet (Addition/Removal of ControlLoop
206 // elements to existing ControlLoop has to be supported).
207 if (controlLoop != null) {
208 controlLoopUpdateAck.setMessage("Control loop " + updateMsg.getControlLoopId()
209 + " already defined on participant " + participantId);
210 controlLoopUpdateAck.setResult(false);
211 controlLoopUpdateAck.setResponseTo(updateMsg.getMessageId());
212 controlLoopUpdateAck.setControlLoopId(updateMsg.getControlLoopId());
213 messageSender.sendAckResponse(controlLoopUpdateAck);
217 List<ControlLoopElement> clElements = storeElementsOnThisParticipant(updateMsg.getParticipantUpdatesList());
220 for (ControlLoopElement element : clElements) {
221 ToscaNodeTemplate clElementNodeTemplate = getClElementNodeTemplate(
222 clElementDefinitions, element.getDefinition());
223 for (ControlLoopElementListener clElementListener : listeners) {
224 clElementListener.controlLoopElementUpdate(element, clElementNodeTemplate);
227 } catch (PfModelException e) {
228 LOGGER.debug("Control loop element update failed {}", updateMsg.getControlLoopId());
231 Map<UUID, ControlLoopElement> clElementMap = prepareClElementMap(clElements);
232 controlLoop = new ControlLoop();
233 controlLoop.setDefinition(updateMsg.getControlLoopId());
234 controlLoop.setElements(clElementMap);
235 controlLoopMap.put(updateMsg.getControlLoopId(), controlLoop);
238 private ToscaNodeTemplate getClElementNodeTemplate(List<ControlLoopElementDefinition> clElementDefinitions,
239 ToscaConceptIdentifier clElementDefId) {
240 for (ControlLoopElementDefinition clElementDefinition : clElementDefinitions) {
241 if (clElementDefinition.getClElementDefinitionId().equals(clElementDefId)) {
242 return clElementDefinition.getControlLoopElementToscaNodeTemplate();
248 private List<ControlLoopElement> storeElementsOnThisParticipant(List<ParticipantUpdates> participantUpdates) {
250 participantUpdates.stream()
251 .flatMap(participantUpdate -> participantUpdate.getControlLoopElementList().stream())
252 .filter(element -> participantType.equals(element.getParticipantType()))
253 .collect(Collectors.toList());
255 for (var element : clElementMap) {
256 elementsOnThisParticipant.put(element.getId(), element);
261 private Map<UUID, ControlLoopElement> prepareClElementMap(List<ControlLoopElement> clElements) {
262 Map<UUID, ControlLoopElement> clElementMap = new LinkedHashMap<>();
263 for (ControlLoopElement element : clElements) {
264 clElementMap.put(element.getId(), element);
270 * Method to handle when the new state from participant is UNINITIALISED state.
272 * @param controlLoop participant response
273 * @param orderedState orderedState
275 private void handleUninitialisedState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState) {
276 handleStateChange(controlLoop, orderedState, ControlLoopState.UNINITIALISED);
277 controlLoopMap.remove(controlLoop.getKey().asIdentifier());
279 for (ControlLoopElementListener clElementListener : listeners) {
281 for (ControlLoopElement element : controlLoop.getElements().values()) {
282 clElementListener.controlLoopElementStateChange(element.getId(), element.getState(), orderedState);
284 } catch (PfModelException e) {
285 LOGGER.debug("Control loop element update failed {}", controlLoop.getDefinition());
291 * Method to handle when the new state from participant is PASSIVE state.
293 * @param controlLoop participant response
294 * @param orderedState orderedState
296 private void handlePassiveState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState) {
297 handleStateChange(controlLoop, orderedState, ControlLoopState.PASSIVE);
301 * Method to handle when the new state from participant is RUNNING state.
303 * @param controlLoop participant response
304 * @param orderedState orderedState
306 private void handleRunningState(final ControlLoop controlLoop, final ControlLoopOrderedState orderedState) {
307 handleStateChange(controlLoop, orderedState, ControlLoopState.RUNNING);
311 * Method to update the state of control loop elements.
313 * @param controlLoop participant status in memory
314 * @param orderedState orderedState the new ordered state the participant should have
315 * @param newState new state of the control loop elements
317 private void handleStateChange(ControlLoop controlLoop, final ControlLoopOrderedState orderedState,
318 ControlLoopState newState) {
320 if (orderedState.equals(controlLoop.getOrderedState())) {
321 var controlLoopAck = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_STATE_CHANGE);
322 controlLoopAck.setMessage("Control loop is already in state" + orderedState);
323 controlLoopAck.setResult(false);
324 controlLoopAck.setControlLoopId(controlLoop.getDefinition());
325 messageSender.sendAckResponse(controlLoopAck);
329 if (!CollectionUtils.isEmpty(controlLoop.getElements().values())) {
330 controlLoop.getElements().values().forEach(element -> {
331 element.setState(newState);
332 element.setOrderedState(orderedState);
336 controlLoop.setOrderedState(orderedState);
340 * Get control loops as a {@link ConrolLoops} class.
342 * @return the control loops
344 public ControlLoops getControlLoops() {
345 var controlLoops = new ControlLoops();
346 controlLoops.setControlLoopList(new ArrayList<>(controlLoopMap.values()));