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