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