72c153b6d2bdf0c8049d535a56a6c82259d6d7fd
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021 Nordix Foundation.
4  * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.clamp.controlloop.runtime.commissioning;
23
24 import com.fasterxml.jackson.core.JsonProcessingException;
25 import com.fasterxml.jackson.databind.ObjectMapper;
26 import com.fasterxml.jackson.databind.PropertyNamingStrategies;
27 import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.stream.Collectors;
34 import javax.ws.rs.core.Response.Status;
35 import org.apache.commons.collections4.CollectionUtils;
36 import org.apache.commons.collections4.MapUtils;
37 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
38 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
39 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantProvider;
40 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ServiceTemplateProvider;
41 import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse;
42 import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler;
43 import org.onap.policy.models.base.PfModelException;
44 import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
49 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaRelationshipType;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
52 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates;
53 import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
54 import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter;
55 import org.springframework.stereotype.Component;
56
57 /**
58  * This class provides the create, read and delete actions on Commissioning of Control Loop concepts in the database to
59  * the callers.
60  */
61 @Component
62 public class CommissioningProvider {
63     public static final String CONTROL_LOOP_NODE_TYPE = "org.onap.policy.clamp.controlloop.ControlLoop";
64     private static final String INSTANCE_TEXT = "_Instance";
65
66     private final ServiceTemplateProvider serviceTemplateProvider;
67     private final ControlLoopProvider clProvider;
68     private final ObjectMapper mapper = new ObjectMapper();
69     private final ParticipantProvider participantProvider;
70     private final SupervisionHandler supervisionHandler;
71
72     private static final Object lockit = new Object();
73
74     /**
75      * Create a commissioning provider.
76      *
77      * @param serviceTemplateProvider the ServiceTemplate Provider
78      * @param clProvider the ControlLoop Provider
79      * @param supervisionHandler the Supervision Handler
80      * @param participantProvider the Participant Provider
81      */
82     public CommissioningProvider(ServiceTemplateProvider serviceTemplateProvider, ControlLoopProvider clProvider,
83             SupervisionHandler supervisionHandler, ParticipantProvider participantProvider) {
84         this.serviceTemplateProvider = serviceTemplateProvider;
85         this.clProvider = clProvider;
86         this.supervisionHandler = supervisionHandler;
87         this.participantProvider = participantProvider;
88         mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
89     }
90
91     /**
92      * Create control loops from a service template.
93      *
94      * @param serviceTemplate the service template
95      * @return the result of the commissioning operation
96      * @throws PfModelException on creation errors
97      */
98     public CommissioningResponse createControlLoopDefinitions(ToscaServiceTemplate serviceTemplate)
99             throws PfModelException {
100
101         if (verifyIfInstancePropertiesExists()) {
102             throw new PfModelException(Status.BAD_REQUEST, "Delete instances, to commission control loop definitions");
103         }
104
105         synchronized (lockit) {
106             serviceTemplateProvider.createServiceTemplate(serviceTemplate);
107             List<Participant> participantList = participantProvider.getParticipants(null, null);
108             if (!participantList.isEmpty()) {
109                 supervisionHandler.handleSendCommissionMessage(serviceTemplate.getName(), serviceTemplate.getVersion());
110             }
111         }
112
113         var response = new CommissioningResponse();
114         // @formatter:off
115         response.setAffectedControlLoopDefinitions(serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
116                 .values()
117                 .stream()
118                 .map(template -> template.getKey().asIdentifier())
119                 .collect(Collectors.toList()));
120         // @formatter:on
121
122         return response;
123     }
124
125     /**
126      * Delete the control loop definition with the given name and version.
127      *
128      * @param name the name of the control loop definition to delete
129      * @param version the version of the control loop to delete
130      * @return the result of the deletion
131      * @throws PfModelException on deletion errors
132      */
133     public CommissioningResponse deleteControlLoopDefinition(String name, String version) throws PfModelException {
134
135         if (verifyIfInstancePropertiesExists()) {
136             throw new PfModelException(Status.BAD_REQUEST, "Delete instances, to commission control loop definitions");
137         }
138
139         synchronized (lockit) {
140             List<Participant> participantList = participantProvider.getParticipants(null, null);
141             if (!participantList.isEmpty()) {
142                 supervisionHandler.handleSendDeCommissionMessage();
143             }
144             serviceTemplateProvider.deleteServiceTemplate(name, version);
145         }
146
147         var response = new CommissioningResponse();
148         response.setAffectedControlLoopDefinitions(
149                 Collections.singletonList(new ToscaConceptIdentifier(name, version)));
150
151         return response;
152     }
153
154     /**
155      * Get control loop node templates.
156      *
157      * @param clName the name of the control loop, null for all
158      * @param clVersion the version of the control loop, null for all
159      * @return list of control loop node templates
160      * @throws PfModelException on errors getting control loop definitions
161      */
162     public List<ToscaNodeTemplate> getControlLoopDefinitions(String clName, String clVersion) throws PfModelException {
163
164         // @formatter:off
165         ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
166                 .<ToscaNodeTemplate>builder()
167                 .name(clName)
168                 .version(clVersion)
169                 .type(CONTROL_LOOP_NODE_TYPE)
170                 .build();
171         // @formatter:on
172
173         return clProvider.getFilteredNodeTemplates(nodeTemplateFilter);
174     }
175
176     /**
177      * Get the control loop elements from a control loop node template.
178      *
179      * @param controlLoopNodeTemplate the control loop node template
180      * @return a list of the control loop element node templates in a control loop node template
181      * @throws PfModelException on errors get control loop element node templates
182      */
183     public List<ToscaNodeTemplate> getControlLoopElementDefinitions(ToscaNodeTemplate controlLoopNodeTemplate)
184             throws PfModelException {
185         if (!CONTROL_LOOP_NODE_TYPE.equals(controlLoopNodeTemplate.getType())) {
186             return Collections.emptyList();
187         }
188
189         if (MapUtils.isEmpty(controlLoopNodeTemplate.getProperties())) {
190             return Collections.emptyList();
191         }
192
193         @SuppressWarnings("unchecked")
194         List<Map<String, String>> controlLoopElements =
195                 (List<Map<String, String>>) controlLoopNodeTemplate.getProperties().get("elements");
196
197         if (CollectionUtils.isEmpty(controlLoopElements)) {
198             return Collections.emptyList();
199         }
200
201         List<ToscaNodeTemplate> controlLoopElementList = new ArrayList<>();
202         // @formatter:off
203         controlLoopElementList.addAll(
204                 controlLoopElements
205                         .stream()
206                         .map(elementMap -> clProvider.getNodeTemplates(elementMap.get("name"),
207                                 elementMap.get("version")))
208                         .flatMap(List::stream)
209                         .collect(Collectors.toList())
210         );
211         // @formatter:on
212
213         return controlLoopElementList;
214     }
215
216     /**
217      * Get node templates with common properties added.
218      *
219      * @param common boolean indicating common or instance properties to be used
220      * @param name the name of the definition to use, null for all definitions
221      * @param version the version of the definition to use, null for all definitions
222      * @return the nodes templates with common or instance properties
223      * @throws PfModelException on errors getting common or instance properties from node_templates
224      */
225     public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(boolean common, String name,
226             String version) throws PfModelException {
227
228         if (common && verifyIfInstancePropertiesExists()) {
229             throw new PfModelException(Status.BAD_REQUEST,
230                     "Cannot create or edit common properties, delete all the instantiations first");
231         }
232
233         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
234         var commonOrInstanceNodeTypeProps =
235                 serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
236
237         var serviceTemplates = new ToscaServiceTemplates();
238         serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList));
239
240         return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
241                 serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
242                 commonOrInstanceNodeTypeProps);
243     }
244
245     /**
246      * Get the requested control loop definitions.
247      *
248      * @param name the name of the definition to get, null for all definitions
249      * @param version the version of the definition to get, null for all definitions
250      * @return the control loop definitions
251      * @throws PfModelException on errors getting control loop definitions
252      */
253     public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
254         return serviceTemplateProvider.getToscaServiceTemplate(name, version);
255     }
256
257     /**
258      * Get the tosca service template with only required sections.
259      *
260      * @param name the name of the template to get, null for all definitions
261      * @param version the version of the template to get, null for all definitions
262      * @return the tosca service template
263      * @throws PfModelException on errors getting tosca service template
264      */
265     public String getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
266
267         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
268
269         ToscaServiceTemplate fullTemplate = filterToscaNodeTemplateInstance(serviceTemplateList).get(0);
270
271         var template = new HashMap<String, Object>();
272         template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
273         template.put("data_types", fullTemplate.getDataTypes());
274         template.put("policy_types", fullTemplate.getPolicyTypes());
275         template.put("node_types", fullTemplate.getNodeTypes());
276         template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
277
278         try {
279             return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(template);
280
281         } catch (JsonProcessingException e) {
282             throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
283         }
284     }
285
286     /**
287      * Get the requested json schema.
288      *
289      * @param section section of the tosca service template to get schema for
290      * @return the specified tosca service template or section Json Schema
291      * @throws PfModelException on errors with retrieving the classes
292      */
293     public String getToscaServiceTemplateSchema(String section) throws PfModelException {
294         var visitor = new SchemaFactoryWrapper();
295
296         try {
297             switch (section) {
298                 case "data_types":
299                     mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaDataType.class), visitor);
300                     break;
301                 case "capability_types":
302                     mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaCapabilityType.class), visitor);
303                     break;
304                 case "node_types":
305                     mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaNodeType.class), visitor);
306                     break;
307                 case "relationship_types":
308                     mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaRelationshipType.class), visitor);
309                     break;
310                 case "policy_types":
311                     mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaPolicyType.class), visitor);
312                     break;
313                 case "topology_template":
314                     mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaTopologyTemplate.class), visitor);
315                     break;
316                 case "node_templates":
317                     mapper.acceptJsonFormatVisitor(
318                             mapper.getTypeFactory().constructCollectionType(List.class, ToscaNodeTemplate.class),
319                             visitor);
320                     break;
321                 default:
322                     mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaServiceTemplate.class), visitor);
323             }
324
325             var jsonSchema = visitor.finalSchema();
326             return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
327         } catch (JsonProcessingException e) {
328             throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
329         }
330     }
331
332     private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(List<ToscaServiceTemplate> serviceTemplates) {
333
334         List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
335
336         serviceTemplates.stream().forEach(serviceTemplate -> {
337
338             Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
339
340             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
341                 if (!nodeTemplate.getName().contains(INSTANCE_TEXT)) {
342                     toscaNodeTemplates.put(key, nodeTemplate);
343                 }
344             });
345
346             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
347             serviceTemplate.getToscaTopologyTemplate().setNodeTemplates(toscaNodeTemplates);
348
349             toscaServiceTemplates.add(serviceTemplate);
350         });
351
352         return toscaServiceTemplates;
353     }
354
355     /**
356      * Validates to see if there is any instance properties saved.
357      *
358      * @return true if exists instance properties
359      */
360     private boolean verifyIfInstancePropertiesExists() {
361         return clProvider.getNodeTemplates(null, null).stream()
362                 .anyMatch(nodeTemplate -> nodeTemplate.getKey().getName().contains(INSTANCE_TEXT));
363
364     }
365 }