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