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
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.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
39 import org.onap.policy.clamp.models.acm.concepts.Participant;
40 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
41 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
42 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
43 import org.onap.policy.clamp.models.acm.persistence.provider.ServiceTemplateProvider;
44 import org.onap.policy.models.base.PfModelException;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
49 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
50 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaRelationshipType;
52 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
53 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates;
54 import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
55 import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter;
56 import org.springframework.boot.context.event.ApplicationReadyEvent;
57 import org.springframework.context.event.EventListener;
58 import org.springframework.stereotype.Service;
59 import org.springframework.transaction.annotation.Transactional;
62 * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
63 * database to the callers.
67 public class CommissioningProvider {
68 public static final String AUTOMATION_COMPOSITION_NODE_TYPE = "org.onap.policy.clamp.acm.AutomationComposition";
69 private static final String HYPHEN = "-";
71 private final ServiceTemplateProvider serviceTemplateProvider;
72 private final AutomationCompositionProvider acProvider;
73 private final ObjectMapper mapper = new ObjectMapper();
74 private final ParticipantProvider participantProvider;
75 private final SupervisionHandler supervisionHandler;
77 private static final Map<String, JavaType> sections = new HashMap<>();
80 * Create a commissioning provider.
82 * @param serviceTemplateProvider the ServiceTemplate Provider
83 * @param acProvider the AutomationComposition Provider
84 * @param supervisionHandler the Supervision Handler
85 * @param participantProvider the Participant Provider
87 public CommissioningProvider(ServiceTemplateProvider serviceTemplateProvider,
88 AutomationCompositionProvider acProvider, SupervisionHandler supervisionHandler,
89 ParticipantProvider participantProvider) {
90 this.serviceTemplateProvider = serviceTemplateProvider;
91 this.acProvider = acProvider;
92 this.supervisionHandler = supervisionHandler;
93 this.participantProvider = participantProvider;
94 mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
98 * Event listener initiilize function called at ApplicationReadyEvent.
101 @EventListener(ApplicationReadyEvent.class)
102 public void initialize() {
103 sections.put("data_types", mapper.constructType(ToscaDataType.class));
104 sections.put("capability_types", mapper.constructType(ToscaCapabilityType.class));
105 sections.put("node_types", mapper.constructType(ToscaNodeType.class));
106 sections.put("relationship_types", mapper.constructType(ToscaRelationshipType.class));
107 sections.put("policy_types", mapper.constructType(ToscaPolicyType.class));
108 sections.put("topology_template", mapper.constructType(ToscaTopologyTemplate.class));
109 sections.put("node_templates",
110 mapper.getTypeFactory().constructCollectionType(List.class, ToscaNodeTemplate.class));
111 sections.put("all", mapper.constructType(ToscaServiceTemplate.class));
115 * Create automation compositions from a service template.
117 * @param serviceTemplate the service template
118 * @return the result of the commissioning operation
119 * @throws PfModelException on creation errors
121 public CommissioningResponse createAutomationCompositionDefinitions(ToscaServiceTemplate serviceTemplate)
122 throws PfModelException {
124 if (verifyIfInstancePropertiesExists()) {
125 throw new PfModelException(Status.BAD_REQUEST,
126 "Delete instances, to commission automation composition definitions");
128 serviceTemplate = serviceTemplateProvider.createServiceTemplate(serviceTemplate);
129 List<Participant> participantList = participantProvider.getParticipants();
130 if (!participantList.isEmpty()) {
131 supervisionHandler.handleSendCommissionMessage(serviceTemplate.getName(), serviceTemplate.getVersion());
133 var response = new CommissioningResponse();
135 response.setAffectedAutomationCompositionDefinitions(
136 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
139 .map(template -> template.getKey().asIdentifier())
140 .collect(Collectors.toList()));
147 * Delete the automation composition definition with the given name and version.
149 * @param name the name of the automation composition definition to delete
150 * @param version the version of the automation composition to delete
151 * @return the result of the deletion
152 * @throws PfModelException on deletion errors
154 public CommissioningResponse deleteAutomationCompositionDefinition(String name, String version)
155 throws PfModelException {
157 if (verifyIfInstancePropertiesExists()) {
158 throw new PfModelException(Status.BAD_REQUEST,
159 "Delete instances, to commission automation composition definitions");
161 List<Participant> participantList = participantProvider.getParticipants();
162 if (!participantList.isEmpty()) {
163 supervisionHandler.handleSendDeCommissionMessage();
165 serviceTemplateProvider.deleteServiceTemplate(name, version);
166 var response = new CommissioningResponse();
167 response.setAffectedAutomationCompositionDefinitions(List.of(new ToscaConceptIdentifier(name, version)));
173 * Get automation composition node templates.
175 * @param acName the name of the automation composition, null for all
176 * @param acVersion the version of the automation composition, null for all
177 * @return list of automation composition node templates
178 * @throws PfModelException on errors getting automation composition definitions
180 @Transactional(readOnly = true)
181 public List<ToscaNodeTemplate> getAutomationCompositionDefinitions(String acName, String acVersion)
182 throws PfModelException {
185 ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
186 .<ToscaNodeTemplate>builder()
189 .type(AUTOMATION_COMPOSITION_NODE_TYPE)
193 return acProvider.getFilteredNodeTemplates(nodeTemplateFilter);
197 * Get the automation composition elements from a automation composition node template.
199 * @param automationCompositionNodeTemplate the automation composition node template
200 * @return a list of the automation composition element node templates in a automation composition node template
201 * @throws PfModelException on errors get automation composition element node templates
203 @Transactional(readOnly = true)
204 public List<ToscaNodeTemplate> getAutomationCompositionElementDefinitions(
205 ToscaNodeTemplate automationCompositionNodeTemplate) throws PfModelException {
206 if (!AUTOMATION_COMPOSITION_NODE_TYPE.equals(automationCompositionNodeTemplate.getType())) {
207 return Collections.emptyList();
210 if (MapUtils.isEmpty(automationCompositionNodeTemplate.getProperties())) {
211 return Collections.emptyList();
214 @SuppressWarnings("unchecked")
215 List<Map<String, String>> automationCompositionElements =
216 (List<Map<String, String>>) automationCompositionNodeTemplate.getProperties().get("elements");
218 if (CollectionUtils.isEmpty(automationCompositionElements)) {
219 return Collections.emptyList();
222 List<ToscaNodeTemplate> automationCompositionElementList = new ArrayList<>();
224 automationCompositionElementList.addAll(
225 automationCompositionElements
227 .map(elementMap -> acProvider.getNodeTemplates(elementMap.get("name"),
228 elementMap.get("version")))
229 .flatMap(List::stream)
230 .collect(Collectors.toList())
234 return automationCompositionElementList;
238 * Get node templates with common properties added.
240 * @param common boolean indicating common or instance properties to be used
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 * @return the nodes templates with common or instance properties
244 * @throws PfModelException on errors getting common or instance properties from node_templates
246 @Transactional(readOnly = true)
247 public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(boolean common, String name,
248 String version) throws PfModelException {
250 if (common && verifyIfInstancePropertiesExists()) {
251 throw new PfModelException(Status.BAD_REQUEST,
252 "Cannot create or edit common properties, delete all the instantiations first");
255 var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
256 var commonOrInstanceNodeTypeProps =
257 serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
259 var serviceTemplates = new ToscaServiceTemplates();
260 serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList));
262 return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
263 serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
264 commonOrInstanceNodeTypeProps);
268 * Get the requested automation composition definitions.
270 * @param name the name of the definition to get, null for all definitions
271 * @param version the version of the definition to get, null for all definitions
272 * @return the automation composition definitions
273 * @throws PfModelException on errors getting automation composition definitions
275 @Transactional(readOnly = true)
276 public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
277 return serviceTemplateProvider.getToscaServiceTemplate(name, version);
281 * Get All the requested automation composition definitions.
283 * @return the automation composition definitions
284 * @throws PfModelException on errors getting automation composition definitions
286 @Transactional(readOnly = true)
287 public List<ToscaServiceTemplate> getAllToscaServiceTemplate() throws PfModelException {
288 return serviceTemplateProvider.getAllServiceTemplates();
292 * Get the tosca service template with only required sections.
294 * @param name the name of the template to get, null for all definitions
295 * @param version the version of the template to get, null for all definitions
296 * @return the tosca service template
297 * @throws PfModelException on errors getting tosca service template
299 @Transactional(readOnly = true)
300 public String getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
301 var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
303 List<ToscaServiceTemplate> filteredServiceTemplateList = filterToscaNodeTemplateInstance(serviceTemplateList);
305 if (filteredServiceTemplateList.isEmpty()) {
306 throw new PfModelException(Status.BAD_REQUEST, "Invalid Service Template");
309 ToscaServiceTemplate fullTemplate = filteredServiceTemplateList.get(0);
311 var template = new HashMap<String, Object>();
312 template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
313 template.put("data_types", fullTemplate.getDataTypes());
314 template.put("policy_types", fullTemplate.getPolicyTypes());
315 template.put("node_types", fullTemplate.getNodeTypes());
316 template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
319 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(template);
321 } catch (JsonProcessingException e) {
322 throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
327 * Get the requested json schema.
329 * @param section section of the tosca service template to get schema for
330 * @return the specified tosca service template or section Json Schema
331 * @throws PfModelException on errors with retrieving the classes
333 public String getToscaServiceTemplateSchema(String section) throws PfModelException {
334 var visitor = new SchemaFactoryWrapper();
335 var sectionMapper = sections.getOrDefault(section, sections.get("all"));
337 mapper.acceptJsonFormatVisitor(sectionMapper, visitor);
338 var jsonSchema = visitor.finalSchema();
339 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
340 } catch (JsonProcessingException e) {
341 throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
345 private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(List<ToscaServiceTemplate> serviceTemplates) {
347 List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
349 serviceTemplates.stream().forEach(serviceTemplate -> {
351 Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
353 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
354 if (!nodeTemplate.getName().contains(HYPHEN)) {
355 toscaNodeTemplates.put(key, nodeTemplate);
359 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
360 serviceTemplate.getToscaTopologyTemplate().setNodeTemplates(toscaNodeTemplates);
362 toscaServiceTemplates.add(serviceTemplate);
365 return toscaServiceTemplates;
369 * Validates to see if there is any instance properties saved.
371 * @return true if exists instance properties
373 private boolean verifyIfInstancePropertiesExists() {
374 return acProvider.getAllNodeTemplates().stream()
375 .anyMatch(nodeTemplate -> nodeTemplate.getKey().getName().contains(HYPHEN));