c01a0b989e6cb401d47a589a21bbc7c2eac971fb
[policy/clamp.git] /
1 /*-
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.controlloop.runtime.instantiation;
22
23 import java.io.Closeable;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.function.UnaryOperator;
30 import java.util.stream.Collectors;
31 import javax.ws.rs.core.Response;
32 import javax.ws.rs.core.Response.Status;
33 import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
34 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
35 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
36 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
37 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
38 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
39 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
40 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse;
41 import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider;
42 import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup;
43 import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler;
44 import org.onap.policy.common.parameters.BeanValidationResult;
45 import org.onap.policy.common.parameters.ObjectValidationResult;
46 import org.onap.policy.common.parameters.ValidationResult;
47 import org.onap.policy.common.parameters.ValidationStatus;
48 import org.onap.policy.models.base.PfModelException;
49 import org.onap.policy.models.base.PfModelRuntimeException;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
52 import org.springframework.stereotype.Component;
53
54 /**
55  * This class is dedicated to the Instantiation of Commissioned control loop.
56  */
57 @Component
58 public class ControlLoopInstantiationProvider implements Closeable {
59     private final ControlLoopProvider controlLoopProvider;
60     private final CommissioningProvider commissioningProvider;
61     private final SupervisionHandler supervisionHandler;
62
63     private static final Object lockit = new Object();
64
65     /**
66      * Create a instantiation provider.
67      *
68      * @param controlLoopParameters the parameters for access to the database
69      * @param commissioningProvider CommissioningProvider
70      * @param supervisionHandler SupervisionHandler
71      * @throws PfModelRuntimeException on errors creating a provider
72      */
73     public ControlLoopInstantiationProvider(ClRuntimeParameterGroup controlLoopParameters,
74             CommissioningProvider commissioningProvider, SupervisionHandler supervisionHandler) {
75         this.commissioningProvider = commissioningProvider;
76         this.supervisionHandler = supervisionHandler;
77         try {
78             controlLoopProvider = new ControlLoopProvider(controlLoopParameters.getDatabaseProviderParameters());
79         } catch (PfModelException e) {
80             throw new PfModelRuntimeException(e);
81         }
82     }
83
84     @Override
85     public void close() throws IOException {
86         controlLoopProvider.close();
87     }
88
89     /**
90      * Create control loops.
91      *
92      * @param controlLoops the control loop
93      * @return the result of the instantiation operation
94      * @throws PfModelException on creation errors
95      */
96     public InstantiationResponse createControlLoops(ControlLoops controlLoops) throws PfModelException {
97
98         synchronized (lockit) {
99             for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
100                 var checkControlLoop = controlLoopProvider.getControlLoop(controlLoop.getKey().asIdentifier());
101                 if (checkControlLoop != null) {
102                     throw new PfModelException(Response.Status.BAD_REQUEST,
103                             controlLoop.getKey().asIdentifier() + " already defined");
104                 }
105             }
106             BeanValidationResult validationResult = validateControlLoops(controlLoops);
107             if (!validationResult.isValid()) {
108                 throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
109             }
110             controlLoopProvider.createControlLoops(controlLoops.getControlLoopList());
111         }
112
113         var response = new InstantiationResponse();
114         response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
115                 .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList()));
116
117         return response;
118     }
119
120     /**
121      * Update control loops.
122      *
123      * @param controlLoops the control loop
124      * @return the result of the instantiation operation
125      * @throws PfModelException on update errors
126      */
127     public InstantiationResponse updateControlLoops(ControlLoops controlLoops) throws PfModelException {
128         synchronized (lockit) {
129             BeanValidationResult validationResult = validateControlLoops(controlLoops);
130             if (!validationResult.isValid()) {
131                 throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
132             }
133             controlLoopProvider.updateControlLoops(controlLoops.getControlLoopList());
134         }
135
136         var response = new InstantiationResponse();
137         response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
138                 .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList()));
139
140         return response;
141     }
142
143     /**
144      * Validate ControlLoops.
145      *
146      * @param controlLoops ControlLoops to validate
147      * @return the result of validation
148      * @throws PfModelException if controlLoops is not valid
149      */
150     private BeanValidationResult validateControlLoops(ControlLoops controlLoops) throws PfModelException {
151
152         var result = new BeanValidationResult("ControlLoops", controlLoops);
153
154         for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
155             var subResult = new BeanValidationResult("entry " + controlLoop.getDefinition().getName(), controlLoop);
156
157             List<ToscaNodeTemplate> toscaNodeTemplates = commissioningProvider.getControlLoopDefinitions(
158                     controlLoop.getDefinition().getName(), controlLoop.getDefinition().getVersion());
159
160             if (toscaNodeTemplates.isEmpty()) {
161                 subResult.addResult(new ObjectValidationResult("ControlLoop", controlLoop.getDefinition().getName(),
162                         ValidationStatus.INVALID, "Commissioned control loop definition not FOUND"));
163             } else if (toscaNodeTemplates.size() > 1) {
164                 subResult.addResult(new ObjectValidationResult("ControlLoop", controlLoop.getDefinition().getName(),
165                         ValidationStatus.INVALID, "Commissioned control loop definition not VALID"));
166             } else {
167
168                 List<ToscaNodeTemplate> clElementDefinitions =
169                         commissioningProvider.getControlLoopElementDefinitions(toscaNodeTemplates.get(0));
170
171                 // @formatter:off
172                 Map<String, ToscaConceptIdentifier> definitions = clElementDefinitions
173                         .stream()
174                         .map(nodeTemplate -> nodeTemplate.getKey().asIdentifier())
175                         .collect(Collectors.toMap(ToscaConceptIdentifier::getName, UnaryOperator.identity()));
176                 // @formatter:on
177
178                 for (ControlLoopElement element : controlLoop.getElements().values()) {
179                     subResult.addResult(validateDefinition(definitions, element.getDefinition()));
180                 }
181             }
182             result.addResult(subResult);
183         }
184         return result;
185     }
186
187     /**
188      * Validate ToscaConceptIdentifier, checking if exist in ToscaConceptIdentifiers map.
189      *
190      * @param definitions map of all ToscaConceptIdentifiers
191      * @param definition ToscaConceptIdentifier to validate
192      * @return the validation result
193      */
194     private ValidationResult validateDefinition(Map<String, ToscaConceptIdentifier> definitions,
195             ToscaConceptIdentifier definition) {
196         var result = new BeanValidationResult("entry " + definition.getName(), definition);
197         ToscaConceptIdentifier identifier = definitions.get(definition.getName());
198         if (identifier == null) {
199             result.setResult(ValidationStatus.INVALID, "Not FOUND");
200         } else if (!identifier.equals(definition)) {
201             result.setResult(ValidationStatus.INVALID, "Version not matching");
202         }
203         return (result.isClean() ? null : result);
204     }
205
206     /**
207      * Delete the control loop with the given name and version.
208      *
209      * @param name the name of the control loop to delete
210      * @param version the version of the control loop to delete
211      * @return the result of the deletion
212      * @throws PfModelException on deletion errors
213      */
214     public InstantiationResponse deleteControlLoop(String name, String version) throws PfModelException {
215         var response = new InstantiationResponse();
216         synchronized (lockit) {
217             List<ControlLoop> controlLoops = controlLoopProvider.getControlLoops(name, version);
218             if (controlLoops.isEmpty()) {
219                 throw new PfModelException(Response.Status.NOT_FOUND, "Control Loop not found");
220             }
221             for (ControlLoop controlLoop : controlLoops) {
222                 if (!ControlLoopState.UNINITIALISED.equals(controlLoop.getState())) {
223                     throw new PfModelException(Response.Status.BAD_REQUEST,
224                             "Control Loop State is still " + controlLoop.getState());
225                 }
226             }
227
228             response.setAffectedControlLoops(Collections
229                     .singletonList(controlLoopProvider.deleteControlLoop(name, version).getKey().asIdentifier()));
230         }
231         return response;
232     }
233
234     /**
235      * Get the requested control loops.
236      *
237      * @param name the name of the control loop to get, null for all control loops
238      * @param version the version of the control loop to get, null for all control loops
239      * @return the control loops
240      * @throws PfModelException on errors getting control loops
241      */
242     public ControlLoops getControlLoops(String name, String version) throws PfModelException {
243         var controlLoops = new ControlLoops();
244         controlLoops.setControlLoopList(controlLoopProvider.getControlLoops(name, version));
245
246         return controlLoops;
247     }
248
249     /**
250      * Issue a command to control loops, setting their ordered state.
251      *
252      * @param command the command to issue to control loops
253      * @return the result of the initiation command
254      * @throws PfModelException on errors setting the ordered state on the control loops
255      * @throws ControlLoopException on ordered state invalid
256      */
257     public InstantiationResponse issueControlLoopCommand(InstantiationCommand command)
258             throws ControlLoopException, PfModelException {
259
260         if (command.getOrderedState() == null) {
261             throw new ControlLoopException(Status.BAD_REQUEST, "ordered state invalid or not specified on command");
262         }
263
264         synchronized (lockit) {
265             List<ControlLoop> controlLoops = new ArrayList<>(command.getControlLoopIdentifierList().size());
266             for (ToscaConceptIdentifier id : command.getControlLoopIdentifierList()) {
267                 var controlLoop = controlLoopProvider.getControlLoop(id);
268                 controlLoop.setCascadedOrderedState(command.getOrderedState());
269                 controlLoops.add(controlLoop);
270             }
271             controlLoopProvider.updateControlLoops(controlLoops);
272         }
273
274         supervisionHandler.triggerControlLoopSupervision(command.getControlLoopIdentifierList());
275         var response = new InstantiationResponse();
276         response.setAffectedControlLoops(command.getControlLoopIdentifierList());
277
278         return response;
279     }
280 }