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.
16 package org.openecomp.sdc.tosca.services.impl;
18 import java.io.ByteArrayInputStream;
19 import java.io.IOException;
20 import java.lang.reflect.InvocationTargetException;
21 import java.nio.file.Path;
22 import java.nio.file.Paths;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
30 import java.util.Objects;
31 import java.util.Optional;
33 import java.util.zip.ZipEntry;
34 import java.util.zip.ZipInputStream;
35 import org.apache.commons.collections4.CollectionUtils;
36 import org.apache.commons.collections4.MapUtils;
37 import org.apache.commons.lang3.StringUtils;
38 import org.onap.sdc.tosca.datatypes.model.AttributeDefinition;
39 import org.onap.sdc.tosca.datatypes.model.CapabilityDefinition;
40 import org.onap.sdc.tosca.datatypes.model.CapabilityType;
41 import org.onap.sdc.tosca.datatypes.model.DataType;
42 import org.onap.sdc.tosca.datatypes.model.DefinitionOfDataType;
43 import org.onap.sdc.tosca.datatypes.model.Import;
44 import org.onap.sdc.tosca.datatypes.model.InterfaceDefinitionType;
45 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
46 import org.onap.sdc.tosca.datatypes.model.NodeType;
47 import org.onap.sdc.tosca.datatypes.model.ParameterDefinition;
48 import org.onap.sdc.tosca.datatypes.model.PropertyDefinition;
49 import org.onap.sdc.tosca.datatypes.model.PropertyType;
50 import org.onap.sdc.tosca.datatypes.model.RequirementAssignment;
51 import org.onap.sdc.tosca.datatypes.model.RequirementDefinition;
52 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
53 import org.onap.sdc.tosca.services.ToscaExtensionYamlUtil;
54 import org.onap.sdc.tosca.services.YamlUtil;
55 import org.openecomp.core.utilities.CommonMethods;
56 import org.openecomp.core.utilities.file.FileContentHandler;
57 import org.openecomp.core.utilities.file.FileUtils;
58 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
59 import org.openecomp.sdc.common.errors.CoreException;
60 import org.openecomp.sdc.common.errors.SdcRuntimeException;
61 import org.openecomp.sdc.common.zip.ZipUtils;
62 import org.openecomp.sdc.common.zip.exception.ZipSlipException;
63 import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes;
64 import org.openecomp.sdc.tosca.datatypes.ToscaFlatData;
65 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
66 import org.openecomp.sdc.tosca.errors.InvalidToscaFile;
67 import org.openecomp.sdc.tosca.errors.InvalidToscaMetaFile;
68 import org.openecomp.sdc.tosca.errors.ToscaElementTypeNotFoundErrorBuilder;
69 import org.openecomp.sdc.tosca.errors.ToscaEntryDefinitionWasNotFound;
70 import org.openecomp.sdc.tosca.errors.ToscaFileNotFoundErrorBuilder;
71 import org.openecomp.sdc.tosca.errors.ToscaInvalidEntryNotFoundErrorBuilder;
72 import org.openecomp.sdc.tosca.errors.ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder;
73 import org.openecomp.sdc.tosca.errors.ToscaInvalidSubstitutionServiceTemplateErrorBuilder;
74 import org.openecomp.sdc.tosca.services.DataModelUtil;
75 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
76 import org.openecomp.sdc.tosca.services.ToscaConstants;
77 import org.openecomp.sdc.tosca.services.ToscaUtil;
79 public class ToscaAnalyzerServiceImpl implements ToscaAnalyzerService {
81 private static final String GET_NODE_TYPE_METHOD_NAME = "getNode_types";
82 private static final String GET_DERIVED_FROM_METHOD_NAME = "getDerived_from";
83 private static final String GET_TYPE_METHOD_NAME = "getType";
84 private static final String GET_DATA_TYPE_METHOD_NAME = "getData_types";
85 private static final String GET_INTERFACE_TYPE_METHOD_NAME = "getNormalizeInterfaceTypes";
86 private static final String GET_CAPABILITY_TYPE_METHOD_NAME = "getCapability_types";
87 private static final String TOSCA_DOT = "tosca.";
88 private static final String DOT_ROOT = ".Root";
89 private static final String IMPORTS = "imports";
90 private static final String TOSCA_META_FILE = "TOSCA-Metadata/TOSCA.meta";
91 private static final String ENTRY_DEFINITIONS = "Entry-Definitions";
93 private static boolean isFile(String currentEntryName) {
94 return !(currentEntryName.endsWith("\\") || currentEntryName.endsWith("/"));
97 private static boolean evaluateRequirementFulfillment(RequirementDefinition requirementDefinition) {
98 Object[] occurrences = requirementDefinition.getOccurrences();
99 if (occurrences == null) {
100 requirementDefinition.setOccurrences(new Object[]{1, 1});
103 if (occurrences[1].equals(ToscaConstants.UNBOUNDED)) {
106 if (occurrences[1].equals(1)) {
109 occurrences[1] = (Integer) occurrences[1] - 1;
113 private static boolean evaluateCapabilityFulfillment(CapabilityDefinition capabilityDefinition) {
114 Object[] occurrences = capabilityDefinition.getOccurrences();
115 if (occurrences == null) {
116 capabilityDefinition.setOccurrences(new Object[]{1, ToscaConstants.UNBOUNDED});
119 if (occurrences[1].equals(ToscaConstants.UNBOUNDED)) {
122 if (occurrences[1].equals(1)) {
125 occurrences[1] = (Integer) occurrences[1] - 1;
129 private static boolean isPrimitiveType(String toscaType) {
130 return (toscaType.equals(PropertyType.STRING.getDisplayName()) || toscaType.equals(PropertyType.INTEGER.getDisplayName()) || toscaType
131 .equals(PropertyType.FLOAT.getDisplayName()));
135 public List<Map<String, RequirementDefinition>> calculateExposedRequirements(
136 List<Map<String, RequirementDefinition>> nodeTypeRequirementsDefinitionList,
137 Map<String, RequirementAssignment> nodeTemplateRequirementsAssignment) {
138 if (nodeTypeRequirementsDefinitionList == null) {
139 return Collections.emptyList();
141 for (Map.Entry<String, RequirementAssignment> entry : nodeTemplateRequirementsAssignment.entrySet()) {
142 if (entry.getValue().getNode() != null) {
143 Optional<RequirementDefinition> requirementDefinition = DataModelUtil
144 .getRequirementDefinition(nodeTypeRequirementsDefinitionList, entry.getKey());
145 RequirementDefinition cloneRequirementDefinition;
146 if (requirementDefinition.isPresent()) {
147 cloneRequirementDefinition = requirementDefinition.get().clone();
148 updateRequirementDefinition(nodeTypeRequirementsDefinitionList, entry, cloneRequirementDefinition);
151 for (Map<String, RequirementDefinition> nodeTypeRequirementsMap : nodeTypeRequirementsDefinitionList) {
152 updateMinMaxOccurencesForNodeTypeRequirement(entry, nodeTypeRequirementsMap);
156 return nodeTypeRequirementsDefinitionList;
160 public ToscaServiceModel loadToscaCsarPackage(byte[] toscaCsarPackage) {
161 ToscaServiceModel toscaServiceModel = new ToscaServiceModel();
162 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
163 FileContentHandler artifactFiles = new FileContentHandler();
164 try (ZipInputStream inputZipStream = new ZipInputStream(new ByteArrayInputStream(toscaCsarPackage))) {
166 while ((zipEntry = inputZipStream.getNextEntry()) != null) {
167 ZipUtils.checkForZipSlipInRead(zipEntry);
168 byte[] fileContent = FileUtils.toByteArray(inputZipStream);
169 String currentEntryName = zipEntry.getName();
170 if (!isFile(currentEntryName)) {
173 if (isYamlFile(currentEntryName) && isToscaYamlFile(fileContent)) {
174 loadToscaYamlFile(toscaServiceModel, toscaExtensionYamlUtil, fileContent, currentEntryName);
175 } else if (currentEntryName.equals(TOSCA_META_FILE)) {
176 loadToscaMetaFile(toscaServiceModel, fileContent);
178 artifactFiles.addFile(currentEntryName, fileContent);
181 toscaServiceModel.setArtifactFiles(artifactFiles);
182 if (StringUtils.isEmpty(toscaServiceModel.getEntryDefinitionServiceTemplate())) {
183 handleToscaCsarWithoutToscaMetadata(toscaServiceModel);
185 } catch (IOException | ZipSlipException exc) {
186 throw new SdcRuntimeException(exc.getMessage(), exc);
188 return toscaServiceModel;
191 private void handleToscaCsarWithoutToscaMetadata(ToscaServiceModel toscaServiceModel) {
192 for (String fileName : toscaServiceModel.getServiceTemplates().keySet()) {
193 if (!fileName.contains("/")) {
194 if (StringUtils.isNotEmpty(toscaServiceModel.getEntryDefinitionServiceTemplate())) {
195 throw new CoreException(new ToscaEntryDefinitionWasNotFound().build());
197 toscaServiceModel.setEntryDefinitionServiceTemplate(fileName);
202 void loadToscaMetaFile(ToscaServiceModel toscaServiceModel, byte[] toscaMetaFileContent) {
203 String toscaMeta = new String(toscaMetaFileContent);
204 Map toscaMetaMap = new YamlUtil().yamlToObject(toscaMeta, Map.class);
205 if (Objects.isNull(toscaMetaMap.get(ENTRY_DEFINITIONS))) {
206 throw new CoreException(new InvalidToscaMetaFile(ENTRY_DEFINITIONS).build());
208 String entryDefinition = (String) toscaMetaMap.get(ENTRY_DEFINITIONS);
209 toscaServiceModel.setEntryDefinitionServiceTemplate(entryDefinition);
212 void loadToscaYamlFile(ToscaServiceModel toscaServiceModel, ToscaExtensionYamlUtil toscaExtensionYamlUtil, byte[] fileContent,
213 String fileFullName) {
215 ServiceTemplate serviceTemplate = toscaExtensionYamlUtil.yamlToObject(new String(fileContent), ServiceTemplate.class);
216 toscaServiceModel.addServiceTemplate(fileFullName, serviceTemplate);
217 } catch (Exception exc) {
218 throw new CoreException(new InvalidToscaFile(fileFullName, exc.getMessage()).build());
222 private boolean isYamlFile(String fileName) {
223 return fileName.endsWith("yaml") || fileName.endsWith("yml");
226 private boolean isToscaYamlFile(byte[] fileContent) {
227 final Map fileMap = new YamlUtil().yamlToObject(new String(fileContent), Map.class);
228 return fileMap.containsKey(ToscaTagNamesEnum.TOSCA_VERSION.getElementName());
231 private void updateMinMaxOccurencesForNodeTypeRequirement(Map.Entry<String, RequirementAssignment> entry,
232 Map<String, RequirementDefinition> nodeTypeRequirementsMap) {
233 Object max = nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences() != null
234 && nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences().length > 0 ? nodeTypeRequirementsMap.get(entry.getKey())
235 .getOccurrences()[1] : 1;
236 Object min = nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences() != null
237 && nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences().length > 0 ? nodeTypeRequirementsMap.get(entry.getKey())
238 .getOccurrences()[0] : 1;
239 nodeTypeRequirementsMap.get(entry.getKey()).setOccurrences(new Object[]{min, max});
242 private void updateRequirementDefinition(List<Map<String, RequirementDefinition>> nodeTypeRequirementsDefinitionList,
243 Map.Entry<String, RequirementAssignment> entry, RequirementDefinition cloneRequirementDefinition) {
244 if (!evaluateRequirementFulfillment(cloneRequirementDefinition)) {
245 CommonMethods.mergeEntryInList(entry.getKey(), cloneRequirementDefinition, nodeTypeRequirementsDefinitionList);
247 DataModelUtil.removeRequirementsDefinition(nodeTypeRequirementsDefinitionList, entry.getKey());
252 public Map<String, CapabilityDefinition> calculateExposedCapabilities(Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition,
253 Map<String, Map<String, RequirementAssignment>> fullFilledRequirementsDefinitionMap) {
254 String capabilityKey;
257 for (Map.Entry<String, Map<String, RequirementAssignment>> entry : fullFilledRequirementsDefinitionMap.entrySet()) {
258 for (Map.Entry<String, RequirementAssignment> fullFilledEntry : entry.getValue().entrySet()) {
259 capability = fullFilledEntry.getValue().getCapability();
260 node = fullFilledEntry.getValue().getNode();
261 capabilityKey = capability + "_" + node;
262 CapabilityDefinition capabilityDefinition = nodeTypeCapabilitiesDefinition.get(capabilityKey);
263 if (capabilityDefinition != null) {
264 CapabilityDefinition clonedCapabilityDefinition = capabilityDefinition.clone();
265 nodeTypeCapabilitiesDefinition.put(capabilityKey, capabilityDefinition.clone());
266 updateNodeTypeCapabilitiesDefinition(nodeTypeCapabilitiesDefinition, capabilityKey, clonedCapabilityDefinition);
270 Map<String, CapabilityDefinition> exposedCapabilitiesDefinition = new HashMap<>();
271 for (Map.Entry<String, CapabilityDefinition> entry : nodeTypeCapabilitiesDefinition.entrySet()) {
272 exposedCapabilitiesDefinition.put(entry.getKey(), entry.getValue());
274 return exposedCapabilitiesDefinition;
277 private void updateNodeTypeCapabilitiesDefinition(Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition, String capabilityKey,
278 CapabilityDefinition clonedCapabilityDefinition) {
279 if (evaluateCapabilityFulfillment(clonedCapabilityDefinition)) {
280 nodeTypeCapabilitiesDefinition.remove(capabilityKey);
282 nodeTypeCapabilitiesDefinition.put(capabilityKey, clonedCapabilityDefinition);
287 node template with type equal to node type or derived from node type
290 public Map<String, NodeTemplate> getNodeTemplatesByType(ServiceTemplate serviceTemplate, String nodeType, ToscaServiceModel toscaServiceModel) {
291 Map<String, NodeTemplate> nodeTemplates = new HashMap<>();
292 if (Objects.nonNull(serviceTemplate.getTopology_template()) && MapUtils
293 .isNotEmpty(serviceTemplate.getTopology_template().getNode_templates())) {
294 for (Map.Entry<String, NodeTemplate> nodeTemplateEntry : serviceTemplate.getTopology_template().getNode_templates().entrySet()) {
295 if (isTypeOf(nodeTemplateEntry.getValue(), nodeType, serviceTemplate, toscaServiceModel)) {
296 nodeTemplates.put(nodeTemplateEntry.getKey(), nodeTemplateEntry.getValue());
300 return nodeTemplates;
304 public Optional<NodeType> fetchNodeType(String nodeTypeKey, Collection<ServiceTemplate> serviceTemplates) {
305 Optional<Map<String, NodeType>> nodeTypeMap = serviceTemplates.stream().map(ServiceTemplate::getNode_types)
306 .filter(nodeTypes -> Objects.nonNull(nodeTypes) && nodeTypes.containsKey(nodeTypeKey)).findFirst();
307 return nodeTypeMap.map(stringNodeTypeMap -> stringNodeTypeMap.get(nodeTypeKey));
311 public boolean isTypeOf(NodeTemplate nodeTemplate, String nodeType, ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel) {
312 return isTypeOf(nodeTemplate, nodeType, GET_NODE_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
316 public boolean isTypeOf(InterfaceDefinitionType interfaceDefinition, String interfaceType, ServiceTemplate serviceTemplate,
317 ToscaServiceModel toscaServiceModel) {
318 return isTypeOf(interfaceDefinition, interfaceType, GET_INTERFACE_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
322 public boolean isTypeOf(DefinitionOfDataType parameterDefinition, String dataType, ServiceTemplate serviceTemplate,
323 ToscaServiceModel toscaServiceModel) {
324 return isTypeOf(parameterDefinition, dataType, GET_DATA_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
328 public boolean isTypeOf(CapabilityDefinition capabilityDefinition, String capabilityType, ServiceTemplate serviceTemplate,
329 ToscaServiceModel toscaServiceModel) {
330 return isTypeOf(capabilityDefinition, capabilityType, GET_CAPABILITY_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
334 public List<RequirementAssignment> getRequirements(NodeTemplate nodeTemplate, String requirementId) {
335 List<RequirementAssignment> requirements = new ArrayList<>();
336 List<Map<String, RequirementAssignment>> requirementList = nodeTemplate.getRequirements();
337 if (requirementList != null) {
338 requirementList.stream().filter(reqMap -> reqMap.get(requirementId) != null).forEach(reqMap -> {
339 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
340 RequirementAssignment reqAssignment = toscaExtensionYamlUtil
341 .yamlToObject(toscaExtensionYamlUtil.objectToYaml(reqMap.get(requirementId)), RequirementAssignment.class);
342 requirements.add(reqAssignment);
349 public Optional<NodeTemplate> getNodeTemplateById(ServiceTemplate serviceTemplate, String nodeTemplateId) {
350 if ((serviceTemplate.getTopology_template() != null) && (serviceTemplate.getTopology_template().getNode_templates() != null) && (
351 serviceTemplate.getTopology_template().getNode_templates().get(nodeTemplateId) != null)) {
352 return Optional.of(serviceTemplate.getTopology_template().getNode_templates().get(nodeTemplateId));
354 return Optional.empty();
358 public Optional<String> getSubstituteServiceTemplateName(String substituteNodeTemplateId, NodeTemplate substitutableNodeTemplate) {
359 if (!isSubstitutableNodeTemplate(substitutableNodeTemplate)) {
360 return Optional.empty();
362 if (substitutableNodeTemplate.getProperties() != null
363 && substitutableNodeTemplate.getProperties().get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME) != null) {
364 Object serviceTemplateFilter = substitutableNodeTemplate.getProperties().get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
365 if (serviceTemplateFilter instanceof Map) {
366 Object substituteServiceTemplate = ((Map) serviceTemplateFilter).get(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME);
367 handleNoSubstituteServiceTemplate(substituteNodeTemplateId, substituteServiceTemplate);
368 return Optional.of(substituteServiceTemplate.toString());
371 throw new CoreException(new ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder(substituteNodeTemplateId).build());
374 private void handleNoSubstituteServiceTemplate(String substituteNodeTemplateId, Object substituteServiceTemplate) {
375 if (substituteServiceTemplate == null) {
376 throw new CoreException(new ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder(substituteNodeTemplateId).build());
381 public Map<String, NodeTemplate> getSubstitutableNodeTemplates(ServiceTemplate serviceTemplate) {
382 Map<String, NodeTemplate> substitutableNodeTemplates = new HashMap<>();
383 if (serviceTemplate == null || serviceTemplate.getTopology_template() == null
384 || serviceTemplate.getTopology_template().getNode_templates() == null) {
385 return substitutableNodeTemplates;
387 Map<String, NodeTemplate> nodeTemplates = serviceTemplate.getTopology_template().getNode_templates();
388 for (Map.Entry<String, NodeTemplate> entry : nodeTemplates.entrySet()) {
389 String nodeTemplateId = entry.getKey();
390 NodeTemplate nodeTemplate = entry.getValue();
391 if (isSubstitutableNodeTemplate(nodeTemplate)) {
392 substitutableNodeTemplates.put(nodeTemplateId, nodeTemplate);
395 return substitutableNodeTemplates;
399 public Optional<Map.Entry<String, NodeTemplate>> getSubstitutionMappedNodeTemplateByExposedReq(String substituteServiceTemplateFileName,
400 ServiceTemplate substituteServiceTemplate,
401 String requirementId) {
402 if (isSubstitutionServiceTemplate(substituteServiceTemplateFileName, substituteServiceTemplate)) {
403 Map<String, List<String>> substitutionMappingRequirements = substituteServiceTemplate.getTopology_template().getSubstitution_mappings()
405 if (substitutionMappingRequirements != null) {
406 List<String> requirementMapping = substitutionMappingRequirements.get(requirementId);
407 if (requirementMapping != null && !requirementMapping.isEmpty()) {
408 String mappedNodeTemplateId = requirementMapping.get(0);
409 Optional<NodeTemplate> mappedNodeTemplate = getNodeTemplateById(substituteServiceTemplate, mappedNodeTemplateId);
410 if (mappedNodeTemplate.isPresent()) {
411 final NodeTemplate nodeTemplate = mappedNodeTemplate.get();
412 return Optional.of(new HashMap.Entry<>() {
414 public String getKey() {
415 return mappedNodeTemplateId;
418 public NodeTemplate getValue() {
422 public NodeTemplate setValue(final NodeTemplate nodeTemplate) {
427 throw new CoreException(new ToscaInvalidEntryNotFoundErrorBuilder("Node Template", mappedNodeTemplateId).build());
432 return Optional.empty();
436 match only for the input which is not null
439 public boolean isDesiredRequirementAssignment(RequirementAssignment requirementAssignment, String capability, String node, String relationship) {
440 if (isSameCapability(requirementAssignment, capability)) {
443 if (isSameRequirement(requirementAssignment, node)) {
446 if (isSameRelationship(requirementAssignment, relationship)) {
449 return !(capability == null && node == null && relationship == null);
452 private boolean isSameRelationship(RequirementAssignment requirementAssignment, String relationship) {
453 return relationship != null && (requirementAssignment.getRelationship() == null || !requirementAssignment.getRelationship()
454 .equals(relationship));
457 private boolean isSameRequirement(RequirementAssignment requirementAssignment, String node) {
458 return node != null && (requirementAssignment.getNode() == null || !requirementAssignment.getNode().equals(node));
461 private boolean isSameCapability(RequirementAssignment requirementAssignment, String capability) {
462 return capability != null && (requirementAssignment.getCapability() == null || !requirementAssignment.getCapability().equals(capability));
466 public ToscaFlatData getFlatEntity(ToscaElementTypes elementType, String typeId, ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel) {
467 ToscaFlatData flatData = new ToscaFlatData();
468 flatData.setElementType(elementType);
469 switch (elementType) {
470 case CAPABILITY_TYPE:
471 flatData.setFlatEntity(new CapabilityType());
474 flatData.setFlatEntity(new NodeType());
477 flatData.setFlatEntity(new DataType());
480 throw new SdcRuntimeException("Entity[" + elementType + "] id[" + typeId + "] flat not supported");
482 boolean isEntityFound = scanAnFlatEntity(elementType, typeId, flatData, serviceTemplate, toscaModel, new ArrayList<>(), 0);
483 if (!isEntityFound) {
484 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
490 public boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
491 return nodeTemplate.getDirectives() != null && nodeTemplate.getDirectives().contains(ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
494 private <T> Optional<Boolean> isTypeExistInServiceTemplateHierarchy(String typeToMatch, String typeToSearch, String getTypesMethodName,
495 ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel,
496 Set<String> analyzedImportFiles)
497 throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
498 Map<String, T> searchableTypes = (Map<String, T>) serviceTemplate.getClass().getMethod(getTypesMethodName).invoke(serviceTemplate);
499 if (!MapUtils.isEmpty(searchableTypes)) {
500 T typeObject = searchableTypes.get(typeToSearch);
501 if (Objects.nonNull(typeObject)) {
502 String derivedFromTypeVal = (String) typeObject.getClass().getMethod(GET_DERIVED_FROM_METHOD_NAME).invoke(typeObject);
503 if (Objects.equals(derivedFromTypeVal, typeToMatch)) {
504 return Optional.of(true);
505 } else if (Objects.isNull(derivedFromTypeVal) || isTypeIsToscaRoot(derivedFromTypeVal)) {
506 return Optional.of(false);
508 return isTypeExistInServiceTemplateHierarchy(typeToMatch, derivedFromTypeVal, getTypesMethodName, serviceTemplate,
509 toscaServiceModel, null);
512 return isTypeExistInImports(typeToMatch, typeToSearch, getTypesMethodName, serviceTemplate, toscaServiceModel, analyzedImportFiles);
515 return isTypeExistInImports(typeToMatch, typeToSearch, getTypesMethodName, serviceTemplate, toscaServiceModel, analyzedImportFiles);
518 private Optional<Boolean> isTypeExistInImports(String typeToMatch, String typeToSearch, String getTypesMethodName,
519 ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel, Set<String> filesScanned)
520 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
521 List<Map<String, Import>> imports = serviceTemplate.getImports();
522 if (CollectionUtils.isEmpty(imports)) {
523 return Optional.empty();
525 Set<String> createdFilesScanned = createFilesScannedSet(filesScanned);
526 for (Map<String, Import> map : imports) {
527 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
528 Import anImport = toscaExtensionYamlUtil.yamlToObject(toscaExtensionYamlUtil.objectToYaml(map.values().iterator().next()), Import.class);
529 handleImportWithNoFileEntry(anImport);
530 String importFile = anImport.getFile();
531 ServiceTemplate template = toscaServiceModel.getServiceTemplates().get(
532 fetchFullFileNameForImport(importFile, serviceTemplate.getMetadata() == null ? null : serviceTemplate.getMetadata().get("filename"),
533 serviceTemplate, toscaServiceModel));
534 if (Objects.isNull(template) || createdFilesScanned.contains(ToscaUtil.getServiceTemplateFileName(template))) {
537 createdFilesScanned.add(ToscaUtil.getServiceTemplateFileName(template));
539 Optional<Boolean> typeExistInServiceTemplateHierarchy = isTypeExistInServiceTemplateHierarchy(typeToMatch, typeToSearch,
540 getTypesMethodName, template, toscaServiceModel, createdFilesScanned);
541 if (typeExistInServiceTemplateHierarchy.isPresent() && (typeExistInServiceTemplateHierarchy.get())) {
542 createdFilesScanned.clear();
543 return Optional.of(true);
546 return Optional.of(false);
549 private void handleImportWithNoFileEntry(Import anImport) {
550 if (Objects.isNull(anImport) || Objects.isNull(anImport.getFile())) {
551 throw new SdcRuntimeException("import without file entry");
555 private Set<String> createFilesScannedSet(Set<String> filesScanned) {
556 Set<String> retFileScanned = filesScanned;
557 if (Objects.isNull(retFileScanned)) {
558 retFileScanned = new HashSet<>();
560 return retFileScanned;
563 private boolean isTypeIsToscaRoot(String type) {
564 return (type.contains(TOSCA_DOT) && type.contains(DOT_ROOT));
567 private boolean isSubstitutionServiceTemplate(String substituteServiceTemplateFileName, ServiceTemplate substituteServiceTemplate) {
568 if (substituteServiceTemplate != null && substituteServiceTemplate.getTopology_template() != null
569 && substituteServiceTemplate.getTopology_template().getSubstitution_mappings() != null) {
570 if (substituteServiceTemplate.getTopology_template().getSubstitution_mappings().getNode_type() == null) {
571 throw new CoreException(new ToscaInvalidSubstitutionServiceTemplateErrorBuilder(substituteServiceTemplateFileName).build());
578 private boolean scanAnFlatEntity(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData, ServiceTemplate serviceTemplate,
579 ToscaServiceModel toscaModel, List<String> filesScanned, int rootScanStartInx) {
580 boolean entityFound = enrichEntityFromCurrentServiceTemplate(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned,
583 List<Map<String, Import>> imports = serviceTemplate.getImports();
584 if (CollectionUtils.isEmpty(imports)) {
587 boolean found = false;
588 for (Map<String, Import> importMap : imports) {
592 found = isFlatEntity(importMap, flatData, serviceTemplate, filesScanned, toscaModel, elementType, typeId);
599 private boolean isFlatEntity(Map<String, Import> importMap, ToscaFlatData flatData, ServiceTemplate serviceTemplate, List<String> filesScanned,
600 ToscaServiceModel toscaModel, ToscaElementTypes elementType, String typeId) {
601 boolean found = false;
602 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
603 for (Object importObject : importMap.values()) {
604 Import importServiceTemplate = toscaExtensionYamlUtil.yamlToObject(toscaExtensionYamlUtil.objectToYaml(importObject), Import.class);
605 String fileName = fetchFullFileNameForImport(importServiceTemplate.getFile(),
606 serviceTemplate.getMetadata() == null ? null : serviceTemplate.getMetadata().get("filename"), serviceTemplate, toscaModel);
607 if (filesScanned.contains(fileName)) {
610 filesScanned.add(fileName);
612 ServiceTemplate template = toscaModel.getServiceTemplates().get(fileName);
613 if (Objects.isNull(template)) {
614 throw new CoreException(new ToscaFileNotFoundErrorBuilder(fileName).build());
616 found = scanAnFlatEntity(elementType, typeId, flatData, template, toscaModel, filesScanned, filesScanned.size());
621 String fetchFullFileNameForImport(String importServiceTemplateFile, String currentMetadatafileName, ServiceTemplate serviceTemplate,
622 ToscaServiceModel toscaServiceModel) {
623 Optional<Map.Entry<String, ServiceTemplate>> serviceTemplateEntry = toscaServiceModel.getServiceTemplates().entrySet().stream()
624 .filter(entry -> entry.getValue() == serviceTemplate).findFirst();
625 if (!serviceTemplateEntry.isPresent()) {
626 if (importServiceTemplateFile.contains("../")) {
627 return importServiceTemplateFile.replace("../", "");
628 } else if (currentMetadatafileName != null && currentMetadatafileName.indexOf('/') != -1) {
629 return currentMetadatafileName.substring(0, currentMetadatafileName.indexOf('/')) + "/" + importServiceTemplateFile;
631 return importServiceTemplateFile;
634 Path currentPath = Paths.get(serviceTemplateEntry.get().getKey()).getParent();
635 if (currentPath == null) {
636 currentPath = Paths.get("");
638 return currentPath.resolve(importServiceTemplateFile).normalize().toString().replaceAll("\\\\", "/");
641 private boolean enrichEntityFromCurrentServiceTemplate(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
642 ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel, List<String> filesScanned,
643 int rootScanStartInx) {
644 switch (elementType) {
645 case CAPABILITY_TYPE:
646 if (enrichCapabilityType(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned, rootScanStartInx)) {
651 if (enrichNodeTypeInfo(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned, rootScanStartInx)) {
656 if (enrichDataTypeInfo(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned, rootScanStartInx)) {
661 throw new SdcRuntimeException("Entity[" + elementType + "] id[" + typeId + "] flat not supported");
666 private boolean enrichNodeTypeInfo(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData, ServiceTemplate serviceTemplate,
667 ToscaServiceModel toscaModel, List<String> filesScanned, int rootScanStartInx) {
669 if (serviceTemplate.getNode_types() != null && serviceTemplate.getNode_types().containsKey(typeId)) {
670 filesScanned.clear();
671 flatData.addInheritanceHierarchyType(typeId);
672 NodeType targetNodeType = (NodeType) flatData.getFlatEntity();
673 NodeType sourceNodeType = serviceTemplate.getNode_types().get(typeId);
674 derivedFrom = sourceNodeType.getDerived_from();
675 if (derivedFrom != null) {
676 boolean isEntityFound = scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
678 if (!isEntityFound) {
679 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
682 combineNodeTypeInfo(sourceNodeType, targetNodeType);
689 private boolean enrichDataTypeInfo(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData, ServiceTemplate serviceTemplate,
690 ToscaServiceModel toscaModel, List<String> filesScanned, int rootScanStartInx) {
692 if (serviceTemplate.getData_types() != null && serviceTemplate.getData_types().containsKey(typeId)) {
693 filesScanned.clear();
694 flatData.addInheritanceHierarchyType(typeId);
695 DataType targetDataType = (DataType) flatData.getFlatEntity();
696 DataType sourceDataType = serviceTemplate.getData_types().get(typeId);
697 derivedFrom = sourceDataType.getDerived_from();
698 if (derivedFrom != null && !isPrimitiveType(derivedFrom)) {
699 boolean isEntityFound = scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
701 if (!isEntityFound) {
702 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
705 combineDataTypeInfo(sourceDataType, targetDataType);
712 private boolean enrichCapabilityType(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData, ServiceTemplate serviceTemplate,
713 ToscaServiceModel toscaModel, List<String> filesScanned, int rootScanStartInx) {
715 if (serviceTemplate.getCapability_types() != null && serviceTemplate.getCapability_types().containsKey(typeId)) {
716 filesScanned.clear();
717 flatData.addInheritanceHierarchyType(typeId);
718 CapabilityType targetCapabilityType = (CapabilityType) flatData.getFlatEntity();
719 CapabilityType sourceCapabilityType = serviceTemplate.getCapability_types().get(typeId);
720 derivedFrom = sourceCapabilityType.getDerived_from();
721 if (derivedFrom != null) {
722 boolean isEntityFound = scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
724 if (!isEntityFound) {
725 throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
728 combineCapabilityTypeInfo(sourceCapabilityType, targetCapabilityType);
735 private void combineNodeTypeInfo(NodeType sourceNodeType, NodeType targetNodeType) {
736 targetNodeType.setDerived_from(sourceNodeType.getDerived_from());
737 targetNodeType.setDescription(sourceNodeType.getDescription());
738 targetNodeType.setVersion(sourceNodeType.getVersion());
739 targetNodeType.setProperties(CommonMethods.mergeMaps(targetNodeType.getProperties(), sourceNodeType.getProperties()));
740 combineNodeTypeInterfaceInfo(sourceNodeType, targetNodeType);
741 targetNodeType.setArtifacts(CommonMethods.mergeMaps(targetNodeType.getArtifacts(), sourceNodeType.getArtifacts()));
742 targetNodeType.setAttributes(CommonMethods.mergeMaps(targetNodeType.getAttributes(), sourceNodeType.getAttributes()));
743 targetNodeType.setCapabilities(CommonMethods.mergeMaps(targetNodeType.getCapabilities(), sourceNodeType.getCapabilities()));
744 targetNodeType.setRequirements(CommonMethods.mergeListsOfMap(targetNodeType.getRequirements(), sourceNodeType.getRequirements()));
747 private void combineNodeTypeInterfaceInfo(NodeType sourceNodeType, NodeType targetNodeType) {
748 Optional<Map<String, Object>> interfaceNoMerge = combineInterfaceNoMerge(sourceNodeType, targetNodeType);
749 if (interfaceNoMerge.isPresent()) {
750 targetNodeType.setInterfaces(interfaceNoMerge.get());
753 combineInterfaces(sourceNodeType, targetNodeType).ifPresent(targetNodeType::setInterfaces);
756 private Optional<Map<String, Object>> combineInterfaces(NodeType sourceNodeType, NodeType targetNodeType) {
757 if (MapUtils.isEmpty(sourceNodeType.getInterfaces())) {
758 return Optional.empty();
760 Map<String, Object> combineInterfaces = new HashMap<>();
761 for (Map.Entry<String, Object> sourceInterfaceDefEntry : sourceNodeType.getInterfaces().entrySet()) {
762 String interfaceName = sourceInterfaceDefEntry.getKey();
763 if (!MapUtils.isEmpty(targetNodeType.getInterfaces()) && targetNodeType.getInterfaces().containsKey(interfaceName)) {
764 combineInterfaces.put(interfaceName,
765 combineInterfaceDefinition(sourceInterfaceDefEntry.getValue(), targetNodeType.getInterfaces().get(interfaceName)));
767 combineInterfaces.put(sourceInterfaceDefEntry.getKey(), sourceInterfaceDefEntry.getValue());
770 for (Map.Entry<String, Object> targetInterfaceDefEntry : targetNodeType.getInterfaces().entrySet()) {
771 String interfaceName = targetInterfaceDefEntry.getKey();
772 if (!sourceNodeType.getInterfaces().containsKey(interfaceName)) {
773 combineInterfaces.put(targetInterfaceDefEntry.getKey(), targetInterfaceDefEntry.getValue());
776 return Optional.of(combineInterfaces);
779 private Optional<Map<String, Object>> combineInterfaceNoMerge(NodeType sourceNodeType, NodeType targetNodeType) {
780 if ((MapUtils.isEmpty(sourceNodeType.getInterfaces()) && MapUtils.isEmpty(targetNodeType.getInterfaces()))) {
781 return Optional.empty();
783 if (MapUtils.isEmpty(sourceNodeType.getInterfaces()) && !MapUtils.isEmpty(targetNodeType.getInterfaces())) {
784 return Optional.of(targetNodeType.getInterfaces());
786 if (!MapUtils.isEmpty(sourceNodeType.getInterfaces()) && MapUtils.isEmpty(targetNodeType.getInterfaces())) {
787 return Optional.of(sourceNodeType.getInterfaces());
789 return Optional.empty();
792 private Object combineInterfaceDefinition(Object sourceInterfaceDefType, Object targetInterfaceDefType) {
793 InterfaceDefinitionType sourceInterface = new InterfaceDefinitionType(sourceInterfaceDefType);
794 InterfaceDefinitionType targetInterface = new InterfaceDefinitionType(targetInterfaceDefType);
795 InterfaceDefinitionType combineInterface = new InterfaceDefinitionType();
796 combineInterface.setType(sourceInterface.getType());
797 combineInterface.setInputs(CommonMethods.mergeMaps(targetInterface.getInputs(), sourceInterface.getInputs()));
798 combineInterface.setOperations(CommonMethods.mergeMaps(targetInterface.getOperations(), sourceInterface.getOperations()));
799 Optional<Object> interfaceDefObject = combineInterface.convertInterfaceDefinitionTypeToToscaObj();
800 if (!interfaceDefObject.isPresent()) {
801 throw new SdcRuntimeException("Illegal Statement");
803 return interfaceDefObject.get();
806 private void combineDataTypeInfo(DataType sourceDataType, DataType targetDataType) {
807 targetDataType.setDerived_from(sourceDataType.getDerived_from());
808 targetDataType.setDescription(sourceDataType.getDescription());
809 targetDataType.setVersion(sourceDataType.getVersion());
810 targetDataType.setProperties(CommonMethods.mergeMaps(targetDataType.getProperties(), sourceDataType.getProperties()));
811 targetDataType.setConstraints(CommonMethods.mergeLists(targetDataType.getConstraints(), sourceDataType.getConstraints()));
814 private void combineCapabilityTypeInfo(CapabilityType sourceCapabilityType, CapabilityType targetCapabilityType) {
815 targetCapabilityType.setAttributes(CommonMethods.mergeMaps(targetCapabilityType.getAttributes(), sourceCapabilityType.getAttributes()));
816 targetCapabilityType.setProperties(CommonMethods.mergeMaps(targetCapabilityType.getProperties(), sourceCapabilityType.getProperties()));
817 targetCapabilityType.setValid_source_types(
818 CommonMethods.mergeLists(targetCapabilityType.getValid_source_types(), sourceCapabilityType.getValid_source_types()));
819 if (StringUtils.isNotEmpty(sourceCapabilityType.getDerived_from())) {
820 targetCapabilityType.setDerived_from(sourceCapabilityType.getDerived_from());
822 if (StringUtils.isNotEmpty(sourceCapabilityType.getDescription())) {
823 targetCapabilityType.setDescription(sourceCapabilityType.getDescription());
825 if (StringUtils.isNotEmpty(sourceCapabilityType.getVersion())) {
826 targetCapabilityType.setVersion(sourceCapabilityType.getVersion());
831 * Create node type according to the input substitution service template, while the substitution
832 * service template can be mappted to this node type, for substitution mapping.
834 * @param substitutionServiceTemplate substitution serivce template
835 * @param nodeTypeDerivedFromValue derived from value for the created node type
836 * @return the node type
839 public NodeType createInitSubstitutionNodeType(ServiceTemplate substitutionServiceTemplate, String nodeTypeDerivedFromValue) {
840 NodeType substitutionNodeType = new NodeType();
841 substitutionNodeType.setDerived_from(nodeTypeDerivedFromValue);
842 substitutionNodeType.setDescription(substitutionServiceTemplate.getDescription());
843 substitutionNodeType.setProperties(manageSubstitutionNodeTypeProperties(substitutionServiceTemplate));
844 substitutionNodeType.setAttributes(manageSubstitutionNodeTypeAttributes(substitutionServiceTemplate));
845 return substitutionNodeType;
849 public Map<String, PropertyDefinition> manageSubstitutionNodeTypeProperties(ServiceTemplate substitutionServiceTemplate) {
850 Map<String, PropertyDefinition> substitutionNodeTypeProperties = new HashMap<>();
851 Map<String, ParameterDefinition> properties = substitutionServiceTemplate.getTopology_template().getInputs();
852 if (properties == null) {
855 PropertyDefinition propertyDefinition;
856 String toscaPropertyName;
857 for (Map.Entry<String, ParameterDefinition> entry : properties.entrySet()) {
858 toscaPropertyName = entry.getKey();
859 propertyDefinition = new PropertyDefinition();
860 ParameterDefinition parameterDefinition = substitutionServiceTemplate.getTopology_template().getInputs().get(toscaPropertyName);
861 propertyDefinition.setType(parameterDefinition.getType());
862 propertyDefinition.setDescription(parameterDefinition.getDescription());
863 propertyDefinition.set_default(parameterDefinition.get_default());
864 if (parameterDefinition.getRequired() != null) {
865 propertyDefinition.setRequired(parameterDefinition.getRequired());
867 if (propertyDefinition.get_default() != null) {
868 propertyDefinition.setRequired(false);
870 if (!CollectionUtils.isEmpty(parameterDefinition.getConstraints())) {
871 propertyDefinition.setConstraints(parameterDefinition.getConstraints());
873 propertyDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
874 if (parameterDefinition.getStatus() != null) {
875 propertyDefinition.setStatus(parameterDefinition.getStatus());
877 substitutionNodeTypeProperties.put(toscaPropertyName, propertyDefinition);
879 return substitutionNodeTypeProperties;
882 private Map<String, AttributeDefinition> manageSubstitutionNodeTypeAttributes(ServiceTemplate substitutionServiceTemplate) {
883 Map<String, AttributeDefinition> substitutionNodeTypeAttributes = new HashMap<>();
884 Map<String, ParameterDefinition> attributes = substitutionServiceTemplate.getTopology_template().getOutputs();
885 if (attributes == null) {
888 AttributeDefinition attributeDefinition;
889 String toscaAttributeName;
890 for (Map.Entry<String, ParameterDefinition> entry : attributes.entrySet()) {
891 attributeDefinition = new AttributeDefinition();
892 toscaAttributeName = entry.getKey();
893 ParameterDefinition parameterDefinition = substitutionServiceTemplate.getTopology_template().getOutputs().get(toscaAttributeName);
894 if (parameterDefinition.getType() != null && !parameterDefinition.getType().isEmpty()) {
895 attributeDefinition.setType(parameterDefinition.getType());
897 attributeDefinition.setType(PropertyType.STRING.getDisplayName());
899 attributeDefinition.setDescription(parameterDefinition.getDescription());
900 attributeDefinition.set_default(parameterDefinition.get_default());
901 attributeDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
902 if (Objects.nonNull(parameterDefinition.getStatus())) {
903 attributeDefinition.setStatus(parameterDefinition.getStatus());
905 substitutionNodeTypeAttributes.put(toscaAttributeName, attributeDefinition);
907 return substitutionNodeTypeAttributes;
911 * Checks if the requirement exists in the node template.
913 * @param nodeTemplate the node template
914 * @param requirementId the requirement id
915 * @param requirementAssignment the requirement assignment
916 * @return true if the requirement already exists and false otherwise
919 public boolean isRequirementExistInNodeTemplate(NodeTemplate nodeTemplate, String requirementId, RequirementAssignment requirementAssignment) {
920 List<Map<String, RequirementAssignment>> nodeTemplateRequirements = nodeTemplate.getRequirements();
921 return nodeTemplateRequirements != null && nodeTemplateRequirements.stream().anyMatch(
922 requirement -> requirement.containsKey(requirementId) && DataModelUtil
923 .compareRequirementAssignment(requirementAssignment, requirement.get(requirementId)));
926 private <T> boolean isTypeOf(T object, String type, String getTypesMethodName, ServiceTemplate serviceTemplate,
927 ToscaServiceModel toscaServiceModel) {
928 if (object == null) {
932 String objectType = (String) object.getClass().getMethod(GET_TYPE_METHOD_NAME).invoke(object);
933 if (Objects.equals(objectType, type)) {
936 Optional<Boolean> typeExistInServiceTemplateHierarchy = isTypeExistInServiceTemplateHierarchy(type, objectType, getTypesMethodName,
937 serviceTemplate, toscaServiceModel, null);
938 return typeExistInServiceTemplateHierarchy
939 .orElseThrow(() -> new CoreException(new ToscaElementTypeNotFoundErrorBuilder(objectType).build()));
940 } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
941 throw new SdcRuntimeException(e);