2d0d3fb59c936558d1af8fae18b1a000d48531c9
[sdc.git] /
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package org.openecomp.sdc.tosca.services.impl;
18
19 import org.apache.commons.collections4.CollectionUtils;
20 import org.apache.commons.collections4.MapUtils;
21 import org.apache.commons.lang3.StringUtils;
22 import org.onap.sdc.tosca.datatypes.model.*;
23 import org.onap.sdc.tosca.services.ToscaExtensionYamlUtil;
24 import org.openecomp.core.utilities.CommonMethods;
25 import org.openecomp.sdc.common.errors.CoreException;
26 import org.openecomp.sdc.common.errors.SdcRuntimeException;
27 import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes;
28 import org.openecomp.sdc.tosca.datatypes.ToscaFlatData;
29 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
30 import org.openecomp.sdc.tosca.errors.*;
31 import org.openecomp.sdc.tosca.services.DataModelUtil;
32 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
33 import org.openecomp.sdc.tosca.services.ToscaConstants;
34 import org.openecomp.sdc.tosca.services.ToscaUtil;
35
36 import java.lang.reflect.InvocationTargetException;
37 import java.util.*;
38
39 public class ToscaAnalyzerServiceImpl implements ToscaAnalyzerService {
40
41     private static final String GET_NODE_TYPE_METHOD_NAME = "getNode_types";
42     private static final String GET_DERIVED_FROM_METHOD_NAME = "getDerived_from";
43     private static final String GET_TYPE_METHOD_NAME = "getType";
44     private static final String GET_DATA_TYPE_METHOD_NAME = "getData_types";
45     private static final String GET_INTERFACE_TYPE_METHOD_NAME = "getInterface_types";
46     private static final String GET_CAPABILITY_TYPE_METHOD_NAME = "getCapability_types";
47     private static final String TOSCA_DOT = "tosca.";
48     private static final String DOT_ROOT = ".Root";
49
50     @Override
51     public List<Map<String, RequirementDefinition>> calculateExposedRequirements(List<Map<String, RequirementDefinition>> nodeTypeRequirementsDefinitionList,
52                                                                                         Map<String, RequirementAssignment> nodeTemplateRequirementsAssignment) {
53
54         if (nodeTypeRequirementsDefinitionList == null) {
55             return Collections.emptyList();
56         }
57         for (Map.Entry<String, RequirementAssignment> entry : nodeTemplateRequirementsAssignment.entrySet()) {
58             if (entry.getValue().getNode() != null) {
59                 Optional<RequirementDefinition> requirementDefinition =
60                         DataModelUtil.getRequirementDefinition(nodeTypeRequirementsDefinitionList, entry.getKey());
61                 RequirementDefinition cloneRequirementDefinition;
62                 if (requirementDefinition.isPresent()) {
63                     cloneRequirementDefinition = requirementDefinition.get().clone();
64                     updateRequirementDefinition(nodeTypeRequirementsDefinitionList, entry, cloneRequirementDefinition);
65                 }
66             } else {
67                 for (Map<String, RequirementDefinition> nodeTypeRequirementsMap : nodeTypeRequirementsDefinitionList) {
68                     updateMinMaxOccurencesForNodeTypeRequirement(entry, nodeTypeRequirementsMap);
69                 }
70             }
71         }
72         return nodeTypeRequirementsDefinitionList;
73     }
74
75     private void updateMinMaxOccurencesForNodeTypeRequirement(Map.Entry<String, RequirementAssignment> entry,
76                                                                      Map<String, RequirementDefinition> nodeTypeRequirementsMap) {
77         Object max = nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences() != null
78                              && nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences().length > 0 ?
79                              nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences()[1] : 1;
80         Object min = nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences() != null
81                              && nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences().length > 0 ?
82                              nodeTypeRequirementsMap.get(entry.getKey()).getOccurrences()[0] : 1;
83         nodeTypeRequirementsMap.get(entry.getKey()).setOccurrences(new Object[] {min, max});
84     }
85
86     private void updateRequirementDefinition(List<Map<String, RequirementDefinition>> nodeTypeRequirementsDefinitionList,
87                                                     Map.Entry<String, RequirementAssignment> entry,
88                                                     RequirementDefinition cloneRequirementDefinition) {
89         if (!evaluateRequirementFulfillment(cloneRequirementDefinition)) {
90             CommonMethods
91                     .mergeEntryInList(entry.getKey(), cloneRequirementDefinition, nodeTypeRequirementsDefinitionList);
92         } else {
93             DataModelUtil.removeRequirementsDefinition(nodeTypeRequirementsDefinitionList, entry.getKey());
94         }
95     }
96
97     private static boolean evaluateRequirementFulfillment(RequirementDefinition requirementDefinition) {
98         Object[] occurrences = requirementDefinition.getOccurrences();
99         if (occurrences == null) {
100             requirementDefinition.setOccurrences(new Object[] {1, 1});
101             return false;
102         }
103         if (occurrences[1].equals(ToscaConstants.UNBOUNDED)) {
104             return false;
105         }
106
107         if (occurrences[1].equals(1)) {
108             return true;
109         }
110         occurrences[1] = (Integer) occurrences[1] - 1;
111         return false;
112     }
113
114     @Override
115     public Map<String, CapabilityDefinition> calculateExposedCapabilities(Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition,
116                                                                                  Map<String, Map<String, RequirementAssignment>> fullFilledRequirementsDefinitionMap) {
117
118         String capabilityKey;
119         String capability;
120         String node;
121         for (Map.Entry<String, Map<String, RequirementAssignment>> entry : fullFilledRequirementsDefinitionMap
122                                                                                    .entrySet()) {
123             for (Map.Entry<String, RequirementAssignment> fullFilledEntry : entry.getValue().entrySet()) {
124
125                 capability = fullFilledEntry.getValue().getCapability();
126                 node = fullFilledEntry.getValue().getNode();
127                 capabilityKey = capability + "_" + node;
128                 CapabilityDefinition capabilityDefinition = nodeTypeCapabilitiesDefinition.get(capabilityKey);
129                 if (capabilityDefinition != null) {
130                     CapabilityDefinition clonedCapabilityDefinition = capabilityDefinition.clone();
131                     nodeTypeCapabilitiesDefinition.put(capabilityKey, capabilityDefinition.clone());
132                     updateNodeTypeCapabilitiesDefinition(nodeTypeCapabilitiesDefinition, capabilityKey,
133                             clonedCapabilityDefinition);
134                 }
135             }
136         }
137
138         Map<String, CapabilityDefinition> exposedCapabilitiesDefinition = new HashMap<>();
139         for (Map.Entry<String, CapabilityDefinition> entry : nodeTypeCapabilitiesDefinition.entrySet()) {
140             exposedCapabilitiesDefinition.put(entry.getKey(), entry.getValue());
141         }
142         return exposedCapabilitiesDefinition;
143     }
144
145     private void updateNodeTypeCapabilitiesDefinition(Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition,
146                                                              String capabilityKey,
147                                                              CapabilityDefinition clonedCapabilityDefinition) {
148         if (evaluateCapabilityFulfillment(clonedCapabilityDefinition)) {
149             nodeTypeCapabilitiesDefinition.remove(capabilityKey);
150         } else {
151             nodeTypeCapabilitiesDefinition.put(capabilityKey, clonedCapabilityDefinition);
152         }
153     }
154
155     private static boolean evaluateCapabilityFulfillment(CapabilityDefinition capabilityDefinition) {
156
157         Object[] occurrences = capabilityDefinition.getOccurrences();
158         if (occurrences == null) {
159             capabilityDefinition.setOccurrences(new Object[] {1, ToscaConstants.UNBOUNDED});
160             return false;
161         }
162         if (occurrences[1].equals(ToscaConstants.UNBOUNDED)) {
163             return false;
164         }
165
166         if (occurrences[1].equals(1)) {
167             return true;
168         }
169         occurrences[1] = (Integer) occurrences[1] - 1;
170         return false;
171     }
172
173     /*
174       node template with type equal to node type or derived from node type
175        */
176     @Override
177     public Map<String, NodeTemplate> getNodeTemplatesByType(ServiceTemplate serviceTemplate, String nodeType,
178                                                                    ToscaServiceModel toscaServiceModel) {
179         Map<String, NodeTemplate> nodeTemplates = new HashMap<>();
180
181         if (Objects.nonNull(serviceTemplate.getTopology_template()) && MapUtils.isNotEmpty(
182                 serviceTemplate.getTopology_template().getNode_templates())) {
183             for (Map.Entry<String, NodeTemplate> nodeTemplateEntry : serviceTemplate.getTopology_template()
184                                                                                     .getNode_templates().entrySet()) {
185                 if (isTypeOf(nodeTemplateEntry.getValue(), nodeType, serviceTemplate, toscaServiceModel)) {
186                     nodeTemplates.put(nodeTemplateEntry.getKey(), nodeTemplateEntry.getValue());
187                 }
188
189             }
190         }
191         return nodeTemplates;
192     }
193
194     @Override
195     public Optional<NodeType> fetchNodeType(String nodeTypeKey, Collection<ServiceTemplate> serviceTemplates) {
196         Optional<Map<String, NodeType>> nodeTypeMap = serviceTemplates.stream().map(ServiceTemplate::getNode_types)
197                                                                       .filter(nodeTypes -> Objects.nonNull(nodeTypes)
198                                                                                                    && nodeTypes
199                                                                                                               .containsKey(
200                                                                                                                       nodeTypeKey))
201                                                                       .findFirst();
202         return nodeTypeMap.map(stringNodeTypeMap -> stringNodeTypeMap.get(nodeTypeKey));
203     }
204
205     @Override
206     public boolean isTypeOf(NodeTemplate nodeTemplate, String nodeType, ServiceTemplate serviceTemplate,
207                                    ToscaServiceModel toscaServiceModel) {
208         return isTypeOf(nodeTemplate, nodeType, GET_NODE_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
209     }
210
211     @Override
212     public List<RequirementAssignment> getRequirements(NodeTemplate nodeTemplate, String requirementId) {
213         List<RequirementAssignment> requirements = new ArrayList<>();
214         List<Map<String, RequirementAssignment>> requirementList = nodeTemplate.getRequirements();
215         if (requirementList != null) {
216             requirementList.stream().filter(reqMap -> reqMap.get(requirementId) != null).forEach(reqMap -> {
217                 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
218                 RequirementAssignment reqAssignment = toscaExtensionYamlUtil.yamlToObject(
219                         toscaExtensionYamlUtil.objectToYaml(reqMap.get(requirementId)), RequirementAssignment.class);
220                 requirements.add(reqAssignment);
221             });
222         }
223         return requirements;
224     }
225
226     @Override
227     public Optional<NodeTemplate> getNodeTemplateById(ServiceTemplate serviceTemplate, String nodeTemplateId) {
228         if ((serviceTemplate.getTopology_template() != null) && (serviceTemplate.getTopology_template()
229                                                                                 .getNode_templates() != null)
230                     && (serviceTemplate.getTopology_template().getNode_templates().get(nodeTemplateId) != null)) {
231             return Optional.of(serviceTemplate.getTopology_template().getNode_templates().get(nodeTemplateId));
232         }
233         return Optional.empty();
234     }
235
236     @Override
237     public Optional<String> getSubstituteServiceTemplateName(String substituteNodeTemplateId,
238                                                                     NodeTemplate substitutableNodeTemplate) {
239         if (!isSubstitutableNodeTemplate(substitutableNodeTemplate)) {
240             return Optional.empty();
241         }
242
243         if (substitutableNodeTemplate.getProperties() != null &&
244                     substitutableNodeTemplate.getProperties().get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME)
245                             != null) {
246             Object serviceTemplateFilter =
247                     substitutableNodeTemplate.getProperties().get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
248             if (serviceTemplateFilter instanceof Map) {
249                 Object substituteServiceTemplate =
250                         ((Map) serviceTemplateFilter).get(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME);
251                 handleNoSubstituteServiceTemplate(substituteNodeTemplateId, substituteServiceTemplate);
252                 return Optional.of(substituteServiceTemplate.toString());
253             }
254         }
255         throw new CoreException(new ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder(substituteNodeTemplateId)
256                                         .build());
257     }
258
259     private void handleNoSubstituteServiceTemplate(String substituteNodeTemplateId, Object substituteServiceTemplate) {
260         if (substituteServiceTemplate == null) {
261             throw new CoreException(new ToscaInvalidSubstituteNodeTemplatePropertiesErrorBuilder(substituteNodeTemplateId)
262                                             .build());
263         }
264     }
265
266     @Override
267     public Map<String, NodeTemplate> getSubstitutableNodeTemplates(ServiceTemplate serviceTemplate) {
268         Map<String, NodeTemplate> substitutableNodeTemplates = new HashMap<>();
269
270         if (serviceTemplate == null || serviceTemplate.getTopology_template() == null
271                     || serviceTemplate.getTopology_template().getNode_templates() == null) {
272             return substitutableNodeTemplates;
273         }
274
275         Map<String, NodeTemplate> nodeTemplates = serviceTemplate.getTopology_template().getNode_templates();
276         for (Map.Entry<String, NodeTemplate> entry : nodeTemplates.entrySet()) {
277             String nodeTemplateId = entry.getKey();
278             NodeTemplate nodeTemplate = entry.getValue();
279             if (isSubstitutableNodeTemplate(nodeTemplate)) {
280                 substitutableNodeTemplates.put(nodeTemplateId, nodeTemplate);
281             }
282         }
283
284         return substitutableNodeTemplates;
285     }
286
287     @Override
288     public Optional<Map.Entry<String, NodeTemplate>> getSubstitutionMappedNodeTemplateByExposedReq(String substituteServiceTemplateFileName,
289                                                                                                           ServiceTemplate substituteServiceTemplate,
290                                                                                                           String requirementId) {
291         if (isSubstitutionServiceTemplate(substituteServiceTemplateFileName, substituteServiceTemplate)) {
292             Map<String, List<String>> substitutionMappingRequirements =
293                     substituteServiceTemplate.getTopology_template().getSubstitution_mappings().getRequirements();
294             if (substitutionMappingRequirements != null) {
295                 List<String> requirementMapping = substitutionMappingRequirements.get(requirementId);
296                 if (requirementMapping != null && !requirementMapping.isEmpty()) {
297                     String mappedNodeTemplateId = requirementMapping.get(0);
298                     Optional<NodeTemplate> mappedNodeTemplate =
299                             getNodeTemplateById(substituteServiceTemplate, mappedNodeTemplateId);
300                     mappedNodeTemplate.orElseThrow(
301                             () -> new CoreException(new ToscaInvalidEntryNotFoundErrorBuilder("Node Template",
302                                                                                                      mappedNodeTemplateId)
303                                                             .build()));
304                     Map.Entry<String, NodeTemplate> mappedNodeTemplateEntry = new Map.Entry<String, NodeTemplate>() {
305                         @Override
306                         public String getKey() {
307                             return mappedNodeTemplateId;
308                         }
309
310                         @Override
311                         public NodeTemplate getValue() {
312                             return mappedNodeTemplate.get();
313                         }
314
315                         @Override
316                         public NodeTemplate setValue(NodeTemplate value) {
317                             return null;
318                         }
319                     };
320                     return Optional.of(mappedNodeTemplateEntry);
321                 }
322             }
323         }
324         return Optional.empty();
325     }
326
327     /*
328     match only for the input which is not null
329      */
330     @Override
331     public boolean isDesiredRequirementAssignment(RequirementAssignment requirementAssignment, String capability,
332                                                          String node, String relationship) {
333         if (isSameCapability(requirementAssignment, capability)) {
334             return false;
335         }
336
337         if (isSameRequirement(requirementAssignment, node)) {
338             return false;
339         }
340
341         if (isSameRelationship(requirementAssignment, relationship)) {
342             return false;
343         }
344
345         return !(capability == null && node == null && relationship == null);
346
347     }
348
349     private boolean isSameRelationship(RequirementAssignment requirementAssignment, String relationship) {
350         return relationship != null && (requirementAssignment.getRelationship() == null || !requirementAssignment
351                                                                                                     .getRelationship()
352                                                                                                     .equals(relationship));
353     }
354
355     private boolean isSameRequirement(RequirementAssignment requirementAssignment, String node) {
356         return node != null && (requirementAssignment.getNode() == null || !requirementAssignment.getNode()
357                                                                                                  .equals(node));
358     }
359
360     private boolean isSameCapability(RequirementAssignment requirementAssignment, String capability) {
361         return capability != null && (requirementAssignment.getCapability() == null || !requirementAssignment
362                                                                                                 .getCapability()
363                                                                                                 .equals(capability));
364     }
365
366     @Override
367     public ToscaFlatData getFlatEntity(ToscaElementTypes elementType, String typeId, ServiceTemplate serviceTemplate,
368                                               ToscaServiceModel toscaModel) {
369         ToscaFlatData flatData = new ToscaFlatData();
370         flatData.setElementType(elementType);
371
372         switch (elementType) {
373             case CAPABILITY_TYPE:
374                 flatData.setFlatEntity(new CapabilityType());
375                 break;
376             case NODE_TYPE:
377                 flatData.setFlatEntity(new NodeType());
378                 break;
379             case DATA_TYPE:
380                 flatData.setFlatEntity(new DataType());
381                 break;
382             default:
383                 throw new RuntimeException("Entity[" + elementType + "] id[" + typeId + "] flat not supported");
384         }
385
386         boolean isEntityFound =
387                 scanAnFlatEntity(elementType, typeId, flatData, serviceTemplate, toscaModel, new ArrayList<>(), 0);
388         if (!isEntityFound) {
389             throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
390         }
391
392         return flatData;
393     }
394
395     @Override
396     public boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
397         return nodeTemplate.getDirectives() != null && nodeTemplate.getDirectives().contains(
398                 ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
399     }
400
401     private <T> Optional<Boolean> isTypeExistInServiceTemplateHierarchy(String typeToMatch, String typeToSearch,
402                                                                                String getTypesMethodName,
403                                                                                ServiceTemplate serviceTemplate,
404                                                                                ToscaServiceModel toscaServiceModel,
405                                                                                Set<String> analyzedImportFiles)
406             throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
407         Map<String, T> searchableTypes =
408                 (Map<String, T>) serviceTemplate.getClass().getMethod(getTypesMethodName).invoke(serviceTemplate);
409
410         if (!MapUtils.isEmpty(searchableTypes)) {
411             T typeObject = searchableTypes.get(typeToSearch);
412             if (Objects.nonNull(typeObject)) {
413                 String derivedFromTypeVal =
414                         (String) typeObject.getClass().getMethod(GET_DERIVED_FROM_METHOD_NAME).invoke(typeObject);
415                 if (Objects.equals(derivedFromTypeVal, typeToMatch)) {
416                     return Optional.of(true);
417                 } else if (Objects.isNull(derivedFromTypeVal) || isTypeIsToscaRoot(derivedFromTypeVal)) {
418                     return Optional.of(false);
419                 } else {
420                     return isTypeExistInServiceTemplateHierarchy(typeToMatch, derivedFromTypeVal, getTypesMethodName,
421                             serviceTemplate, toscaServiceModel, null);
422                 }
423             } else {
424                 return isTypeExistInImports(typeToMatch, typeToSearch, getTypesMethodName, serviceTemplate,
425                         toscaServiceModel, analyzedImportFiles);
426             }
427         }
428         return isTypeExistInImports(typeToMatch, typeToSearch, getTypesMethodName, serviceTemplate, toscaServiceModel,
429                 analyzedImportFiles);
430     }
431
432     private Optional<Boolean> isTypeExistInImports(String typeToMatch, String typeToSearch, String getTypesMethodName,
433                                                           ServiceTemplate serviceTemplate,
434                                                           ToscaServiceModel toscaServiceModel, Set<String> filesScanned)
435             throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
436         List<Map<String, Import>> imports = serviceTemplate.getImports();
437         if (CollectionUtils.isEmpty(imports)) {
438             return Optional.empty();
439         }
440
441         Set<String> createdFilesScanned = createFilesScannedSet(filesScanned);
442
443         for (Map<String, Import> map : imports) {
444             ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
445             Import anImport = toscaExtensionYamlUtil
446                                       .yamlToObject(toscaExtensionYamlUtil.objectToYaml(map.values().iterator().next()),
447                                               Import.class);
448             handleImportWithNoFileEntry(anImport);
449             String importFile = anImport.getFile();
450             ServiceTemplate template = toscaServiceModel.getServiceTemplates().get(fetchFileNameForImport(importFile,
451                     serviceTemplate.getMetadata() == null ? null : serviceTemplate.getMetadata().get("filename")));
452             if (Objects.isNull(template) || createdFilesScanned
453                                                     .contains(ToscaUtil.getServiceTemplateFileName(template))) {
454                 continue;
455             } else {
456                 createdFilesScanned.add(ToscaUtil.getServiceTemplateFileName(template));
457             }
458             Optional<Boolean> typeExistInServiceTemplateHierarchy =
459                     isTypeExistInServiceTemplateHierarchy(typeToMatch, typeToSearch, getTypesMethodName, template,
460                             toscaServiceModel, createdFilesScanned);
461             if (typeExistInServiceTemplateHierarchy.isPresent() && (typeExistInServiceTemplateHierarchy.get())) {
462                 createdFilesScanned.clear();
463                 return Optional.of(true);
464             }
465
466         }
467         return Optional.of(false);
468     }
469
470     private void handleImportWithNoFileEntry(Import anImport) {
471         if (Objects.isNull(anImport) || Objects.isNull(anImport.getFile())) {
472             throw new RuntimeException("import without file entry");
473         }
474     }
475
476     private Set<String> createFilesScannedSet(Set<String> filesScanned) {
477         Set<String> retFileScanned = filesScanned;
478         if (Objects.isNull(retFileScanned)) {
479             retFileScanned = new HashSet<>();
480         }
481         return retFileScanned;
482     }
483
484     private boolean isTypeIsToscaRoot(String type) {
485         return (type.contains(TOSCA_DOT) && type.contains(DOT_ROOT));
486     }
487
488     private boolean isSubstitutionServiceTemplate(String substituteServiceTemplateFileName,
489                                                          ServiceTemplate substituteServiceTemplate) {
490         if (substituteServiceTemplate != null && substituteServiceTemplate.getTopology_template() != null
491                     && substituteServiceTemplate.getTopology_template().getSubstitution_mappings() != null) {
492             if (substituteServiceTemplate.getTopology_template().getSubstitution_mappings().getNode_type() == null) {
493                 throw new CoreException(new ToscaInvalidSubstitutionServiceTemplateErrorBuilder(substituteServiceTemplateFileName)
494                                                 .build());
495             }
496             return true;
497         }
498         return false;
499
500     }
501
502     private boolean scanAnFlatEntity(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
503                                             ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel,
504                                             List<String> filesScanned, int rootScanStartInx) {
505
506
507         boolean entityFound =
508                 enrichEntityFromCurrentServiceTemplate(elementType, typeId, flatData, serviceTemplate, toscaModel,
509                         filesScanned, rootScanStartInx);
510         if (!entityFound) {
511             List<Map<String, Import>> imports = serviceTemplate.getImports();
512             if (CollectionUtils.isEmpty(imports)) {
513                 return false;
514             }
515             boolean found = false;
516             for (Map<String, Import> importMap : imports) {
517                 if (found) {
518                     return true;
519                 }
520                 found = isFlatEntity(importMap, flatData, serviceTemplate, filesScanned, toscaModel, elementType,
521                         typeId);
522             }
523             return found;
524         }
525         return true;
526     }
527
528     private boolean isFlatEntity(Map<String, Import> importMap, ToscaFlatData flatData, ServiceTemplate serviceTemplate,
529                                         List<String> filesScanned, ToscaServiceModel toscaModel,
530                                         ToscaElementTypes elementType, String typeId) {
531         boolean found = false;
532         ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
533         for (Object importObject : importMap.values()) {
534             Import importServiceTemplate = toscaExtensionYamlUtil
535                                                    .yamlToObject(toscaExtensionYamlUtil.objectToYaml(importObject),
536                                                            Import.class);
537             String fileName = fetchFileNameForImport(importServiceTemplate.getFile(),
538                     serviceTemplate.getMetadata() == null ? null : serviceTemplate.getMetadata().get("filename"));
539             if (filesScanned.contains(fileName)) {
540                 return false;
541             } else {
542                 filesScanned.add(fileName);
543             }
544             ServiceTemplate template = toscaModel.getServiceTemplates().get(fileName);
545             if (Objects.isNull(template)) {
546                 throw new CoreException(new ToscaFileNotFoundErrorBuilder(fileName).build());
547             }
548             found = scanAnFlatEntity(elementType, typeId, flatData, template, toscaModel, filesScanned,
549                     filesScanned.size());
550         }
551         return found;
552     }
553
554     private String fetchFileNameForImport(String importServiceTemplateFile, String currentMetadatafileName) {
555         if (importServiceTemplateFile.contains("../")) {
556             return importServiceTemplateFile.replace("../", "");
557         } else if (currentMetadatafileName != null && currentMetadatafileName.indexOf('/') != -1) {
558             return currentMetadatafileName.substring(0, currentMetadatafileName.indexOf('/')) + "/"
559                            + importServiceTemplateFile;
560         } else {
561             return importServiceTemplateFile;
562         }
563
564     }
565
566     private boolean enrichEntityFromCurrentServiceTemplate(ToscaElementTypes elementType, String typeId,
567                                                                   ToscaFlatData flatData,
568                                                                   ServiceTemplate serviceTemplate,
569                                                                   ToscaServiceModel toscaModel,
570                                                                   List<String> filesScanned, int rootScanStartInx) {
571         switch (elementType) {
572             case CAPABILITY_TYPE:
573                 if (enrichCapabilityType(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned,
574                         rootScanStartInx)) {
575                     return false;
576                 }
577                 break;
578             case NODE_TYPE:
579                 if (enrichNodeTypeInfo(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned,
580                         rootScanStartInx)) {
581                     return false;
582                 }
583                 break;
584             case DATA_TYPE:
585                 if (enrichDataTypeInfo(elementType, typeId, flatData, serviceTemplate, toscaModel, filesScanned,
586                         rootScanStartInx)) {
587                     return false;
588                 }
589                 break;
590             default:
591                 throw new RuntimeException("Entity[" + elementType + "] id[" + typeId + "] flat not supported");
592         }
593
594         return true;
595
596
597     }
598
599     private boolean enrichNodeTypeInfo(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
600                                               ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel,
601                                               List<String> filesScanned, int rootScanStartInx) {
602         String derivedFrom;
603         if (serviceTemplate.getNode_types() != null && serviceTemplate.getNode_types().containsKey(typeId)) {
604
605             filesScanned.clear();
606             flatData.addInheritanceHierarchyType(typeId);
607             NodeType targetNodeType = (NodeType) flatData.getFlatEntity();
608             NodeType sourceNodeType = serviceTemplate.getNode_types().get(typeId);
609             derivedFrom = sourceNodeType.getDerived_from();
610             if (derivedFrom != null) {
611                 boolean isEntityFound =
612                         scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
613                                 rootScanStartInx);
614                 if (!isEntityFound) {
615                     throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
616                 }
617             }
618             combineNodeTypeInfo(sourceNodeType, targetNodeType);
619         } else {
620             return true;
621         }
622         return false;
623     }
624
625     private boolean enrichDataTypeInfo(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
626                                               ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel,
627                                               List<String> filesScanned, int rootScanStartInx) {
628         String derivedFrom;
629         if (serviceTemplate.getData_types() != null && serviceTemplate.getData_types().containsKey(typeId)) {
630
631             filesScanned.clear();
632             flatData.addInheritanceHierarchyType(typeId);
633             DataType targetDataType = (DataType) flatData.getFlatEntity();
634             DataType sourceDataType = serviceTemplate.getData_types().get(typeId);
635             derivedFrom = sourceDataType.getDerived_from();
636             if (derivedFrom != null && !isPrimitiveType(derivedFrom)) {
637                 boolean isEntityFound =
638                         scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
639                                 rootScanStartInx);
640                 if (!isEntityFound) {
641                     throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
642                 }
643             }
644             combineDataTypeInfo(sourceDataType, targetDataType);
645         } else {
646             return true;
647         }
648         return false;
649     }
650
651     private static boolean isPrimitiveType(String toscaType) {
652         return (toscaType.equals(PropertyType.STRING.getDisplayName()) || toscaType.equals(PropertyType.INTEGER
653                                                                                                    .getDisplayName())
654                         || toscaType.equals(PropertyType.FLOAT.getDisplayName()));
655     }
656
657     private boolean enrichCapabilityType(ToscaElementTypes elementType, String typeId, ToscaFlatData flatData,
658                                                 ServiceTemplate serviceTemplate, ToscaServiceModel toscaModel,
659                                                 List<String> filesScanned, int rootScanStartInx) {
660         String derivedFrom;
661         if (serviceTemplate.getCapability_types() != null && serviceTemplate.getCapability_types()
662                                                                             .containsKey(typeId)) {
663
664             filesScanned.clear();
665             flatData.addInheritanceHierarchyType(typeId);
666             CapabilityType targetCapabilityType = (CapabilityType) flatData.getFlatEntity();
667             CapabilityType sourceCapabilityType = serviceTemplate.getCapability_types().get(typeId);
668             derivedFrom = sourceCapabilityType.getDerived_from();
669             if (derivedFrom != null) {
670                 boolean isEntityFound =
671                         scanAnFlatEntity(elementType, derivedFrom, flatData, serviceTemplate, toscaModel, filesScanned,
672                                 rootScanStartInx);
673                 if (!isEntityFound) {
674                     throw new CoreException(new ToscaElementTypeNotFoundErrorBuilder(typeId).build());
675                 }
676             }
677             combineCapabilityTypeInfo(sourceCapabilityType, targetCapabilityType);
678         } else {
679             return true;
680         }
681         return false;
682     }
683
684     private void combineNodeTypeInfo(NodeType sourceNodeType, NodeType targetNodeType) {
685         targetNodeType.setDerived_from(sourceNodeType.getDerived_from());
686         targetNodeType.setDescription(sourceNodeType.getDescription());
687         targetNodeType.setVersion(sourceNodeType.getVersion());
688         targetNodeType
689                 .setProperties(CommonMethods.mergeMaps(targetNodeType.getProperties(), sourceNodeType.getProperties()));
690         combineNodeTypeInterfaceInfo(sourceNodeType, targetNodeType);
691         targetNodeType
692                 .setArtifacts(CommonMethods.mergeMaps(targetNodeType.getArtifacts(), sourceNodeType.getArtifacts()));
693         targetNodeType
694                 .setAttributes(CommonMethods.mergeMaps(targetNodeType.getAttributes(), sourceNodeType.getAttributes()));
695         targetNodeType.setCapabilities(
696                 CommonMethods.mergeMaps(targetNodeType.getCapabilities(), sourceNodeType.getCapabilities()));
697         targetNodeType.setRequirements(
698                 CommonMethods.mergeListsOfMap(targetNodeType.getRequirements(), sourceNodeType.getRequirements()));
699
700     }
701
702     private InterfaceDefinitionType getInterfaceDefinitionType(String interfaceName, Object interfaceDefTypeObj) {
703         Optional<InterfaceDefinitionType> interfaceDefinitionType = DataModelUtil.convertObjToInterfaceDefinition(
704                 interfaceName, interfaceDefTypeObj, InterfaceDefinitionType.class);
705         if (!interfaceDefinitionType.isPresent()) {
706             throw new CoreException(new CreateInterfaceObjectErrorBuilder("InterfaceDefinitionType", interfaceName,
707                                                                                  "Invalid interface object").build());
708         }
709         return interfaceDefinitionType.get();
710     }
711
712     private void combineNodeTypeInterfaceInfo(NodeType sourceNodeType, NodeType targetNodeType) {
713         Optional<Map<String, Object>> interfaceNoMerge = combineInterfaceNoMerge(sourceNodeType, targetNodeType);
714         if (interfaceNoMerge.isPresent()) {
715             targetNodeType.setInterfaces(interfaceNoMerge.get());
716             return;
717         }
718         targetNodeType.setInterfaces(combineInterfaces(sourceNodeType, targetNodeType));
719     }
720
721     private Map<String, Object> combineInterfaces(NodeType sourceNodeType, NodeType targetNodeType) {
722         Map<String, Object> combineInterfaces = new HashMap<>();
723         for (Map.Entry<String, Object> sourceInterfaceDefEntry : sourceNodeType.getInterfaces().entrySet()) {
724             String interfaceName = sourceInterfaceDefEntry.getKey();
725             if (!MapUtils.isEmpty(targetNodeType.getInterfaces()) && targetNodeType.getInterfaces()
726                                                                                    .containsKey(interfaceName)) {
727                 combineInterfaces.put(interfaceName,
728                         combineInterfaceDefinition(interfaceName, sourceInterfaceDefEntry.getValue(),
729                                 targetNodeType.getInterfaces().get(interfaceName)));
730             } else {
731                 combineInterfaces.put(sourceInterfaceDefEntry.getKey(), sourceInterfaceDefEntry.getValue());
732             }
733         }
734
735         for (Map.Entry<String, Object> targetInterfaceDefEntry : targetNodeType.getInterfaces().entrySet()) {
736             String interfaceName = targetInterfaceDefEntry.getKey();
737             if (!sourceNodeType.getInterfaces().containsKey(interfaceName)) {
738                 combineInterfaces.put(targetInterfaceDefEntry.getKey(), targetInterfaceDefEntry.getValue());
739             }
740         }
741
742         return combineInterfaces;
743     }
744
745     private Optional<Map<String, Object>> combineInterfaceNoMerge(NodeType sourceNodeType, NodeType targetNodeType) {
746         if ((MapUtils.isEmpty(sourceNodeType.getInterfaces()) && MapUtils.isEmpty(targetNodeType.getInterfaces()))) {
747             return Optional.empty();
748         }
749
750         if (MapUtils.isEmpty(sourceNodeType.getInterfaces()) && !MapUtils.isEmpty(targetNodeType.getInterfaces())) {
751             return Optional.of(targetNodeType.getInterfaces());
752         }
753
754         if (!MapUtils.isEmpty(sourceNodeType.getInterfaces()) && MapUtils.isEmpty(targetNodeType.getInterfaces())) {
755             return Optional.of(sourceNodeType.getInterfaces());
756         }
757         return Optional.empty();
758
759     }
760
761     private Object combineInterfaceDefinition(String interfaceName, Object sourceInterfaceDefType,
762                                                      Object targetInterfaceDefType) {
763         InterfaceDefinitionType sourceInterface = getInterfaceDefinitionType(interfaceName, sourceInterfaceDefType);
764         InterfaceDefinitionType targetInterface = getInterfaceDefinitionType(interfaceName, targetInterfaceDefType);
765         InterfaceDefinitionType combineInterface = new InterfaceDefinitionType();
766         combineInterface.setType(sourceInterface.getType());
767         combineInterface.setInputs(CommonMethods.mergeMaps(targetInterface.getInputs(), sourceInterface.getInputs()));
768         combineInterface.setOperations(
769                 CommonMethods.mergeMaps(targetInterface.getOperations(), sourceInterface.getOperations()));
770
771         Optional<Object> interfaceDefObject = DataModelUtil.convertInterfaceDefinitionTypeToObj(combineInterface);
772         if( !interfaceDefObject.isPresent()){
773             throw new SdcRuntimeException("Illegal Statement");
774         }
775         return interfaceDefObject.get();
776     }
777
778     private void combineDataTypeInfo(DataType sourceDataType, DataType targetDataType) {
779         targetDataType.setDerived_from(sourceDataType.getDerived_from());
780         targetDataType.setDescription(sourceDataType.getDescription());
781         targetDataType.setVersion(sourceDataType.getVersion());
782         targetDataType
783                 .setProperties(CommonMethods.mergeMaps(targetDataType.getProperties(), sourceDataType.getProperties()));
784         targetDataType.setConstraints(
785                 CommonMethods.mergeLists(targetDataType.getConstraints(), sourceDataType.getConstraints()));
786     }
787
788
789     private void combineCapabilityTypeInfo(CapabilityType sourceCapabilityType, CapabilityType targetCapabilityType) {
790
791         targetCapabilityType.setAttributes(
792                 CommonMethods.mergeMaps(targetCapabilityType.getAttributes(), sourceCapabilityType.getAttributes()));
793         targetCapabilityType.setProperties(
794                 CommonMethods.mergeMaps(targetCapabilityType.getProperties(), sourceCapabilityType.getProperties()));
795         targetCapabilityType.setValid_source_types(CommonMethods
796                                                            .mergeLists(targetCapabilityType.getValid_source_types(),
797                                                                    sourceCapabilityType.getValid_source_types()));
798
799         if (StringUtils.isNotEmpty(sourceCapabilityType.getDerived_from())) {
800             targetCapabilityType.setDerived_from(sourceCapabilityType.getDerived_from());
801         }
802         if (StringUtils.isNotEmpty(sourceCapabilityType.getDescription())) {
803             targetCapabilityType.setDescription(sourceCapabilityType.getDescription());
804         }
805         if (StringUtils.isNotEmpty(sourceCapabilityType.getVersion())) {
806             targetCapabilityType.setVersion(sourceCapabilityType.getVersion());
807         }
808
809
810     }
811
812
813     /*
814    * Create node type according to the input substitution service template, while the substitution
815    * service template can be mappted to this node type, for substitution mapping.
816    *
817    * @param substitutionServiceTemplate  substitution serivce template
818    * @param nodeTypeDerivedFromValue derived from value for the created node type
819    * @return the node type
820    */
821     @Override
822     public NodeType createInitSubstitutionNodeType(ServiceTemplate substitutionServiceTemplate,
823                                                           String nodeTypeDerivedFromValue) {
824         NodeType substitutionNodeType = new NodeType();
825         substitutionNodeType.setDerived_from(nodeTypeDerivedFromValue);
826         substitutionNodeType.setDescription(substitutionServiceTemplate.getDescription());
827         substitutionNodeType.setProperties(manageSubstitutionNodeTypeProperties(substitutionServiceTemplate));
828         substitutionNodeType.setAttributes(manageSubstitutionNodeTypeAttributes(substitutionServiceTemplate));
829         return substitutionNodeType;
830     }
831
832     @Override
833     public Map<String, PropertyDefinition> manageSubstitutionNodeTypeProperties(ServiceTemplate substitutionServiceTemplate) {
834         Map<String, PropertyDefinition> substitutionNodeTypeProperties = new HashMap<>();
835         Map<String, ParameterDefinition> properties = substitutionServiceTemplate.getTopology_template().getInputs();
836         if (properties == null) {
837             return null;
838         }
839
840         PropertyDefinition propertyDefinition;
841         String toscaPropertyName;
842         for (Map.Entry<String, ParameterDefinition> entry : properties.entrySet()) {
843             toscaPropertyName = entry.getKey();
844             propertyDefinition = new PropertyDefinition();
845             ParameterDefinition parameterDefinition =
846                     substitutionServiceTemplate.getTopology_template().getInputs().get(toscaPropertyName);
847             propertyDefinition.setType(parameterDefinition.getType());
848             propertyDefinition.setDescription(parameterDefinition.getDescription());
849             propertyDefinition.set_default(parameterDefinition.get_default());
850             if (parameterDefinition.getRequired() != null) {
851                 propertyDefinition.setRequired(parameterDefinition.getRequired());
852             }
853             if (propertyDefinition.get_default() != null) {
854                 propertyDefinition.setRequired(false);
855             }
856             if (!CollectionUtils.isEmpty(parameterDefinition.getConstraints())) {
857                 propertyDefinition.setConstraints(parameterDefinition.getConstraints());
858             }
859             propertyDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
860             if (parameterDefinition.getStatus() != null) {
861                 propertyDefinition.setStatus(parameterDefinition.getStatus());
862             }
863             substitutionNodeTypeProperties.put(toscaPropertyName, propertyDefinition);
864         }
865         return substitutionNodeTypeProperties;
866     }
867
868
869     private Map<String, AttributeDefinition> manageSubstitutionNodeTypeAttributes(ServiceTemplate substitutionServiceTemplate) {
870         Map<String, AttributeDefinition> substitutionNodeTypeAttributes = new HashMap<>();
871         Map<String, ParameterDefinition> attributes = substitutionServiceTemplate.getTopology_template().getOutputs();
872         if (attributes == null) {
873             return null;
874         }
875         AttributeDefinition attributeDefinition;
876         String toscaAttributeName;
877
878         for (Map.Entry<String, ParameterDefinition> entry : attributes.entrySet()) {
879             attributeDefinition = new AttributeDefinition();
880             toscaAttributeName = entry.getKey();
881             ParameterDefinition parameterDefinition =
882                     substitutionServiceTemplate.getTopology_template().getOutputs().get(toscaAttributeName);
883             if (parameterDefinition.getType() != null && !parameterDefinition.getType().isEmpty()) {
884                 attributeDefinition.setType(parameterDefinition.getType());
885             } else {
886                 attributeDefinition.setType(PropertyType.STRING.getDisplayName());
887             }
888             attributeDefinition.setDescription(parameterDefinition.getDescription());
889             attributeDefinition.set_default(parameterDefinition.get_default());
890             attributeDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
891             if (Objects.nonNull(parameterDefinition.getStatus())) {
892                 attributeDefinition.setStatus(parameterDefinition.getStatus());
893             }
894             substitutionNodeTypeAttributes.put(toscaAttributeName, attributeDefinition);
895         }
896         return substitutionNodeTypeAttributes;
897     }
898
899     /**
900      * Checks if the requirement exists in the node template.
901      *
902      * @param nodeTemplate          the node template
903      * @param requirementId         the requirement id
904      * @param requirementAssignment the requirement assignment
905      * @return true if the requirement already exists and false otherwise
906      */
907     @Override
908     public boolean isRequirementExistInNodeTemplate(NodeTemplate nodeTemplate, String requirementId,
909                                                            RequirementAssignment requirementAssignment) {
910         List<Map<String, RequirementAssignment>> nodeTemplateRequirements = nodeTemplate.getRequirements();
911         return nodeTemplateRequirements != null && nodeTemplateRequirements.stream().anyMatch(
912                 requirement -> requirement.containsKey(requirementId) && DataModelUtil.compareRequirementAssignment(
913                         requirementAssignment, requirement.get(requirementId)));
914     }
915
916     @Override
917     public boolean isTypeOf(InterfaceDefinitionType interfaceDefinition, String interfaceType,
918                                    ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel) {
919         return isTypeOf(interfaceDefinition, interfaceType, GET_INTERFACE_TYPE_METHOD_NAME, serviceTemplate,
920                 toscaServiceModel);
921     }
922
923     @Override
924     public boolean isTypeOf(DefinitionOfDataType parameterDefinition, String dataType, ServiceTemplate serviceTemplate,
925                                    ToscaServiceModel toscaServiceModel) {
926         return isTypeOf(parameterDefinition, dataType, GET_DATA_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
927     }
928
929     @Override
930     public boolean isTypeOf(CapabilityDefinition capabilityDefinition, String capabilityType,
931                                    ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel) {
932         return isTypeOf(capabilityDefinition, capabilityType, GET_CAPABILITY_TYPE_METHOD_NAME, serviceTemplate, toscaServiceModel);
933     }
934
935
936     private <T> boolean isTypeOf(T object, String type, String getTypesMethodName, ServiceTemplate serviceTemplate,
937                                         ToscaServiceModel toscaServiceModel) {
938         if (object == null) {
939             return false;
940         }
941
942         try {
943             String objectType = (String) object.getClass().getMethod(GET_TYPE_METHOD_NAME).invoke(object);
944             if (Objects.equals(objectType, type)) {
945                 return true;
946             }
947
948             Optional<Boolean> typeExistInServiceTemplateHierarchy =
949                     isTypeExistInServiceTemplateHierarchy(type, objectType, getTypesMethodName, serviceTemplate,
950                             toscaServiceModel, null);
951             return typeExistInServiceTemplateHierarchy.orElseThrow(
952                     () -> new CoreException(new ToscaElementTypeNotFoundErrorBuilder(objectType).build()));
953
954         } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
955             throw new SdcRuntimeException(e);
956         }
957     }
958 }
959
960