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