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