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