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