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