891d42072dfe99b1b995ac7384bdc453c37637a9
[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.commissioning;
22
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.fasterxml.jackson.databind.PropertyNamingStrategies;
26 import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.stream.Collectors;
33 import org.apache.commons.collections4.CollectionUtils;
34 import org.apache.commons.collections4.MapUtils;
35 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
36 import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse;
37 import org.onap.policy.models.base.PfModelException;
38 import org.onap.policy.models.provider.PolicyModelsProvider;
39 import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType;
40 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
41 import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
44 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaProperty;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaRelationshipType;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates;
49 import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter;
51 import org.springframework.stereotype.Component;
52
53 /**
54  * This class provides the create, read and delete actions on Commissioning of Control Loop concepts in the database to
55  * the callers.
56  */
57 @Component
58 public class CommissioningProvider {
59     public static final String CONTROL_LOOP_NODE_TYPE = "org.onap.policy.clamp.controlloop.ControlLoop";
60
61     private final PolicyModelsProvider modelsProvider;
62     private final ControlLoopProvider clProvider;
63
64     private static final Object lockit = new Object();
65
66     /**
67      * Create a commissioning provider.
68      *
69      * @param modelsProvider the PolicyModelsProvider
70      * @param clProvider the ControlLoopProvider
71      */
72     public CommissioningProvider(PolicyModelsProvider modelsProvider, ControlLoopProvider clProvider) {
73         this.modelsProvider = modelsProvider;
74         this.clProvider = clProvider;
75     }
76
77     /**
78      * Create control loops from a service template.
79      *
80      * @param serviceTemplate the service template
81      * @return the result of the commissioning operation
82      * @throws PfModelException on creation errors
83      */
84     public CommissioningResponse createControlLoopDefinitions(ToscaServiceTemplate serviceTemplate)
85             throws PfModelException {
86         synchronized (lockit) {
87             modelsProvider.createServiceTemplate(serviceTemplate);
88         }
89
90         var response = new CommissioningResponse();
91         // @formatter:off
92         response.setAffectedControlLoopDefinitions(serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
93                 .values()
94                 .stream()
95                 .map(template -> template.getKey().asIdentifier())
96                 .collect(Collectors.toList()));
97         // @formatter:on
98
99         return response;
100     }
101
102     /**
103      * Delete the control loop definition with the given name and version.
104      *
105      * @param name the name of the control loop definition to delete
106      * @param version the version of the control loop to delete
107      * @return the result of the deletion
108      * @throws PfModelException on deletion errors
109      */
110     public CommissioningResponse deleteControlLoopDefinition(String name, String version) throws PfModelException {
111         synchronized (lockit) {
112             modelsProvider.deleteServiceTemplate(name, version);
113         }
114
115         var response = new CommissioningResponse();
116         response.setAffectedControlLoopDefinitions(
117                 Collections.singletonList(new ToscaConceptIdentifier(name, version)));
118
119         return response;
120     }
121
122     /**
123      * Get control loop node templates.
124      *
125      * @param clName the name of the control loop, null for all
126      * @param clVersion the version of the control loop, null for all
127      * @return list of control loop node templates
128      * @throws PfModelException on errors getting control loop definitions
129      */
130     public List<ToscaNodeTemplate> getControlLoopDefinitions(String clName, String clVersion) throws PfModelException {
131
132         // @formatter:off
133         ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
134                 .<ToscaNodeTemplate>builder()
135                 .name(clName)
136                 .version(clVersion)
137                 .type(CONTROL_LOOP_NODE_TYPE)
138                 .build();
139         // @formatter:on
140
141         return clProvider.getFilteredNodeTemplates(nodeTemplateFilter);
142     }
143
144     /**
145      * Get the control loop elements from a control loop node template.
146      *
147      * @param controlLoopNodeTemplate the control loop node template
148      * @return a list of the control loop element node templates in a control loop node template
149      * @throws PfModelException on errors get control loop element node templates
150      */
151     public List<ToscaNodeTemplate> getControlLoopElementDefinitions(ToscaNodeTemplate controlLoopNodeTemplate)
152             throws PfModelException {
153         if (!CONTROL_LOOP_NODE_TYPE.equals(controlLoopNodeTemplate.getType())) {
154             return Collections.emptyList();
155         }
156
157         if (MapUtils.isEmpty(controlLoopNodeTemplate.getProperties())) {
158             return Collections.emptyList();
159         }
160
161         @SuppressWarnings("unchecked")
162         List<Map<String, String>> controlLoopElements =
163                 (List<Map<String, String>>) controlLoopNodeTemplate.getProperties().get("elements");
164
165         if (CollectionUtils.isEmpty(controlLoopElements)) {
166             return Collections.emptyList();
167         }
168
169         List<ToscaNodeTemplate> controlLoopElementList = new ArrayList<>();
170         // @formatter:off
171         controlLoopElementList.addAll(
172                 controlLoopElements
173                         .stream()
174                         .map(elementMap -> clProvider.getNodeTemplates(elementMap.get("name"),
175                                 elementMap.get("version")))
176                         .flatMap(List::stream)
177                         .collect(Collectors.toList())
178         );
179         // @formatter:on
180
181         return controlLoopElementList;
182     }
183
184     /**
185      * Get the initial node types with common or instance properties.
186      *
187      * @param fullNodeTypes map of all the node types in the specified template
188      * @param common boolean to indicate whether common or instance properties are required
189      * @return node types map that only has common properties
190      * @throws PfModelException on errors getting node type with common properties
191      */
192     private Map<String, ToscaNodeType> getInitialNodeTypesMap(
193         Map<String, ToscaNodeType> fullNodeTypes, boolean common) {
194
195         var tempNodeTypesMap = new HashMap<String, ToscaNodeType>();
196
197         fullNodeTypes.forEach((key, nodeType) -> {
198             var tempToscaNodeType = new ToscaNodeType();
199             tempToscaNodeType.setName(key);
200
201             var resultantPropertyMap = findCommonOrInstancePropsInNodeTypes(
202                 nodeType, common);
203
204             if (!resultantPropertyMap.isEmpty()) {
205                 tempToscaNodeType.setProperties(resultantPropertyMap);
206                 tempNodeTypesMap.put(key, tempToscaNodeType);
207             }
208         });
209         return tempNodeTypesMap;
210     }
211
212     private Map<String, ToscaProperty> findCommonOrInstancePropsInNodeTypes(
213         ToscaNodeType nodeType, boolean common) {
214
215         var tempCommonPropertyMap = new HashMap<String, ToscaProperty>();
216         var tempInstancePropertyMap = new HashMap<String, ToscaProperty>();
217
218         nodeType.getProperties().forEach((propKey, prop) -> {
219
220             if (prop.getMetadata() != null) {
221                 prop.getMetadata().forEach((k, v) -> {
222                     if (k.equals("common") && v.equals("true") && common) {
223                         tempCommonPropertyMap.put(propKey, prop);
224                     } else if (k.equals("common") && v.equals("false") && !common) {
225                         tempInstancePropertyMap.put(propKey, prop);
226                     }
227
228                 });
229             } else {
230                 tempInstancePropertyMap.put(propKey, prop);
231             }
232         });
233
234         if (tempCommonPropertyMap.isEmpty() && !common) {
235             return tempInstancePropertyMap;
236         } else {
237             return tempCommonPropertyMap;
238         }
239     }
240
241     /**
242      * Get the node types derived from those that have common properties.
243      *
244      * @param initialNodeTypes map of all the node types in the specified template
245      * @param filteredNodeTypes map of all the node types that have common or instance properties
246      * @return all node types that have common properties including their children
247      * @throws PfModelException on errors getting node type with common properties
248      */
249     private Map<String, ToscaNodeType> getFinalNodeTypesMap(
250         Map<String, ToscaNodeType> initialNodeTypes,
251         Map<String, ToscaNodeType> filteredNodeTypes) {
252         for (var i = 0; i < initialNodeTypes.size(); i++) {
253             initialNodeTypes.forEach((key, nodeType) -> {
254                 var tempToscaNodeType = new ToscaNodeType();
255                 tempToscaNodeType.setName(key);
256
257                 if (filteredNodeTypes.get(nodeType.getDerivedFrom()) != null) {
258                     tempToscaNodeType.setName(key);
259
260                     var finalProps = new HashMap<String, ToscaProperty>(
261                         filteredNodeTypes.get(nodeType.getDerivedFrom()).getProperties());
262
263                     tempToscaNodeType.setProperties(finalProps);
264                 } else {
265                     return;
266                 }
267                 filteredNodeTypes.putIfAbsent(key, tempToscaNodeType);
268
269             });
270         }
271         return filteredNodeTypes;
272     }
273
274     /**
275      * Get the requested node types with common or instance properties.
276      *
277      * @param common boolean indicating common or instance properties
278      * @param name the name of the definition to get, null for all definitions
279      * @param version the version of the definition to get, null for all definitions
280      * @return the node types with common or instance properties
281      * @throws PfModelException on errors getting node type properties
282      */
283     private Map<String, ToscaNodeType> getCommonOrInstancePropertiesFromNodeTypes(
284         boolean common, String name, String version)
285         throws PfModelException {
286         var serviceTemplates = new ToscaServiceTemplates();
287         serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
288         var tempNodeTypesMap =
289             this.getInitialNodeTypesMap(serviceTemplates.getServiceTemplates().get(0).getNodeTypes(), common);
290
291         return this.getFinalNodeTypesMap(
292             serviceTemplates.getServiceTemplates().get(0).getNodeTypes(), tempNodeTypesMap);
293
294     }
295
296     /**
297      * Get node templates with appropriate common or instance properties added.
298      *
299      * @param initialNodeTemplates map of all the node templates in the specified template
300      * @param nodeTypeProps map of all the node types that have common or instance properties including children
301      * @return all node templates with appropriate common or instance properties added
302      * @throws PfModelException on errors getting map of node templates with common or instance properties added
303      */
304     private Map<String, ToscaNodeTemplate> getDerivedCommonOrInstanceNodeTemplates(
305         Map<String, ToscaNodeTemplate> initialNodeTemplates,
306         Map<String, ToscaNodeType> nodeTypeProps) {
307
308         var finalNodeTemplatesMap = new HashMap<String, ToscaNodeTemplate>();
309
310         initialNodeTemplates.forEach((templateKey, template) -> {
311             if (nodeTypeProps.containsKey(template.getType())) {
312                 var finalMergedProps = new HashMap<String, Object>();
313
314                 nodeTypeProps.get(template.getType()).getProperties().forEach(finalMergedProps::putIfAbsent);
315
316                 template.setProperties(finalMergedProps);
317
318                 finalNodeTemplatesMap.put(templateKey, template);
319             } else {
320                 return;
321             }
322         });
323         return finalNodeTemplatesMap;
324     }
325
326     /**
327      * Get node templates with common properties added.
328      *
329      * @param common boolean indicating common or instance properties to be used
330      * @param name the name of the definition to use, null for all definitions
331      * @param version the version of the definition to use, null for all definitions
332      * @return the nodes templates with common or instance properties
333      * @throws PfModelException on errors getting common or instance properties from node_templates
334      */
335     public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(
336         boolean common, String name, String version) throws PfModelException {
337
338         var commonOrInstanceNodeTypeProps =
339             this.getCommonOrInstancePropertiesFromNodeTypes(common, name, version);
340
341         var serviceTemplates = new ToscaServiceTemplates();
342         serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
343
344         return this.getDerivedCommonOrInstanceNodeTemplates(
345             serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
346             commonOrInstanceNodeTypeProps);
347     }
348
349     /**
350      * Get the requested control loop definitions.
351      *
352      * @param name the name of the definition to get, null for all definitions
353      * @param version the version of the definition to get, null for all definitions
354      * @return the control loop definitions
355      * @throws PfModelException on errors getting control loop definitions
356      */
357     public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
358         var serviceTemplates = new ToscaServiceTemplates();
359         serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
360         return serviceTemplates.getServiceTemplates().get(0);
361     }
362
363     /**
364      * Get the tosca service template with only required sections.
365      *
366      * @param name the name of the template to get, null for all definitions
367      * @param version the version of the template to get, null for all definitions
368      * @return the tosca service template
369      * @throws PfModelException on errors getting tosca service template
370      */
371     public Map<String, Object> getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
372         var serviceTemplates = new ToscaServiceTemplates();
373         serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
374
375         ToscaServiceTemplate fullTemplate = serviceTemplates.getServiceTemplates().get(0);
376
377         var template = new HashMap<String, Object>();
378         template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
379         template.put("data_types", fullTemplate.getDataTypes());
380         template.put("policy_types", fullTemplate.getPolicyTypes());
381         template.put("node_types", fullTemplate.getNodeTypes());
382         template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
383
384         return template;
385     }
386
387     /**
388      * Get the requested json schema.
389      *
390      * @param section section of the tosca service template to get schema for
391      * @return the specified tosca service template or section Json Schema
392      * @throws PfModelException on errors with retrieving the classes
393      * @throws JsonProcessingException on errors generating the schema
394      */
395     public String getToscaServiceTemplateSchema(String section) throws PfModelException, JsonProcessingException {
396         var mapper = new ObjectMapper();
397         mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
398         var visitor = new SchemaFactoryWrapper();
399
400         switch (section) {
401             case "data_types":
402                 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaDataType.class), visitor);
403                 break;
404             case "capability_types":
405                 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaCapabilityType.class), visitor);
406                 break;
407             case "node_types":
408                 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaNodeType.class), visitor);
409                 break;
410             case "relationship_types":
411                 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaRelationshipType.class), visitor);
412                 break;
413             case "policy_types":
414                 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaPolicyType.class), visitor);
415                 break;
416             case "topology_template":
417                 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaTopologyTemplate.class), visitor);
418                 break;
419             case "node_templates":
420                 mapper.acceptJsonFormatVisitor(mapper.getTypeFactory()
421                     .constructCollectionType(List.class, ToscaNodeTemplate.class), visitor);
422                 break;
423             default:
424                 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaServiceTemplate.class), visitor);
425         }
426
427         var jsonSchema = visitor.finalSchema();
428         return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
429     }
430 }