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