push addional code
[sdc.git] / openecomp-be / lib / openecomp-sdc-translator-lib / openecomp-sdc-translator-core / src / main / java / org / openecomp / sdc / translator / services / heattotosca / impl / ResourceTranslationBase.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.translator.services.heattotosca.impl;
22
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.apache.commons.lang3.StringUtils;
26 import org.openecomp.core.utilities.yaml.YamlUtil;
27 import org.openecomp.sdc.common.errors.CoreException;
28 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
29 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
30 import org.openecomp.sdc.heat.datatypes.model.Output;
31 import org.openecomp.sdc.heat.datatypes.model.Resource;
32 import org.openecomp.sdc.tosca.datatypes.ToscaCapabilityType;
33 import org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType;
34 import org.openecomp.sdc.tosca.datatypes.model.ArtifactDefinition;
35 import org.openecomp.sdc.tosca.datatypes.model.AttributeDefinition;
36 import org.openecomp.sdc.tosca.datatypes.model.CapabilityDefinition;
37 import org.openecomp.sdc.tosca.datatypes.model.Import;
38 import org.openecomp.sdc.tosca.datatypes.model.InterfaceDefinition;
39 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
40 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
41 import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition;
42 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
43 import org.openecomp.sdc.tosca.datatypes.model.RequirementDefinition;
44 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
45 import org.openecomp.sdc.tosca.services.DataModelUtil;
46 import org.openecomp.sdc.tosca.services.ToscaConstants;
47 import org.openecomp.sdc.tosca.services.ToscaNativeTypesServiceTemplate;
48 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedResourceId;
49 import org.openecomp.sdc.translator.datatypes.heattotosca.to.ResourceFileDataAndIDs;
50 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslateTo;
51 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
52 import org.openecomp.sdc.translator.services.heattotosca.ResourceTranslation;
53 import org.openecomp.sdc.translator.services.heattotosca.ResourceTranslationFactory;
54 import org.openecomp.sdc.translator.services.heattotosca.TranslationContext;
55 import org.openecomp.sdc.translator.services.heattotosca.TranslationService;
56 import org.openecomp.sdc.translator.services.heattotosca.errors.ResourceNotFoundInHeatFileErrorBuilder;
57 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 import java.util.ArrayList;
62 import java.util.Collection;
63 import java.util.HashMap;
64 import java.util.HashSet;
65 import java.util.List;
66 import java.util.Map;
67 import java.util.Objects;
68 import java.util.Optional;
69 import java.util.function.Predicate;
70 import java.util.stream.Collectors;
71
72 public abstract class ResourceTranslationBase implements ResourceTranslation {
73
74   protected static Logger logger = LoggerFactory.getLogger(ResourceTranslationBase.class);
75
76   static Optional<ResourceFileDataAndIDs> getFileDataContainingResource(
77       List<FileData> filesToSearch, String resourceId, TranslationContext context,
78       FileData.Type... types) {
79     if (CollectionUtils.isEmpty(filesToSearch)) {
80       return Optional.empty();
81     }
82
83     List<FileData> fileDatas = Objects.isNull(types) ? filesToSearch
84         : HeatToToscaUtil.getFilteredListOfFileDataByTypes(filesToSearch, types);
85     for (FileData data : fileDatas) {
86       HeatOrchestrationTemplate heatOrchestrationTemplate = new YamlUtil()
87           .yamlToObject(context.getFiles().getFileContent(data.getFile()),
88               HeatOrchestrationTemplate.class);
89       Map<String, Output> outputs = heatOrchestrationTemplate.getOutputs();
90       if (Objects.isNull(outputs)) {
91         continue;
92       }
93       Output output = outputs.get(resourceId);
94       if (Objects.nonNull(output)) {
95         Optional<AttachedResourceId> attachedOutputId = HeatToToscaUtil
96             .extractAttachedResourceId(data.getFile(), heatOrchestrationTemplate, context,
97                 output.getValue());
98         if (attachedOutputId.isPresent()) {
99           AttachedResourceId attachedResourceId = attachedOutputId.get();
100           if (!attachedResourceId.isGetResource()) {
101             logger.warn("output: '" + resourceId + "' in file '" + data.getFile()
102                 + "' is not defined as get_resource and therefor not supported.");
103             continue;
104           }
105           ResourceFileDataAndIDs fileDataAndIDs =
106               new ResourceFileDataAndIDs((String) attachedResourceId.getEntityId(),
107                   (String) attachedResourceId.getTranslatedId(),
108                   data);
109           return Optional.of(fileDataAndIDs);
110         }
111       }
112     }
113     return Optional.empty();
114   }
115
116   /**
117    * Gets resource translated id.
118    *
119    * @param heatFileName              the heat file name
120    * @param heatOrchestrationTemplate the heat orchestration template
121    * @param resourceId                the resource id
122    * @param context                   the context
123    * @return the resource translated id
124    */
125   public static Optional<String> getResourceTranslatedId(String heatFileName,
126                                                          HeatOrchestrationTemplate
127                                                                  heatOrchestrationTemplate,
128                                                          String resourceId,
129                                                          TranslationContext context) {
130     if (!context.getTranslatedIds().containsKey(heatFileName)) {
131       context.getTranslatedIds().put(heatFileName, new HashMap<>());
132     }
133
134     Map<String, String> translatedIdsPerFile = context.getTranslatedIds().get(heatFileName);
135     String translatedId = translatedIdsPerFile.get(resourceId);
136     if (translatedId != null) {
137       return Optional.of(translatedId);
138     }
139
140     Resource resource = heatOrchestrationTemplate.getResources().get(resourceId);
141     if (resource == null) {
142       throw new CoreException(
143           new ResourceNotFoundInHeatFileErrorBuilder(resourceId, heatFileName).build());
144     }
145     TranslateTo translateTo =
146         generateTranslationTo(heatFileName, null, heatOrchestrationTemplate, resource, resourceId,
147             null, context);
148     translatedId =
149         ResourceTranslationFactory.getInstance(resource).generateTranslatedId(translateTo);
150     if (translatedId != null) {
151       context.getTranslatedIds().get(heatFileName).put(resourceId, translatedId);
152     }
153     return Optional.ofNullable(translatedId);
154   }
155
156   private static TranslateTo generateTranslationTo(String heatFileName,
157                                                    ServiceTemplate serviceTemplate,
158                                                    HeatOrchestrationTemplate
159                                                            heatOrchestrationTemplate,
160                                                    Resource resource, String resourceId,
161                                                    String translatedId,
162                                                    TranslationContext context) {
163     TranslateTo to = new TranslateTo();
164     to.setHeatFileName(heatFileName);
165     to.setServiceTemplate(serviceTemplate);
166     to.setHeatOrchestrationTemplate(heatOrchestrationTemplate);
167     to.setResource(resource);
168     to.setResourceId(resourceId);
169     to.setTranslatedId(translatedId);
170     to.setContext(context);
171     return to;
172   }
173
174   protected abstract void translate(TranslateTo translateTo);
175
176   protected String generateTranslatedId(TranslateTo translateTo) {
177     isEssentialRequirementsValid(translateTo);
178     return translateTo.getResourceId();
179   }
180
181   protected boolean isEssentialRequirementsValid(TranslateTo translateTo) {
182     return true;
183   }
184
185   @Override
186   public Optional<String> translateResource(String heatFileName, ServiceTemplate serviceTemplate,
187                                             HeatOrchestrationTemplate heatOrchestrationTemplate,
188                                             Resource resource, String resourceId,
189                                             TranslationContext context) {
190     Optional<String> translatedId =
191         getResourceTranslatedId(heatFileName, heatOrchestrationTemplate, resourceId, context);
192     context.getTranslatedResources().putIfAbsent(heatFileName, new HashSet<>());
193     if (context.getTranslatedResources().get(heatFileName).contains(resourceId)) {
194       return translatedId;
195     }
196     if (!translatedId.isPresent()) {
197       return Optional.empty();
198     }
199     logger.debug("Translate- file:" + heatFileName + " resource Id:" + resourceId
200         + " translated resource id:" + translatedId.get());
201     translate(new TranslateTo(heatFileName, serviceTemplate, heatOrchestrationTemplate, resource,
202             resourceId, translatedId.get(), context));
203     context.getTranslatedResources().get(heatFileName).add(resourceId);
204
205     if (isNodeTemplate(translatedId.get(), serviceTemplate)) {
206       if (!context.getHeatStackGroupMembers().containsKey(heatFileName)) {
207         context.getHeatStackGroupMembers().put(heatFileName, new HashSet<>());
208       }
209       context.getHeatStackGroupMembers().get(heatFileName).add(translatedId.get());
210       updateResourceDependency(heatFileName, resource, heatOrchestrationTemplate,
211           translatedId.get(), serviceTemplate, context);
212     }
213
214     return translatedId;
215   }
216
217   private void updateResourceDependency(String heatFileName, Resource resource,
218                                         HeatOrchestrationTemplate heatOrchestrationTemplate,
219                                         String translatedId, ServiceTemplate serviceTemplate,
220                                         TranslationContext context) {
221     if (resource.getDepends_on() == null) {
222       return;
223     }
224
225     if (resource.getDepends_on() instanceof List) {
226       List<String> dependsOnList = (List<String>) resource.getDepends_on();
227       for (String dependsOnResourceId : dependsOnList) {
228         addDependOnRequirement(dependsOnResourceId, translatedId, serviceTemplate, heatFileName,
229             heatOrchestrationTemplate, context);
230       }
231     } else {
232       String dependsOnResourceId = (String) resource.getDepends_on();
233       addDependOnRequirement(dependsOnResourceId, translatedId, serviceTemplate, heatFileName,
234           heatOrchestrationTemplate, context);
235     }
236
237   }
238
239   private void addDependOnRequirement(String dependsOnResourceId, String nodeTemplateId,
240                                       ServiceTemplate serviceTemplate, String heatFileName,
241                                       HeatOrchestrationTemplate heatOrchestrationTemplate,
242                                       TranslationContext context) {
243     RequirementAssignment requirementAssignment = new RequirementAssignment();
244     Optional<String> resourceTranslatedId =
245         getResourceTranslatedId(heatFileName, heatOrchestrationTemplate, dependsOnResourceId,
246             context);
247
248     if (resourceTranslatedId.isPresent()
249         && isNodeTemplate(resourceTranslatedId.get(), serviceTemplate)) {
250       requirementAssignment.setNode(resourceTranslatedId.get());
251       requirementAssignment.setCapability(ToscaCapabilityType.NODE.getDisplayName());
252       requirementAssignment.setRelationship(ToscaRelationshipType.DEPENDS_ON.getDisplayName());
253       DataModelUtil.addRequirementAssignment(
254           serviceTemplate.getTopology_template().getNode_templates().get(nodeTemplateId),
255           ToscaConstants.DEPENDS_ON_REQUIREMENT_ID, requirementAssignment);
256     }
257   }
258
259   private boolean isNodeTemplate(String entryId, ServiceTemplate serviceTemplate) {
260     return serviceTemplate.getTopology_template().getNode_templates() != null
261         && serviceTemplate.getTopology_template().getNode_templates().get(entryId) != null;
262   }
263
264   FileData getFileData(String fileName, TranslationContext context) {
265
266     List<FileData> fileDataList = context.getManifest().getContent().getData();
267     for (FileData fileData : fileDataList) {
268       if (TranslationService.getTypesToProcessByTranslator().contains(fileData.getType())
269           && fileData.getFile().equals(fileName)) {
270         return fileData;
271       }
272     }
273     return null;
274   }
275
276   NodeType getNodeTypeWithFlatHierarchy(String nodeTypeId, ServiceTemplate serviceTemplate,
277                                         TranslationContext context) {
278     NodeType nodeType;
279     if (serviceTemplate != null && serviceTemplate.getNode_types() != null) {
280       nodeType = serviceTemplate.getNode_types().get(nodeTypeId);
281
282       if (nodeType != null) {
283         return enrichNodeType(nodeType, serviceTemplate, context);
284       }
285     }
286     Map<String, Map<String, NodeType>> globalNodeTypesMap = new HashMap<>();
287     Collection<ServiceTemplate> globalNodeTypes =
288         GlobalTypesGenerator.getGlobalTypesServiceTemplate().values();
289     ServiceTemplate nativeNodeTypeServiceTemplate =
290         ToscaNativeTypesServiceTemplate.createServiceTemplate();
291     for (ServiceTemplate globalNodeType : globalNodeTypes) {
292       globalNodeTypesMap
293           .put(globalNodeType.getMetadata().getTemplate_name(), globalNodeType.getNode_types());
294     }
295     if (Objects.nonNull(serviceTemplate) && MapUtils.isNotEmpty(serviceTemplate.getImports())) {
296       for (Map.Entry<String, Import> entry : serviceTemplate.getImports().entrySet()) {
297         if (globalNodeTypesMap.containsKey(entry.getKey())) {
298           Map<String, NodeType> nodeTypes = globalNodeTypesMap.get(entry.getKey());
299           if (nodeTypes != null && nodeTypes.containsKey(nodeTypeId)) {
300             return enrichNodeType(nodeTypes.get(nodeTypeId), serviceTemplate, context);
301           }
302         }
303         if (context.getGlobalSubstitutionServiceTemplate() != null
304             && context.getGlobalSubstitutionServiceTemplate().getNode_types() != null
305             && context.getGlobalSubstitutionServiceTemplate().getNode_types()
306                 .containsKey(nodeTypeId)) {
307           return enrichNodeType(
308               context.getGlobalSubstitutionServiceTemplate().getNode_types().get(nodeTypeId),
309               serviceTemplate, context);
310         }
311         if (nativeNodeTypeServiceTemplate.getNode_types().containsKey(nodeTypeId)) {
312           return enrichNodeType(nativeNodeTypeServiceTemplate.getNode_types().get(nodeTypeId),
313               serviceTemplate, context);
314         }
315       }
316     }
317     return new NodeType();
318
319   }
320
321   private NodeType enrichNodeType(NodeType nodeType, ServiceTemplate serviceTemplate,
322                                   TranslationContext context) {
323     NodeType clonedNodeType;
324
325     if (StringUtils.isEmpty(nodeType.getDerived_from())) {
326       return nodeType.clone();
327     }
328
329     clonedNodeType = enrichNodeType(
330         getNodeTypeWithFlatHierarchy(nodeType.getDerived_from(), serviceTemplate, context),
331         serviceTemplate, context);
332     mergeNodeTypes(clonedNodeType, nodeType);
333     return clonedNodeType;
334
335   }
336
337   private void mergeNodeTypes(NodeType target, NodeType source) {
338     target.setDerived_from(source.getDerived_from());
339     target.setDescription(source.getDescription());
340     target.setVersion(source.getVersion());
341     target.setProperties(
342         mergeMaps(target.getProperties(), source.getProperties(), PropertyDefinition.class));
343     target.setInterfaces(
344         mergeMaps(target.getInterfaces(), source.getInterfaces(), InterfaceDefinition.class));
345     target.setArtifacts(
346         mergeMaps(target.getArtifacts(), source.getArtifacts(), ArtifactDefinition.class));
347     target.setAttributes(
348         mergeMaps(target.getAttributes(), source.getAttributes(), AttributeDefinition.class));
349     target.setCapabilities(
350         mergeMaps(target.getCapabilities(), source.getCapabilities(), CapabilityDefinition.class));
351     target.setRequirements(mergeLists(target.getRequirements(), source.getRequirements(),
352         RequirementDefinition.class));
353   }
354
355   private <T, S> List<Map<T, S>> mergeLists(List<Map<T, S>> target, List<Map<T, S>> source,
356                                             Class<S> value) {
357     List<Map<T, S>> retList = new ArrayList<>();
358     if (Objects.nonNull(target)) {
359       retList.addAll(target);
360     }
361
362     if (Objects.nonNull(source)) {
363       for (Map<T, S> sourceMap : source) {
364         for (Map.Entry<T, S> entry : sourceMap.entrySet()) {
365           mergeEntryInList(entry.getKey(), entry.getValue(), retList);
366         }
367       }
368     }
369     return retList;
370   }
371
372   <T, S> void mergeEntryInList(T key, S value, List<Map<T, S>> target) {
373     boolean found = false;
374     for (Map<T, S> map : target) {
375       if (map.containsKey(key)) {
376         map.put(key, value);
377         found = true;
378       }
379     }
380
381     if (!found) {
382       Map<T, S> newMap = new HashMap<>();
383       newMap.put(key, value);
384       target.add(newMap);
385     }
386   }
387
388
389   private <T, S> Map<T, S> mergeMaps(Map<T, S> target, Map<T, S> source, Class<S> value) {
390     Map<T, S> retMap = new HashMap<>();
391     if (MapUtils.isNotEmpty(target)) {
392       retMap.putAll(target);
393     }
394
395     if (MapUtils.isNotEmpty(source)) {
396       retMap.putAll(source);
397     }
398     return retMap;
399   }
400
401   Optional<List<Map.Entry<String, Resource>>> getResourceByTranslatedResourceId(
402           String fileName,
403           HeatOrchestrationTemplate heatOrchestrationTemplate,
404           String translatedResourceId,TranslateTo translateTo,String heatResourceType) {
405     List<Map.Entry<String, Resource>> list = heatOrchestrationTemplate.getResources().entrySet()
406         .stream()
407         .filter(
408             entry -> getPredicatesForTranslatedIdToResourceId(fileName, heatOrchestrationTemplate,
409                 translatedResourceId, translateTo.getContext(), heatResourceType)
410                 .stream()
411                     .allMatch(p -> p.test(entry)))
412         .collect(Collectors.toList());
413     if (CollectionUtils.isEmpty(list)) {
414       return Optional.empty();
415     } else {
416       return Optional.of(list);
417     }
418   }
419
420   private List<Predicate<Map.Entry<String, Resource>>> getPredicatesForTranslatedIdToResourceId(
421       String fileName, HeatOrchestrationTemplate heatOrchestrationTemplate,
422       String translatedResourceId, TranslationContext context, String heatResourceType) {
423     List<Predicate<Map.Entry<String, Resource>>> list = new ArrayList<>();
424     list.add(entry ->
425         entry.getValue().getType().equals(heatResourceType));
426     list.add(entry -> {
427       Optional<String> resourceTranslatedId =
428           getResourceTranslatedId(fileName, heatOrchestrationTemplate, entry.getKey(), context);
429       return resourceTranslatedId.isPresent()
430           && resourceTranslatedId.get().equals(translatedResourceId);
431     });
432     return list;
433   }
434
435   void addBindingReqFromPortToCompute(String computeNodeTemplateId, NodeTemplate portNodeTemplate) {
436     RequirementAssignment requirementAssignment = new RequirementAssignment();
437     requirementAssignment.setCapability(ToscaCapabilityType.NETWORK_BINDABLE.getDisplayName());
438     requirementAssignment.setRelationship(ToscaRelationshipType.NETWORK_BINDS_TO.getDisplayName());
439     requirementAssignment.setNode(computeNodeTemplateId);
440     DataModelUtil.addRequirementAssignment(portNodeTemplate, ToscaConstants.BINDING_REQUIREMENT_ID,
441         requirementAssignment);
442   }
443
444   void addLinkReqFromPortToNetwork(NodeTemplate nodeTemplate, String translatedId) {
445     RequirementAssignment requirement = new RequirementAssignment();
446     requirement.setCapability(ToscaCapabilityType.NETWORK_LINKABLE.getDisplayName());
447     requirement.setRelationship(ToscaRelationshipType.NETWORK_LINK_TO.getDisplayName());
448     requirement.setNode(translatedId);
449     DataModelUtil
450         .addRequirementAssignment(nodeTemplate, ToscaConstants.LINK_REQUIREMENT_ID, requirement);
451   }
452
453   boolean isResourceTypeSupported(Resource resource, List<String> supportedTypes) {
454     return Objects.nonNull(resource) && supportedTypes.contains(resource.getType());
455   }
456 }