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