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