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.runtime.supervision;
23 import java.util.List;
24 import javax.ws.rs.core.Response;
25 import lombok.AllArgsConstructor;
26 import org.apache.commons.collections4.CollectionUtils;
27 import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
28 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
29 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
30 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
31 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
32 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
33 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider;
34 import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus;
35 import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider;
36 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopStateChangePublisher;
37 import org.onap.policy.clamp.controlloop.runtime.supervision.comm.ParticipantControlLoopUpdatePublisher;
38 import org.onap.policy.models.base.PfModelException;
39 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.springframework.stereotype.Component;
45 * This class handles supervision of control loop instances, so only one object of this type should be built at a time.
48 * It is effectively a singleton that is started at system start.
52 public class SupervisionHandler {
53 private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionHandler.class);
55 private static final String CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE = "Control loop can't transition from state ";
56 private static final String CONTROL_LOOP_IS_ALREADY_IN_STATE = "Control loop is already in state ";
57 private static final String TO_STATE = " to state ";
58 private static final String AND_TRANSITIONING_TO_STATE = " and transitioning to state ";
60 private final ControlLoopProvider controlLoopProvider;
61 private final ParticipantProvider participantProvider;
62 private final MonitoringProvider monitoringProvider;
64 // Publishers for participant communication
65 private final ParticipantControlLoopUpdatePublisher controlLoopUpdatePublisher;
66 private final ParticipantControlLoopStateChangePublisher controlLoopStateChangePublisher;
69 * Supervision trigger called when a command is issued on control loops.
72 * Causes supervision to start or continue supervision on the control loops in question.
74 * @param controlLoopIdentifierList the control loops for which the supervision command has been issued
75 * @throws ControlLoopException on supervision triggering exceptions
77 public void triggerControlLoopSupervision(List<ToscaConceptIdentifier> controlLoopIdentifierList)
78 throws ControlLoopException {
80 LOGGER.debug("triggering control loop supervision on control loops {}", controlLoopIdentifierList);
82 if (CollectionUtils.isEmpty(controlLoopIdentifierList)) {
83 // This is just to force throwing of the exception in certain circumstances.
84 exceptionOccured(Response.Status.NOT_ACCEPTABLE, "The list of control loops for supervision is empty");
87 for (ToscaConceptIdentifier controlLoopId : controlLoopIdentifierList) {
89 var controlLoop = controlLoopProvider.getControlLoop(controlLoopId);
91 superviseControlLoop(controlLoop);
93 controlLoopProvider.updateControlLoop(controlLoop);
94 } catch (PfModelException pfme) {
95 throw new ControlLoopException(pfme.getErrorResponse().getResponseCode(), pfme.getMessage(), pfme);
101 * Handle a ParticipantStatus message from a participant.
103 * @param participantStatusMessage the ParticipantStatus message received from a participant
105 public void handleParticipantStatusMessage(ParticipantStatus participantStatusMessage) {
106 LOGGER.debug("Participant Status received {}", participantStatusMessage);
109 superviseParticipant(participantStatusMessage);
110 } catch (PfModelException | ControlLoopException svExc) {
111 LOGGER.warn("error supervising participant {}", participantStatusMessage.getParticipantId(), svExc);
116 superviseControlLoops(participantStatusMessage);
117 } catch (PfModelException | ControlLoopException svExc) {
118 LOGGER.warn("error supervising participant {}", participantStatusMessage.getParticipantId(), svExc);
123 * Supervise a control loop, performing whatever actions need to be performed on the control loop.
125 * @param controlLoop the control loop to supervises
126 * @throws PfModelException on accessing models in the database
127 * @throws ControlLoopException on supervision errors
129 private void superviseControlLoop(ControlLoop controlLoop) throws ControlLoopException, PfModelException {
130 switch (controlLoop.getOrderedState()) {
132 superviseControlLoopUninitialization(controlLoop);
136 superviseControlLoopPassivation(controlLoop);
140 superviseControlLoopActivation(controlLoop);
144 exceptionOccured(Response.Status.NOT_ACCEPTABLE,
145 "A control loop cannot be commanded to go into state " + controlLoop.getOrderedState().name());
150 * Supervise a control loop uninitialisation, performing whatever actions need to be performed on the control loop,
151 * control loop ordered state is UNINITIALIZED.
153 * @param controlLoop the control loop to supervises
154 * @throws ControlLoopException on supervision errors
156 private void superviseControlLoopUninitialization(ControlLoop controlLoop) throws ControlLoopException {
157 switch (controlLoop.getState()) {
159 exceptionOccured(Response.Status.NOT_ACCEPTABLE,
160 CONTROL_LOOP_IS_ALREADY_IN_STATE + controlLoop.getState().name());
163 case UNINITIALISED2PASSIVE:
165 controlLoop.setState(ControlLoopState.PASSIVE2UNINITIALISED);
166 controlLoopStateChangePublisher.send(controlLoop);
169 case PASSIVE2UNINITIALISED:
170 exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_IS_ALREADY_IN_STATE
171 + controlLoop.getState().name() + AND_TRANSITIONING_TO_STATE + controlLoop.getOrderedState());
175 exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE
176 + controlLoop.getState().name() + TO_STATE + controlLoop.getOrderedState());
181 private void superviseControlLoopPassivation(ControlLoop controlLoop)
182 throws ControlLoopException, PfModelException {
183 switch (controlLoop.getState()) {
185 exceptionOccured(Response.Status.NOT_ACCEPTABLE,
186 CONTROL_LOOP_IS_ALREADY_IN_STATE + controlLoop.getState().name());
189 controlLoop.setState(ControlLoopState.UNINITIALISED2PASSIVE);
190 controlLoopUpdatePublisher.send(controlLoop);
193 case UNINITIALISED2PASSIVE:
194 case RUNNING2PASSIVE:
195 exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_IS_ALREADY_IN_STATE
196 + controlLoop.getState().name() + AND_TRANSITIONING_TO_STATE + controlLoop.getOrderedState());
200 controlLoop.setState(ControlLoopState.RUNNING2PASSIVE);
201 controlLoopStateChangePublisher.send(controlLoop);
205 exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE
206 + controlLoop.getState().name() + TO_STATE + controlLoop.getOrderedState());
211 private void superviseControlLoopActivation(ControlLoop controlLoop) throws ControlLoopException {
212 switch (controlLoop.getState()) {
214 exceptionOccured(Response.Status.NOT_ACCEPTABLE,
215 CONTROL_LOOP_IS_ALREADY_IN_STATE + controlLoop.getState().name());
218 case PASSIVE2RUNNING:
219 exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_IS_ALREADY_IN_STATE
220 + controlLoop.getState().name() + AND_TRANSITIONING_TO_STATE + controlLoop.getOrderedState());
224 controlLoop.setState(ControlLoopState.PASSIVE2RUNNING);
225 controlLoopStateChangePublisher.send(controlLoop);
229 exceptionOccured(Response.Status.NOT_ACCEPTABLE, CONTROL_LOOP_CANNOT_TRANSITION_FROM_STATE
230 + controlLoop.getState().name() + TO_STATE + controlLoop.getOrderedState());
235 private void superviseParticipant(ParticipantStatus participantStatusMessage)
236 throws PfModelException, ControlLoopException {
237 if (participantStatusMessage.getParticipantId() == null) {
238 exceptionOccured(Response.Status.NOT_FOUND, "Participant ID on PARTICIPANT_STATUS message is null");
241 List<Participant> participantList =
242 participantProvider.getParticipants(participantStatusMessage.getParticipantId().getName(),
243 participantStatusMessage.getParticipantId().getVersion());
245 if (CollectionUtils.isEmpty(participantList)) {
246 var participant = new Participant();
247 participant.setName(participantStatusMessage.getParticipantId().getName());
248 participant.setVersion(participantStatusMessage.getParticipantId().getVersion());
249 participant.setDefinition(new ToscaConceptIdentifier("unknown", "0.0.0"));
250 participant.setParticipantState(participantStatusMessage.getState());
251 participant.setHealthStatus(participantStatusMessage.getHealthStatus());
253 participantList.add(participant);
254 participantProvider.createParticipants(participantList);
256 for (Participant participant : participantList) {
257 participant.setParticipantState(participantStatusMessage.getState());
258 participant.setHealthStatus(participantStatusMessage.getHealthStatus());
260 participantProvider.updateParticipants(participantList);
263 monitoringProvider.createParticipantStatistics(List.of(participantStatusMessage.getParticipantStatistics()));
266 private void superviseControlLoops(ParticipantStatus participantStatusMessage)
267 throws PfModelException, ControlLoopException {
268 if (CollectionUtils.isEmpty(participantStatusMessage.getControlLoops().getControlLoopList())) {
272 for (ControlLoop controlLoop : participantStatusMessage.getControlLoops().getControlLoopList()) {
273 if (controlLoop == null) {
274 exceptionOccured(Response.Status.NOT_FOUND,
275 "PARTICIPANT_STATUS message references unknown control loop: " + controlLoop);
278 var dbControlLoop = controlLoopProvider
279 .getControlLoop(new ToscaConceptIdentifier(controlLoop.getName(), controlLoop.getVersion()));
280 if (dbControlLoop == null) {
281 exceptionOccured(Response.Status.NOT_FOUND,
282 "PARTICIPANT_STATUS control loop not found in database: " + controlLoop);
285 for (ControlLoopElement element : controlLoop.getElements().values()) {
286 ControlLoopElement dbElement = dbControlLoop.getElements().get(element.getId());
288 if (dbElement == null) {
289 exceptionOccured(Response.Status.NOT_FOUND,
290 "PARTICIPANT_STATUS message references unknown control loop element: " + element);
293 // Replace element entry in the database
294 dbControlLoop.getElements().put(element.getId(), element);
296 controlLoopProvider.updateControlLoop(dbControlLoop);
299 for (ControlLoop controlLoop : participantStatusMessage.getControlLoops().getControlLoopList()) {
300 monitoringProvider.createClElementStatistics(controlLoop.getControlLoopElementStatisticsList(controlLoop));
304 private void exceptionOccured(Response.Status status, String reason) throws ControlLoopException {
305 throw new ControlLoopException(status, reason);