2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021-2022 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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.clamp.acm.runtime.commissioning;
24 import com.fasterxml.jackson.core.JsonProcessingException;
25 import com.fasterxml.jackson.databind.JavaType;
26 import com.fasterxml.jackson.databind.ObjectMapper;
27 import com.fasterxml.jackson.databind.PropertyNamingStrategies;
28 import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
34 import java.util.stream.Collectors;
35 import javax.ws.rs.core.Response.Status;
36 import org.apache.commons.collections4.CollectionUtils;
37 import org.apache.commons.collections4.MapUtils;
38 import org.apache.commons.lang3.StringUtils;
39 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
40 import org.onap.policy.clamp.models.acm.concepts.Participant;
41 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
42 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
43 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
44 import org.onap.policy.clamp.models.acm.persistence.provider.ServiceTemplateProvider;
45 import org.onap.policy.models.base.PfModelException;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
49 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
52 import org.onap.policy.models.tosca.authorative.concepts.ToscaRelationshipType;
53 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
54 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates;
55 import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
56 import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter;
57 import org.springframework.boot.context.event.ApplicationReadyEvent;
58 import org.springframework.context.event.EventListener;
59 import org.springframework.stereotype.Service;
60 import org.springframework.transaction.annotation.Transactional;
63 * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
64 * database to the callers.
68 public class CommissioningProvider {
69 public static final String AUTOMATION_COMPOSITION_NODE_TYPE = "org.onap.policy.clamp.acm.AutomationComposition";
70 private static final String HYPHEN = "-";
72 private final ServiceTemplateProvider serviceTemplateProvider;
73 private final AutomationCompositionProvider acProvider;
74 private final ObjectMapper mapper = new ObjectMapper();
75 private final ParticipantProvider participantProvider;
76 private final SupervisionHandler supervisionHandler;
78 private static final Map<String, JavaType> sections = new HashMap<>();
81 * Create a commissioning provider.
83 * @param serviceTemplateProvider the ServiceTemplate Provider
84 * @param acProvider the AutomationComposition Provider
85 * @param supervisionHandler the Supervision Handler
86 * @param participantProvider the Participant Provider
88 public CommissioningProvider(ServiceTemplateProvider serviceTemplateProvider,
89 AutomationCompositionProvider acProvider, SupervisionHandler supervisionHandler,
90 ParticipantProvider participantProvider) {
91 this.serviceTemplateProvider = serviceTemplateProvider;
92 this.acProvider = acProvider;
93 this.supervisionHandler = supervisionHandler;
94 this.participantProvider = participantProvider;
95 mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
99 * Event listener initiilize function called at ApplicationReadyEvent.
102 @EventListener(ApplicationReadyEvent.class)
103 public void initialize() {
104 sections.put("data_types", mapper.constructType(ToscaDataType.class));
105 sections.put("capability_types", mapper.constructType(ToscaCapabilityType.class));
106 sections.put("node_types", mapper.constructType(ToscaNodeType.class));
107 sections.put("relationship_types", mapper.constructType(ToscaRelationshipType.class));
108 sections.put("policy_types", mapper.constructType(ToscaPolicyType.class));
109 sections.put("topology_template", mapper.constructType(ToscaTopologyTemplate.class));
110 sections.put("node_templates",
111 mapper.getTypeFactory().constructCollectionType(List.class, ToscaNodeTemplate.class));
112 sections.put("all", mapper.constructType(ToscaServiceTemplate.class));
116 * Create automation compositions from a service template.
118 * @param serviceTemplate the service template
119 * @return the result of the commissioning operation
120 * @throws PfModelException on creation errors
122 public CommissioningResponse createAutomationCompositionDefinitions(ToscaServiceTemplate serviceTemplate)
123 throws PfModelException {
125 if (verifyIfInstancePropertiesExists()) {
126 throw new PfModelException(Status.BAD_REQUEST,
127 "Delete instances, to commission automation composition definitions");
129 serviceTemplate = serviceTemplateProvider.createServiceTemplate(serviceTemplate);
130 List<Participant> participantList = participantProvider.getParticipants();
131 if (!participantList.isEmpty()) {
132 supervisionHandler.handleSendCommissionMessage(serviceTemplate.getName(), serviceTemplate.getVersion());
134 var response = new CommissioningResponse();
136 response.setAffectedAutomationCompositionDefinitions(
137 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
140 .map(template -> template.getKey().asIdentifier())
141 .collect(Collectors.toList()));
148 * Delete the automation composition definition with the given name and version.
150 * @param name the name of the automation composition definition to delete
151 * @param version the version of the automation composition to delete
152 * @return the result of the deletion
153 * @throws PfModelException on deletion errors
155 public CommissioningResponse deleteAutomationCompositionDefinition(String name, String version)
156 throws PfModelException {
158 if (verifyIfInstancePropertiesExists()) {
159 throw new PfModelException(Status.BAD_REQUEST,
160 "Delete instances, to commission automation composition definitions");
162 List<Participant> participantList = participantProvider.getParticipants();
163 if (!participantList.isEmpty()) {
164 supervisionHandler.handleSendDeCommissionMessage();
166 serviceTemplateProvider.deleteServiceTemplate(name, version);
167 var response = new CommissioningResponse();
168 response.setAffectedAutomationCompositionDefinitions(List.of(new ToscaConceptIdentifier(name, version)));
174 * Get automation composition node templates.
176 * @param acName the name of the automation composition, null for all
177 * @param acVersion the version of the automation composition, null for all
178 * @return list of automation composition node templates
179 * @throws PfModelException on errors getting automation composition definitions
181 @Transactional(readOnly = true)
182 public List<ToscaNodeTemplate> getAutomationCompositionDefinitions(String acName, String acVersion)
183 throws PfModelException {
186 ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
187 .<ToscaNodeTemplate>builder()
190 .type(AUTOMATION_COMPOSITION_NODE_TYPE)
194 return acProvider.getFilteredNodeTemplates(nodeTemplateFilter);
198 * Get the automation composition elements from a automation composition node template.
200 * @param automationCompositionNodeTemplate the automation composition node template
201 * @return a list of the automation composition element node templates in a automation composition node template
202 * @throws PfModelException on errors get automation composition element node templates
204 @Transactional(readOnly = true)
205 public List<ToscaNodeTemplate> getAutomationCompositionElementDefinitions(
206 ToscaNodeTemplate automationCompositionNodeTemplate) throws PfModelException {
207 if (!AUTOMATION_COMPOSITION_NODE_TYPE.equals(automationCompositionNodeTemplate.getType())) {
208 return Collections.emptyList();
211 if (MapUtils.isEmpty(automationCompositionNodeTemplate.getProperties())) {
212 return Collections.emptyList();
215 @SuppressWarnings("unchecked")
216 List<Map<String, String>> automationCompositionElements =
217 (List<Map<String, String>>) automationCompositionNodeTemplate.getProperties().get("elements");
219 if (CollectionUtils.isEmpty(automationCompositionElements)) {
220 return Collections.emptyList();
223 List<ToscaNodeTemplate> automationCompositionElementList = new ArrayList<>();
225 automationCompositionElementList.addAll(
226 automationCompositionElements
228 .map(elementMap -> acProvider.getNodeTemplates(elementMap.get("name"),
229 elementMap.get("version")))
230 .flatMap(List::stream)
231 .collect(Collectors.toList())
235 return automationCompositionElementList;
239 * Get node templates with common properties added.
241 * @param name the name of the definition to use, null for all definitions
242 * @param version the version of the definition to use, null for all definitions
243 * @param instanceName automation composition name
244 * @param common boolean indicating common or instance properties to be used
245 * @return the nodes templates with common or instance properties
246 * @throws PfModelException on errors getting common or instance properties from node_templates
248 @Transactional(readOnly = true)
249 public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(
250 final String name, final String version, final String instanceName, final boolean common)
251 throws PfModelException {
253 if (common && verifyIfInstancePropertiesExists()) {
254 throw new PfModelException(Status.BAD_REQUEST,
255 "Cannot create or edit common properties, delete all the instantiations first");
258 var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
260 if (serviceTemplateList.isEmpty()) {
261 throw new PfModelException(Status.BAD_REQUEST,
262 "Tosca service template has to be commissioned before saving instance properties");
265 var commonOrInstanceNodeTypeProps =
266 serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
268 var serviceTemplates = new ToscaServiceTemplates();
269 serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList, instanceName));
271 return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
272 serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
273 commonOrInstanceNodeTypeProps);
277 * Get the requested automation composition definitions.
279 * @param name the name of the definition to get, null for all definitions
280 * @param version the version of the definition to get, null for all definitions
281 * @return the automation composition definitions
282 * @throws PfModelException on errors getting automation composition definitions
284 @Transactional(readOnly = true)
285 public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
286 return serviceTemplateProvider.getToscaServiceTemplate(name, version);
290 * Get All the requested automation composition definitions.
292 * @return the automation composition definitions
293 * @throws PfModelException on errors getting automation composition definitions
295 @Transactional(readOnly = true)
296 public List<ToscaServiceTemplate> getAllToscaServiceTemplate() throws PfModelException {
297 return serviceTemplateProvider.getAllServiceTemplates();
301 * Get the tosca service template with only required sections.
303 * @param name the name of the template to get, null for all definitions
304 * @param version the version of the template to get, null for all definitions
305 * @param instanceName automation composition name
306 * @return the tosca service template
307 * @throws PfModelException on errors getting tosca service template
309 @Transactional(readOnly = true)
310 public String getToscaServiceTemplateReduced(
311 final String name, final String version, final String instanceName)
312 throws PfModelException {
314 var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
316 List<ToscaServiceTemplate> filteredServiceTemplateList =
317 filterToscaNodeTemplateInstance(serviceTemplateList, instanceName);
319 if (filteredServiceTemplateList.isEmpty()) {
320 throw new PfModelException(Status.BAD_REQUEST, "Invalid Service Template");
323 ToscaServiceTemplate fullTemplate = filteredServiceTemplateList.get(0);
325 var template = new HashMap<String, Object>();
326 template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
327 template.put("data_types", fullTemplate.getDataTypes());
328 template.put("policy_types", fullTemplate.getPolicyTypes());
329 template.put("node_types", fullTemplate.getNodeTypes());
330 template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
333 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(template);
335 } catch (JsonProcessingException e) {
336 throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
341 * Get the requested json schema.
343 * @param section section of the tosca service template to get schema for
344 * @return the specified tosca service template or section Json Schema
345 * @throws PfModelException on errors with retrieving the classes
347 public String getToscaServiceTemplateSchema(String section) throws PfModelException {
348 var visitor = new SchemaFactoryWrapper();
349 var sectionMapper = sections.getOrDefault(section, sections.get("all"));
351 mapper.acceptJsonFormatVisitor(sectionMapper, visitor);
352 var jsonSchema = visitor.finalSchema();
353 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
354 } catch (JsonProcessingException e) {
355 throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
360 * Filters service templates if is not an instantiation type.
362 * @param serviceTemplates tosca service template
363 * @param instanceName automation composition name
364 * @return List of tosca service templates
366 private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(
367 List<ToscaServiceTemplate> serviceTemplates, String instanceName) {
369 List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
371 serviceTemplates.forEach(serviceTemplate -> {
373 Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
375 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
376 if (StringUtils.isNotEmpty(instanceName) && nodeTemplate.getName().contains(instanceName)) {
377 toscaNodeTemplates.put(key, nodeTemplate);
378 } else if (!nodeTemplate.getName().contains(HYPHEN)) {
379 toscaNodeTemplates.put(key, nodeTemplate);
383 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
384 serviceTemplate.getToscaTopologyTemplate().setNodeTemplates(toscaNodeTemplates);
386 toscaServiceTemplates.add(serviceTemplate);
389 return toscaServiceTemplates;
393 * Validates to see if there is any instance properties saved.
395 * @return true if exists instance properties
397 private boolean verifyIfInstancePropertiesExists() {
398 return acProvider.getAllNodeTemplates().stream()
399 .anyMatch(nodeTemplate -> nodeTemplate.getKey().getName().contains(HYPHEN));