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