a625bb6fc2b9071f16411547e8a53a122609bdc5
[sdc.git] / openecomp-be / lib / openecomp-tosca-converter-lib / openecomp-tosca-converter-core / src / main / java / org / openecomp / core / impl / ToscaConverterImpl.java
1 /*
2  * Copyright © 2016-2017 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.core.impl;
18
19 import static org.openecomp.core.converter.datatypes.Constants.ONAP_INDEX;
20 import static org.openecomp.core.converter.datatypes.Constants.capabilities;
21 import static org.openecomp.core.converter.datatypes.Constants.definitionsDir;
22 import static org.openecomp.core.converter.datatypes.Constants.globalStName;
23 import static org.openecomp.core.converter.datatypes.Constants.globalSubstitution;
24 import static org.openecomp.core.converter.datatypes.Constants.inputs;
25 import static org.openecomp.core.converter.datatypes.Constants.mainStName;
26 import static org.openecomp.core.converter.datatypes.Constants.manifestFileName;
27 import static org.openecomp.core.converter.datatypes.Constants.metadataFile;
28 import static org.openecomp.core.converter.datatypes.Constants.nodeType;
29 import static org.openecomp.core.converter.datatypes.Constants.openecompHeatIndex;
30 import static org.openecomp.core.converter.datatypes.Constants.outputs;
31 import static org.openecomp.core.converter.datatypes.Constants.requirements;
32 import static org.openecomp.core.impl.GlobalSubstitutionServiceTemplate.GLOBAL_SUBSTITUTION_SERVICE_FILE_NAME;
33 import static org.openecomp.core.impl.GlobalSubstitutionServiceTemplate.HEAT_INDEX_IMPORT_FILE;
34 import static org.openecomp.core.impl.GlobalSubstitutionServiceTemplate.ONAP_INDEX_IMPORT_FILE;
35
36 import org.apache.commons.collections.MapUtils;
37 import org.openecomp.core.converter.ServiceTemplateReaderService;
38 import org.openecomp.core.converter.ToscaConverter;
39 import org.openecomp.core.converter.datatypes.Constants;
40 import org.openecomp.core.converter.datatypes.CsarFileTypes;
41 import org.openecomp.core.converter.errors.SubstitutionMappingsConverterErrorBuilder;
42 import org.openecomp.core.impl.services.ServiceTemplateReaderServiceImpl;
43 import org.openecomp.core.utilities.file.FileContentHandler;
44 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
45 import org.openecomp.sdc.common.errors.CoreException;
46 import org.openecomp.sdc.common.errors.ErrorCategory;
47 import org.openecomp.sdc.common.errors.ErrorCode;
48 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
49 import org.openecomp.sdc.tosca.datatypes.model.ArtifactDefinition;
50 import org.openecomp.sdc.tosca.datatypes.model.CapabilityAssignment;
51 import org.openecomp.sdc.tosca.datatypes.model.Import;
52 import org.openecomp.sdc.tosca.datatypes.model.NodeFilter;
53 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
54 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
55 import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition;
56 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
57 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
58 import org.openecomp.sdc.tosca.datatypes.model.SubstitutionMapping;
59 import org.openecomp.sdc.tosca.services.DataModelUtil;
60 import org.openecomp.sdc.tosca.services.ToscaUtil;
61 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
62 import org.yaml.snakeyaml.error.YAMLException;
63
64 import java.io.File;
65 import java.io.IOException;
66 import java.util.ArrayList;
67 import java.util.Collection;
68 import java.util.HashMap;
69 import java.util.List;
70 import java.util.Map;
71 import java.util.Objects;
72 import java.util.Optional;
73 import java.util.regex.Pattern;
74
75 public class ToscaConverterImpl implements ToscaConverter {
76
77     private static final String ORIGINAL = ".original";
78   public ToscaConverterImpl() {
79
80   }
81
82   @Override
83   public ToscaServiceModel convert(FileContentHandler fileContentHandler) {
84     Map<String, byte[]> csarFiles = new HashMap<>(fileContentHandler.getFiles());
85     ToscaServiceModel toscaServiceModel = new ToscaServiceModel();
86     Map<String, ServiceTemplate> serviceTemplates = new HashMap<>();
87     FileContentHandler artifacts = new FileContentHandler();
88     GlobalSubstitutionServiceTemplate gsst = new GlobalSubstitutionServiceTemplate();
89     for (Map.Entry<String, byte[]> fileEntry : csarFiles.entrySet()) {
90       CsarFileTypes fileType = getFileType(fileEntry.getKey());
91       switch (fileType) {
92         case mainServiceTemplate:
93           handleServiceTemplate(mainStName, fileEntry.getKey(), csarFiles, serviceTemplates);
94           break;
95
96                 case globalServiceTemplate:
97                     handleServiceTemplate(globalStName, fileEntry.getKey(), csarFiles, serviceTemplates);
98                     break;
99
100                 case externalFile:
101                     artifacts.addFile(
102                         getConcreteArtifactFileName(fileEntry.getKey()), fileEntry.getValue());
103                     break;
104
105                 case definitionsFile:
106                     handleDefintionTemplate(fileEntry.getKey(), csarFiles, gsst);
107                     break;
108
109                 default:
110                     break;
111             }
112         }
113         handleMetadataFile(csarFiles);
114         updateToscaServiceModel(toscaServiceModel, serviceTemplates, artifacts, gsst, csarFiles);
115         return toscaServiceModel;
116     }
117
118     private void handleMetadataFile(Map<String, byte[]> csarFiles) {
119         byte[] bytes = csarFiles.remove(metadataFile);
120         if (bytes != null) {
121             csarFiles.put(metadataFile + ORIGINAL, bytes);
122         }
123     }
124
125     private void handleDefintionTemplate(String key, Map<String, byte[]> csarFiles,
126                                          GlobalSubstitutionServiceTemplate gsst) {
127         try {
128             ServiceTemplateReaderService readerService = new ServiceTemplateReaderServiceImpl(csarFiles.get(key));
129             Object nodeTypes = readerService.getNodeTypes();
130             if (nodeTypes instanceof Map) {
131                 Map<String, NodeType> nodeTypeMap = (Map<String, NodeType>) nodeTypes;
132                 gsst.appendNodes(nodeTypeMap);
133             }
134         } catch (YAMLException ye) {
135             throw new CoreException(new ErrorCode.ErrorCodeBuilder()
136                 .withMessage("Invalid YAML content in file " + key)
137                 .withCategory(ErrorCategory.APPLICATION).build(), ye);
138         }
139     }
140
141     private String getConcreteArtifactFileName(String fileName){
142         int artifactIndex = fileName.indexOf(CsarFileTypes.Artifacts.name());
143         if(artifactIndex < 0){
144             return fileName;
145         }
146
147         int artifactDirectoryIndex =
148             artifactIndex + CsarFileTypes.Artifacts.name().length() + 1;
149         return fileName.substring(artifactDirectoryIndex);
150     }
151
152     private void updateToscaServiceModel(ToscaServiceModel toscaServiceModel,
153                                          Map<String, ServiceTemplate> serviceTemplates,
154                                          FileContentHandler externalFilesHandler,
155                                          GlobalSubstitutionServiceTemplate globalSubstitutionServiceTemplate,
156                                          Map<String, byte[]> csarFiles) {
157         Collection<ServiceTemplate> globalServiceTemplates =
158             GlobalTypesGenerator.getGlobalTypesServiceTemplate(OnboardingTypesEnum.CSAR).values();
159         addGlobalServiceTemplates(globalServiceTemplates, serviceTemplates);
160         toscaServiceModel.setEntryDefinitionServiceTemplate(mainStName);
161         toscaServiceModel.setServiceTemplates(serviceTemplates);
162         externalFilesHandler.addFile(metadataFile + ORIGINAL,
163             csarFiles.get(metadataFile + ORIGINAL));
164         toscaServiceModel.setArtifactFiles(externalFilesHandler);
165
166         if(MapUtils.isNotEmpty(globalSubstitutionServiceTemplate.getNode_types())) {
167             serviceTemplates
168                 .put(GLOBAL_SUBSTITUTION_SERVICE_FILE_NAME, globalSubstitutionServiceTemplate);
169         }
170     }
171
172     private void addGlobalServiceTemplates(Collection<ServiceTemplate> globalServiceTemplates,
173                                            Map<String, ServiceTemplate> serviceTemplates) {
174         for (ServiceTemplate serviceTemplate : globalServiceTemplates) {
175             serviceTemplates.put(ToscaUtil.getServiceTemplateFileName(serviceTemplate), serviceTemplate);
176         }
177     }
178
179     private void handleServiceTemplate(String serviceTemplateName,
180                                        String fileName, Map<String, byte[]> csarFiles,
181                                        Map<String, ServiceTemplate> serviceTemplates) {
182         Optional<ServiceTemplate> serviceTemplate =
183             getServiceTemplateFromCsar(fileName, csarFiles);
184         serviceTemplate.ifPresent(
185             serviceTemplateValue -> addServiceTemplate(serviceTemplateName, serviceTemplateValue,
186                 serviceTemplates));
187     }
188
189     private void addServiceTemplate(String serviceTemplateName,
190                                     ServiceTemplate serviceTemplate,
191                                     Map<String, ServiceTemplate> serviceTemplates) {
192         serviceTemplates.put(serviceTemplateName, serviceTemplate);
193     }
194
195     private Optional<ServiceTemplate> getServiceTemplateFromCsar(String fileName,
196                                                                  Map<String, byte[]> csarFiles) {
197         byte[] fileContent = csarFiles.get(fileName);
198         ServiceTemplate serviceTemplate = convertServiceTemplate(fileName, fileContent);
199
200         return Optional.of(serviceTemplate);
201     }
202
203     private ServiceTemplate convertServiceTemplate(String serviceTemplateName,
204                                                    byte[] fileContent) {
205         ServiceTemplate serviceTemplate = new ServiceTemplate();
206         try {
207             ServiceTemplateReaderService readerService =
208                 new ServiceTemplateReaderServiceImpl(fileContent);
209             convertMetadata(serviceTemplateName, serviceTemplate, readerService);
210             convertToscaVersion(serviceTemplate, readerService);
211             convertImports(serviceTemplate);
212             convertNodeTypes(serviceTemplate, readerService);
213             convertTopologyTemplate(serviceTemplate, readerService);
214
215         } catch (YAMLException ye) {
216             throw new CoreException(new ErrorCode.ErrorCodeBuilder()
217                 .withMessage("Invalid YAML content in file" + serviceTemplateName)
218                 .withCategory(ErrorCategory.APPLICATION).build(), ye);
219         }
220
221
222         return serviceTemplate;
223     }
224
225     private void convertToscaVersion(ServiceTemplate serviceTemplate,
226                                      ServiceTemplateReaderService readerService) {
227         Object toscaVersion = readerService.getToscaVersion();
228         serviceTemplate.setTosca_definitions_version((String) toscaVersion);
229     }
230
231     private void convertImports(ServiceTemplate serviceTemplate) {
232         serviceTemplate.setImports(new ArrayList<>());
233         serviceTemplate.getImports()
234             .add(createImportMap(openecompHeatIndex, HEAT_INDEX_IMPORT_FILE));
235         serviceTemplate.getImports().add(createImportMap(ONAP_INDEX, ONAP_INDEX_IMPORT_FILE));
236         serviceTemplate.getImports().add(createImportMap(globalSubstitution, globalStName));
237
238     }
239
240     private Map<String, Import> createImportMap(String key, String fileName) {
241         Map<String, Import> importMap = new HashMap<>();
242         Import anImport = new Import();
243         anImport.setFile(fileName);
244         importMap.put(key, anImport);
245
246         return importMap;
247     }
248
249     private void convertMetadata(String serviceTemplateName,
250                                  ServiceTemplate serviceTemplate,
251                                  ServiceTemplateReaderService readerService) {
252         Map<String, Object> metadataToConvert = (Map<String, Object>) readerService.getMetadata();
253         Map<String, String> finalMetadata = new HashMap<>();
254
255         if (MapUtils.isNotEmpty(metadataToConvert)) {
256             for (Map.Entry<String, Object> metadataEntry : metadataToConvert.entrySet()) {
257                 if (Objects.isNull(metadataEntry.getValue()) ||
258                     !(metadataEntry.getValue() instanceof String)) {
259                     continue;
260                 }
261                 finalMetadata.put(metadataEntry.getKey(), (String) metadataEntry.getValue());
262             }
263         }
264
265         finalMetadata.put("template_name", getTemplateNameFromStName(serviceTemplateName));
266         serviceTemplate.setMetadata(finalMetadata);
267     }
268
269     private void convertNodeTypes(ServiceTemplate serviceTemplate, ServiceTemplateReaderService readerService) {
270         Map<String, Object> nodeTypes = readerService.getNodeTypes();
271         if (MapUtils.isEmpty(nodeTypes)) {
272             return;
273         }
274
275     for (Map.Entry<String, Object> nodeTypeEntry : nodeTypes.entrySet()) {
276       Optional<NodeType> nodeType = ToscaConverterUtil
277           .createObjectFromClass(nodeTypeEntry.getKey(), nodeTypeEntry.getValue(),
278               NodeType.class);
279
280       nodeType.ifPresent(nodeTypeValue -> DataModelUtil
281           .addNodeType(serviceTemplate, nodeTypeEntry.getKey(), nodeTypeValue));
282     }
283   }
284
285   private void convertTopologyTemplate(ServiceTemplate serviceTemplate,
286                                        ServiceTemplateReaderService readerService) {
287
288     convertInputs(serviceTemplate, readerService);
289     convertNodeTemplates(serviceTemplate, readerService);
290     convertOutputs(serviceTemplate, readerService);
291     convertSubstitutionMappings(serviceTemplate, readerService);
292   }
293
294   private void convertInputs(ServiceTemplate serviceTemplate,
295                              ServiceTemplateReaderService readerService) {
296     Map<String, Object> inputs = readerService.getInputs();
297     addInputsOrOutputsToServiceTemplate(serviceTemplate, inputs, Constants.inputs);
298   }
299
300   private void convertOutputs(ServiceTemplate serviceTemplate,
301                               ServiceTemplateReaderService readerService) {
302     Map<String, Object> outputs = readerService.getOutputs();
303     addInputsOrOutputsToServiceTemplate(serviceTemplate, outputs, Constants.outputs);
304   }
305
306   private void addInputsOrOutputsToServiceTemplate(ServiceTemplate serviceTemplate,
307                                                    Map<String, Object> mapToConvert,
308                                                    String inputsOrOutputs) {
309     if (MapUtils.isEmpty(mapToConvert)) {
310       return;
311     }
312
313     for (Map.Entry<String, Object> entry : mapToConvert.entrySet()) {
314       Optional<ParameterDefinition> parameterDefinition =
315           ToscaConverterUtil.createObjectFromClass(
316               entry.getKey(), entry.getValue(), ParameterDefinition.class);
317
318       parameterDefinition.ifPresent(parameterDefinitionValue -> {
319         Optional<Object> defaultValue =
320             ToscaConverterUtil.getDefaultValue(entry.getValue(), parameterDefinition.get());
321         defaultValue.ifPresent(parameterDefinitionValue::set_default);
322         addToServiceTemplateAccordingToSection(
323             serviceTemplate, inputsOrOutputs, entry.getKey(), parameterDefinition.get());
324       });
325     }
326   }
327
328     private void addToServiceTemplateAccordingToSection(ServiceTemplate serviceTemplate,
329                                                         String inputsOrOutputs,
330                                                         String parameterId,
331                                                         ParameterDefinition parameterDefinition) {
332         if (inputsOrOutputs.equals(inputs)) {
333             DataModelUtil
334                 .addInputParameterToTopologyTemplate(serviceTemplate, parameterId, parameterDefinition);
335         } else if (inputsOrOutputs.equals(outputs)) {
336             DataModelUtil
337                 .addOutputParameterToTopologyTemplate(serviceTemplate, parameterId, parameterDefinition);
338         }
339     }
340
341   private void convertNodeTemplates(ServiceTemplate serviceTemplate,
342                                     ServiceTemplateReaderService readerService) {
343     Map<String, Object> nodeTemplates = readerService.getNodeTemplates();
344     if (MapUtils.isEmpty(nodeTemplates)) {
345       return;
346     }
347
348     for (Map.Entry<String, Object> nodeTemplateEntry : nodeTemplates.entrySet()) {
349       NodeTemplate nodeTemplate = convertNodeTemplate(nodeTemplateEntry.getValue());
350       DataModelUtil.addNodeTemplate(serviceTemplate, nodeTemplateEntry.getKey(), nodeTemplate);
351     }
352   }
353
354   private void convertSubstitutionMappings(ServiceTemplate serviceTemplate,
355                                            ServiceTemplateReaderService readerService) {
356     Map<String, Object> substitutionMappings = readerService.getSubstitutionMappings();
357     if (MapUtils.isEmpty(substitutionMappings)) {
358       return;
359     }
360     SubstitutionMapping substitutionMapping = convertSubstitutionMappings(substitutionMappings);
361     DataModelUtil.addSubstitutionMapping(serviceTemplate, substitutionMapping);
362   }
363
364   private SubstitutionMapping convertSubstitutionMappings(
365       Map<String, Object> substitutionMappings) {
366     SubstitutionMapping substitutionMapping = new SubstitutionMapping();
367
368     substitutionMapping.setNode_type((String) substitutionMappings.get(nodeType));
369     substitutionMapping.setCapabilities(
370         convertSubstitutionMappingsSections(capabilities, substitutionMappings.get(capabilities)));
371     substitutionMapping.setRequirements(
372         convertSubstitutionMappingsSections(requirements, substitutionMappings.get(requirements)));
373
374     return substitutionMapping;
375   }
376
377   private Map<String, List<String>> convertSubstitutionMappingsSections(String sectionName,
378                                                                         Object sectionToConvert) {
379
380     if (Objects.isNull(sectionToConvert)) {
381       return null;
382     }
383
384     if (!(sectionToConvert instanceof Map)) {
385       throw new CoreException(
386           new SubstitutionMappingsConverterErrorBuilder(
387               sectionName, sectionToConvert.getClass().getSimpleName()).build());
388     }
389
390     return convertSection(sectionToConvert);
391   }
392
393   private Map<String, List<String>> convertSection(Object sectionToConvert) {
394
395     Map<String, Object> sectionAsMap = (Map<String, Object>) sectionToConvert;
396     Map<String, List<String>> convertedSection = new HashMap<>();
397
398     if (MapUtils.isEmpty(sectionAsMap)) {
399       return null;
400     }
401
402     for (Map.Entry<String, Object> entry : sectionAsMap.entrySet()) {
403       if (entry.getValue() instanceof List) {
404         convertedSection.put(entry.getKey(), (List<String>) entry.getValue());
405       }
406     }
407
408     return convertedSection;
409   }
410
411   private CsarFileTypes getFileType(String fileName) {
412     if (isMainServiceTemplate(fileName)) {
413       return CsarFileTypes.mainServiceTemplate;
414     } else if (isGlobalServiceTemplate(fileName)) {
415       return CsarFileTypes.globalServiceTemplate;
416     } else if (isDefinitions(fileName)) {
417       return CsarFileTypes.definitionsFile;
418     } else if (isMetadataFile(fileName)) {
419       return CsarFileTypes.toscaMetadata;
420     }
421     return CsarFileTypes.externalFile;
422   }
423
424     private NodeTemplate convertNodeTemplate(Object candidateNodeTemplate) {
425         NodeTemplate nodeTemplate = new NodeTemplate();
426
427         Map<String, Object> nodeTemplateAsMap = (Map<String, Object>) candidateNodeTemplate;
428         nodeTemplate.setArtifacts((Map<String, ArtifactDefinition>) nodeTemplateAsMap.get("artifacts"));
429         nodeTemplate.setAttributes((Map<String, Object>) nodeTemplateAsMap.get("attributes"));
430         nodeTemplate.setCopy((String) nodeTemplateAsMap.get("copy"));
431         nodeTemplate.setDescription((String) nodeTemplateAsMap.get("description"));
432         nodeTemplate.setDirectives((List<String>) nodeTemplateAsMap.get("directives"));
433         nodeTemplate.setInterfaces(
434             (Map<String, Object>) nodeTemplateAsMap.get("interfaces"));
435         nodeTemplate.setNode_filter((NodeFilter) nodeTemplateAsMap.get("node_filter"));
436         nodeTemplate.setProperties((Map<String, Object>) nodeTemplateAsMap.get("properties"));
437         nodeTemplate.setRequirements(
438             (List<Map<String, RequirementAssignment>>) nodeTemplateAsMap.get("requirements"));
439         nodeTemplate.setType((String) nodeTemplateAsMap.get("type"));
440         nodeTemplate.setCapabilities(
441             convertCapabilities((Map<String, Object>) nodeTemplateAsMap.get("capabilities")));
442
443     return nodeTemplate;
444   }
445
446   private Map<String, CapabilityAssignment> convertCapabilities(Map<String, Object> capabilities) {
447     if (MapUtils.isEmpty(capabilities)) {
448       return null;
449     }
450
451     Map<String, CapabilityAssignment> convertedCapabilities = new HashMap<>();
452     for (Map.Entry<String, Object> capabilityAssignmentEntry : capabilities.entrySet()) {
453       Optional<CapabilityAssignment> capabilityAssignment = ToscaConverterUtil.createObjectFromClass
454           (capabilityAssignmentEntry.getKey(), capabilityAssignmentEntry.getValue(),
455               CapabilityAssignment.class);
456
457       capabilityAssignment.ifPresent(capabilityAssignmentValue ->
458           convertedCapabilities.put(capabilityAssignmentEntry.getKey(), capabilityAssignmentValue));
459
460     }
461     return convertedCapabilities;
462   }
463
464
465   private boolean isMainServiceTemplate(String fileName) {
466     return fileName.endsWith(mainStName);
467   }
468
469   private boolean isMetadataFile(String fileName) {
470     return fileName.equals(metadataFile);
471   }
472
473   private boolean isGlobalServiceTemplate(String fileName) {
474     return fileName.endsWith(globalStName);
475   }
476
477   private boolean isDefinitions(String fileName) {
478     return fileName.startsWith(definitionsDir);
479   }
480
481   private String getTemplateNameFromStName(String serviceTemplateName) {
482     String fileNameWithoutDirectories;
483     fileNameWithoutDirectories = getFileNameWithoutDirectories(serviceTemplateName);
484     return fileNameWithoutDirectories.split("ServiceTemplate")[0];
485   }
486
487   private String getFileNameWithoutDirectories(String serviceTemplateName) {
488     String fileNameWithoutDirectories;
489     if (serviceTemplateName.contains("/")) {
490       String[] split = serviceTemplateName.split("/");
491       fileNameWithoutDirectories = split[split.length - 1];
492     } else if (serviceTemplateName.contains(File.separator)) {
493       String[] split = serviceTemplateName.split(Pattern.quote(File.separator));
494       fileNameWithoutDirectories = split[split.length - 1];
495     } else {
496       fileNameWithoutDirectories = serviceTemplateName;
497     }
498     return fileNameWithoutDirectories;
499   }
500 }