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.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;
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.stereotype.Service;
56 import org.springframework.transaction.annotation.Transactional;
59 * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
60 * database to the callers.
64 public class CommissioningProvider {
65 public static final String AUTOMATION_COMPOSITION_NODE_TYPE = "org.onap.policy.clamp.acm.AutomationComposition";
66 private static final String INSTANCE_TEXT = "_Instance";
68 private final ServiceTemplateProvider serviceTemplateProvider;
69 private final AutomationCompositionProvider acProvider;
70 private final ObjectMapper mapper = new ObjectMapper();
71 private final ParticipantProvider participantProvider;
72 private final SupervisionHandler supervisionHandler;
75 * Create a commissioning provider.
77 * @param serviceTemplateProvider the ServiceTemplate Provider
78 * @param acProvider the AutomationComposition Provider
79 * @param supervisionHandler the Supervision Handler
80 * @param participantProvider the Participant Provider
82 public CommissioningProvider(ServiceTemplateProvider serviceTemplateProvider,
83 AutomationCompositionProvider acProvider, SupervisionHandler supervisionHandler,
84 ParticipantProvider participantProvider) {
85 this.serviceTemplateProvider = serviceTemplateProvider;
86 this.acProvider = acProvider;
87 this.supervisionHandler = supervisionHandler;
88 this.participantProvider = participantProvider;
89 mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
93 * Create automation compositions from a service template.
95 * @param serviceTemplate the service template
96 * @return the result of the commissioning operation
97 * @throws PfModelException on creation errors
99 public CommissioningResponse createAutomationCompositionDefinitions(ToscaServiceTemplate serviceTemplate)
100 throws PfModelException {
102 if (verifyIfInstancePropertiesExists()) {
103 throw new PfModelException(Status.BAD_REQUEST,
104 "Delete instances, to commission automation composition definitions");
106 serviceTemplate = serviceTemplateProvider.createServiceTemplate(serviceTemplate);
107 List<Participant> participantList = participantProvider.getParticipants();
108 if (!participantList.isEmpty()) {
109 supervisionHandler.handleSendCommissionMessage(serviceTemplate.getName(), serviceTemplate.getVersion());
111 var response = new CommissioningResponse();
113 response.setAffectedAutomationCompositionDefinitions(
114 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
117 .map(template -> template.getKey().asIdentifier())
118 .collect(Collectors.toList()));
125 * Delete the automation composition definition with the given name and version.
127 * @param name the name of the automation composition definition to delete
128 * @param version the version of the automation composition to delete
129 * @return the result of the deletion
130 * @throws PfModelException on deletion errors
132 public CommissioningResponse deleteAutomationCompositionDefinition(String name, String version)
133 throws PfModelException {
135 if (verifyIfInstancePropertiesExists()) {
136 throw new PfModelException(Status.BAD_REQUEST,
137 "Delete instances, to commission automation composition definitions");
139 List<Participant> participantList = participantProvider.getParticipants();
140 if (!participantList.isEmpty()) {
141 supervisionHandler.handleSendDeCommissionMessage();
143 serviceTemplateProvider.deleteServiceTemplate(name, version);
144 var response = new CommissioningResponse();
145 response.setAffectedAutomationCompositionDefinitions(List.of(new ToscaConceptIdentifier(name, version)));
151 * Get automation composition node templates.
153 * @param acName the name of the automation composition, null for all
154 * @param acVersion the version of the automation composition, null for all
155 * @return list of automation composition node templates
156 * @throws PfModelException on errors getting automation composition definitions
158 @Transactional(readOnly = true)
159 public List<ToscaNodeTemplate> getAutomationCompositionDefinitions(String acName, String acVersion)
160 throws PfModelException {
163 ToscaTypedEntityFilter<ToscaNodeTemplate> nodeTemplateFilter = ToscaTypedEntityFilter
164 .<ToscaNodeTemplate>builder()
167 .type(AUTOMATION_COMPOSITION_NODE_TYPE)
171 return acProvider.getFilteredNodeTemplates(nodeTemplateFilter);
175 * Get the automation composition elements from a automation composition node template.
177 * @param automationCompositionNodeTemplate the automation composition node template
178 * @return a list of the automation composition element node templates in a automation composition node template
179 * @throws PfModelException on errors get automation composition element node templates
181 @Transactional(readOnly = true)
182 public List<ToscaNodeTemplate> getAutomationCompositionElementDefinitions(
183 ToscaNodeTemplate automationCompositionNodeTemplate) throws PfModelException {
184 if (!AUTOMATION_COMPOSITION_NODE_TYPE.equals(automationCompositionNodeTemplate.getType())) {
185 return Collections.emptyList();
188 if (MapUtils.isEmpty(automationCompositionNodeTemplate.getProperties())) {
189 return Collections.emptyList();
192 @SuppressWarnings("unchecked")
193 List<Map<String, String>> automationCompositionElements =
194 (List<Map<String, String>>) automationCompositionNodeTemplate.getProperties().get("elements");
196 if (CollectionUtils.isEmpty(automationCompositionElements)) {
197 return Collections.emptyList();
200 List<ToscaNodeTemplate> automationCompositionElementList = new ArrayList<>();
202 automationCompositionElementList.addAll(
203 automationCompositionElements
205 .map(elementMap -> acProvider.getNodeTemplates(elementMap.get("name"),
206 elementMap.get("version")))
207 .flatMap(List::stream)
208 .collect(Collectors.toList())
212 return automationCompositionElementList;
216 * Get node templates with common properties added.
218 * @param common boolean indicating common or instance properties to be used
219 * @param name the name of the definition to use, null for all definitions
220 * @param version the version of the definition to use, null for all definitions
221 * @return the nodes templates with common or instance properties
222 * @throws PfModelException on errors getting common or instance properties from node_templates
224 @Transactional(readOnly = true)
225 public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(boolean common, String name,
226 String version) throws PfModelException {
228 if (common && verifyIfInstancePropertiesExists()) {
229 throw new PfModelException(Status.BAD_REQUEST,
230 "Cannot create or edit common properties, delete all the instantiations first");
233 var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
234 var commonOrInstanceNodeTypeProps =
235 serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
237 var serviceTemplates = new ToscaServiceTemplates();
238 serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList));
240 return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
241 serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
242 commonOrInstanceNodeTypeProps);
246 * Get the requested automation composition definitions.
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 automation composition definitions
251 * @throws PfModelException on errors getting automation composition definitions
253 @Transactional(readOnly = true)
254 public ToscaServiceTemplate getToscaServiceTemplate(String name, String version) throws PfModelException {
255 return serviceTemplateProvider.getToscaServiceTemplate(name, version);
259 * Get All the requested automation composition definitions.
261 * @return the automation composition definitions
262 * @throws PfModelException on errors getting automation composition definitions
264 @Transactional(readOnly = true)
265 public List<ToscaServiceTemplate> getAllToscaServiceTemplate() throws PfModelException {
266 return serviceTemplateProvider.getAllServiceTemplates();
270 * Get the tosca service template with only required sections.
272 * @param name the name of the template to get, null for all definitions
273 * @param version the version of the template to get, null for all definitions
274 * @return the tosca service template
275 * @throws PfModelException on errors getting tosca service template
277 @Transactional(readOnly = true)
278 public String getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
279 var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
281 List<ToscaServiceTemplate> filteredServiceTemplateList = filterToscaNodeTemplateInstance(serviceTemplateList);
283 if (filteredServiceTemplateList.isEmpty()) {
284 throw new PfModelException(Status.BAD_REQUEST, "Invalid Service Template");
287 ToscaServiceTemplate fullTemplate = filteredServiceTemplateList.get(0);
289 var template = new HashMap<String, Object>();
290 template.put("tosca_definitions_version", fullTemplate.getToscaDefinitionsVersion());
291 template.put("data_types", fullTemplate.getDataTypes());
292 template.put("policy_types", fullTemplate.getPolicyTypes());
293 template.put("node_types", fullTemplate.getNodeTypes());
294 template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
297 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(template);
299 } catch (JsonProcessingException e) {
300 throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
305 * Get the requested json schema.
307 * @param section section of the tosca service template to get schema for
308 * @return the specified tosca service template or section Json Schema
309 * @throws PfModelException on errors with retrieving the classes
311 @Transactional(readOnly = true)
312 public String getToscaServiceTemplateSchema(String section) throws PfModelException {
313 var visitor = new SchemaFactoryWrapper();
318 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaDataType.class), visitor);
320 case "capability_types":
321 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaCapabilityType.class), visitor);
324 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaNodeType.class), visitor);
326 case "relationship_types":
327 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaRelationshipType.class), visitor);
330 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaPolicyType.class), visitor);
332 case "topology_template":
333 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaTopologyTemplate.class), visitor);
335 case "node_templates":
336 mapper.acceptJsonFormatVisitor(
337 mapper.getTypeFactory().constructCollectionType(List.class, ToscaNodeTemplate.class), visitor);
340 mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaServiceTemplate.class), visitor);
343 var jsonSchema = visitor.finalSchema();
344 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
345 } catch (JsonProcessingException e) {
346 throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
350 private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(List<ToscaServiceTemplate> serviceTemplates) {
352 List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
354 serviceTemplates.stream().forEach(serviceTemplate -> {
356 Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
358 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
359 if (!nodeTemplate.getName().contains(INSTANCE_TEXT)) {
360 toscaNodeTemplates.put(key, nodeTemplate);
364 serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
365 serviceTemplate.getToscaTopologyTemplate().setNodeTemplates(toscaNodeTemplates);
367 toscaServiceTemplates.add(serviceTemplate);
370 return toscaServiceTemplates;
374 * Validates to see if there is any instance properties saved.
376 * @return true if exists instance properties
378 private boolean verifyIfInstancePropertiesExists() {
379 return acProvider.getAllNodeTemplates().stream()
380 .anyMatch(nodeTemplate -> nodeTemplate.getKey().getName().contains(INSTANCE_TEXT));