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