43a94e03f0b3a2cff91314f586c04005f4c33aed
[sdc.git] /
1 /*
2  * Copyright © 2016-2018 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.sdc.vendorsoftwareproduct.services.impl.filedatastructuremodule;
18
19 import org.apache.commons.collections4.CollectionUtils;
20 import org.openecomp.core.utilities.file.FileContentHandler;
21 import org.openecomp.core.utilities.json.JsonUtil;
22 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
23 import org.openecomp.sdc.common.errors.CoreException;
24 import org.openecomp.sdc.common.errors.ErrorCategory;
25 import org.openecomp.sdc.common.errors.ErrorCode;
26 import org.openecomp.sdc.common.errors.Messages;
27 import org.openecomp.sdc.common.utils.SdcCommon;
28 import org.openecomp.sdc.datatypes.error.ErrorLevel;
29 import org.openecomp.sdc.datatypes.error.ErrorMessage;
30 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
31 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
32 import org.openecomp.sdc.heat.datatypes.structure.Artifact;
33 import org.openecomp.sdc.heat.datatypes.structure.HeatStructureTree;
34 import org.openecomp.sdc.heat.datatypes.structure.ValidationStructureList;
35 import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateCandidateDao;
36 import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateCandidateDaoFactory;
37 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData;
38 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
39 import org.openecomp.sdc.vendorsoftwareproduct.errors.utils.ErrorsUtil;
40 import org.openecomp.sdc.vendorsoftwareproduct.services.HeatFileAnalyzer;
41 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.CandidateService;
42 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.ManifestCreator;
43 import org.openecomp.sdc.vendorsoftwareproduct.services.utils.CandidateServiceValidator;
44 import org.openecomp.sdc.vendorsoftwareproduct.types.CandidateDataEntityTo;
45 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.AnalyzedZipHeatFiles;
46 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure;
47 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module;
48 import org.openecomp.sdc.versioning.dao.types.Version;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import java.io.ByteArrayInputStream;
53 import java.io.ByteArrayOutputStream;
54 import java.io.IOException;
55 import java.io.InputStream;
56 import java.nio.ByteBuffer;
57 import java.nio.charset.StandardCharsets;
58 import java.util.ArrayList;
59 import java.util.HashSet;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.Objects;
63 import java.util.Optional;
64 import java.util.Set;
65 import java.util.stream.Collectors;
66 import java.util.zip.ZipEntry;
67 import java.util.zip.ZipInputStream;
68 import java.util.zip.ZipOutputStream;
69
70 import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters;
71
72 public class CandidateServiceImpl implements CandidateService {
73   private static final Logger logger = LoggerFactory.getLogger(CandidateServiceImpl.class);
74   private CandidateServiceValidator candidateServiceValidator = new CandidateServiceValidator();
75   private ManifestCreator manifestCreator;
76   private OrchestrationTemplateCandidateDao orchestrationTemplateCandidateDao;
77
78   public CandidateServiceImpl(ManifestCreator manifestCreator,
79                               OrchestrationTemplateCandidateDao orchestrationTemplateCandidateDao) {
80     this.manifestCreator = manifestCreator;
81     this.orchestrationTemplateCandidateDao = orchestrationTemplateCandidateDao;
82   }
83
84   public CandidateServiceImpl() {
85   }
86
87   @Override
88   public Optional<ErrorMessage> validateNonEmptyFileToUpload(InputStream fileToUpload,
89                                                              String fileSuffix) {
90     String errorMessage =
91         getErrorWithParameters(Messages.NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(),
92             fileSuffix);
93
94     if (Objects.isNull(fileToUpload)) {
95       return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
96           errorMessage));
97     } else {
98       try {
99         int available = fileToUpload.available();
100         if (available == 0) {
101           return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
102               errorMessage));
103         }
104       } catch (IOException e) {
105         logger.debug(e.getMessage(), e);
106         return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
107             errorMessage));
108       }
109     }
110     return Optional.empty();
111   }
112
113   @Override
114   public Optional<ErrorMessage> validateRawZipData(String fileSuffix,
115                                                    byte[] uploadedFileData) {
116     if (Objects.isNull(uploadedFileData)) {
117       return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
118           getErrorWithParameters(Messages.NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(),
119               fileSuffix)));
120     }
121     return Optional.empty();
122   }
123
124   private String heatStructureTreeToFileDataStructure(HeatStructureTree tree,
125                                                       FileContentHandler zipContentMap,
126                                                       Map<String, List<ErrorMessage>> uploadErrors,
127                                                       AnalyzedZipHeatFiles analyzedZipHeatFiles) {
128     FilesDataStructure structure = new FilesDataStructure();
129     Set<String> usedEnvFiles = new HashSet<>();
130     addHeatsToFileDataStructure(tree, usedEnvFiles, structure, uploadErrors,
131         analyzedZipHeatFiles);
132     handleOtherResources(tree, usedEnvFiles, structure);
133     FilesDataStructure fileDataStructureFromManifest =
134         createFileDataStructureFromManifest(zipContentMap.getFileContent(SdcCommon.MANIFEST_NAME));
135     List<String> structureArtifacts = structure.getArtifacts();
136     structureArtifacts.addAll(fileDataStructureFromManifest.getArtifacts().stream().filter
137         (artifact -> isNotStrctureArtifact(structureArtifacts, artifact))
138         .collect(Collectors.toList()));
139     handleArtifactsFromTree(tree, structure);
140
141     return JsonUtil.object2Json(structure);
142   }
143
144   private boolean isNotStrctureArtifact(List<String> structureArtifacts, String artifact) {
145     return !structureArtifacts.contains(artifact);
146   }
147
148   @Override
149   public OrchestrationTemplateCandidateData createCandidateDataEntity(
150       CandidateDataEntityTo candidateDataEntityTo, InputStream zipFileManifest,
151       AnalyzedZipHeatFiles analyzedZipHeatFiles) {
152     FileContentHandler zipContentMap = candidateDataEntityTo.getContentMap();
153     FilesDataStructure filesDataStructure;
154     String dataStructureJson;
155
156     if (zipFileManifest != null) {
157       // create data structure from manifest
158       filesDataStructure = createFileDataStructureFromManifest(zipFileManifest);
159       Set<String> zipFileList = zipContentMap.getFileList();
160       balanceManifestFilesWithZipFiles(filesDataStructure,
161           zipContentMap, analyzedZipHeatFiles);
162       Set<String> filesDataStructureFiles = getFlatFileNames(filesDataStructure);
163       filesDataStructure.getUnassigned().addAll(zipFileList.stream()
164           .filter(fileName -> (!filesDataStructureFiles.contains(fileName)
165               && !filesDataStructure.getNested().contains(fileName)
166               && !fileName.equals(SdcCommon.MANIFEST_NAME)))
167           .collect(Collectors.toList()));
168       dataStructureJson = JsonUtil.object2Json(filesDataStructure);
169     } else {
170       // create data structure from based on naming convention
171       dataStructureJson =
172           heatStructureTreeToFileDataStructure(candidateDataEntityTo.getTree(), zipContentMap,
173               candidateDataEntityTo.getErrors(), analyzedZipHeatFiles);
174     }
175
176     OrchestrationTemplateCandidateData candidateData = new OrchestrationTemplateCandidateData();
177     candidateData.setContentData(ByteBuffer.wrap(candidateDataEntityTo.getUploadedFileData()));
178     candidateData.setFilesDataStructure(dataStructureJson);
179     return candidateData;
180   }
181
182   private void balanceManifestFilesWithZipFiles(
183       FilesDataStructure filesDataStructure,
184       FileContentHandler fileContentHandler, AnalyzedZipHeatFiles analyzedZipHeatFiles) {
185     Set<String> zipFileList = fileContentHandler.getFileList();
186     filesDataStructure.getNested().addAll(analyzedZipHeatFiles.getNestedFiles());
187     List<Module> modules = filesDataStructure.getModules();
188     if (CollectionUtils.isEmpty(modules)) {
189       return;
190     }
191
192     for (int i = 0; i < modules.size(); i++) {
193       Module module = modules.get(i);
194       if (!isFileExistInZipContains(zipFileList, module.getYaml())) {
195         addFileToUnassigned(filesDataStructure, zipFileList, module.getEnv());
196         addFileToUnassigned(filesDataStructure, zipFileList, module.getVol());
197         addFileToUnassigned(filesDataStructure, zipFileList, module.getVolEnv());
198         modules.remove(i--);
199       } else if (Objects.nonNull(module.getVol()) && !zipFileList.contains(module.getVol())) {
200         module.setVol(null);
201         CollectionUtils
202             .addIgnoreNull(filesDataStructure.getUnassigned(), module.getVolEnv());
203       } else {
204         if (filesDataStructure.getNested().contains(module.getYaml())) {
205           moveModuleFileToNested(filesDataStructure, i--, module);
206         }
207       }
208     }
209   }
210
211   private void addFileToUnassigned(FilesDataStructure filesDataStructure, Set<String> zipFileList,
212                                    String fileName) {
213     if (isFileExistInZipContains(zipFileList, fileName)) {
214       filesDataStructure.getUnassigned().add(fileName);
215     }
216   }
217
218   private boolean isFileExistInZipContains(Set<String> zipFileList, String fileName) {
219     return Objects.nonNull(fileName) && zipFileList.contains(fileName);
220   }
221
222   private void moveModuleFileToNested(FilesDataStructure filesDataStructure, int i,
223                                       Module module) {
224     if (!filesDataStructure.getNested().contains(module.getYaml())) {
225       filesDataStructure.getNested().add(module.getYaml());
226     }
227     if (Objects.nonNull(module.getEnv())) {
228       filesDataStructure.getNested().add(module.getEnv());
229     }
230     if (Objects.nonNull(module.getVol())) {
231       filesDataStructure.getNested().add(module.getVol());
232     }
233     if (Objects.nonNull(module.getVolEnv())) {
234       filesDataStructure.getNested().add(module.getVolEnv());
235     }
236     filesDataStructure.getModules().remove(i);
237   }
238
239   private Set<String> getFlatFileNames(FilesDataStructure filesDataStructure) {
240     Set<String> fileNames = new HashSet<>();
241     if (!CollectionUtils.isEmpty(filesDataStructure.getModules())) {
242       for (Module module : filesDataStructure.getModules()) {
243         CollectionUtils.addIgnoreNull(fileNames, module.getEnv());
244         CollectionUtils.addIgnoreNull(fileNames, module.getVol());
245         CollectionUtils.addIgnoreNull(fileNames, module.getVolEnv());
246         CollectionUtils.addIgnoreNull(fileNames, module.getYaml());
247       }
248     }
249     fileNames.addAll(filesDataStructure.getArtifacts());
250     fileNames.addAll(filesDataStructure.getNested());
251     fileNames.addAll(filesDataStructure.getUnassigned());
252
253     return fileNames;
254   }
255
256   private FilesDataStructure createFileDataStructureFromManifest(InputStream isManifestContent) {
257     ManifestContent manifestContent =
258         JsonUtil.json2Object(isManifestContent, ManifestContent.class);
259     FilesDataStructure structure = new FilesDataStructure();
260     for (FileData fileData : manifestContent.getData()) {
261       if (Objects.nonNull(fileData.getType()) &&
262           fileData.getType().equals(FileData.Type.HEAT)) {
263         Module module = new Module();
264         module.setYaml(fileData.getFile());
265         module.setIsBase(fileData.getBase());
266         addHeatDependenciesToModule(module, fileData.getData());
267         structure.getModules().add(module);
268       } else if (HeatFileAnalyzer.isYamlOrEnvFile(fileData.getFile()) &&
269           !FileData.Type.isArtifact(fileData.getType())) {
270         structure.getUnassigned().add(fileData.getFile());
271       } else {
272         structure.getArtifacts().add(fileData.getFile());
273       }
274     }
275     return structure;
276   }
277
278   private void addHeatDependenciesToModule(Module module, List<FileData> data) {
279     if (CollectionUtils.isEmpty(data)) {
280       return;
281     }
282
283     for (FileData fileData : data) {
284       if (fileData.getType().equals(FileData.Type.HEAT_ENV)) {
285         module.setEnv(fileData.getFile());
286       } else if (fileData.getType().equals(FileData.Type.HEAT_VOL)) { // must be volume
287         module.setVol(fileData.getFile());
288         if (!CollectionUtils.isEmpty(fileData.getData())) {
289           FileData volEnv = fileData.getData().get(0);
290           if (volEnv.getType().equals(FileData.Type.HEAT_ENV)) {
291             module.setVolEnv(volEnv.getFile());
292           } else {
293             throw new CoreException((new ErrorCode.ErrorCodeBuilder())
294                 .withMessage(Messages.ILLEGAL_MANIFEST.getErrorMessage())
295                 .withId(Messages.ILLEGAL_MANIFEST.getErrorMessage())
296                 .withCategory(ErrorCategory.APPLICATION).build());
297           }
298         }
299       } else {
300         throw new CoreException((new ErrorCode.ErrorCodeBuilder())
301             .withMessage(Messages.FILE_TYPE_NOT_LEGAL.getErrorMessage())
302             .withId(Messages.FILE_TYPE_NOT_LEGAL.getErrorMessage())
303             .withCategory(ErrorCategory.APPLICATION).build());
304       }
305     }
306   }
307
308   @Override
309   public void updateCandidateUploadData(String vspId, Version version,
310                                         OrchestrationTemplateCandidateData uploadData) {
311     orchestrationTemplateCandidateDao.update(vspId, version, uploadData);
312   }
313
314   @Override
315   public Optional<FilesDataStructure> getOrchestrationTemplateCandidateFileDataStructure(
316       String vspId, Version version) {
317     Optional<String> jsonFileDataStructure =
318         orchestrationTemplateCandidateDao.getStructure(vspId, version);
319
320     if (jsonFileDataStructure.isPresent() && JsonUtil.isValidJson(jsonFileDataStructure.get())) {
321       return Optional
322           .of(JsonUtil.json2Object(jsonFileDataStructure.get(), FilesDataStructure.class));
323     } else {
324       return Optional.empty();
325     }
326   }
327
328   @Override
329   public void updateOrchestrationTemplateCandidateFileDataStructure(String vspId, Version version,
330                                                                     FilesDataStructure fileDataStructure) {
331     OrchestrationTemplateCandidateDaoFactory.getInstance().createInterface()
332         .updateStructure(vspId, version, fileDataStructure);
333   }
334
335   @Override
336   public Optional<OrchestrationTemplateCandidateData> getOrchestrationTemplateCandidate(String vspId,
337                                                                                         Version version) {
338     return orchestrationTemplateCandidateDao.get(vspId, version);
339   }
340
341   @Override
342   public Optional<OrchestrationTemplateCandidateData> getOrchestrationTemplateCandidateInfo(
343       String vspId,
344       Version version) {
345     return orchestrationTemplateCandidateDao.getInfo(vspId, version);
346   }
347
348   @Override
349   public String createManifest(VspDetails vspDetails, FilesDataStructure structure) {
350     return JsonUtil.object2Json(manifestCreator.createManifest(vspDetails, structure)
351         .orElseThrow(() -> new CoreException(new ErrorCode.ErrorCodeBuilder()
352             .withMessage(Messages.CREATE_MANIFEST_FROM_ZIP.getErrorMessage()).build())));
353   }
354
355   @Override
356   public Optional<ManifestContent> createManifest(VspDetails vspDetails,
357                                                   FileContentHandler fileContentHandler,
358                                                   AnalyzedZipHeatFiles analyzedZipHeatFiles) {
359     return manifestCreator.createManifest(vspDetails, fileContentHandler, analyzedZipHeatFiles);
360   }
361
362   @Override
363   public Optional<ByteArrayInputStream> fetchZipFileByteArrayInputStream(String vspId,
364                                                                          OrchestrationTemplateCandidateData candidateDataEntity,
365                                                                          String manifest,
366                                                                          OnboardingTypesEnum type,
367                                                                          Map<String, List<ErrorMessage>> uploadErrors) {
368     byte[] file;
369     ByteArrayInputStream byteArrayInputStream = null;
370     try {
371       file = replaceManifestInZip(candidateDataEntity.getContentData(), manifest, type);
372       byteArrayInputStream = new ByteArrayInputStream(
373           Objects.isNull(file) ? candidateDataEntity.getContentData().array()
374               : file);
375     } catch (IOException e) {
376       ErrorMessage errorMessage =
377           new ErrorMessage(ErrorLevel.ERROR,
378               Messages.CANDIDATE_PROCESS_FAILED.getErrorMessage());
379       logger.error(errorMessage.getMessage(), e);
380       ErrorsUtil
381           .addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE, errorMessage, uploadErrors);
382     }
383     return Optional.ofNullable(byteArrayInputStream);
384   }
385
386   @Override
387   public byte[] replaceManifestInZip(ByteBuffer contentData, String manifest,
388                                      OnboardingTypesEnum type)
389       throws IOException {
390     ByteArrayOutputStream baos = new ByteArrayOutputStream();
391
392     try (final ZipOutputStream zos = new ZipOutputStream(baos);
393          ZipInputStream zipStream = new ZipInputStream(
394              new ByteArrayInputStream(contentData.array()))) {
395       ZipEntry zipEntry;
396       boolean manifestWritten = false;
397       while ((zipEntry = zipStream.getNextEntry()) != null) {
398         if (!zipEntry.getName().equalsIgnoreCase(SdcCommon.MANIFEST_NAME)) {
399           ZipEntry loc_ze = new ZipEntry(zipEntry.getName());
400           zos.putNextEntry(loc_ze);
401           byte[] buf = new byte[1024];
402           int len;
403           while ((len = zipStream.read(buf)) > 0) {
404             zos.write(buf, 0, (len < buf.length) ? len : buf.length);
405           }
406         } else {
407           manifestWritten = true;
408           writeManifest(manifest, type, zos);
409         }
410         zos.closeEntry();
411       }
412       if (!manifestWritten) {
413         writeManifest(manifest, type, zos);
414         zos.closeEntry();
415       }
416     }
417     return baos.toByteArray();
418   }
419
420   @Override
421   public byte[] getZipData(ByteBuffer contentData)
422       throws IOException {
423     ByteArrayOutputStream baos = new ByteArrayOutputStream();
424
425     try (final ZipOutputStream zos = new ZipOutputStream(baos);
426          ZipInputStream zipStream = new ZipInputStream(
427              new ByteArrayInputStream(contentData.array()))) {
428       ZipEntry zipEntry;
429       while ((zipEntry = zipStream.getNextEntry()) != null) {
430         ZipEntry locZipEntry = new ZipEntry(zipEntry.getName());
431         zos.putNextEntry(locZipEntry);
432         byte[] buf = new byte[1024];
433         int len;
434         while ((len = zipStream.read(buf)) > 0) {
435           zos.write(buf, 0, (len < buf.length) ? len : buf.length);
436         }
437         zos.closeEntry();
438       }
439     }
440     return baos.toByteArray();
441   }
442
443   @Override
444   public Optional<List<ErrorMessage>> validateFileDataStructure(
445       FilesDataStructure filesDataStructure) {
446     return candidateServiceValidator.validateFileDataStructure(filesDataStructure);
447   }
448
449   @Override
450   public void deleteOrchestrationTemplateCandidate(String vspId, Version versionId) {
451     orchestrationTemplateCandidateDao.delete(vspId, versionId);
452   }
453
454   @Override
455   public void updateValidationData(String vspId, Version version, ValidationStructureList
456       validationData) {
457     orchestrationTemplateCandidateDao.updateValidationData(vspId, version, validationData);
458   }
459
460   private void writeManifest(String manifest,
461                              OnboardingTypesEnum type,
462                              ZipOutputStream zos) throws IOException {
463
464     if (isManifestNeedsToGetWritten(type)) {
465       return;
466     }
467
468     zos.putNextEntry(new ZipEntry(SdcCommon.MANIFEST_NAME));
469     try (InputStream manifestStream = new ByteArrayInputStream(
470         manifest.getBytes(StandardCharsets.UTF_8))) {
471       byte[] buf = new byte[1024];
472       int len;
473       while ((len = (manifestStream.read(buf))) > 0) {
474         zos.write(buf, 0, (len < buf.length) ? len : buf.length);
475       }
476     }
477   }
478
479   private boolean isManifestNeedsToGetWritten(OnboardingTypesEnum type) {
480     return type.equals(OnboardingTypesEnum.CSAR);
481   }
482
483   private void handleArtifactsFromTree(HeatStructureTree tree, FilesDataStructure structure) {
484
485     if (Objects.isNull(tree) || Objects.isNull(tree.getArtifacts())) {
486       return;
487     }
488
489     if (CollectionUtils.isNotEmpty(tree.getArtifacts())) {
490       structure.getArtifacts().addAll(
491           tree.getArtifacts()
492               .stream()
493               .map(Artifact::getFileName)
494               .filter(fileName -> !structure.getArtifacts().contains(fileName))
495               .collect(Collectors.toList()));
496     }
497   }
498
499   private void handleOtherResources(HeatStructureTree tree, Set<String> usedEnvFiles,
500                                     FilesDataStructure structure) {
501     Set<HeatStructureTree> others = tree.getOther();
502     if (Objects.isNull(others)) {
503       return;
504     }
505
506     List<String> artifacts = new ArrayList<>();
507     List<String> unassigned = new ArrayList<>();
508     for (HeatStructureTree other : others) {
509       if (HeatFileAnalyzer.isYamlOrEnvFile(other.getFileName())) {
510         if (isEnvFileUsedByHeatFile(usedEnvFiles, other)) {
511           continue;
512         }
513         unassigned.add(other.getFileName());
514       } else {
515         artifacts.add(other.getFileName());
516       }
517       handleArtifactsFromTree(other, structure);
518     }
519     structure.getArtifacts().addAll(artifacts);
520     structure.getUnassigned().addAll(unassigned);
521   }
522
523   private boolean isEnvFileUsedByHeatFile(Set<String> usedEnvFiles, HeatStructureTree other) {
524     return HeatFileAnalyzer.isEnvFile(other.getFileName()) &&
525         usedEnvFiles.contains(other.getFileName());
526   }
527
528   private void addHeatsToFileDataStructure(HeatStructureTree tree, Set<String> usedEnvFiles,
529                                            FilesDataStructure structure,
530                                            Map<String, List<ErrorMessage>> uploadErrors,
531                                            AnalyzedZipHeatFiles analyzedZipHeatFiles) {
532     List<Module> modules = new ArrayList<>();
533     Set<HeatStructureTree> heatsSet = tree.getHeat();
534     if (Objects.isNull(heatsSet)) {
535       return;
536     }
537     for (HeatStructureTree heat : heatsSet) {
538       if (isFileBaseFile(heat.getFileName())) {
539         handleSingleHeat(structure, modules, heat, uploadErrors);
540       } else if (isFileModuleFile(heat.getFileName(),
541           analyzedZipHeatFiles.getModuleFiles())) {
542         handleSingleHeat(structure, modules, heat, uploadErrors);
543       } else {
544         structure.getUnassigned().add(heat.getFileName());
545         addNestedToFileDataStructure(heat, structure);
546       }
547       if (!Objects.isNull(heat.getEnv())) {
548         usedEnvFiles.add(heat.getEnv() == null ? null : heat.getEnv().getFileName());
549       }
550     }
551     structure.setModules(modules);
552
553   }
554
555   private boolean isFileModuleFile(String fileName, Set<String> modulesFileNames) {
556     return modulesFileNames.contains(fileName);
557   }
558
559   private boolean isFileBaseFile(String fileName) {
560     return manifestCreator.isFileBaseFile(fileName);
561   }
562
563   private void handleSingleHeat(FilesDataStructure structure, List<Module> modules,
564                                 HeatStructureTree heat,
565                                 Map<String, List<ErrorMessage>> uploadErrors) {
566     Module module = new Module();
567     module.setYaml(heat.getFileName());
568     module.setIsBase(heat.getBase());
569     addNestedToFileDataStructure(heat, structure);
570     Set<HeatStructureTree> volumeSet = heat.getVolume();
571     int inx = 0;
572     if (Objects.nonNull(volumeSet)) {
573       handleVolumes(module, volumeSet, structure, inx, uploadErrors);
574     }
575     handleEnv(module, heat, false, structure);
576     modules.add(module);
577   }
578
579   private void handleVolumes(Module module, Set<HeatStructureTree> volumeSet,
580                              FilesDataStructure structure, int inx,
581                              Map<String, List<ErrorMessage>> uploadErrors) {
582     for (HeatStructureTree volume : volumeSet) {
583       Objects.requireNonNull(volume, "volume cannot be null!");
584       if (inx++ > 0) {
585         ErrorsUtil.addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE,
586             new ErrorMessage(ErrorLevel.WARNING,
587                 Messages.MORE_THEN_ONE_VOL_FOR_HEAT.getErrorMessage()), uploadErrors);
588         break;
589       }
590       handleArtifactsFromTree(volume, structure);
591       module.setVol(volume.getFileName());
592       handleEnv(module, volume, true, structure);
593       addNestedToFileDataStructure(volume, structure);
594     }
595   }
596
597   private void handleEnv(Module module, HeatStructureTree tree, boolean isVolEnv,
598                          FilesDataStructure structure) {
599     if (Objects.nonNull(tree.getEnv())) {
600       if (isVolEnv) {
601         module.setVolEnv(tree.getEnv().getFileName());
602       } else {
603         module.setEnv(tree.getEnv().getFileName());
604       }
605       handleArtifactsFromTree(tree.getEnv(), structure);
606     }
607   }
608
609   private void addNestedToFileDataStructure(HeatStructureTree heat,
610                                             FilesDataStructure structure) {
611     Set<HeatStructureTree> nestedSet = heat.getNested();
612     if (Objects.isNull(nestedSet)) {
613       return;
614     }
615     for (HeatStructureTree nested : nestedSet) {
616       if (structure.getNested().contains(nested.getFileName())) {
617         continue;
618       }
619       structure.getNested().add(nested.getFileName());
620       if (CollectionUtils.isNotEmpty(nested.getArtifacts())) {
621         handleArtifactsFromTree(nested, structure);
622       }
623       addNestedToFileDataStructure(nested, structure);
624     }
625   }
626 }