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