2 * Copyright © 2016-2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.openecomp.sdc.tosca.services.impl;
19 import java.io.ByteArrayInputStream;
20 import java.io.IOException;
21 import java.lang.reflect.InvocationTargetException;
22 import java.nio.file.Path;
23 import java.nio.file.Paths;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
31 import java.util.Objects;
32 import java.util.Optional;
34 import java.util.zip.ZipEntry;
35 import java.util.zip.ZipInputStream;
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.sdc.tosca.datatypes.model.AttributeDefinition;
40 import org.onap.sdc.tosca.datatypes.model.CapabilityDefinition;
41 import org.onap.sdc.tosca.datatypes.model.CapabilityType;
42 import org.onap.sdc.tosca.datatypes.model.DataType;
43 import org.onap.sdc.tosca.datatypes.model.DefinitionOfDataType;
44 import org.onap.sdc.tosca.datatypes.model.Import;
45 import org.onap.sdc.tosca.datatypes.model.InterfaceDefinitionType;
46 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
47 import org.onap.sdc.tosca.datatypes.model.NodeType;
48 import org.onap.sdc.tosca.datatypes.model.ParameterDefinition;
49 import org.onap.sdc.tosca.datatypes.model.PropertyDefinition;
50 import org.onap.sdc.tosca.datatypes.model.PropertyType;
51 import org.onap.sdc.tosca.datatypes.model.RequirementAssignment;
52 import org.onap.sdc.tosca.datatypes.model.RequirementDefinition;
53 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
54 import org.onap.sdc.tosca.services.ToscaExtensionYamlUtil;
55 import org.onap.sdc.tosca.services.YamlUtil;
56 import org.openecomp.core.utilities.CommonMethods;
57 import org.openecomp.core.utilities.file.FileContentHandler;
58 import org.openecomp.core.utilities.file.FileUtils;
59 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
60 import org.openecomp.sdc.common.errors.CoreException;
61 import org.openecomp.sdc.common.errors.SdcRuntimeException;
62 import org.openecomp.sdc.common.zip.ZipUtils;
63 import org.openecomp.sdc.common.zip.exception.ZipSlipException;
64 import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes;
65 import org.openecomp.sdc.tosca.datatypes.ToscaFlatData;
66 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
67 import org.openecomp.sdc.tosca.errors.InvalidToscaFile;
68 import org.openecomp.sdc.tosca.errors.InvalidToscaMetaFile;
69 import org.openecomp.sdc.tosca.errors.ToscaElementTypeNotFoundErrorBuilder;
70 import org.openecomp.sdc.tosca.errors.ToscaEntryDefinitionWasNotFound;
71 import org.openecomp.sdc.tosca.errors.ToscaFileNotFoundErrorBuilder;
72 import org.openecomp.sdc.tosca.errors.ToscaInvalidEntryNotFoundErrorBuilder;
73 import org.openecomp.sdc.tosca.errors.ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder;
74 import org.openecomp.sdc.tosca.errors.ToscaInvalidSubstitutionServiceTemplateErrorBuilder;
75 import org.openecomp.sdc.tosca.services.DataModelUtil;
76 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
77 import org.openecomp.sdc.tosca.services.ToscaConstants;
78 import org.openecomp.sdc.tosca.services.ToscaUtil;
80 public class ToscaAnalyzerServiceImpl implements ToscaAnalyzerService {
82 private static final String GET_NODE_TYPE_METHOD_NAME = "getNode_types";
83 private static final String GET_DERIVED_FROM_METHOD_NAME = "getDerived_from";
84 private static final String GET_TYPE_METHOD_NAME = "getType";
85 private static final String GET_DATA_TYPE_METHOD_NAME = "getData_types";
86 private static final String GET_INTERFACE_TYPE_METHOD_NAME = "getNormalizeInterfaceTypes";
87 private static final String GET_CAPABILITY_TYPE_METHOD_NAME = "getCapability_types";
88 private static final String TOSCA_DOT = "tosca.";
89 private static final String DOT_ROOT = ".Root";
90 private static final String IMPORTS = "imports";
91 private static final String TOSCA_META_FILE = "TOSCA-Metadata/TOSCA.meta";
92 private static final String ENTRY_DEFINITIONS = "Entry-Definitions";
95 public List<Map<String, RequirementDefinition>> calculateExposedRequirements(
96 List<Map<String, RequirementDefinition>> nodeTypeRequirementsDefinitionList,
97 Map<String, RequirementAssignment> nodeTemplateRequirementsAssignment) {
99 if (nodeTypeRequirementsDefinitionList == null) {
100 return Collections.emptyList();
102 for (Map.Entry<String, RequirementAssignment> entry : nodeTemplateRequirementsAssignment.entrySet()) {
103 if (entry.getValue().getNode() != null) {
104 Optional<RequirementDefinition> requirementDefinition =
105 DataModelUtil.getRequirementDefinition(nodeTypeRequirementsDefinitionList, entry.getKey());
106 RequirementDefinition cloneRequirementDefinition;
107 if (requirementDefinition.isPresent()) {
108 cloneRequirementDefinition = requirementDefinition.get().clone();
109 updateRequirementDefinition(nodeTypeRequirementsDefinitionList, entry, cloneRequirementDefinition);
112 for (Map<String, RequirementDefinition> nodeTypeRequirementsMap : nodeTypeRequirementsDefinitionList) {
113 updateMinMaxOccurencesForNodeTypeRequirement(entry, nodeTypeRequirementsMap);
117 return nodeTypeRequirementsDefinitionList;
121 public ToscaServiceModel loadToscaCsarPackage(byte[] toscaCsarPackage) {
122 ToscaServiceModel toscaServiceModel = new ToscaServiceModel();
123 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
124 FileContentHandler artifactFiles = new FileContentHandler();
126 try (ZipInputStream inputZipStream = new ZipInputStream(new ByteArrayInputStream(toscaCsarPackage))) {
128 while ((zipEntry = inputZipStream.getNextEntry()) != null) {
129 ZipUtils.checkForZipSlipInRead(zipEntry);
130 byte[] fileContent = FileUtils.toByteArray(inputZipStream);
131 String currentEntryName = zipEntry.getName();
132 if (!isFile(currentEntryName)) {
135 if (isYamlFile(currentEntryName) && isToscaYamlFile(fileContent)) {
136 loadToscaYamlFile(toscaServiceModel, toscaExtensionYamlUtil, fileContent, currentEntryName);
137 } else if (currentEntryName.equals(TOSCA_META_FILE)) {
138 loadToscaMetaFile(toscaServiceModel, fileContent);
140 artifactFiles.addFile(currentEntryName, fileContent);
143 toscaServiceModel.setArtifactFiles(artifactFiles);
144 if (StringUtils.isEmpty(toscaServiceModel.getEntryDefinitionServiceTemplate())) {
145 handleToscaCsarWithoutToscaMetadata(toscaServiceModel);
148 } catch (IOException | ZipSlipException exc) {
149 throw new SdcRuntimeException(exc.getMessage(), exc);
151 return toscaServiceModel;
154 private void handleToscaCsarWithoutToscaMetadata(ToscaServiceModel toscaServiceModel) {
155 for (String fileName : toscaServiceModel.getServiceTemplates().keySet()) {
156 if (!fileName.contains("/")) {
157 if (StringUtils.isNotEmpty(toscaServiceModel.getEntryDefinitionServiceTemplate())) {
158 throw new CoreException(new ToscaEntryDefinitionWasNotFound().build());
160 toscaServiceModel.setEntryDefinitionServiceTemplate(fileName);
165 void loadToscaMetaFile(ToscaServiceModel toscaServiceModel, byte[] toscaMetaFileContent) {
166 String toscaMeta = new String(toscaMetaFileContent);
167 Map toscaMetaMap = new YamlUtil().yamlToObject(toscaMeta, Map.class);
168 if (Objects.isNull(toscaMetaMap.get(ENTRY_DEFINITIONS))) {
169 throw new CoreException(new InvalidToscaMetaFile(ENTRY_DEFINITIONS).build());
171 String entryDefinition = (String) toscaMetaMap.get(ENTRY_DEFINITIONS);
172 toscaServiceModel.setEntryDefinitionServiceTemplate(entryDefinition);
175 void loadToscaYamlFile(ToscaServiceModel toscaServiceModel, ToscaExtensionYamlUtil toscaExtensionYamlUtil,
176 byte[] fileContent, String fileFullName) {
178 ServiceTemplate serviceTemplate =
179 toscaExtensionYamlUtil.yamlToObject(new String(fileContent), ServiceTemplate.class);
180 toscaServiceModel.addServiceTemplate(fileFullName, serviceTemplate);
182 } catch (Exception exc) {
183 throw new CoreException(new InvalidToscaFile(fileFullName, exc.getMessage()).build());
187 private static boolean isFile(String currentEntryName) {
188 return !(currentEntryName.endsWith("\\") || currentEntryName.endsWith("/"));
191 private boolean isYamlFile(String fileName) {
192 return fileName.endsWith("yaml") || fileName.endsWith("yml");
195 private boolean isToscaYamlFile(byte[] fileContent) {
196 final Map fileMap = new YamlUtil().yamlToObject(new String(fileContent), Map.class);
197 return fileMap.containsKey(ToscaTagNamesEnum.TOSCA_VERSION.getElementName());
200 private void updateMinMaxOccurencesForNodeTypeRequirement(Map.Entry<String, RequirementAssignment> entry,
201 Map<String, RequirementDefinition> nodeTypeRequirementsMap) {
202 Object max = nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences() != null
203 && nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences().length > 0
204 ? nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences()[1] : 1;
205 Object min = nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences() != null
206 && nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences().length > 0
207 ? nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences()[0] : 1;
208 nodeTypeRequirementsMap.get(entry.getKey()).setOccurrences(new Object[] {min, max});
211 private void updateRequirementDefinition(
212 List<Map<String, RequirementDefinition>> nodeTypeRequirementsDefinitionList,
213 Map.Entry<String, RequirementAssignment> entry, RequirementDefinition cloneRequirementDefinition) {
214 if (!evaluateRequirementFulfillment(cloneRequirementDefinition)) {
216 .mergeEntryInList(entry.getKey(), cloneRequirementDefinition, nodeTypeRequirementsDefinitionList);
218 DataModelUtil.removeRequirementsDefinition(nodeTypeRequirementsDefinitionList, entry.getKey());
222 private static boolean evaluateRequirementFulfillment(RequirementDefinition requirementDefinition) {
223 Object[] occurrences = requirementDefinition.getOccurrences();
224 if (occurrences == null) {
225 requirementDefinition.setOccurrences(new Object[] {1, 1});
228 if (occurrences[1].equals(ToscaConstants.UNBOUNDED)) {
232 if (occurrences[1].equals(1)) {
235 occurrences[1] = (Integer) occurrences[1] - 1;
240 public Map<String, CapabilityDefinition> calculateExposedCapabilities(
241 Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition,
242 Map<String, Map<String, RequirementAssignment>> fullFilledRequirementsDefinitionMap) {
244 String capabilityKey;
247 for (Map.Entry<String, Map<String, RequirementAssignment>> entry : fullFilledRequirementsDefinitionMap
249 for (Map.Entry<String, RequirementAssignment> fullFilledEntry : entry.getValue().entrySet()) {
252 capability = fullFilledEntry.getValue().getCapability();
253 node = fullFilledEntry.getValue().getNode();
254 capabilityKey = capability + "_" + node;
255 CapabilityDefinition capabilityDefinition = nodeTypeCapabilitiesDefinition.get(capabilityKey);
256 if (capabilityDefinition != null) {
257 CapabilityDefinition clonedCapabilityDefinition = capabilityDefinition.clone();
258 nodeTypeCapabilitiesDefinition.put(capabilityKey, capabilityDefinition.clone());
259 updateNodeTypeCapabilitiesDefinition(nodeTypeCapabilitiesDefinition, capabilityKey,
260 clonedCapabilityDefinition);
265 Map<String, CapabilityDefinition> exposedCapabilitiesDefinition = new HashMap<>();
266 for (Map.Entry<String, CapabilityDefinition> entry : nodeTypeCapabilitiesDefinition.entrySet()) {
267 exposedCapabilitiesDefinition.put(entry.getKey(), entry.getValue());
269 return exposedCapabilitiesDefinition;
272 private void updateNodeTypeCapabilitiesDefinition(Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition,
273 String capabilityKey, CapabilityDefinition clonedCapabilityDefinition) {
274 if (evaluateCapabilityFulfillment(clonedCapabilityDefinition)) {
275 nodeTypeCapabilitiesDefinition.remove(capabilityKey);
277 nodeTypeCapabilitiesDefinition.put(capabilityKey, clonedCapabilityDefinition);
281 private static boolean evaluateCapabilityFulfillment(CapabilityDefinition capabilityDefinition) {
283 Object[] occurrences = capabilityDefinition.getOccurrences();
284 if (occurrences == null) {
285 capabilityDefinition.setOccurrences(new Object[] {1, ToscaConstants.UNBOUNDED});
288 if (occurrences[1].equals(ToscaConstants.UNBOUNDED)) {
292 if (occurrences[1].equals(1)) {
295 occurrences[1] = (Integer) occurrences[1] - 1;
300 node template with type equal to node type or derived from node type
303 public Map<String, NodeTemplate> getNodeTemplatesByType(ServiceTemplate serviceTemplate, String nodeType,
304 ToscaServiceModel toscaServiceModel) {
305 Map<String, NodeTemplate> nodeTemplates = new HashMap<>();
307 if (Objects.nonNull(serviceTemplate.getTopology_template()) && MapUtils.isNotEmpty(
308 serviceTemplate.getTopology_template().getNode_templates())) {
309 for (Map.Entry<String, NodeTemplate> nodeTemplateEntry : serviceTemplate.getTopology_template()
310 .getNode_templates().entrySet()) {
311 if (isTypeOf(nodeTemplateEntry.getValue(), nodeType, serviceTemplate, toscaServiceModel)) {
312 nodeTemplates.put(nodeTemplateEntry.getKey(), nodeTemplateEntry.getValue());
317 return nodeTemplates;
321 public Optional<NodeType> fetchNodeType(String nodeTypeKey, Collection<ServiceTemplate> serviceTemplates) {
322 Optional<Map<String, NodeType>> nodeTypeMap = serviceTemplates.stream().map(ServiceTemplate::getNode_types)
323 .filter(nodeTypes -> Objects.nonNull(nodeTypes)
328 return nodeTypeMap.map(stringNodeTypeMap -> stringNodeTypeMap.get(nodeTypeKey));
332 public boolean isTypeOf(NodeTemplate nodeTemplate, String nodeType, ServiceTemplate serviceTemplate,
333 ToscaServiceModel toscaServiceModel) {
334 return isTypeOf(nodeTemplate, nodeType, GET_NODE_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
338 public boolean isTypeOf(InterfaceDefinitionType interfaceDefinition, String interfaceType,
339 ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel) {
340 return isTypeOf(interfaceDefinition, interfaceType, GET_INTERFACE_TYPE_METHOD_NAME, serviceTemplate,
345 public boolean isTypeOf(DefinitionOfDataType parameterDefinition, String dataType, ServiceTemplate serviceTemplate,
346 ToscaServiceModel toscaServiceModel) {
347 return isTypeOf(parameterDefinition, dataType, GET_DATA_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
351 public boolean isTypeOf(CapabilityDefinition capabilityDefinition, String capabilityType,
352 ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel) {
353 return isTypeOf(capabilityDefinition, capabilityType, GET_CAPABILITY_TYPE_METHOD_NAME, serviceTemplate,
358 public List<RequirementAssignment> getRequirements(NodeTemplate nodeTemplate, String requirementId) {
359 List<RequirementAssignment> requirements = new ArrayList<>();
360 List<Map<String, RequirementAssignment>> requirementList = nodeTemplate.getRequirements();
361 if (requirementList != null) {
362 requirementList.stream().filter(reqMap -> reqMap.get(requirementId) != null).forEach(reqMap -> {
363 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
364 RequirementAssignment reqAssignment = toscaExtensionYamlUtil.yamlToObject(
365 toscaExtensionYamlUtil.objectToYaml(reqMap.get(requirementId)), RequirementAssignment.class);
366 requirements.add(reqAssignment);
373 public Optional<NodeTemplate> getNodeTemplateById(ServiceTemplate serviceTemplate, String nodeTemplateId) {
374 if ((serviceTemplate.getTopology_template() != null) && (
375 serviceTemplate.getTopology_template().getNode_templates() != null) && (
376 serviceTemplate.getTopology_template().getNode_templates().get(nodeTemplateId) != null)) {
377 return Optional.of(serviceTemplate.getTopology_template().getNode_templates().get(nodeTemplateId));
379 return Optional.empty();
383 public Optional<String> getSubstituteServiceTemplateName(String substituteNodeTemplateId,
384 NodeTemplate substitutableNodeTemplate) {
385 if (!isSubstitutableNodeTemplate(substitutableNodeTemplate)) {
386 return Optional.empty();
389 if (substitutableNodeTemplate.getProperties() != null &&
390 substitutableNodeTemplate.getProperties().get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME)
392 Object serviceTemplateFilter =
393 substitutableNodeTemplate.getProperties().get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
394 if (serviceTemplateFilter instanceof Map) {
395 Object substituteServiceTemplate =
396 ((Map) serviceTemplateFilter).get(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME);
397 handleNoSubstituteServiceTemplate(substituteNodeTemplateId, substituteServiceTemplate);
398 return Optional.of(substituteServiceTemplate.toString());
401 throw new CoreException(
402 new ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder(substituteNodeTemplateId).build());
405 private void handleNoSubstituteServiceTemplate(String substituteNodeTemplateId, Object substituteServiceTemplate) {
406 if (substituteServiceTemplate == null) {
407 throw new CoreException(
408 new ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder(substituteNodeTemplateId).build());
413 public Map<String, NodeTemplate> getSubstitutableNodeTemplates(ServiceTemplate serviceTemplate) {
414 Map<String, NodeTemplate> substitutableNodeTemplates = new HashMap<>();
416 if (serviceTemplate == null || serviceTemplate.getTopology_template() == null
417 || serviceTemplate.getTopology_template().getNode_templates() == null) {
418 return substitutableNodeTemplates;
421 Map<String, NodeTemplate> nodeTemplates = serviceTemplate.getTopology_template().getNode_templates();
422 for (Map.Entry<String, NodeTemplate> entry : nodeTemplates.entrySet()) {
423 String nodeTemplateId = entry.getKey();
424 NodeTemplate nodeTemplate = entry.getValue();
425 if (isSubstitutableNodeTemplate(nodeTemplate)) {
426 substitutableNodeTemplates.put(nodeTemplateId, nodeTemplate);
430 return substitutableNodeTemplates;
434 public Optional<Map.Entry<String, NodeTemplate>> getSubstitutionMappedNodeTemplateByExposedReq(
435 String substituteServiceTemplateFileName, ServiceTemplate substituteServiceTemplate, String requirementId) {
436 if (isSubstitutionServiceTemplate(substituteServiceTemplateFileName, substituteServiceTemplate)) {
437 Map<String, List<String>> substitutionMappingRequirements =
438 substituteServiceTemplate.getTopology_template().getSubstitution_mappings().getRequirements();
439 if (substitutionMappingRequirements != null) {
440 List<String> requirementMapping = substitutionMappingRequirements.get(requirementId);
441 if (requirementMapping != null && !requirementMapping.isEmpty()) {
442 String mappedNodeTemplateId = requirementMapping.get(0);
443 Optional<NodeTemplate> mappedNodeTemplate =
444 getNodeTemplateById(substituteServiceTemplate, mappedNodeTemplateId);
445 mappedNodeTemplate.orElseThrow(() -> new CoreException(
446 new ToscaInvalidEntryNotFoundErrorBuilder("Node Template", mappedNodeTemplateId).build()));
447 Map.Entry<String, NodeTemplate> mappedNodeTemplateEntry = new Map.Entry<String, NodeTemplate>() {
449 public String getKey() {
450 return mappedNodeTemplateId;
454 public NodeTemplate getValue() {
455 return mappedNodeTemplate.get();
459 public NodeTemplate setValue(NodeTemplate value) {
463 return Optional.of(mappedNodeTemplateEntry);
467 return Optional.empty();
471 match only for the input which is not null
474 public boolean isDesiredRequirementAssignment(RequirementAssignment requirementAssignment, String capability,
475 String node, String relationship) {
476 if (isSameCapability(requirementAssignment, capability)) {
480 if (isSameRequirement(requirementAssignment, node)) {
484 if (isSameRelationship(requirementAssignment, relationship)) {
488 return !(capability == null && node == null && relationship == null);
492 private boolean isSameRelationship(RequirementAssignment requirementAssignment, String relationship) {
493 return relationship != null && (requirementAssignment.getRelationship() == null || !requirementAssignment
495 .equals(relationship));
498 private boolean isSameRequirement(RequirementAssignment requirementAssignment, String node) {
499 return node != null && (requirementAssignment.getNode() == null || !requirementAssignment.getNode()
503 private boolean isSameCapability(RequirementAssignment requirementAssignment, String capability) {
504 return capability != null && (requirementAssignment.getCapability() == null || !requirementAssignment
506 .equals(capability));
510 public ToscaFlatData getFlatEntity(ToscaElementTypes elementType, String typeId, ServiceTemplate serviceTemplate,
511 ToscaServiceModel toscaModel) {
512 ToscaFlatData flatData = new ToscaFlatData();
513 flatData.setElementType(elementType);
515 switch (elementType) {
516 case CAPABILITY_TYPE:
517 flatData.setFlatEntity(new CapabilityType());
520 flatData.setFlatEntity(new NodeType());
523 flatData.setFlatEntity(new DataType());
526 throw new SdcRuntimeException("Entity[" + elementType + "] id[" + typeId + "] flat not supported");
529 boolean isEntityFound =
530 scanAnFlatEntity(elementType, typeId, flatData, serviceTemplate, toscaModel, new ArrayList<>(), 0);
531 if (!isEntityFound) {
532 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
539 public boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
540 return nodeTemplate.getDirectives() != null && nodeTemplate.getDirectives().contains(
541 ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
544 private <T> Optional<Boolean> isTypeExistInServiceTemplateHierarchy(String typeToMatch, String typeToSearch,
545 String getTypesMethodName, ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel,
546 Set<String> analyzedImportFiles)
547 throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
548 Map<String, T> searchableTypes =
549 (Map<String, T>) serviceTemplate.getClass().getMethod(getTypesMethodName).invoke(serviceTemplate);
551 if (!MapUtils.isEmpty(searchableTypes)) {
552 T typeObject = searchableTypes.get(typeToSearch);
553 if (Objects.nonNull(typeObject)) {
554 String derivedFromTypeVal =
555 (String) typeObject.getClass().getMethod(GET_DERIVED_FROM_METHOD_NAME).invoke(typeObject);
556 if (Objects.equals(derivedFromTypeVal, typeToMatch)) {
557 return Optional.of(true);
558 } else if (Objects.isNull(derivedFromTypeVal) || isTypeIsToscaRoot(derivedFromTypeVal)) {
559 return Optional.of(false);
561 return isTypeExistInServiceTemplateHierarchy(typeToMatch, derivedFromTypeVal, getTypesMethodName,
562 serviceTemplate, toscaServiceModel, null);
565 return isTypeExistInImports(typeToMatch, typeToSearch, getTypesMethodName, serviceTemplate,
566 toscaServiceModel, analyzedImportFiles);
569 return isTypeExistInImports(typeToMatch, typeToSearch, getTypesMethodName, serviceTemplate, toscaServiceModel,
570 analyzedImportFiles);
573 private Optional<Boolean> isTypeExistInImports(String typeToMatch, String typeToSearch, String getTypesMethodName,
574 ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel, Set<String> filesScanned)
575 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
576 List<Map<String, Import>> imports = serviceTemplate.getImports();
577 if (CollectionUtils.isEmpty(imports)) {
578 return Optional.empty();
581 Set<String> createdFilesScanned = createFilesScannedSet(filesScanned);
583 for (Map<String, Import> map : imports) {
584 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
585 Import anImport = toscaExtensionYamlUtil
586 .yamlToObject(toscaExtensionYamlUtil.objectToYaml(map.values().iterator().next()),
588 handleImportWithNoFileEntry(anImport);
589 String importFile = anImport.getFile();
590 ServiceTemplate template = toscaServiceModel.getServiceTemplates()
591 .get(fetchFullFileNameForImport(importFile,
592 serviceTemplate.getMetadata() == null ? null :
593 serviceTemplate.getMetadata().get("filename"),
594 serviceTemplate, toscaServiceModel));
595 if (Objects.isNull(template) || createdFilesScanned
596 .contains(ToscaUtil.getServiceTemplateFileName(template))) {
599 createdFilesScanned.add(ToscaUtil.getServiceTemplateFileName(template));
601 Optional<Boolean> typeExistInServiceTemplateHierarchy =
602 isTypeExistInServiceTemplateHierarchy(typeToMatch, typeToSearch, getTypesMethodName, template,
603 toscaServiceModel, createdFilesScanned);
604 if (typeExistInServiceTemplateHierarchy.isPresent() && (typeExistInServiceTemplateHierarchy.get())) {
605 createdFilesScanned.clear();
606 return Optional.of(true);
610 return Optional.of(false);
613 private void handleImportWithNoFileEntry(Import anImport) {
614 if (Objects.isNull(anImport) || Objects.isNull(anImport.getFile())) {
615 throw new SdcRuntimeException("import without file entry");
619 private Set<String> createFilesScannedSet(Set<String> filesScanned) {
620 Set<String> retFileScanned = filesScanned;
621 if (Objects.isNull(retFileScanned)) {
622 retFileScanned = new HashSet<>();
624 return retFileScanned;
627 private boolean isTypeIsToscaRoot(String type) {
628 return (type.contains(TOSCA_DOT) && type.contains(DOT_ROOT));
631 private boolean isSubstitutionServiceTemplate(String substituteServiceTemplateFileName,
632 ServiceTemplate substituteServiceTemplate) {
633 if (substituteServiceTemplate != null && substituteServiceTemplate.getTopology_template() != null
634 && substituteServiceTemplate.getTopology_template().getSubstitution_mappings() != null) {
635 if (substituteServiceTemplate.getTopology_template().getSubstitution_mappings().getNode_type() == null) {
636 throw new CoreException(
637 new ToscaInvalidSubstitutionServiceTemplateErrorBuilder(substituteServiceTemplateFileName)
646 private boolean scanAnFlatEntity(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
647 ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel, List<String> filesScanned,
648 int rootScanStartInx) {
651 boolean entityFound =
652 enrichEntityFromCurrentServiceTemplate(elementType, typeId, flatData, serviceTemplate, toscaModel,
653 filesScanned, rootScanStartInx);
655 List<Map<String, Import>> imports = serviceTemplate.getImports();
656 if (CollectionUtils.isEmpty(imports)) {
659 boolean found = false;
660 for (Map<String, Import> importMap : imports) {
664 found = isFlatEntity(importMap, flatData, serviceTemplate, filesScanned, toscaModel, elementType,
672 private boolean isFlatEntity(Map<String, Import> importMap, ToscaFlatData flatData, ServiceTemplate serviceTemplate,
673 List<String> filesScanned, ToscaServiceModel toscaModel, ToscaElementTypes elementType, String typeId) {
674 boolean found = false;
675 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
676 for (Object importObject : importMap.values()) {
677 Import importServiceTemplate = toscaExtensionYamlUtil
678 .yamlToObject(toscaExtensionYamlUtil.objectToYaml(importObject),
680 String fileName = fetchFullFileNameForImport(importServiceTemplate.getFile(),
681 serviceTemplate.getMetadata() == null ? null : serviceTemplate.getMetadata().get("filename"),
682 serviceTemplate, toscaModel);
683 if (filesScanned.contains(fileName)) {
686 filesScanned.add(fileName);
688 ServiceTemplate template = toscaModel.getServiceTemplates().get(fileName);
689 if (Objects.isNull(template)) {
690 throw new CoreException(new ToscaFileNotFoundErrorBuilder(fileName).build());
692 found = scanAnFlatEntity(elementType, typeId, flatData, template, toscaModel, filesScanned,
693 filesScanned.size());
698 String fetchFullFileNameForImport(String importServiceTemplateFile, String currentMetadatafileName,
699 ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel) {
700 Optional<Map.Entry<String, ServiceTemplate>> serviceTemplateEntry =
701 toscaServiceModel.getServiceTemplates().entrySet().stream()
702 .filter(entry -> entry.getValue() == serviceTemplate).findFirst();
703 if (!serviceTemplateEntry.isPresent()) {
704 if (importServiceTemplateFile.contains("../")) {
705 return importServiceTemplateFile.replace("../", "");
706 } else if (currentMetadatafileName != null && currentMetadatafileName.indexOf('/') != -1) {
707 return currentMetadatafileName.substring(0, currentMetadatafileName.indexOf('/')) + "/"
708 + importServiceTemplateFile;
710 return importServiceTemplateFile;
714 Path currentPath = Paths.get(serviceTemplateEntry.get().getKey()).getParent();
715 if (currentPath == null) {
716 currentPath = Paths.get("");
718 return currentPath.resolve(importServiceTemplateFile).normalize().toString().replaceAll("\\\\", "/");
721 private boolean enrichEntityFromCurrentServiceTemplate(ToscaElementTypes elementType, String typeId,
722 ToscaFlatData flatData, ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel,
723 List<String> filesScanned, int rootScanStartInx) {
724 switch (elementType) {
725 case CAPABILITY_TYPE:
726 if (enrichCapabilityType(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned,
732 if (enrichNodeTypeInfo(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned,
738 if (enrichDataTypeInfo(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned,
744 throw new SdcRuntimeException("Entity[" + elementType + "] id[" + typeId + "] flat not supported");
752 private boolean enrichNodeTypeInfo(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
753 ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel, List<String> filesScanned,
754 int rootScanStartInx) {
756 if (serviceTemplate.getNode_types() != null && serviceTemplate.getNode_types().containsKey(typeId)) {
758 filesScanned.clear();
759 flatData.addInheritanceHierarchyType(typeId);
760 NodeType targetNodeType = (NodeType) flatData.getFlatEntity();
761 NodeType sourceNodeType = serviceTemplate.getNode_types().get(typeId);
762 derivedFrom = sourceNodeType.getDerived_from();
763 if (derivedFrom != null) {
764 boolean isEntityFound =
765 scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
767 if (!isEntityFound) {
768 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
771 combineNodeTypeInfo(sourceNodeType, targetNodeType);
778 private boolean enrichDataTypeInfo(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
779 ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel, List<String> filesScanned,
780 int rootScanStartInx) {
782 if (serviceTemplate.getData_types() != null && serviceTemplate.getData_types().containsKey(typeId)) {
784 filesScanned.clear();
785 flatData.addInheritanceHierarchyType(typeId);
786 DataType targetDataType = (DataType) flatData.getFlatEntity();
787 DataType sourceDataType = serviceTemplate.getData_types().get(typeId);
788 derivedFrom = sourceDataType.getDerived_from();
789 if (derivedFrom != null && !isPrimitiveType(derivedFrom)) {
790 boolean isEntityFound =
791 scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
793 if (!isEntityFound) {
794 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
797 combineDataTypeInfo(sourceDataType, targetDataType);
804 private static boolean isPrimitiveType(String toscaType) {
805 return (toscaType.equals(PropertyType.STRING.getDisplayName()) || toscaType.equals(PropertyType.INTEGER
807 || toscaType.equals(PropertyType.FLOAT.getDisplayName()));
810 private boolean enrichCapabilityType(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
811 ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel, List<String> filesScanned,
812 int rootScanStartInx) {
814 if (serviceTemplate.getCapability_types() != null && serviceTemplate.getCapability_types()
815 .containsKey(typeId)) {
817 filesScanned.clear();
818 flatData.addInheritanceHierarchyType(typeId);
819 CapabilityType targetCapabilityType = (CapabilityType) flatData.getFlatEntity();
820 CapabilityType sourceCapabilityType = serviceTemplate.getCapability_types().get(typeId);
821 derivedFrom = sourceCapabilityType.getDerived_from();
822 if (derivedFrom != null) {
823 boolean isEntityFound =
824 scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
826 if (!isEntityFound) {
827 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
830 combineCapabilityTypeInfo(sourceCapabilityType, targetCapabilityType);
837 private void combineNodeTypeInfo(NodeType sourceNodeType, NodeType targetNodeType) {
838 targetNodeType.setDerived_from(sourceNodeType.getDerived_from());
839 targetNodeType.setDescription(sourceNodeType.getDescription());
840 targetNodeType.setVersion(sourceNodeType.getVersion());
842 .setProperties(CommonMethods.mergeMaps(targetNodeType.getProperties(), sourceNodeType.getProperties()));
843 combineNodeTypeInterfaceInfo(sourceNodeType, targetNodeType);
845 .setArtifacts(CommonMethods.mergeMaps(targetNodeType.getArtifacts(), sourceNodeType.getArtifacts()));
847 .setAttributes(CommonMethods.mergeMaps(targetNodeType.getAttributes(), sourceNodeType.getAttributes()));
848 targetNodeType.setCapabilities(
849 CommonMethods.mergeMaps(targetNodeType.getCapabilities(), sourceNodeType.getCapabilities()));
850 targetNodeType.setRequirements(
851 CommonMethods.mergeListsOfMap(targetNodeType.getRequirements(), sourceNodeType.getRequirements()));
855 private void combineNodeTypeInterfaceInfo(NodeType sourceNodeType, NodeType targetNodeType) {
856 Optional<Map<String, Object>> interfaceNoMerge = combineInterfaceNoMerge(sourceNodeType, targetNodeType);
857 if (interfaceNoMerge.isPresent()) {
858 targetNodeType.setInterfaces(interfaceNoMerge.get());
861 combineInterfaces(sourceNodeType, targetNodeType).ifPresent(targetNodeType::setInterfaces);
864 private Optional<Map<String, Object>> combineInterfaces(NodeType sourceNodeType, NodeType targetNodeType) {
865 if (MapUtils.isEmpty(sourceNodeType.getInterfaces())) {
866 return Optional.empty();
868 Map<String, Object> combineInterfaces = new HashMap<>();
869 for (Map.Entry<String, Object> sourceInterfaceDefEntry : sourceNodeType.getInterfaces().entrySet()) {
870 String interfaceName = sourceInterfaceDefEntry.getKey();
871 if (!MapUtils.isEmpty(targetNodeType.getInterfaces()) && targetNodeType.getInterfaces()
872 .containsKey(interfaceName)) {
873 combineInterfaces.put(interfaceName, combineInterfaceDefinition(sourceInterfaceDefEntry.getValue(),
874 targetNodeType.getInterfaces().get(interfaceName)));
876 combineInterfaces.put(sourceInterfaceDefEntry.getKey(), sourceInterfaceDefEntry.getValue());
880 for (Map.Entry<String, Object> targetInterfaceDefEntry : targetNodeType.getInterfaces().entrySet()) {
881 String interfaceName = targetInterfaceDefEntry.getKey();
882 if (!sourceNodeType.getInterfaces().containsKey(interfaceName)) {
883 combineInterfaces.put(targetInterfaceDefEntry.getKey(), targetInterfaceDefEntry.getValue());
887 return Optional.of(combineInterfaces);
890 private Optional<Map<String, Object>> combineInterfaceNoMerge(NodeType sourceNodeType, NodeType targetNodeType) {
891 if ((MapUtils.isEmpty(sourceNodeType.getInterfaces()) && MapUtils.isEmpty(targetNodeType.getInterfaces()))) {
892 return Optional.empty();
895 if (MapUtils.isEmpty(sourceNodeType.getInterfaces()) && !MapUtils.isEmpty(targetNodeType.getInterfaces())) {
896 return Optional.of(targetNodeType.getInterfaces());
899 if (!MapUtils.isEmpty(sourceNodeType.getInterfaces()) && MapUtils.isEmpty(targetNodeType.getInterfaces())) {
900 return Optional.of(sourceNodeType.getInterfaces());
902 return Optional.empty();
906 private Object combineInterfaceDefinition(Object sourceInterfaceDefType, Object targetInterfaceDefType) {
907 InterfaceDefinitionType sourceInterface = new InterfaceDefinitionType(sourceInterfaceDefType);
908 InterfaceDefinitionType targetInterface = new InterfaceDefinitionType(targetInterfaceDefType);
909 InterfaceDefinitionType combineInterface = new InterfaceDefinitionType();
910 combineInterface.setType(sourceInterface.getType());
911 combineInterface.setInputs(CommonMethods.mergeMaps(targetInterface.getInputs(), sourceInterface.getInputs()));
912 combineInterface.setOperations(
913 CommonMethods.mergeMaps(targetInterface.getOperations(), sourceInterface.getOperations()));
915 Optional<Object> interfaceDefObject = combineInterface.convertInterfaceDefinitionTypeToToscaObj();
916 if (!interfaceDefObject.isPresent()) {
917 throw new SdcRuntimeException("Illegal Statement");
919 return interfaceDefObject.get();
922 private void combineDataTypeInfo(DataType sourceDataType, DataType targetDataType) {
923 targetDataType.setDerived_from(sourceDataType.getDerived_from());
924 targetDataType.setDescription(sourceDataType.getDescription());
925 targetDataType.setVersion(sourceDataType.getVersion());
927 .setProperties(CommonMethods.mergeMaps(targetDataType.getProperties(), sourceDataType.getProperties()));
928 targetDataType.setConstraints(
929 CommonMethods.mergeLists(targetDataType.getConstraints(), sourceDataType.getConstraints()));
932 private void combineCapabilityTypeInfo(CapabilityType sourceCapabilityType, CapabilityType targetCapabilityType) {
934 targetCapabilityType.setAttributes(
935 CommonMethods.mergeMaps(targetCapabilityType.getAttributes(), sourceCapabilityType.getAttributes()));
936 targetCapabilityType.setProperties(
937 CommonMethods.mergeMaps(targetCapabilityType.getProperties(), sourceCapabilityType.getProperties()));
938 targetCapabilityType.setValid_source_types(CommonMethods
939 .mergeLists(targetCapabilityType.getValid_source_types(),
940 sourceCapabilityType.getValid_source_types()));
942 if (StringUtils.isNotEmpty(sourceCapabilityType.getDerived_from())) {
943 targetCapabilityType.setDerived_from(sourceCapabilityType.getDerived_from());
945 if (StringUtils.isNotEmpty(sourceCapabilityType.getDescription())) {
946 targetCapabilityType.setDescription(sourceCapabilityType.getDescription());
948 if (StringUtils.isNotEmpty(sourceCapabilityType.getVersion())) {
949 targetCapabilityType.setVersion(sourceCapabilityType.getVersion());
957 * Create node type according to the input substitution service template, while the substitution
958 * service template can be mappted to this node type, for substitution mapping.
960 * @param substitutionServiceTemplate substitution serivce template
961 * @param nodeTypeDerivedFromValue derived from value for the created node type
962 * @return the node type
965 public NodeType createInitSubstitutionNodeType(ServiceTemplate substitutionServiceTemplate,
966 String nodeTypeDerivedFromValue) {
967 NodeType substitutionNodeType = new NodeType();
968 substitutionNodeType.setDerived_from(nodeTypeDerivedFromValue);
969 substitutionNodeType.setDescription(substitutionServiceTemplate.getDescription());
970 substitutionNodeType.setProperties(manageSubstitutionNodeTypeProperties(substitutionServiceTemplate));
971 substitutionNodeType.setAttributes(manageSubstitutionNodeTypeAttributes(substitutionServiceTemplate));
972 return substitutionNodeType;
976 public Map<String, PropertyDefinition> manageSubstitutionNodeTypeProperties(
977 ServiceTemplate substitutionServiceTemplate) {
978 Map<String, PropertyDefinition> substitutionNodeTypeProperties = new HashMap<>();
979 Map<String, ParameterDefinition> properties = substitutionServiceTemplate.getTopology_template().getInputs();
980 if (properties == null) {
984 PropertyDefinition propertyDefinition;
985 String toscaPropertyName;
986 for (Map.Entry<String, ParameterDefinition> entry : properties.entrySet()) {
987 toscaPropertyName = entry.getKey();
988 propertyDefinition = new PropertyDefinition();
989 ParameterDefinition parameterDefinition =
990 substitutionServiceTemplate.getTopology_template().getInputs().get(toscaPropertyName);
991 propertyDefinition.setType(parameterDefinition.getType());
992 propertyDefinition.setDescription(parameterDefinition.getDescription());
993 propertyDefinition.set_default(parameterDefinition.get_default());
994 if (parameterDefinition.getRequired() != null) {
995 propertyDefinition.setRequired(parameterDefinition.getRequired());
997 if (propertyDefinition.get_default() != null) {
998 propertyDefinition.setRequired(false);
1000 if (!CollectionUtils.isEmpty(parameterDefinition.getConstraints())) {
1001 propertyDefinition.setConstraints(parameterDefinition.getConstraints());
1003 propertyDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
1004 if (parameterDefinition.getStatus() != null) {
1005 propertyDefinition.setStatus(parameterDefinition.getStatus());
1007 substitutionNodeTypeProperties.put(toscaPropertyName, propertyDefinition);
1009 return substitutionNodeTypeProperties;
1013 private Map<String, AttributeDefinition> manageSubstitutionNodeTypeAttributes(
1014 ServiceTemplate substitutionServiceTemplate) {
1015 Map<String, AttributeDefinition> substitutionNodeTypeAttributes = new HashMap<>();
1016 Map<String, ParameterDefinition> attributes = substitutionServiceTemplate.getTopology_template().getOutputs();
1017 if (attributes == null) {
1020 AttributeDefinition attributeDefinition;
1021 String toscaAttributeName;
1023 for (Map.Entry<String, ParameterDefinition> entry : attributes.entrySet()) {
1024 attributeDefinition = new AttributeDefinition();
1025 toscaAttributeName = entry.getKey();
1026 ParameterDefinition parameterDefinition =
1027 substitutionServiceTemplate.getTopology_template().getOutputs().get(toscaAttributeName);
1028 if (parameterDefinition.getType() != null && !parameterDefinition.getType().isEmpty()) {
1029 attributeDefinition.setType(parameterDefinition.getType());
1031 attributeDefinition.setType(PropertyType.STRING.getDisplayName());
1033 attributeDefinition.setDescription(parameterDefinition.getDescription());
1034 attributeDefinition.set_default(parameterDefinition.get_default());
1035 attributeDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
1036 if (Objects.nonNull(parameterDefinition.getStatus())) {
1037 attributeDefinition.setStatus(parameterDefinition.getStatus());
1039 substitutionNodeTypeAttributes.put(toscaAttributeName, attributeDefinition);
1041 return substitutionNodeTypeAttributes;
1045 * Checks if the requirement exists in the node template.
1047 * @param nodeTemplate the node template
1048 * @param requirementId the requirement id
1049 * @param requirementAssignment the requirement assignment
1050 * @return true if the requirement already exists and false otherwise
1053 public boolean isRequirementExistInNodeTemplate(NodeTemplate nodeTemplate, String requirementId,
1054 RequirementAssignment requirementAssignment) {
1055 List<Map<String, RequirementAssignment>> nodeTemplateRequirements = nodeTemplate.getRequirements();
1056 return nodeTemplateRequirements != null && nodeTemplateRequirements.stream().anyMatch(
1057 requirement -> requirement.containsKey(requirementId) && DataModelUtil.compareRequirementAssignment(
1058 requirementAssignment, requirement.get(requirementId)));
1061 private <T> boolean isTypeOf(T object, String type, String getTypesMethodName, ServiceTemplate serviceTemplate,
1062 ToscaServiceModel toscaServiceModel) {
1063 if (object == null) {
1068 String objectType = (String) object.getClass().getMethod(GET_TYPE_METHOD_NAME).invoke(object);
1069 if (Objects.equals(objectType, type)) {
1073 Optional<Boolean> typeExistInServiceTemplateHierarchy =
1074 isTypeExistInServiceTemplateHierarchy(type, objectType, getTypesMethodName, serviceTemplate,
1075 toscaServiceModel, null);
1076 return typeExistInServiceTemplateHierarchy.orElseThrow(
1077 () -> new CoreException(new ToscaElementTypeNotFoundErrorBuilder(objectType).build()));
1079 } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
1080 throw new SdcRuntimeException(e);