487dd194585b6f334c20912b1c0ca5603dde2af8
[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.translator.services.heattotosca;
18
19 import org.apache.commons.collections4.CollectionUtils;
20 import org.apache.commons.collections4.MapUtils;
21 import org.apache.commons.io.FilenameUtils;
22 import org.openecomp.core.translator.api.HeatToToscaTranslator;
23 import org.openecomp.core.translator.datatypes.TranslatorOutput;
24 import org.openecomp.core.translator.factory.HeatToToscaTranslatorFactory;
25 import org.openecomp.core.utilities.file.FileContentHandler;
26 import org.openecomp.core.utilities.file.FileUtils;
27 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
28 import org.openecomp.core.validation.util.MessageContainerUtil;
29 import org.openecomp.sdc.common.errors.CoreException;
30 import org.openecomp.sdc.common.togglz.ToggleableFeature;
31 import org.openecomp.sdc.common.utils.SdcCommon;
32 import org.openecomp.sdc.datatypes.error.ErrorLevel;
33 import org.openecomp.sdc.datatypes.error.ErrorMessage;
34 import org.openecomp.sdc.heat.datatypes.HeatBoolean;
35 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
36 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
37 import org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes;
38 import org.openecomp.sdc.heat.datatypes.model.Resource;
39 import org.openecomp.sdc.heat.datatypes.model.ResourceReferenceFunctions;
40 import org.openecomp.sdc.heat.datatypes.structure.HeatStructureTree;
41 import org.openecomp.sdc.heat.datatypes.structure.ValidationStructureList;
42 import org.openecomp.sdc.heat.services.HeatConstants;
43 import org.openecomp.sdc.heat.services.tree.HeatTreeManager;
44 import org.openecomp.sdc.heat.services.tree.HeatTreeManagerUtil;
45 import org.openecomp.sdc.logging.api.Logger;
46 import org.openecomp.sdc.logging.api.LoggerFactory;
47 import org.openecomp.sdc.tosca.datatypes.ToscaCapabilityType;
48 import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes;
49 import org.openecomp.sdc.tosca.datatypes.ToscaFunctions;
50 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
51 import org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType;
52 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
53 import org.openecomp.sdc.tosca.datatypes.model.AttributeDefinition;
54 import org.openecomp.sdc.tosca.datatypes.model.CapabilityDefinition;
55 import org.openecomp.sdc.tosca.datatypes.model.Import;
56 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
57 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
58 import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition;
59 import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition;
60 import org.openecomp.sdc.tosca.datatypes.model.PropertyType;
61 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
62 import org.openecomp.sdc.tosca.datatypes.model.RequirementDefinition;
63 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
64 import org.openecomp.sdc.tosca.datatypes.model.Template;
65 import org.openecomp.sdc.tosca.datatypes.model.TopologyTemplate;
66 import org.openecomp.sdc.tosca.services.DataModelUtil;
67 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
68 import org.openecomp.sdc.tosca.services.ToscaConstants;
69 import org.openecomp.sdc.tosca.services.ToscaExtensionYamlUtil;
70 import org.openecomp.sdc.tosca.services.ToscaUtil;
71 import org.openecomp.sdc.tosca.services.YamlUtil;
72 import org.openecomp.sdc.tosca.services.impl.ToscaAnalyzerServiceImpl;
73 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedPropertyVal;
74 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedResourceId;
75 import org.openecomp.sdc.translator.datatypes.heattotosca.ReferenceType;
76 import org.openecomp.sdc.translator.datatypes.heattotosca.TranslationContext;
77 import org.openecomp.sdc.translator.datatypes.heattotosca.to.FileDataCollection;
78 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslateTo;
79 import org.openecomp.sdc.translator.services.heattotosca.errors.ResourceNotFoundInHeatFileErrorBuilder;
80 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
81 import org.openecomp.sdc.translator.services.heattotosca.helper.ContrailV2VirtualMachineInterfaceHelper;
82 import org.openecomp.sdc.translator.services.heattotosca.helper.FunctionTranslationHelper;
83 import org.openecomp.sdc.translator.services.heattotosca.impl.resourcetranslation.ResourceTranslationBase;
84 import org.openecomp.sdc.translator.services.heattotosca.mapping.TranslatorHeatToToscaPropertyConverter;
85
86 import java.io.IOException;
87 import java.io.InputStream;
88 import java.util.ArrayList;
89 import java.util.Collection;
90 import java.util.HashMap;
91 import java.util.HashSet;
92 import java.util.List;
93 import java.util.Map;
94 import java.util.Objects;
95 import java.util.Optional;
96 import java.util.Set;
97 import java.util.regex.Matcher;
98 import java.util.regex.Pattern;
99 import java.util.stream.Collectors;
100
101 /**
102  * The type Heat to tosca util.
103  */
104 public class HeatToToscaUtil {
105
106   private static final Logger LOGGER = LoggerFactory.getLogger(HeatToToscaUtil.class);
107   public static final String FQ_NAME = "fq_name";
108   public static final String GET_PARAM = "get_param";
109   private static final String GET_ATTR = "get_attr";
110   private static final String GET_RESOURCE = "get_resource";
111   private static final String VMI = "vmi";
112   private static final String NEUTRON_PORT_IDENTIFIER = "port";
113   private static final String UNDERSCORE = "_";
114
115   /**
116    * Load and translate template data translator output.
117    *
118    * @param fileNameContentMap the file name content map
119    * @return the translator output
120    */
121   public static TranslatorOutput loadAndTranslateTemplateData(
122       FileContentHandler fileNameContentMap) {
123     HeatToToscaTranslator heatToToscaTranslator =
124         HeatToToscaTranslatorFactory.getInstance().createInterface();
125
126     try (InputStream fileContent = fileNameContentMap.getFileContent(SdcCommon.MANIFEST_NAME)) {
127       heatToToscaTranslator.addManifest(SdcCommon.MANIFEST_NAME, FileUtils.toByteArray(fileContent));
128     } catch (IOException e) {
129       throw new RuntimeException("Failed to read manifest", e);
130     }
131
132     fileNameContentMap.getFileList().stream()
133         .filter(fileName -> !(fileName.equals(SdcCommon.MANIFEST_NAME))).forEach(
134         fileName -> heatToToscaTranslator
135             .addFile(fileName, FileUtils.toByteArray
136                 (fileNameContentMap.getFileContent(fileName))));
137
138     Map<String, List<ErrorMessage>> errors = heatToToscaTranslator.validate();
139     if (MapUtils.isNotEmpty(MessageContainerUtil.getMessageByLevel(ErrorLevel.ERROR, errors))) {
140       TranslatorOutput translatorOutput = new TranslatorOutput();
141       translatorOutput.setErrorMessages(errors);
142       return translatorOutput;
143     }
144
145     try (InputStream structureFile = getHeatStructureTreeFile(fileNameContentMap)) {
146       heatToToscaTranslator.addExternalArtifacts(SdcCommon.HEAT_META, structureFile);
147       return heatToToscaTranslator.translate();
148     } catch (IOException e) {
149       // rethrow as a RuntimeException to keep the signature backward compatible
150       throw new RuntimeException("Failed to read Heat template tree", e);
151     }
152   }
153
154
155   private static InputStream getHeatStructureTreeFile(FileContentHandler fileNameContentMap) {
156     HeatTreeManager heatTreeManager = HeatTreeManagerUtil.initHeatTreeManager(fileNameContentMap);
157     heatTreeManager.createTree();
158     HeatStructureTree tree = heatTreeManager.getTree();
159     ValidationStructureList validationStructureList = new ValidationStructureList(tree);
160     return FileUtils.convertToInputStream(validationStructureList, FileUtils.FileExtension.JSON);
161   }
162
163   /**
164    * Build list of files to search optional.
165    *
166    * @param heatFileName  the heat file name
167    * @param filesDataList the files data list
168    * @param types         the types
169    * @return the optional
170    */
171   public static Optional<List<FileData>> buildListOfFilesToSearch(String heatFileName,
172                                                                   List<FileData> filesDataList,
173                                                                   FileData.Type... types) {
174     List<FileData> list = new ArrayList<>(filesDataList);
175     Optional<FileData> resourceFileData = HeatToToscaUtil.getFileData(heatFileName, filesDataList);
176     if (resourceFileData.isPresent() && Objects.nonNull(resourceFileData.get().getData())) {
177       list.addAll(resourceFileData.get().getData());
178     }
179     return Optional.ofNullable(HeatToToscaUtil.getFilteredListOfFileDataByTypes(list, types));
180   }
181
182   /**
183    * Gets filtered list of file data by types.
184    *
185    * @param filesToSearch the files to search
186    * @param types         the types
187    * @return the filtered list of file data by types
188    */
189   public static List<FileData> getFilteredListOfFileDataByTypes(List<FileData> filesToSearch,
190                                                                 FileData.Type... types) {
191     return filesToSearch.stream().filter(FileData.buildFileDataPredicateByType(types))
192         .collect(Collectors.toList());
193   }
194
195   /**
196    * Gets file data from the list according to the input heat file name.
197    *
198    * @param heatFileName the heat file name
199    * @param fileDataList the file data list
200    * @return the file data
201    */
202   public static Optional<FileData> getFileData(String heatFileName,
203                                                Collection<FileData> fileDataList) {
204     for (FileData file : fileDataList) {
205       if (file.getFile().equals(heatFileName)) {
206         return Optional.of(file);
207       }
208     }
209     return Optional.empty();
210   }
211
212   /**
213    * Gets file data which is supported by the translator, from the context according the input heat
214    * file name.
215    *
216    * @param heatFileName the heat file name
217    * @param context      the translation context
218    * @return the file data
219    */
220   public static FileData getFileData(String heatFileName, TranslationContext context) {
221
222     List<FileData> fileDataList = context.getManifest().getContent().getData();
223     for (FileData fileData : fileDataList) {
224       if (TranslationService.getTypesToProcessByTranslator().contains(fileData.getType())
225           && fileData.getFile().equals(heatFileName)) {
226         return fileData;
227       }
228     }
229     return null;
230   }
231
232   static FileDataCollection getFileCollectionsByFilter(List<FileData> fileDataList,
233                                                        Set<FileData.Type> typeFilter,
234                                                        TranslationContext translationContext) {
235     FileDataCollection fileDataCollection = new FileDataCollection();
236     Map<String, FileData> filteredFiles = filterFileDataListByType(fileDataList, typeFilter);
237     Set<String> referenced = new HashSet<>();
238
239     for (FileData fileData : filteredFiles.values()) {
240       String fileName = fileData.getFile();
241
242       if (FileData.isHeatFile(fileData.getType())) {
243         if (fileData.getBase() != null && fileData.getBase()) {
244           fileDataCollection.addBaseFiles(fileData);
245         }
246         HeatOrchestrationTemplate heatOrchestrationTemplate = new YamlUtil()
247             .yamlToObject(translationContext.getFileContent(fileName),
248                 HeatOrchestrationTemplate.class);
249         if (MapUtils.isNotEmpty(heatOrchestrationTemplate.getResources())) {
250           applyFilterOnFileCollection(heatOrchestrationTemplate, translationContext,
251               fileDataCollection, filteredFiles, referenced);
252         }
253
254       } else {
255         fileDataCollection.addArtifactFiles(fileData);
256         filteredFiles.remove(fileData.getFile());
257       }
258     }
259
260     referenced.forEach(filteredFiles::remove);
261     if (!CollectionUtils.isEmpty(fileDataCollection.getBaseFile())) {
262       for (FileData fileData : fileDataCollection.getBaseFile()) {
263         filteredFiles.remove(fileData.getFile());
264       }
265     }
266     fileDataCollection.setAddOnFiles(filteredFiles.values());
267     return fileDataCollection;
268   }
269
270   private static void applyFilterOnFileCollection(
271       HeatOrchestrationTemplate heatOrchestrationTemplate,
272       TranslationContext translationContext,
273       FileDataCollection fileDataCollection, Map<String, FileData> filteredFiles,
274       Set<String> referenced) {
275     List<String> filenames = extractFilenamesFromFileDataList(filteredFiles.values());
276
277     for (Resource resource : heatOrchestrationTemplate.getResources().values()) {
278       if (filenames.contains(resource.getType())) {
279         handleNestedFile(translationContext, fileDataCollection, filteredFiles, referenced,
280             resource.getType());
281       } else if (resource.getType()
282           .equals(HeatResourcesTypes.RESOURCE_GROUP_RESOURCE_TYPE.getHeatResource())) {
283         handleResourceGrpNestedFile(resource, translationContext, fileDataCollection,
284             filteredFiles, filenames, referenced);
285       }
286     }
287   }
288
289   private static void handleResourceGrpNestedFile(Resource resource,
290                                                   TranslationContext translationContext,
291                                                   FileDataCollection fileDataCollection,
292                                                   Map<String, FileData> filteredFiles,
293                                                   List<String> filenames,
294                                                   Set<String> referenced) {
295     Object resourceDef = resource.getProperties().get(HeatConstants.RESOURCE_DEF_PROPERTY_NAME);
296     Object innerTypeDef = ((Map) resourceDef).get(HeatConstants.RESOURCE_DEF_TYPE_PROPERTY_NAME);
297     if (innerTypeDef instanceof String) {
298       String internalResourceType = (String) innerTypeDef;
299       if (filenames.contains(internalResourceType)) {
300         handleNestedFile(translationContext, fileDataCollection, filteredFiles,
301             referenced, internalResourceType);
302       }
303     }
304   }
305
306   private static void handleNestedFile(TranslationContext translationContext,
307                                        FileDataCollection fileDataCollection,
308                                        Map<String, FileData> filteredFiles, Set<String> referenced,
309                                        String nestedFileName) {
310     referenced.add(nestedFileName);
311     fileDataCollection.addNestedFiles(filteredFiles.get(nestedFileName));
312     translationContext.getNestedHeatsFiles().add(nestedFileName);
313   }
314
315   private static Map<String, FileData> filterFileDataListByType(List<FileData> fileDataList,
316                                                                 Set<FileData.Type> typesToGet) {
317     Map<String, FileData> filtered = new HashMap<>();
318     fileDataList.stream().filter(file -> typesToGet.contains(file.getType()))
319         .forEach(file -> filtered.put(file.getFile(), file));
320     return filtered;
321   }
322
323   private static List<String> extractFilenamesFromFileDataList(Collection<FileData> fileDataList) {
324     return fileDataList.stream().map(FileData::getFile).collect(Collectors.toList());
325   }
326
327   /**
328    * Extract attached resource id optional.
329    *
330    * @param translateTo  the translate to
331    * @param propertyName the property name
332    * @return the optional
333    */
334   public static Optional<AttachedResourceId> extractAttachedResourceId(TranslateTo translateTo,
335                                                                        String propertyName) {
336     Object propertyValue = translateTo.getResource().getProperties().get(propertyName);
337     if (propertyValue == null) {
338       return Optional.empty();
339     }
340     return extractAttachedResourceId(translateTo.getHeatFileName(),
341         translateTo.getHeatOrchestrationTemplate(), translateTo.getContext(), propertyValue);
342   }
343
344   /**
345    * Extract attached resource id optional.
346    *
347    * @param heatFileName              the heat file name
348    * @param heatOrchestrationTemplate the heat orchestration template
349    * @param context                   the context
350    * @param propertyValue             the property value
351    * @return the optional
352    */
353   public static Optional<AttachedResourceId> extractAttachedResourceId(
354       String heatFileName,
355       HeatOrchestrationTemplate heatOrchestrationTemplate,
356       TranslationContext context,
357       Object propertyValue) {
358
359     Object entity;
360     Object translatedId;
361
362     if (Objects.isNull(propertyValue)) {
363       return Optional.empty();
364     }
365
366     ReferenceType referenceType = ReferenceType.OTHER;
367     if (propertyValue instanceof Map && !((Map) propertyValue).isEmpty()) {
368       Map<String, Object> propMap = (Map) propertyValue;
369       Map.Entry<String, Object> entry = propMap.entrySet().iterator().next();
370       entity = entry.getValue();
371       String key = entry.getKey();
372       referenceType = getReferenceTypeFromAttachedResouce(key);
373
374       if (!FunctionTranslationFactory.getInstance(entry.getKey()).isPresent()) {
375         translatedId = null;
376       } else {
377         translatedId = FunctionTranslationFactory.getInstance(entry.getKey()).get()
378             .translateFunction(null, null, null, entry.getKey(), entry.getValue(), heatFileName,
379                 heatOrchestrationTemplate, null, context);
380       }
381       if (translatedId instanceof String
382           && !FunctionTranslationHelper.isResourceSupported((String) translatedId)) {
383         translatedId = null;
384       }
385
386     } else {
387       translatedId = propertyValue;
388       entity = propertyValue;
389     }
390
391     return Optional.of(new AttachedResourceId(translatedId, entity, referenceType));
392   }
393
394   private static ReferenceType getReferenceTypeFromAttachedResouce(String key) {
395     ReferenceType referenceType;
396     switch (key) {
397       case GET_RESOURCE:
398         referenceType = ReferenceType.GET_RESOURCE;
399         break;
400       case GET_PARAM:
401         referenceType = ReferenceType.GET_PARAM;
402         break;
403       case GET_ATTR:
404         referenceType = ReferenceType.GET_ATTR;
405         break;
406       default:
407         referenceType = ReferenceType.OTHER;
408         break;
409     }
410
411     return referenceType;
412   }
413
414   /**
415    * Gets contrail attached heat resource id.
416    *
417    * @param attachedResource the attached resource
418    * @return the contrail attached heat resource id
419    */
420   public static Optional<String> getContrailAttachedHeatResourceId(
421       AttachedResourceId attachedResource) {
422     if (attachedResource == null) {
423       return Optional.empty();
424     }
425
426     if (attachedResource.isGetResource()) {
427       return Optional.of((String) attachedResource.getEntityId());
428     }
429
430     if (attachedResource.isGetAttr()) {
431       return getResourceId(attachedResource.getEntityId());
432     }
433     return Optional.empty();
434   }
435
436   /**
437    * Extract property optional.
438    *
439    * @param propertyValue the property value
440    * @return the optional
441    */
442   public static Optional<AttachedPropertyVal> extractProperty(Object propertyValue) {
443     Object attachedPropertyVal;
444     if (Objects.isNull(propertyValue)) {
445       return Optional.empty();
446     }
447
448     ReferenceType referenceType = ReferenceType.OTHER;
449     if (propertyValue instanceof Map && !((Map) propertyValue).isEmpty()) {
450       Map<String, Object> propMap = (Map) propertyValue;
451       Map.Entry<String, Object> entry = propMap.entrySet().iterator().next();
452       attachedPropertyVal = entry.getValue();
453       String key = entry.getKey();
454       switch (key) {
455         case GET_RESOURCE:
456           referenceType = ReferenceType.GET_RESOURCE;
457           break;
458         case GET_PARAM:
459           referenceType = ReferenceType.GET_PARAM;
460           break;
461         case GET_ATTR:
462           referenceType = ReferenceType.GET_ATTR;
463           break;
464         default:
465           break;
466       }
467
468     } else {
469       attachedPropertyVal = propertyValue;
470     }
471     return Optional.of(new AttachedPropertyVal(attachedPropertyVal, referenceType));
472   }
473
474   /**
475    * Map boolean.
476    *
477    * @param nodeTemplate the node template
478    * @param propertyKey  the property key
479    */
480   public static void mapBoolean(NodeTemplate nodeTemplate, String propertyKey) {
481     Object value = nodeTemplate.getProperties().get(propertyKey);
482     if (value != null && !(value instanceof Map)) {
483       nodeTemplate.getProperties().put(propertyKey, HeatBoolean.eval(value));
484     }
485   }
486
487   /**
488    * Map boolean list.
489    *
490    * @param nodeTemplate    the node template
491    * @param propertyListKey the property list key
492    */
493   public static void mapBooleanList(NodeTemplate nodeTemplate, String propertyListKey) {
494     Object listValue = nodeTemplate.getProperties().get(propertyListKey);
495     if (listValue instanceof List) {
496       List booleanList = (List) listValue;
497       for (int i = 0; i < booleanList.size(); i++) {
498         Object value = booleanList.get(i);
499         if (value != null && !(value instanceof Map)) {
500           booleanList.set(i, HeatBoolean.eval(value));
501         }
502       }
503     }
504   }
505
506
507   /**
508    * Is yml file type boolean.
509    *
510    * @param filename the filename
511    * @return the boolean
512    */
513   public static boolean isYmlFileType(String filename) {
514     String extension = FilenameUtils.getExtension(filename);
515     return "yaml".equalsIgnoreCase(extension)
516         || "yml".equalsIgnoreCase(extension);
517   }
518
519   /**
520    * Is nested resource boolean.
521    *
522    * @param resource the resource
523    * @return the boolean
524    */
525   public static boolean isNestedResource(Resource resource) {
526     String resourceType = resource.getType();
527
528     if (resourceType.equals(HeatResourcesTypes.RESOURCE_GROUP_RESOURCE_TYPE.getHeatResource())) {
529       Object resourceDef = resource.getProperties().get(HeatConstants.RESOURCE_DEF_PROPERTY_NAME);
530       if (!(((Map) resourceDef).get(HeatConstants.RESOURCE_DEF_TYPE_PROPERTY_NAME) instanceof
531           String)) {
532         //currently only resource group which is poinitng to nested heat file is supported
533         //dynamic type is currently not supported
534         return false;
535       }
536       String internalResourceType = (String) ((Map) resourceDef).get(HeatConstants
537           .RESOURCE_DEF_TYPE_PROPERTY_NAME);
538       if (isYamlFile(internalResourceType)) {
539         return true;
540       }
541     } else if (isYamlFile(resourceType)) {
542       return true;
543     }
544     return false;
545   }
546
547   /**
548    * Checks if the current HEAT resource if of type sub interface.
549    *
550    * @param resource the resource
551    * @return true if the resource is of sub interface type and false otherwise
552    */
553   public static boolean isSubInterfaceResource(Resource resource, TranslationContext context) {
554     if (!ToggleableFeature.VLAN_TAGGING.isActive()) {
555       //Remove this once feature is stable and moved to production
556       return false;
557     }
558     //Check if resource group is a nested resource
559     if (!isNestedResource(resource)) {
560       return false;
561     }
562     Optional<String> nestedHeatFileName = HeatToToscaUtil.getNestedHeatFileName(resource);
563     return nestedHeatFileName.filter(fileName ->
564         isNestedVlanResource(fileName, context)).isPresent();
565   }
566
567   private static boolean isNestedVlanResource(String nestedHeatFileName,
568                                               TranslationContext translationContext) {
569     HeatOrchestrationTemplate nestedHeatOrchestrationTemplate = new YamlUtil()
570         .yamlToObject(translationContext.getFileContent(nestedHeatFileName),
571             HeatOrchestrationTemplate.class);
572     return Objects.nonNull(nestedHeatOrchestrationTemplate.getResources())
573         && nestedHeatOrchestrationTemplate.getResources().values().stream()
574         .anyMatch(new ContrailV2VirtualMachineInterfaceHelper()::isVlanSubInterfaceResource);
575   }
576
577   public static Optional<String> getSubInterfaceParentPortNodeTemplateId(TranslateTo subInterfaceTo) {
578     String subInterfaceResourceType = getSubInterfaceResourceType(subInterfaceTo.getResource());
579     HeatOrchestrationTemplate nestedHeatOrchestrationTemplate = new YamlUtil()
580         .yamlToObject(subInterfaceTo.getContext().getFileContent(subInterfaceResourceType),
581             HeatOrchestrationTemplate.class);
582     if (Objects.isNull(nestedHeatOrchestrationTemplate.getResources())) {
583       return Optional.empty();
584     }
585     for (Map.Entry<String, Resource> resourceEntry : nestedHeatOrchestrationTemplate
586         .getResources().entrySet()) {
587       Resource resource = resourceEntry.getValue();
588       if (isVmiRefsPropertyExists(resource)) {
589         Object toscaPropertyValue =
590             TranslatorHeatToToscaPropertyConverter.getToscaPropertyValue(subInterfaceTo.getServiceTemplate(),
591                 resourceEntry.getKey(), HeatConstants.VMI_REFS_PROPERTY_NAME,
592                 resource.getProperties().get(HeatConstants.VMI_REFS_PROPERTY_NAME),
593                 resource.getType(), subInterfaceResourceType, nestedHeatOrchestrationTemplate,
594                 null, subInterfaceTo.getContext());
595         return getParentNodeTemplateIdFromPropertyValue(toscaPropertyValue, subInterfaceTo);
596       }
597     }
598     return Optional.empty();
599   }
600
601   private static boolean isVmiRefsPropertyExists(Resource resource) {
602     return HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE
603         .getHeatResource().equals(resource.getType())
604         && MapUtils.isNotEmpty(resource.getProperties())
605         && resource.getProperties().containsKey(HeatConstants.VMI_REFS_PROPERTY_NAME);
606   }
607
608   public static String getSubInterfaceResourceType(Resource resource) {
609     if (!HeatToToscaUtil.isYamlFile(resource.getType())) {
610       return ((Map) resource.getProperties()
611           .get(HeatConstants.RESOURCE_DEF_PROPERTY_NAME))
612           .get(HeatConstants.RESOURCE_DEF_TYPE_PROPERTY_NAME)
613           .toString();
614     }
615     return resource.getType();
616   }
617
618   private static Optional<String> getParentNodeTemplateIdFromPropertyValue(Object toscaPropertyValue,
619                                                                            TranslateTo subInterfaceTo) {
620     if (toscaPropertyValue instanceof List
621         && ((List) toscaPropertyValue).get(0) instanceof Map) {
622       Resource subInterfaceResource = subInterfaceTo.getResource();
623       Map<String, String> toscaPropertyValueMap = (Map) ((List) toscaPropertyValue).get(0);
624       String parentPortPropertyInput = toscaPropertyValueMap.get(ToscaFunctions.GET_INPUT
625           .getDisplayName());
626       Map<String, Object> resourceDefPropertiesMap;
627       if (!isYamlFile(subInterfaceResource.getType())) {
628         resourceDefPropertiesMap = (Map)((Map) subInterfaceResource
629             .getProperties().get(HeatConstants.RESOURCE_DEF_PROPERTY_NAME))
630             .get(HeatConstants.RESOURCE_DEF_PROPERTIES);
631       } else {
632         resourceDefPropertiesMap = subInterfaceResource.getProperties();
633       }
634       Object parentPortObj = resourceDefPropertiesMap.get(parentPortPropertyInput);
635       if (parentPortObj instanceof  Map) {
636         Map<String, String> parentPortPropertyValue = (Map) parentPortObj;
637         if (parentPortPropertyValue.keySet().contains(ResourceReferenceFunctions
638             .GET_RESOURCE.getFunction())) {
639           return ResourceTranslationBase.getResourceTranslatedId(subInterfaceTo.getHeatFileName(),
640               subInterfaceTo.getHeatOrchestrationTemplate(),
641               parentPortPropertyValue.get(ResourceReferenceFunctions.GET_RESOURCE.getFunction()),
642               subInterfaceTo.getContext());
643         }
644       }
645     }
646     return Optional.empty();
647   }
648
649   /**
650    * Checks if the nested resource represents a VFC or a complex VFC (Heat file should contain at
651    * least one or more compute nodes).
652    *
653    * @param resource the resource
654    * @param context the context
655    * @return true if the resource represents a VFC and false otherwise.
656    */
657   public static boolean isNestedVfcResource(Resource resource, TranslationContext context) {
658     Optional<String> nestedHeatFileName = HeatToToscaUtil.getNestedHeatFileName(resource);
659     HeatOrchestrationTemplate nestedHeatOrchestrationTemplate = new YamlUtil()
660         .yamlToObject(context.getFileContent(nestedHeatFileName.get()),
661             HeatOrchestrationTemplate.class);
662     if (Objects.nonNull(nestedHeatOrchestrationTemplate.getResources())) {
663       for (String innerResourceId : nestedHeatOrchestrationTemplate.getResources().keySet()) {
664         if (ConsolidationDataUtil
665             .isComputeResource(nestedHeatOrchestrationTemplate, innerResourceId)) {
666           return true;
667         }
668       }
669     }
670     return false;
671   }
672
673   /**
674    * Get nested heat file name in case of nested resource.
675    *
676    * @param resource the resource
677    * @return the nested heat file name
678    */
679   public static Optional<String> getNestedHeatFileName(Resource resource) {
680     if (!isNestedResource(resource)) {
681       return Optional.empty();
682     }
683
684     String resourceType = resource.getType();
685
686     if (resourceType.equals(HeatResourcesTypes.RESOURCE_GROUP_RESOURCE_TYPE.getHeatResource())) {
687       Object resourceDef = resource.getProperties().get(HeatConstants.RESOURCE_DEF_PROPERTY_NAME);
688       String internalResourceType = (String) ((Map) resourceDef).get(HeatConstants
689           .RESOURCE_DEF_TYPE_PROPERTY_NAME);
690       return Optional.of(internalResourceType);
691     }
692     return Optional.of(resourceType);
693   }
694
695   /**
696    * Gets nested file.
697    *
698    * @param resource the resource
699    * @return the nested file
700    */
701   public static Optional<String> getNestedFile(Resource resource) {
702     if (!isNestedResource(resource)) {
703       return Optional.empty();
704     }
705     String resourceType = resource.getType();
706     if (resourceType.equals(HeatResourcesTypes.RESOURCE_GROUP_RESOURCE_TYPE.getHeatResource())) {
707       Object resourceDef = resource.getProperties().get(HeatConstants.RESOURCE_DEF_PROPERTY_NAME);
708       String internalResourceType = (String) ((Map) resourceDef).get(HeatConstants
709           .RESOURCE_DEF_TYPE_PROPERTY_NAME);
710       return Optional.of(internalResourceType);
711     } else {
712       return Optional.of(resourceType);
713     }
714   }
715
716   public static boolean isYamlFile(String fileName) {
717     return fileName.endsWith(".yaml") || fileName.endsWith(".yml");
718   }
719
720   /**
721    * Gets resource.
722    *
723    * @param heatOrchestrationTemplate the heat orchestration template
724    * @param resourceId                the resource id
725    * @param heatFileName              the heat file name
726    * @return the resource
727    */
728   public static Resource getResource(HeatOrchestrationTemplate heatOrchestrationTemplate,
729                                      String resourceId, String heatFileName) {
730     Resource resource = heatOrchestrationTemplate.getResources().get(resourceId);
731     if (resource == null) {
732       throw new CoreException(
733           new ResourceNotFoundInHeatFileErrorBuilder(resourceId, heatFileName).build());
734     }
735     return resource;
736   }
737
738
739   /**
740    * Get resource type.
741    *
742    * @param resourceId                the resource id
743    * @param heatOrchestrationTemplate heat orchestration template
744    * @param heatFileName              heat file name
745    * @return resource type
746    */
747   public static String getResourceType(String resourceId,
748                                        HeatOrchestrationTemplate heatOrchestrationTemplate,
749                                        String heatFileName) {
750     return HeatToToscaUtil.getResource(heatOrchestrationTemplate, resourceId, heatFileName)
751         .getType();
752   }
753
754   /**
755    * Is heat file nested boolean.
756    *
757    * @param translateTo  the translate to
758    * @param heatFileName the heat file name
759    * @return the boolean
760    */
761   public static boolean isHeatFileNested(TranslateTo translateTo, String heatFileName) {
762     return isHeatFileNested(translateTo.getContext(), heatFileName);
763   }
764
765   public static boolean isHeatFileNested(TranslationContext context, String heatFileName) {
766     return context.getNestedHeatsFiles().contains(heatFileName);
767   }
768
769   /**
770    * Extract contrail get resource attached heat resource id optional.
771    *
772    * @param propertyValue the property value
773    * @return the optional
774    */
775   public static Optional<String> extractContrailGetResourceAttachedHeatResourceId(
776       Object propertyValue) {
777     if (propertyValue instanceof Map) {
778       if (((Map) propertyValue).containsKey(GET_ATTR)) {
779         return getResourceId(((Map) propertyValue).get(GET_ATTR));
780       } else if (((Map) propertyValue).containsKey(GET_RESOURCE)) {
781         return getHeatResourceIdFromResource((Map) propertyValue);
782       } else {
783         Collection valCollection = ((Map) propertyValue).values();
784         return evaluateHeatResourceId(valCollection);
785       }
786     } else if (propertyValue instanceof List) {
787       return evaluateHeatResourceId((List) propertyValue);
788     }
789     return Optional.empty();
790   }
791
792   private static Optional<String> getResourceId(Object data) {
793     if (data instanceof List && CollectionUtils.size(data) > 1
794         && FQ_NAME.equals(((List) data).get(1))
795         && ((List) data).get(0) instanceof String) {
796       return Optional.of((String) ((List) data).get(0));
797     } else {
798       LOGGER.warn("invalid format of 'get_attr' function - " + data.toString());
799       return Optional.empty();
800     }
801   }
802
803   private static Optional<String> getHeatResourceIdFromResource(Map propertyValue) {
804     Object value = propertyValue.get(GET_RESOURCE);
805     if (value instanceof String) {
806       return Optional.of((String) value);
807     } else {
808       LOGGER.warn("invalid format of 'get_resource' function - " + propertyValue.toString());
809       return Optional.empty();
810     }
811   }
812
813   private static Optional<String> evaluateHeatResourceId(Collection propertyValue) {
814     for (Object prop : propertyValue) {
815       Optional<String> ret = extractContrailGetResourceAttachedHeatResourceId(prop);
816       if (ret.isPresent()) {
817         return ret;
818       }
819     }
820     return Optional.empty();
821   }
822   /**
823    * Gets tosca service model.
824    *
825    * @param context translation context
826    * @return the tosca service model
827    */
828   public static ToscaServiceModel getToscaServiceModel(TranslationContext context) {
829     Map<String, String> metadata = new HashMap<>();
830     metadata.put(ToscaConstants.ST_METADATA_TEMPLATE_NAME, Constants.MAIN_TEMPLATE_NAME);
831     return getToscaServiceModel(context, metadata);
832   }
833
834   /**
835    * Gets tosca service model.
836    *
837    * @param context                 translation context
838    * @param entryDefinitionMetadata template name of the entry definition servie template
839    * @return the tosca service model
840    */
841   public static ToscaServiceModel getToscaServiceModel(
842       TranslationContext context,
843       Map<String, String> entryDefinitionMetadata) {
844     Map<String, ServiceTemplate> serviceTemplates =
845         new HashMap<>(context.getGlobalServiceTemplates());
846     Collection<ServiceTemplate> tmpServiceTemplates =
847         context.getTranslatedServiceTemplates().values();
848     for (ServiceTemplate serviceTemplate : tmpServiceTemplates) {
849       ToscaUtil.addServiceTemplateToMapWithKeyFileName(serviceTemplates, serviceTemplate);
850     }
851     return new ToscaServiceModel(null, serviceTemplates,
852         ToscaUtil.getServiceTemplateFileName(entryDefinitionMetadata));
853   }
854
855   /**
856    * Gets service template from context.
857    *
858    * @param serviceTemplateFileName the service template file name
859    * @param context                 the context
860    * @return the service template from context
861    */
862   public static Optional<ServiceTemplate> getServiceTemplateFromContext(
863       String serviceTemplateFileName, TranslationContext context) {
864     for (ServiceTemplate serviceTemplate : context.getTranslatedServiceTemplates().values()) {
865       if (ToscaUtil.getServiceTemplateFileName(serviceTemplate).equals(serviceTemplateFileName)) {
866         return Optional.of(serviceTemplate);
867       }
868     }
869     return Optional.empty();
870   }
871
872   /**
873    * Adding link requerment from port node template to network node template.
874    *
875    * @param portNodeTemplate    port node template
876    * @param networkTranslatedId network node template id
877    */
878   public static RequirementAssignment addLinkReqFromPortToNetwork(NodeTemplate portNodeTemplate,
879                                                                   String networkTranslatedId) {
880     RequirementAssignment requirement = new RequirementAssignment();
881     requirement.setCapability(ToscaCapabilityType.NATIVE_NETWORK_LINKABLE);
882     requirement.setRelationship(ToscaRelationshipType.NATIVE_NETWORK_LINK_TO);
883     requirement.setNode(networkTranslatedId);
884     DataModelUtil.addRequirementAssignment(portNodeTemplate,
885         ToscaConstants.LINK_REQUIREMENT_ID, requirement);
886     return requirement;
887   }
888
889   /**
890    * Adding binding requerment from sub interface node template to interface (port) node template.
891    *
892    * @param subInterfaceNodeTemplate sub interface template
893    * @param interfaceTranslatedId    interface node template id
894    */
895   public static void addBindingReqFromSubInterfaceToInterface(
896       NodeTemplate subInterfaceNodeTemplate, String interfaceTranslatedId) {
897     RequirementAssignment requirement = new RequirementAssignment();
898     requirement.setCapability(ToscaCapabilityType.NATIVE_NETWORK_BINDABLE);
899     requirement.setRelationship(ToscaRelationshipType.NATIVE_NETWORK_BINDS_TO);
900     requirement.setNode(interfaceTranslatedId);
901     DataModelUtil
902         .addRequirementAssignment(subInterfaceNodeTemplate,
903             ToscaConstants.BINDING_REQUIREMENT_ID, requirement);
904   }
905
906   /**
907    * Get property Parameter Name Value.
908    *
909    * @param property property
910    * @return Parameter name in case the property include "get_param" function
911    */
912   public static Optional<String> getPropertyParameterNameValue(Object property) {
913     if (Objects.isNull(property)) {
914       return Optional.empty();
915     }
916     Optional<AttachedPropertyVal> extractedProperty = extractProperty(property);
917     if (extractedProperty.isPresent()) {
918       return getParameterName(extractedProperty.get());
919     }
920     return Optional.empty();
921   }
922
923   private static Optional<String> getParameterName(AttachedPropertyVal extractedProperty) {
924     if (!extractedProperty.isGetParam()) {
925       return Optional.empty();
926     }
927     Object getParamFuncValue = extractedProperty.getPropertyValue();
928     if (getParamFuncValue instanceof String) {
929       return Optional.of((String) getParamFuncValue);
930     } else {
931       return Optional.of((String) ((List) getParamFuncValue).get(0));
932     }
933   }
934
935   public static String getToscaPropertyName(TranslationContext context, String heatResourceType,
936                                             String heatPropertyName) {
937     return context.getElementMapping(heatResourceType, Constants.PROP, heatPropertyName);
938   }
939
940   /**
941    * Gets tosca property name.
942    *
943    * @param translateTo      the translate to
944    * @param heatPropertyName the heat property name
945    * @return the tosca property name
946    */
947   public static String getToscaPropertyName(TranslateTo translateTo, String heatPropertyName) {
948     return translateTo.getContext()
949         .getElementMapping(translateTo.getResource().getType(), Constants.PROP, heatPropertyName);
950   }
951
952   /**
953    * Gets tosca attribute name.
954    *
955    * @param context          the context
956    * @param heatResourceType the heat resource type
957    * @param heatAttrName     the heat attr name
958    * @return the tosca attribute name
959    */
960   public static String getToscaAttributeName(TranslationContext context, String heatResourceType,
961                                              String heatAttrName) {
962     return context.getElementMapping(heatResourceType, Constants.ATTR, heatAttrName);
963   }
964
965   /**
966    * Gets tosca attribute name.
967    *
968    * @param translateTo  the translate to
969    * @param heatAttrName the heat attr name
970    * @return the tosca attribute name
971    */
972   public static String getToscaAttributeName(TranslateTo translateTo, String heatAttrName) {
973     return translateTo.getContext()
974         .getElementMapping(translateTo.getResource().getType(), Constants.ATTR, heatAttrName);
975   }
976
977   /**
978    * Create init substitution service template service template.
979    *
980    * @param templateName the template name
981    * @return the service template
982    */
983   public static ServiceTemplate createInitSubstitutionServiceTemplate(String templateName) {
984     ServiceTemplate nestedSubstitutionServiceTemplate = new ServiceTemplate();
985     Map<String, String> templateMetadata = new HashMap<>();
986     templateMetadata.put(ToscaConstants.ST_METADATA_TEMPLATE_NAME, templateName);
987     nestedSubstitutionServiceTemplate.setMetadata(templateMetadata);
988     nestedSubstitutionServiceTemplate
989         .setTosca_definitions_version(ToscaConstants.TOSCA_DEFINITIONS_VERSION);
990     nestedSubstitutionServiceTemplate.setTopology_template(new TopologyTemplate());
991     List<Map<String, Import>> globalTypesImportList =
992         GlobalTypesGenerator.getGlobalTypesImportList();
993     globalTypesImportList.addAll(
994         HeatToToscaUtil.createImportList(Constants.GLOBAL_SUBSTITUTION_TYPES_TEMPLATE_NAME));
995     nestedSubstitutionServiceTemplate.setImports(globalTypesImportList);
996     return nestedSubstitutionServiceTemplate;
997   }
998
999   /**
1000    * Create init global substitution service template service template.
1001    *
1002    * @return the service template
1003    */
1004   public static ServiceTemplate createInitGlobalSubstitutionServiceTemplate() {
1005     ServiceTemplate globalSubstitutionServiceTemplate = new ServiceTemplate();
1006     Map<String, String> templateMetadata = new HashMap<>();
1007     templateMetadata.put(ToscaConstants.ST_METADATA_TEMPLATE_NAME,
1008         Constants.GLOBAL_SUBSTITUTION_TYPES_TEMPLATE_NAME);
1009     globalSubstitutionServiceTemplate.setMetadata(templateMetadata);
1010     globalSubstitutionServiceTemplate
1011         .setImports(GlobalTypesGenerator.getGlobalTypesImportList());
1012     globalSubstitutionServiceTemplate
1013         .setTosca_definitions_version(ToscaConstants.TOSCA_DEFINITIONS_VERSION);
1014     return globalSubstitutionServiceTemplate;
1015   }
1016
1017   /**
1018    * Create substitution node type node type.
1019    *
1020    * @param substitutionServiceTemplate the substitution service template
1021    * @return the node type
1022    */
1023   public NodeType createSubstitutionNodeType(ServiceTemplate substitutionServiceTemplate) {
1024     NodeType substitutionNodeType = new NodeType();
1025     substitutionNodeType.setDerived_from(ToscaNodeType.ABSTRACT_SUBSTITUTE);
1026     substitutionNodeType.setDescription(substitutionServiceTemplate.getDescription());
1027     substitutionNodeType
1028         .setProperties(manageSubstitutionNodeTypeProperties(substitutionServiceTemplate));
1029     substitutionNodeType
1030         .setAttributes(manageSubstitutionNodeTypeAttributes(substitutionServiceTemplate));
1031     return substitutionNodeType;
1032   }
1033
1034   private Map<String, PropertyDefinition> manageSubstitutionNodeTypeProperties(
1035       ServiceTemplate substitutionServiceTemplate) {
1036     Map<String, PropertyDefinition> substitutionNodeTypeProperties = new HashMap<>();
1037     Map<String, ParameterDefinition> properties =
1038         substitutionServiceTemplate.getTopology_template().getInputs();
1039     if (properties == null) {
1040       return null;
1041     }
1042
1043     PropertyDefinition propertyDefinition;
1044     String toscaPropertyName;
1045     for (Map.Entry<String, ParameterDefinition> entry : properties.entrySet()) {
1046       toscaPropertyName = entry.getKey();
1047       propertyDefinition = new PropertyDefinition();
1048       ParameterDefinition parameterDefinition =
1049           substitutionServiceTemplate.getTopology_template().getInputs().get(toscaPropertyName);
1050       propertyDefinition.setType(parameterDefinition.getType());
1051       propertyDefinition.setDescription(parameterDefinition.getDescription());
1052       propertyDefinition.setRequired(parameterDefinition.getRequired());
1053       propertyDefinition.set_default(parameterDefinition.get_default());
1054       propertyDefinition.setConstraints(parameterDefinition.getConstraints());
1055       propertyDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
1056       propertyDefinition.setStatus(parameterDefinition.getStatus());
1057       substitutionNodeTypeProperties.put(toscaPropertyName, propertyDefinition);
1058     }
1059     return substitutionNodeTypeProperties;
1060   }
1061
1062   private Map<String, AttributeDefinition> manageSubstitutionNodeTypeAttributes(
1063       ServiceTemplate substitutionServiceTemplate) {
1064     Map<String, AttributeDefinition> substitutionNodeTypeAttributes = new HashMap<>();
1065     Map<String, ParameterDefinition> attributes =
1066         substitutionServiceTemplate.getTopology_template().getOutputs();
1067     if (attributes == null) {
1068       return null;
1069     }
1070     AttributeDefinition attributeDefinition;
1071     String toscaAttributeName;
1072
1073     for (Map.Entry<String, ParameterDefinition> entry : attributes.entrySet()) {
1074       attributeDefinition = new AttributeDefinition();
1075       toscaAttributeName = entry.getKey();
1076       ParameterDefinition parameterDefinition =
1077           substitutionServiceTemplate.getTopology_template().getOutputs().get(toscaAttributeName);
1078       if (parameterDefinition.getType() != null && !parameterDefinition.getType().isEmpty()) {
1079         attributeDefinition.setType(parameterDefinition.getType());
1080       } else {
1081         attributeDefinition.setType(PropertyType.STRING.getDisplayName());
1082       }
1083       attributeDefinition.setDescription(parameterDefinition.getDescription());
1084       attributeDefinition.set_default(parameterDefinition.get_default());
1085       attributeDefinition.setEntry_schema(parameterDefinition.getEntry_schema());
1086       attributeDefinition.setStatus(parameterDefinition.getStatus());
1087       substitutionNodeTypeAttributes.put(toscaAttributeName, attributeDefinition);
1088     }
1089     return substitutionNodeTypeAttributes;
1090   }
1091
1092   /**
1093    * .
1094    * Create and add substitution mapping to the nested substitution service template, and update
1095    * the subtitution node type accordingly with the exposed requerments and capabilities
1096    *
1097    * @param context                           the translation context
1098    * @param substitutionNodeTypeKey           the substitution node type key
1099    * @param nestedSubstitutionServiceTemplate the nested substitution service template
1100    * @param substitutionNodeType              the substitution node type
1101    */
1102   public static void handleSubstitutionMapping(
1103       TranslationContext context,
1104       String substitutionNodeTypeKey,
1105       ServiceTemplate nestedSubstitutionServiceTemplate,
1106       NodeType substitutionNodeType) {
1107     Map<String, Map<String, List<String>>> substitutionMapping =
1108         getSubstitutionNodeTypeExposedConnectionPoints(substitutionNodeType,
1109             nestedSubstitutionServiceTemplate, context);
1110     //add substitution mapping after capability and requirement expose calculation
1111     nestedSubstitutionServiceTemplate.getTopology_template().setSubstitution_mappings(
1112         DataModelUtil.createSubstitutionTemplateSubMapping(substitutionNodeTypeKey,
1113             substitutionNodeType, substitutionMapping));
1114   }
1115
1116   /**
1117    * Gets node type with flat hierarchy.
1118    *
1119    * @param nodeTypeId      the node type id
1120    * @param serviceTemplate the service template
1121    * @param context         the context
1122    * @return the node type with flat hierarchy
1123    */
1124   public static NodeType getNodeTypeWithFlatHierarchy(String nodeTypeId,
1125                                                       ServiceTemplate serviceTemplate,
1126                                                       TranslationContext context) {
1127     ToscaAnalyzerService toscaAnalyzerService = new ToscaAnalyzerServiceImpl();
1128     ToscaServiceModel toscaServiceModel = HeatToToscaUtil
1129         .getToscaServiceModel(context, serviceTemplate.getMetadata());
1130     return (NodeType) toscaAnalyzerService
1131         .getFlatEntity(ToscaElementTypes.NODE_TYPE, nodeTypeId, serviceTemplate, toscaServiceModel);
1132   }
1133
1134   /**
1135    * Create substitution node template node template.
1136    *
1137    * @param translateTo             the translate to
1138    * @param templateName            the template name
1139    * @param substitutionNodeTypeKey the substitution node type key
1140    * @return the node template
1141    */
1142   public NodeTemplate createSubstitutionNodeTemplate(TranslateTo translateTo, String templateName,
1143                                                      String substitutionNodeTypeKey) {
1144     NodeTemplate substitutionNodeTemplate = new NodeTemplate();
1145     List<String> directiveList = new ArrayList<>();
1146     directiveList.add(ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
1147     substitutionNodeTemplate.setDirectives(directiveList);
1148     substitutionNodeTemplate.setType(substitutionNodeTypeKey);
1149     substitutionNodeTemplate.setProperties(
1150         managerSubstitutionNodeTemplateProperties(translateTo, substitutionNodeTemplate,
1151             templateName));
1152     return substitutionNodeTemplate;
1153   }
1154
1155   /**
1156    * Create abstract substitution node template.
1157    *
1158    * @param translateTo             the translate to
1159    * @param templateName            the template name
1160    * @param substitutionNodeTypeKey the substitution node type key
1161    * @return the abstract substitute node template
1162    */
1163   public static NodeTemplate createAbstractSubstitutionNodeTemplate(
1164       TranslateTo translateTo,
1165       String templateName,
1166       String substitutionNodeTypeKey) {
1167     NodeTemplate substitutionNodeTemplate = new NodeTemplate();
1168     List<String> directiveList = new ArrayList<>();
1169     directiveList.add(ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
1170     substitutionNodeTemplate.setDirectives(directiveList);
1171     substitutionNodeTemplate.setType(substitutionNodeTypeKey);
1172     substitutionNodeTemplate.setProperties(
1173         managerSubstitutionNodeTemplateProperties(translateTo, substitutionNodeTemplate,
1174             templateName));
1175     return substitutionNodeTemplate;
1176   }
1177
1178
1179   /**
1180    * Checks if the source and target resource is a valid candidate for adding tosca dependency
1181    * relationship.
1182    *
1183    * @param sourceResource          the source resource
1184    * @param targetResource          the target resource
1185    * @param dependencyEntity        the dependency entity
1186    * @return true if the candidate resources are a valid combination for the dependency relationship
1187    *              and false otherwise
1188    */
1189   public static boolean isValidDependsOnCandidate(Resource sourceResource,
1190                                                   Resource targetResource,
1191                                                   ConsolidationEntityType dependencyEntity,
1192                                                   TranslationContext context) {
1193     dependencyEntity.setEntityType(sourceResource, targetResource, context);
1194     ConsolidationEntityType sourceEntityType = dependencyEntity.getSourceEntityType();
1195     ConsolidationEntityType targetEntityType = dependencyEntity.getTargetEntityType();
1196
1197     return ConsolidationTypesConnectivity
1198         .isDependsOnRelationshipValid(sourceEntityType, targetEntityType);
1199   }
1200
1201   private static Map<String, Object> managerSubstitutionNodeTemplateProperties(
1202       TranslateTo translateTo,
1203       Template template,
1204       String templateName) {
1205     Map<String, Object> substitutionProperties = new HashMap<>();
1206     Map<String, Object> heatProperties = translateTo.getResource().getProperties();
1207     if (Objects.nonNull(heatProperties)) {
1208       for (Map.Entry<String, Object> entry : heatProperties.entrySet()) {
1209         Object property = TranslatorHeatToToscaPropertyConverter
1210             .getToscaPropertyValue(translateTo.getServiceTemplate(),
1211                 translateTo.getTranslatedId(), entry.getKey(),
1212                 entry.getValue(), null, translateTo.getHeatFileName(),
1213                 translateTo.getHeatOrchestrationTemplate(), template, translateTo.getContext());
1214         substitutionProperties.put(entry.getKey(), property);
1215       }
1216     }
1217     return addAbstractSubstitutionProperty(templateName, substitutionProperties);
1218   }
1219
1220   private static Map<String, Object> addAbstractSubstitutionProperty(String templateName,
1221                                                                      Map<String, Object>
1222                                                                          substitutionProperties) {
1223     Map<String, Object> innerProps = new HashMap<>();
1224     innerProps.put(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME,
1225         ToscaUtil.getServiceTemplateFileName(templateName));
1226     substitutionProperties.put(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME, innerProps);
1227     return substitutionProperties;
1228   }
1229
1230   private static Map<String, Map<String, List<String>>>
1231   getSubstitutionNodeTypeExposedConnectionPoints(NodeType substitutionNodeType,
1232                                                  ServiceTemplate substitutionServiceTemplate,
1233                                                  TranslationContext context) {
1234     Map<String, NodeTemplate> nodeTemplates =
1235         substitutionServiceTemplate.getTopology_template().getNode_templates();
1236     String nodeTemplateId;
1237     NodeTemplate nodeTemplate;
1238     String nodeType;
1239     Map<String, Map<String, List<String>>> substitutionMapping = new HashMap<>();
1240     if (nodeTemplates == null) {
1241       return substitutionMapping;
1242     }
1243
1244     Map<String, List<String>> capabilitySubstitutionMapping = new HashMap<>();
1245     Map<String, List<String>> requirementSubstitutionMapping = new HashMap<>();
1246     substitutionMapping.put("capability", capabilitySubstitutionMapping);
1247     substitutionMapping.put("requirement", requirementSubstitutionMapping);
1248     List<Map<String, RequirementDefinition>> nodeTypeRequirementsDefinition;
1249     Map<String, RequirementAssignment> nodeTemplateRequirementsAssignment;
1250     List<Map<String, RequirementDefinition>> exposedRequirementsDefinition;
1251     Map<String, Map<String, RequirementAssignment>> fullFilledRequirementsDefinition =
1252         new HashMap<>();
1253     Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition = new HashMap<>();
1254     Map<String, CapabilityDefinition> exposedCapabilitiesDefinition;
1255     ToscaAnalyzerService toscaAnalyzerService = new ToscaAnalyzerServiceImpl();
1256
1257     for (Map.Entry<String, NodeTemplate> entry : nodeTemplates.entrySet()) {
1258       nodeTemplateId = entry.getKey();
1259       nodeTemplate = entry.getValue();
1260       nodeType = nodeTemplate.getType();
1261
1262       // get requirements
1263       nodeTypeRequirementsDefinition =
1264           getNodeTypeReqs(nodeType, nodeTemplateId, substitutionServiceTemplate,
1265               requirementSubstitutionMapping, context);
1266       nodeTemplateRequirementsAssignment = DataModelUtil.getNodeTemplateRequirements(nodeTemplate);
1267       fullFilledRequirementsDefinition.put(nodeTemplateId, nodeTemplateRequirementsAssignment);
1268       //set substitution node type requirements
1269       exposedRequirementsDefinition =
1270           toscaAnalyzerService.calculateExposedRequirements(nodeTypeRequirementsDefinition,
1271               nodeTemplateRequirementsAssignment);
1272       DataModelUtil
1273           .addSubstitutionNodeTypeRequirements(substitutionNodeType, exposedRequirementsDefinition,
1274               nodeTemplateId);
1275
1276       //get capabilities
1277       addNodeTypeCapabilitiesToSubMapping(nodeTypeCapabilitiesDefinition,
1278           capabilitySubstitutionMapping, nodeType,
1279           nodeTemplateId, substitutionServiceTemplate, context);
1280     }
1281
1282     exposedCapabilitiesDefinition =
1283         toscaAnalyzerService.calculateExposedCapabilities(nodeTypeCapabilitiesDefinition,
1284             fullFilledRequirementsDefinition);
1285     DataModelUtil.addNodeTypeCapabilitiesDef(substitutionNodeType, exposedCapabilitiesDefinition);
1286     return substitutionMapping;
1287   }
1288
1289   private static void addNodeTypeCapabilitiesToSubMapping(
1290       Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition,
1291       Map<String, List<String>> capabilitySubstitutionMapping, String type, String templateName,
1292       ServiceTemplate serviceTemplate, TranslationContext context) {
1293     NodeType flatNodeType =
1294         getNodeTypeWithFlatHierarchy(type, serviceTemplate, context);
1295
1296     if (flatNodeType.getCapabilities() != null) {
1297       flatNodeType.getCapabilities()
1298           .entrySet()
1299           .stream()
1300           .forEach(capabilityNodeEntry ->
1301               addCapabilityToSubMapping(
1302                   templateName, capabilityNodeEntry, nodeTypeCapabilitiesDefinition, capabilitySubstitutionMapping));
1303     }
1304   }
1305
1306   public static boolean shouldAnnotationsToBeAdded() {
1307     return ToggleableFeature.ANNOTATIONS.isActive();
1308   }
1309
1310   private static void addCapabilityToSubMapping(String templateName,
1311                                                 Map.Entry<String, CapabilityDefinition> capabilityNodeEntry,
1312                                                 Map<String, CapabilityDefinition> nodeTypeCapabilitiesDefinition,
1313                                                 Map<String, List<String>> capabilitySubstitutionMapping) {
1314     String capabilityKey;
1315     List<String> capabilityMapping;
1316     capabilityKey = capabilityNodeEntry.getKey() + UNDERSCORE + templateName;
1317     nodeTypeCapabilitiesDefinition.put(capabilityKey, capabilityNodeEntry.getValue().clone());
1318     capabilityMapping = new ArrayList<>();
1319     capabilityMapping.add(templateName);
1320     capabilityMapping.add(capabilityNodeEntry.getKey());
1321     capabilitySubstitutionMapping.put(capabilityKey, capabilityMapping);
1322   }
1323
1324   private static List<Map<String, RequirementDefinition>> getNodeTypeReqs(
1325       String type,
1326       String templateName,
1327       ServiceTemplate serviceTemplate,
1328       Map<String, List<String>> requirementSubstitutionMapping,
1329       TranslationContext context) {
1330     List<Map<String, RequirementDefinition>> requirementList = new ArrayList<>();
1331     NodeType flatNodeType = getNodeTypeWithFlatHierarchy(type, serviceTemplate, context);
1332     List<String> requirementMapping;
1333
1334     if (flatNodeType.getRequirements() == null) {
1335       return requirementList;
1336     }
1337
1338     for (Map<String, RequirementDefinition> requirementMap : flatNodeType.getRequirements()) {
1339       for (Map.Entry<String, RequirementDefinition> requirementNodeEntry : requirementMap
1340           .entrySet()) {
1341         ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
1342         RequirementDefinition requirementNodeEntryValue = toscaExtensionYamlUtil
1343             .yamlToObject(toscaExtensionYamlUtil.objectToYaml(requirementNodeEntry.getValue()),
1344                 RequirementDefinition.class);
1345         if (Objects.isNull(requirementNodeEntryValue.getOccurrences())) {
1346           requirementNodeEntryValue.setOccurrences(new Object[]{1, 1});
1347         }
1348         Map<String, RequirementDefinition> requirementDef = new HashMap<>();
1349         requirementDef.put(requirementNodeEntry.getKey(), requirementNodeEntryValue);
1350         DataModelUtil.addRequirementToList(requirementList, requirementDef);
1351         requirementMapping = new ArrayList<>();
1352         requirementMapping.add(templateName);
1353         requirementMapping.add(requirementNodeEntry.getKey());
1354         requirementSubstitutionMapping
1355             .put(requirementNodeEntry.getKey() + UNDERSCORE + templateName, requirementMapping);
1356         if (Objects.isNull(requirementNodeEntryValue.getNode())) {
1357           requirementNodeEntryValue.setOccurrences(new Object[]{1, 1});
1358         }
1359       }
1360     }
1361     return requirementList;
1362   }
1363
1364   /**
1365    * Fetch global substitution service template service template.
1366    *
1367    * @param serviceTemplate the service template
1368    * @param context         the context
1369    * @return the service template
1370    */
1371   public static ServiceTemplate fetchGlobalSubstitutionServiceTemplate(
1372       ServiceTemplate serviceTemplate,
1373       TranslationContext context) {
1374     ServiceTemplate globalSubstitutionServiceTemplate =
1375         context.getTranslatedServiceTemplates()
1376             .get(Constants.GLOBAL_SUBSTITUTION_TYPES_TEMPLATE_NAME);
1377     if (globalSubstitutionServiceTemplate == null) {
1378       globalSubstitutionServiceTemplate =
1379           HeatToToscaUtil.createInitGlobalSubstitutionServiceTemplate();
1380       context.getTranslatedServiceTemplates()
1381           .put(Constants.GLOBAL_SUBSTITUTION_TYPES_TEMPLATE_NAME,
1382               globalSubstitutionServiceTemplate);
1383     }
1384     boolean isImportAddedToServiceTemplate =
1385         DataModelUtil.isImportAddedToServiceTemplate(serviceTemplate.getImports(), Constants
1386             .GLOBAL_SUBSTITUTION_TYPES_TEMPLATE_NAME);
1387     if (!isImportAddedToServiceTemplate) {
1388       serviceTemplate.getImports()
1389           .addAll(
1390               HeatToToscaUtil.createImportList(Constants.GLOBAL_SUBSTITUTION_TYPES_TEMPLATE_NAME));
1391     }
1392     return globalSubstitutionServiceTemplate;
1393   }
1394
1395   public static List<Map<String, Import>> createImportList(String templateName) {
1396     List<Map<String, Import>> imports = new ArrayList<>();
1397     Map<String, Import> importsMap = new HashMap<>();
1398     importsMap.put(templateName, HeatToToscaUtil.createServiceTemplateImport(templateName));
1399     imports.add(importsMap);
1400     return imports;
1401   }
1402
1403   /**
1404    * Create service template import import.
1405    *
1406    * @param serviceTemplate the service template
1407    * @return the import
1408    */
1409   public static Import createServiceTemplateImport(ServiceTemplate serviceTemplate) {
1410     Import serviceTemplateImport = new Import();
1411     serviceTemplateImport.setFile(ToscaUtil.getServiceTemplateFileName(serviceTemplate));
1412     return serviceTemplateImport;
1413   }
1414
1415   /**
1416    * Create service template import import.
1417    *
1418    * @param metadataTemplateName the service template name
1419    * @return the import
1420    */
1421   public static Import createServiceTemplateImport(String metadataTemplateName) {
1422     Import serviceTemplateImport = new Import();
1423     serviceTemplateImport.setFile(ToscaUtil.getServiceTemplateFileName(metadataTemplateName));
1424     return serviceTemplateImport;
1425   }
1426
1427   public static ToscaServiceModel createToscaServiceModel(ServiceTemplate
1428                                                               entryDefinitionServiceTemplate,
1429                                                           TranslationContext translationContext) {
1430     return new ToscaServiceModel(getCsarArtifactFiles(translationContext),
1431         getServiceTemplates(translationContext),
1432         ToscaUtil.getServiceTemplateFileName(entryDefinitionServiceTemplate));
1433   }
1434
1435   private static FileContentHandler getCsarArtifactFiles(TranslationContext translationContext) {
1436     FileContentHandler artifactFiles = new FileContentHandler();
1437     artifactFiles.setFiles(translationContext.getFiles());
1438     artifactFiles.setFiles(translationContext.getExternalArtifacts());
1439
1440     HeatTreeManager heatTreeManager =
1441         HeatTreeManagerUtil.initHeatTreeManager(translationContext.getFiles());
1442     heatTreeManager.createTree();
1443     ValidationStructureList validationStructureList =
1444         new ValidationStructureList(heatTreeManager.getTree());
1445     byte[] validationStructureFile =
1446         FileUtils.convertToBytes(validationStructureList, FileUtils.FileExtension.JSON);
1447     artifactFiles.addFile("HEAT.meta", validationStructureFile);
1448     return artifactFiles;
1449   }
1450
1451
1452   private static Map<String, ServiceTemplate> getServiceTemplates(TranslationContext
1453                                                                       translationContext) {
1454     List<ServiceTemplate> serviceTemplates = new ArrayList<>();
1455     serviceTemplates.addAll(GlobalTypesGenerator
1456         .getGlobalTypesServiceTemplate(OnboardingTypesEnum.ZIP).values());
1457     serviceTemplates.addAll(translationContext.getTranslatedServiceTemplates().values());
1458     Map<String, ServiceTemplate> serviceTemplatesMap = new HashMap<>();
1459
1460     for (ServiceTemplate template : serviceTemplates) {
1461       serviceTemplatesMap.put(ToscaUtil.getServiceTemplateFileName(template), template);
1462     }
1463     return serviceTemplatesMap;
1464   }
1465
1466   public static String getNestedResourceTypePrefix(TranslateTo translateTo) {
1467     String nestedFileName = translateTo.getResource().getType();
1468     if (isSubInterfaceResource(translateTo.getResource(), translateTo.getContext())
1469         && isSubInterfaceBoundToPort(translateTo)) {
1470       return ToscaNodeType.VLAN_SUB_INTERFACE_RESOURCE_TYPE_PREFIX;
1471     }
1472     return ToscaNodeType.NESTED_HEAT_RESOURCE_TYPE_PREFIX;
1473   }
1474
1475   private static boolean isSubInterfaceBoundToPort(TranslateTo translateTo) {
1476     return HeatToToscaUtil.getSubInterfaceParentPortNodeTemplateId(translateTo).isPresent();
1477   }
1478
1479   //Method evaluate the  network role from sub interface node template id, designed considering
1480   // only single sub interface present in nested file else it will return null
1481   public static Optional<String> getNetworkRoleFromResource(Resource resource,
1482                                                             TranslationContext translationContext) {
1483     Optional<String> networkRole = Optional.empty();
1484     Optional<String> nestedHeatFileName = HeatToToscaUtil.getNestedHeatFileName(resource);
1485
1486     if (!nestedHeatFileName.isPresent()) {
1487       return networkRole;
1488     }
1489
1490     HeatOrchestrationTemplate nestedHeatOrchestrationTemplate = new YamlUtil()
1491         .yamlToObject(translationContext.getFileContent(nestedHeatFileName.get()),
1492             HeatOrchestrationTemplate.class);
1493
1494     if (MapUtils.isNotEmpty(nestedHeatOrchestrationTemplate.getResources())) {
1495       ContrailV2VirtualMachineInterfaceHelper contrailV2VirtualMachineInterfaceHelper =
1496           new ContrailV2VirtualMachineInterfaceHelper();
1497       Optional<Map.Entry<String, Resource>> vlanSubInterfaceResource = nestedHeatOrchestrationTemplate
1498           .getResources().entrySet().stream()
1499           .filter(resourceEntry -> contrailV2VirtualMachineInterfaceHelper
1500               .isVlanSubInterfaceResource(resourceEntry.getValue()))
1501           .findFirst();
1502       if (vlanSubInterfaceResource.isPresent()) {
1503         Map.Entry<String, Resource> vlanSubInterfaceResourceEntry = vlanSubInterfaceResource.get();
1504         networkRole = evaluateNetworkRoleFromResourceId(vlanSubInterfaceResourceEntry.getKey(),
1505             vlanSubInterfaceResourceEntry.getValue().getType());
1506       }
1507     }
1508     return networkRole;
1509   }
1510
1511   public static Optional<String> evaluateNetworkRoleFromResourceId(String resourceId, String resourceType) {
1512     if (resourceType.equals(HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE.getHeatResource())) {
1513       return Optional.ofNullable(extractNetworkRoleFromContrailPortId(resourceId));
1514     }
1515
1516     if (resourceType.equals(HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource())) {
1517       return Optional.ofNullable(extractNetworkRoleFromNeutronPortId(resourceId));
1518     }
1519     return Optional.empty();
1520   }
1521
1522   private static String extractNetworkRoleFromContrailPortId(String portResourceId) {
1523     String vmiResourceIdRegex = "(\\w+)(_\\d+){0,1}_(\\w+)_vmi(_\\d+){0,1}";
1524     String vmiIntResourceIdRegex = "(\\w+)(_\\d+){0,1}_int_(\\w+)_vmi(_\\d+){0,1}";
1525
1526     String portNetworkRole = getPortNetworkRole(portResourceId, vmiResourceIdRegex);
1527     String portIntNetworkRole = getPortNetworkRole(portResourceId, vmiIntResourceIdRegex);
1528
1529     return Objects.nonNull(portNetworkRole) ? portNetworkRole : portIntNetworkRole;
1530   }
1531
1532
1533   private static String extractNetworkRoleFromNeutronPortId(String portResourceId) {
1534     String portResourceIdRegex = "(\\w+)(_\\d+){0,1}_(\\w+)_port(_\\d+){0,1}";
1535     String portIntResourceIdRegex = "(\\w+)(_\\d+){0,1}_int_(\\w+)_port(_\\d+){0,1}";
1536
1537     String portNetworkRole = getPortNetworkRole(portResourceId, portResourceIdRegex);
1538     String portIntNetworkRole = getPortNetworkRole(portResourceId, portIntResourceIdRegex);
1539
1540     return Objects.nonNull(portNetworkRole) ? portNetworkRole : portIntNetworkRole;
1541   }
1542
1543   private static String getPortNetworkRole(String portResourceId, String portIdRegex) {
1544     Pattern pattern = Pattern.compile(portIdRegex);
1545     Matcher matcher = pattern.matcher(portResourceId);
1546     if (matcher.matches()) {
1547       String networkRole = matcher.group(3);
1548       //Assuming network role will not contain ONLY digits
1549       if (!networkRole.matches("\\d+")) {
1550         return matcher.group(3);
1551       }
1552     }
1553     return null;
1554   }
1555
1556 }