e0027d36b8a2bae679d847ee62c993c3bfdb22c0
[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.acm.runtime.commissioning;
23
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import com.google.gson.JsonPrimitive;
27 import com.google.gson.JsonSerializer;
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.acm.runtime.supervision.SupervisionHandler;
38 import org.onap.policy.clamp.models.acm.concepts.Participant;
39 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
40 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
41 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
42 import org.onap.policy.clamp.models.acm.persistence.provider.ServiceTemplateProvider;
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.boot.context.event.ApplicationReadyEvent;
56 import org.springframework.context.event.EventListener;
57 import org.springframework.stereotype.Service;
58 import org.springframework.transaction.annotation.Transactional;
59
60 /**
61  * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
62  * database to the callers.
63  */
64 @Service
65 @Transactional
66 public class CommissioningProvider {
67     public static final String AUTOMATION_COMPOSITION_NODE_TYPE = "org.onap.policy.clamp.acm.AutomationComposition";
68     private static final String HYPHEN = "-";
69
70     private final ServiceTemplateProvider serviceTemplateProvider;
71     private final AutomationCompositionProvider acProvider;
72     private final ParticipantProvider participantProvider;
73     private final SupervisionHandler supervisionHandler;
74
75     private static final Map<String, String> sections = new HashMap<>();
76     private Gson gson = new Gson();
77
78     /**
79      * Create a commissioning provider.
80      *
81      * @param serviceTemplateProvider the ServiceTemplate Provider
82      * @param acProvider the AutomationComposition Provider
83      * @param supervisionHandler the Supervision Handler
84      * @param participantProvider the Participant Provider
85      */
86     public CommissioningProvider(ServiceTemplateProvider serviceTemplateProvider,
87         AutomationCompositionProvider acProvider, SupervisionHandler supervisionHandler,
88         ParticipantProvider participantProvider) {
89         this.serviceTemplateProvider = serviceTemplateProvider;
90         this.acProvider = acProvider;
91         this.supervisionHandler = supervisionHandler;
92         this.participantProvider = participantProvider;
93     }
94
95     /**
96      * Event listener initiilize function called at ApplicationReadyEvent.
97      *
98      */
99     @EventListener(ApplicationReadyEvent.class)
100     public void initialize() {
101         GsonBuilder builder = new GsonBuilder();
102         builder.registerTypeAdapter(ToscaServiceTemplate.class,
103                 (JsonSerializer<ToscaServiceTemplate>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
104         builder.registerTypeAdapter(ToscaDataType.class,
105                 (JsonSerializer<ToscaDataType>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
106         builder.registerTypeAdapter(ToscaCapabilityType.class,
107                 (JsonSerializer<ToscaCapabilityType>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
108         builder.registerTypeAdapter(ToscaNodeType.class,
109                 (JsonSerializer<ToscaNodeType>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
110         builder.registerTypeAdapter(ToscaRelationshipType.class,
111                 (JsonSerializer<ToscaRelationshipType>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
112         builder.registerTypeAdapter(ToscaPolicyType.class,
113                 (JsonSerializer<ToscaPolicyType>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
114         builder.registerTypeAdapter(ToscaTopologyTemplate.class,
115                 (JsonSerializer<ToscaTopologyTemplate>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
116         builder.registerTypeAdapter(ToscaNodeTemplate.class,
117                 (JsonSerializer<ToscaNodeTemplate>) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString()));
118         builder.setPrettyPrinting();
119         gson = builder.create();
120
121         sections.put("data_types", gson.toJson(new ToscaDataType()));
122         sections.put("capability_types", gson.toJson(new ToscaCapabilityType()));
123         sections.put("node_types", gson.toJson(new ToscaNodeType()));
124         sections.put("relationship_types", gson.toJson(new ToscaRelationshipType()));
125         sections.put("policy_types", gson.toJson(new ToscaPolicyType()));
126         sections.put("topology_template", gson.toJson(new ToscaTopologyTemplate()));
127         sections.put("node_templates", gson.toJson(new ToscaNodeTemplate()));
128         sections.put("all", gson.toJson(new ToscaServiceTemplate()));
129     }
130
131     /**
132      * Create automation compositions from a service template.
133      *
134      * @param serviceTemplate the service template
135      * @return the result of the commissioning operation
136      * @throws PfModelException on creation errors
137      */
138     public CommissioningResponse createAutomationCompositionDefinitions(ToscaServiceTemplate serviceTemplate)
139         throws PfModelException {
140
141         if (verifyIfInstancePropertiesExists()) {
142             throw new PfModelException(Status.BAD_REQUEST,
143                 "Delete instances, to commission automation composition definitions");
144         }
145         serviceTemplate = serviceTemplateProvider.createServiceTemplate(serviceTemplate);
146         List<Participant> participantList = participantProvider.getParticipants();
147         if (!participantList.isEmpty()) {
148             supervisionHandler.handleSendCommissionMessage(serviceTemplate.getName(), serviceTemplate.getVersion());
149         }
150         var response = new CommissioningResponse();
151         // @formatter:off
152         response.setAffectedAutomationCompositionDefinitions(
153             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
154                 .values()
155                 .stream()
156                 .map(template -> template.getKey().asIdentifier())
157                 .collect(Collectors.toList()));
158         // @formatter:on
159
160         return response;
161     }
162
163     /**
164      * Delete the automation composition definition with the given name and version.
165      *
166      * @param name the name of the automation composition definition to delete
167      * @param version the version of the automation composition to delete
168      * @return the result of the deletion
169      * @throws PfModelException on deletion errors
170      */
171     public CommissioningResponse deleteAutomationCompositionDefinition(String name, String version)
172         throws PfModelException {
173
174         if (verifyIfInstancePropertiesExists()) {
175             throw new PfModelException(Status.BAD_REQUEST,
176                 "Delete instances, to commission automation composition definitions");
177         }
178         List<Participant> participantList = participantProvider.getParticipants();
179         if (!participantList.isEmpty()) {
180             supervisionHandler.handleSendDeCommissionMessage();
181         }
182         serviceTemplateProvider.deleteServiceTemplate(name, version);
183         var response = new CommissioningResponse();
184         response.setAffectedAutomationCompositionDefinitions(List.of(new ToscaConceptIdentifier(name, version)));
185
186         return response;
187     }
188
189     /**
190      * Get automation composition node templates.
191      *
192      * @param acName the name of the automation composition, null for all
193      * @param acVersion the version of the automation composition, null for all
194      * @return list of automation composition node templates
195      * @throws PfModelException on errors getting automation composition definitions
196      */
197     @Transactional(readOnly = true)
198     public List<ToscaNodeTemplate> getAutomationCompositionDefinitions(String acName, String acVersion)
199         throws PfModelException {
200
201         // @formatter:off
202         ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
203                 .<ToscaNodeTemplate>builder()
204                 .name(acName)
205                 .version(acVersion)
206                 .type(AUTOMATION_COMPOSITION_NODE_TYPE)
207                 .build();
208         // @formatter:on
209
210         return acProvider.getFilteredNodeTemplates(nodeTemplateFilter);
211     }
212
213     /**
214      * Get the automation composition elements from a automation composition node template.
215      *
216      * @param automationCompositionNodeTemplate the automation composition node template
217      * @return a list of the automation composition element node templates in a automation composition node template
218      * @throws PfModelException on errors get automation composition element node templates
219      */
220     @Transactional(readOnly = true)
221     public List<ToscaNodeTemplate> getAutomationCompositionElementDefinitions(
222         ToscaNodeTemplate automationCompositionNodeTemplate) throws PfModelException {
223         if (!AUTOMATION_COMPOSITION_NODE_TYPE.equals(automationCompositionNodeTemplate.getType())) {
224             return Collections.emptyList();
225         }
226
227         if (MapUtils.isEmpty(automationCompositionNodeTemplate.getProperties())) {
228             return Collections.emptyList();
229         }
230
231         @SuppressWarnings("unchecked")
232         List<Map<String, String>> automationCompositionElements =
233             (List<Map<String, String>>) automationCompositionNodeTemplate.getProperties().get("elements");
234
235         if (CollectionUtils.isEmpty(automationCompositionElements)) {
236             return Collections.emptyList();
237         }
238
239         List<ToscaNodeTemplate> automationCompositionElementList = new ArrayList<>();
240         // @formatter:off
241         automationCompositionElementList.addAll(
242                 automationCompositionElements
243                         .stream()
244                         .map(elementMap -> acProvider.getNodeTemplates(elementMap.get("name"),
245                                 elementMap.get("version")))
246                         .flatMap(List::stream)
247                         .collect(Collectors.toList())
248         );
249         // @formatter:on
250
251         return automationCompositionElementList;
252     }
253
254     /**
255      * Get node templates with common properties added.
256      *
257      * @param common boolean indicating common or instance properties to be used
258      * @param name the name of the definition to use, null for all definitions
259      * @param version the version of the definition to use, null for all definitions
260      * @return the nodes templates with common or instance properties
261      * @throws PfModelException on errors getting common or instance properties from node_templates
262      */
263     @Transactional(readOnly = true)
264     public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(boolean common, String name,
265         String version) throws PfModelException {
266
267         if (common && verifyIfInstancePropertiesExists()) {
268             throw new PfModelException(Status.BAD_REQUEST,
269                 "Cannot create or edit common properties, delete all the instantiations first");
270         }
271
272         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
273         var commonOrInstanceNodeTypeProps =
274             serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
275
276         var serviceTemplates = new ToscaServiceTemplates();
277         serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList));
278
279         return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
280             serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
281             commonOrInstanceNodeTypeProps);
282     }
283
284     /**
285      * Get the requested automation composition definitions.
286      *
287      * @param name the name of the definition to get, null for all definitions
288      * @param version the version of the definition to get, null for all definitions
289      * @return the automation composition definitions
290      * @throws PfModelException on errors getting automation composition definitions
291      */
292     @Transactional(readOnly = true)
293     public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
294         return serviceTemplateProvider.getToscaServiceTemplate(name, version);
295     }
296
297     /**
298      * Get All the requested automation composition definitions.
299      *
300      * @return the automation composition definitions
301      * @throws PfModelException on errors getting automation composition definitions
302      */
303     @Transactional(readOnly = true)
304     public List<ToscaServiceTemplate> getAllToscaServiceTemplate() throws PfModelException {
305         return serviceTemplateProvider.getAllServiceTemplates();
306     }
307
308     /**
309      * Get the tosca service template with only required sections.
310      *
311      * @param name the name of the template to get, null for all definitions
312      * @param version the version of the template to get, null for all definitions
313      * @return the tosca service template
314      * @throws PfModelException on errors getting tosca service template
315      */
316     @Transactional(readOnly = true)
317     public String getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
318         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
319
320         List<ToscaServiceTemplate> filteredServiceTemplateList = filterToscaNodeTemplateInstance(serviceTemplateList);
321
322         if (filteredServiceTemplateList.isEmpty()) {
323             throw new PfModelException(Status.BAD_REQUEST, "Invalid Service Template");
324         }
325
326         ToscaServiceTemplate fullTemplate = filteredServiceTemplateList.get(0);
327
328         var template = new HashMap<String, Object>();
329         template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
330         template.put("data_types", fullTemplate.getDataTypes());
331         template.put("policy_types", fullTemplate.getPolicyTypes());
332         template.put("node_types", fullTemplate.getNodeTypes());
333         template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
334
335         return gson.toJson(template);
336     }
337
338     /**
339      * Get the requested json schema.
340      *
341      * @param section section of the tosca service template to get schema for
342      * @return the specified tosca service template or section Json Schema
343      * @throws PfModelException on errors with retrieving the classes
344      */
345     public String getToscaServiceTemplateSchema(String section) throws PfModelException {
346         return sections.getOrDefault(section, sections.get("all"));
347     }
348
349     private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(List<ToscaServiceTemplate> serviceTemplates) {
350
351         List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
352
353         serviceTemplates.stream().forEach(serviceTemplate -> {
354
355             Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
356
357             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
358                 if (!nodeTemplate.getName().contains(HYPHEN)) {
359                     toscaNodeTemplates.put(key, nodeTemplate);
360                 }
361             });
362
363             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
364             serviceTemplate.getToscaTopologyTemplate().setNodeTemplates(toscaNodeTemplates);
365
366             toscaServiceTemplates.add(serviceTemplate);
367         });
368
369         return toscaServiceTemplates;
370     }
371
372     /**
373      * Validates to see if there is any instance properties saved.
374      *
375      * @return true if exists instance properties
376      */
377     private boolean verifyIfInstancePropertiesExists() {
378         return acProvider.getAllNodeTemplates().stream()
379             .anyMatch(nodeTemplate -> nodeTemplate.getKey().getName().contains(HYPHEN));
380
381     }
382 }