2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.filedatastructuremodule;
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.openecomp.core.utilities.file.FileContentHandler;
25 import org.openecomp.core.utilities.json.JsonUtil;
26 import org.openecomp.sdc.common.errors.CoreException;
27 import org.openecomp.sdc.common.errors.ErrorCategory;
28 import org.openecomp.sdc.common.errors.ErrorCode;
29 import org.openecomp.sdc.common.errors.Messages;
30 import org.openecomp.sdc.common.utils.SdcCommon;
31 import org.openecomp.sdc.datatypes.error.ErrorLevel;
32 import org.openecomp.sdc.datatypes.error.ErrorMessage;
33 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
34 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
35 import org.openecomp.sdc.heat.datatypes.structure.Artifact;
36 import org.openecomp.sdc.heat.datatypes.structure.HeatStructureTree;
37 import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage;
38 import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateCandidateDao;
39 import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateCandidateDaoFactory;
40 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData;
41 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
42 import org.openecomp.sdc.vendorsoftwareproduct.errors.utils.ErrorsUtil;
43 import org.openecomp.sdc.vendorsoftwareproduct.services.HeatFileAnalyzer;
44 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.CandidateService;
45 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.ManifestCreator;
46 import org.openecomp.sdc.vendorsoftwareproduct.services.utils.CandidateServiceValidator;
47 import org.openecomp.sdc.vendorsoftwareproduct.types.CandidateDataEntityTo;
48 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.AnalyzedZipHeatFiles;
49 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure;
50 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module;
51 import org.openecomp.sdc.versioning.dao.types.Version;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 import java.io.ByteArrayInputStream;
56 import java.io.ByteArrayOutputStream;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.nio.ByteBuffer;
60 import java.nio.charset.StandardCharsets;
61 import java.util.ArrayList;
62 import java.util.HashSet;
63 import java.util.List;
65 import java.util.Objects;
66 import java.util.Optional;
68 import java.util.stream.Collectors;
69 import java.util.zip.ZipEntry;
70 import java.util.zip.ZipInputStream;
71 import java.util.zip.ZipOutputStream;
73 public class CandidateServiceImpl implements CandidateService {
74 protected static final Logger logger = LoggerFactory.getLogger(CandidateServiceImpl.class);
75 private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage();
77 private CandidateServiceValidator candidateServiceValidator = new CandidateServiceValidator();
78 private ManifestCreator manifestCreator;
79 private OrchestrationTemplateCandidateDao orchestrationTemplateCandidateDataDao;
81 public CandidateServiceImpl(ManifestCreator manifestCreator,
82 OrchestrationTemplateCandidateDao orchestrationTemplateCandidateDataDao) {
83 this.manifestCreator = manifestCreator;
84 this.orchestrationTemplateCandidateDataDao = orchestrationTemplateCandidateDataDao;
88 public CandidateServiceImpl() {
92 public Optional<ErrorMessage> validateNonEmptyFileToUpload(InputStream heatFileToUpload) {
95 mdcDataDebugMessage.debugEntryMessage(null);
97 if (Objects.isNull(heatFileToUpload)) {
98 return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
99 Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage()));
102 int available = heatFileToUpload.available();
103 if (available == 0) {
104 mdcDataDebugMessage.debugExitMessage(null);
105 return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
106 Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage()));
108 } catch (IOException e) {
109 mdcDataDebugMessage.debugExitMessage(null);
110 return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
111 Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage()));
115 mdcDataDebugMessage.debugExitMessage(null);
116 return Optional.empty();
120 public Optional<ErrorMessage> validateRawZipData(byte[] uploadedFileData) {
121 if (Objects.isNull(uploadedFileData)) {
122 return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
123 Messages.NO_ZIP_FILE_WAS_UPLOADED_OR_ZIP_NOT_EXIST.getErrorMessage()));
125 return Optional.empty();
128 private String heatStructureTreeToFileDataStructure(HeatStructureTree tree,
129 FileContentHandler zipContentMap,
130 Map<String, List<ErrorMessage>> uploadErrors,
131 AnalyzedZipHeatFiles analyzedZipHeatFiles)
133 FilesDataStructure structure = new FilesDataStructure();
134 Set<String> usedEnvFiles = new HashSet<>();
135 addHeatsToFileDataStructure(tree, usedEnvFiles, structure, uploadErrors,
136 analyzedZipHeatFiles);
137 handleOtherResources(tree, usedEnvFiles, structure);
138 FilesDataStructure fileDataStructureFromManifest =
139 createFileDataStructureFromManifest(zipContentMap.getFileContent
140 (SdcCommon.MANIFEST_NAME));
141 structure.getArtifacts().addAll(fileDataStructureFromManifest.getArtifacts());
142 handleArtifactsFromTree(tree, structure);
144 return JsonUtil.object2Json(structure);
148 public OrchestrationTemplateCandidateData createCandidateDataEntity(
149 CandidateDataEntityTo candidateDataEntityTo, InputStream zipFileManifest,
150 AnalyzedZipHeatFiles analyzedZipHeatFiles) throws Exception {
153 mdcDataDebugMessage.debugEntryMessage(null);
155 FileContentHandler zipContentMap = candidateDataEntityTo.getContentMap();
156 FilesDataStructure filesDataStructure;
157 String dataStructureJson;
159 if (zipFileManifest != null) {
160 // create data structure from manifest
161 filesDataStructure = createFileDataStructureFromManifest(zipFileManifest);
162 Set<String> zipFileList = zipContentMap.getFileList();
163 balanceManifestFilesWithZipFiles(filesDataStructure,
164 zipContentMap, analyzedZipHeatFiles);
165 Set<String> filesDataStructureFiles = getFlatFileNames(filesDataStructure);
166 filesDataStructure.getUnassigned().addAll(zipFileList.stream()
167 .filter(fileName -> (!filesDataStructureFiles.contains(fileName) &&
168 !filesDataStructure.getNested().contains(fileName) &&
169 !fileName.equals(SdcCommon.MANIFEST_NAME)))
170 .collect(Collectors.toList()));
171 dataStructureJson = JsonUtil.object2Json(filesDataStructure);
173 // create data structure from based on naming convention
175 heatStructureTreeToFileDataStructure(candidateDataEntityTo.getTree(), zipContentMap,
176 candidateDataEntityTo.getErrors(), analyzedZipHeatFiles);
179 mdcDataDebugMessage.debugExitMessage(null);
180 return new OrchestrationTemplateCandidateData(
181 ByteBuffer.wrap(candidateDataEntityTo.getUploadedFileData()), dataStructureJson);
184 private void balanceManifestFilesWithZipFiles(
185 FilesDataStructure filesDataStructure,
186 FileContentHandler fileContentHandler, AnalyzedZipHeatFiles analyzedZipHeatFiles)
188 Set<String> zipFileList = fileContentHandler.getFileList();
189 filesDataStructure.getNested().addAll(analyzedZipHeatFiles.getNestedFiles());
190 List<Module> modules = filesDataStructure.getModules();
191 if (CollectionUtils.isEmpty(modules)) {
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());
202 } else if (Objects.nonNull(module.getVol()) && !zipFileList.contains(module.getVol())) {
204 CollectionUtils.addIgnoreNull(filesDataStructure.getUnassigned(), module.getVolEnv());
206 if (filesDataStructure.getNested().contains(module.getYaml())) {
207 moveModuleFileToNested(filesDataStructure, i--, module);
213 private void addFileToUnassigned(FilesDataStructure filesDataStructure, Set<String> zipFileList,
215 if (isFileExistInZipContains(zipFileList, fileName)) {
216 filesDataStructure.getUnassigned().add(fileName);
220 private boolean isFileExistInZipContains(Set<String> zipFileList, String fileName) {
221 return Objects.nonNull(fileName) && zipFileList.contains(fileName);
224 private void moveModuleFileToNested(FilesDataStructure filesDataStructure, int i, Module module) {
225 if (!filesDataStructure.getNested().contains(module.getYaml())) {
226 filesDataStructure.getNested().add(module.getYaml());
228 if (Objects.nonNull(module.getEnv())) {
229 filesDataStructure.getNested().add(module.getEnv());
231 if (Objects.nonNull(module.getVol())) {
232 filesDataStructure.getNested().add(module.getVol());
234 if (Objects.nonNull(module.getVolEnv())) {
235 filesDataStructure.getNested().add(module.getVolEnv());
237 filesDataStructure.getModules().remove(i);
240 private Set<String> getFlatFileNames(FilesDataStructure filesDataStructure) {
241 Set<String> fileNames = new HashSet<>();
242 if (!CollectionUtils.isEmpty(filesDataStructure.getModules())) {
243 for (Module module : filesDataStructure.getModules()) {
244 CollectionUtils.addIgnoreNull(fileNames, module.getEnv());
245 CollectionUtils.addIgnoreNull(fileNames, module.getVol());
246 CollectionUtils.addIgnoreNull(fileNames, module.getVolEnv());
247 CollectionUtils.addIgnoreNull(fileNames, module.getYaml());
250 fileNames.addAll(filesDataStructure.getArtifacts().stream().collect(Collectors.toSet()));
251 fileNames.addAll(filesDataStructure.getNested().stream().collect(Collectors.toSet()));
252 fileNames.addAll(filesDataStructure.getUnassigned().stream().collect(Collectors.toSet()));
257 private FilesDataStructure createFileDataStructureFromManifest(InputStream isManifestContent) {
260 mdcDataDebugMessage.debugEntryMessage(null);
262 ManifestContent manifestContent =
263 JsonUtil.json2Object(isManifestContent, ManifestContent.class);
264 FilesDataStructure structure = new FilesDataStructure();
265 for (FileData fileData : manifestContent.getData()) {
266 if (Objects.nonNull(fileData.getType()) && fileData.getType().equals(FileData.Type.HEAT)) {
267 Module module = new Module();
268 module.setYaml(fileData.getFile());
269 module.setIsBase(fileData.getBase());
270 addHeatDependenciesToModule(module, fileData.getData());
271 structure.getModules().add(module);
272 } else if (HeatFileAnalyzer.isYamlOrEnvFile(fileData.getFile()) &&
273 !FileData.Type.isArtifact(fileData.getType())) {
274 structure.getUnassigned().add(fileData.getFile());
276 structure.getArtifacts().add(fileData.getFile());
280 mdcDataDebugMessage.debugExitMessage(null);
284 private void addHeatDependenciesToModule(Module module, List<FileData> data) {
285 if (CollectionUtils.isEmpty(data)) {
289 for (FileData fileData : data) {
290 if (fileData.getType().equals(FileData.Type.HEAT_ENV)) {
291 module.setEnv(fileData.getFile());
292 } else if (fileData.getType().equals(FileData.Type.HEAT_VOL))// must be volume
294 module.setVol(fileData.getFile());
295 if (!CollectionUtils.isEmpty(fileData.getData())) {
296 FileData volEnv = fileData.getData().get(0);
297 if (volEnv.getType().equals(FileData.Type.HEAT_ENV)) {
298 module.setVolEnv(volEnv.getFile());
300 throw new CoreException((new ErrorCode.ErrorCodeBuilder())
301 .withMessage(Messages.ILLEGAL_MANIFEST.getErrorMessage())
302 .withId(Messages.ILLEGAL_MANIFEST.getErrorMessage())
303 .withCategory(ErrorCategory.APPLICATION).build());
307 throw new CoreException((new ErrorCode.ErrorCodeBuilder())
308 .withMessage(Messages.FILE_TYPE_NOT_LEGAL.getErrorMessage())
309 .withId(Messages.FILE_TYPE_NOT_LEGAL.getErrorMessage())
310 .withCategory(ErrorCategory.APPLICATION).build());
316 public void updateCandidateUploadData(OrchestrationTemplateCandidateData uploadData,
318 mdcDataDebugMessage.debugEntryMessage(null);
320 //vendorSoftwareProductDao.updateCandidateUploadData(uploadData);
321 orchestrationTemplateCandidateDataDao.update(itemId, uploadData);
323 mdcDataDebugMessage.debugExitMessage(null);
327 public Optional<FilesDataStructure> getOrchestrationTemplateCandidateFileDataStructure(
328 String vspId, Version version) {
330 mdcDataDebugMessage.debugEntryMessage("VSP Id", vspId);
332 Optional<String> jsonFileDataStructure =
333 orchestrationTemplateCandidateDataDao.getStructure(vspId, version);
335 if (jsonFileDataStructure.isPresent()) {
336 mdcDataDebugMessage.debugExitMessage("VSP Id", vspId);
338 .of(JsonUtil.json2Object(jsonFileDataStructure.get(), FilesDataStructure.class));
340 mdcDataDebugMessage.debugExitMessage("VSP Id", vspId);
341 return Optional.empty();
346 public void updateOrchestrationTemplateCandidateFileDataStructure(String vspId, Version version,
347 FilesDataStructure fileDataStructure) {
348 OrchestrationTemplateCandidateDaoFactory.getInstance().createInterface()
349 .updateStructure(vspId, version, fileDataStructure);
353 public OrchestrationTemplateCandidateData getOrchestrationTemplateCandidate(String vspId,
355 mdcDataDebugMessage.debugEntryMessage("VSP Id", vspId);
356 mdcDataDebugMessage.debugExitMessage("VSP Id", vspId);
358 return orchestrationTemplateCandidateDataDao.get(vspId, version);
362 public String createManifest(VspDetails vspDetails, FilesDataStructure structure) {
364 mdcDataDebugMessage.debugEntryMessage("VSP Id", vspDetails.getId());
366 Optional<ManifestContent> manifest = manifestCreator.createManifest(vspDetails, structure);
367 if (!manifest.isPresent()) {
368 throw new RuntimeException(Messages.CREATE_MANIFEST_FROM_ZIP.getErrorMessage());
371 mdcDataDebugMessage.debugExitMessage("VSP Id", vspDetails.getId());
372 return JsonUtil.object2Json(manifest.get());
376 public Optional<ManifestContent> createManifest(VspDetails vspDetails,
377 FileContentHandler fileContentHandler,
378 AnalyzedZipHeatFiles analyzedZipHeatFiles) {
381 mdcDataDebugMessage.debugEntryMessage("VSP Id", vspDetails.getId());
383 mdcDataDebugMessage.debugExitMessage("VSP Id", vspDetails.getId());
384 return manifestCreator.createManifest(vspDetails, fileContentHandler, analyzedZipHeatFiles);
388 public Optional<ByteArrayInputStream> fetchZipFileByteArrayInputStream(String vspId,
389 OrchestrationTemplateCandidateData candidateDataEntity,
391 Map<String, List<ErrorMessage>> uploadErrors) {
393 ByteArrayInputStream byteArrayInputStream = null;
395 file = replaceManifestInZip(candidateDataEntity.getContentData(), manifest, vspId);
396 byteArrayInputStream = new ByteArrayInputStream(
397 Objects.isNull(file) ? candidateDataEntity.getContentData().array()
399 } catch (IOException e) {
400 ErrorMessage errorMessage =
401 new ErrorMessage(ErrorLevel.ERROR, Messages.CANDIDATE_PROCESS_FAILED.getErrorMessage());
402 logger.error(errorMessage.getMessage(), e);
403 ErrorsUtil.addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE, errorMessage, uploadErrors);
405 return Optional.ofNullable(byteArrayInputStream);
409 public byte[] replaceManifestInZip(ByteBuffer contentData, String manifest, String vspId)
411 ByteArrayOutputStream baos = new ByteArrayOutputStream();
413 try (final ZipOutputStream zos = new ZipOutputStream(baos);
414 ZipInputStream zipStream = new ZipInputStream(
415 new ByteArrayInputStream(contentData.array()))) {
417 boolean manifestWritten = false;
418 while ((zipEntry = zipStream.getNextEntry()) != null) {
419 if (!zipEntry.getName().equalsIgnoreCase(SdcCommon.MANIFEST_NAME)) {
420 ZipEntry loc_ze = new ZipEntry(zipEntry.getName());
421 zos.putNextEntry(loc_ze);
422 byte[] buf = new byte[1024];
424 while ((len = zipStream.read(buf)) > 0) {
425 zos.write(buf, 0, (len < buf.length) ? len : buf.length);
428 manifestWritten = true;
429 writeManifest(manifest, zos);
433 if (!manifestWritten) {
434 writeManifest(manifest, zos);
438 return baos.toByteArray();
442 public Optional<List<ErrorMessage>> validateFileDataStructure(
443 FilesDataStructure filesDataStructure) {
444 return candidateServiceValidator.validateFileDataStructure(filesDataStructure);
447 private void writeManifest(String manifest, ZipOutputStream zos) throws IOException {
448 zos.putNextEntry(new ZipEntry(SdcCommon.MANIFEST_NAME));
449 try (InputStream manifestStream = new ByteArrayInputStream(
450 manifest.getBytes(StandardCharsets.UTF_8))) {
451 byte[] buf = new byte[1024];
453 while ((len = (manifestStream.read(buf))) > 0) {
454 zos.write(buf, 0, (len < buf.length) ? len : buf.length);
459 private void handleArtifactsFromTree(HeatStructureTree tree, FilesDataStructure structure) {
461 if (Objects.isNull(tree) || Objects.isNull(tree.getArtifacts())) {
465 if (CollectionUtils.isNotEmpty(tree.getArtifacts())) {
466 structure.getArtifacts().addAll(
469 .map(Artifact::getFileName)
470 .filter(fileName -> !structure.getArtifacts().contains(fileName))
471 .collect(Collectors.toList()));
475 private void handleOtherResources(HeatStructureTree tree, Set<String> usedEnvFiles,
476 FilesDataStructure structure) {
477 Set<HeatStructureTree> others = tree.getOther();
478 if (Objects.isNull(others)) {
482 List<String> artifacts = new ArrayList<>();
483 List<String> unassigned = new ArrayList<>();
484 for (HeatStructureTree other : others) {
485 if (HeatFileAnalyzer.isYamlOrEnvFile(other.getFileName())) {
486 if (isEnvFileUsedByHeatFile(usedEnvFiles, other)) {
489 unassigned.add(other.getFileName());
491 artifacts.add(other.getFileName());
493 handleArtifactsFromTree(other, structure);
495 structure.getArtifacts().addAll(artifacts);
496 structure.getUnassigned().addAll(unassigned);
499 private boolean isEnvFileUsedByHeatFile(Set<String> usedEnvFiles, HeatStructureTree other) {
500 if (HeatFileAnalyzer.isEnvFile(other.getFileName())) {
501 if (usedEnvFiles.contains(other.getFileName())) {
508 private void addHeatsToFileDataStructure(HeatStructureTree tree, Set<String> usedEnvFiles,
509 FilesDataStructure structure,
510 Map<String, List<ErrorMessage>> uploadErrors,
511 AnalyzedZipHeatFiles analyzedZipHeatFiles)
513 List<Module> modules = new ArrayList<>();
514 Set<HeatStructureTree> heatsSet = tree.getHeat();
515 if (Objects.isNull(heatsSet)) {
518 for (HeatStructureTree heat : heatsSet) {
519 if (isFileBaseFile(heat.getFileName())) {
520 handleSingleHeat(structure, modules, heat, uploadErrors);
521 } else if (isFileModuleFile(heat.getFileName(), analyzedZipHeatFiles.getModuleFiles())) {
522 handleSingleHeat(structure, modules, heat, uploadErrors);
524 structure.getUnassigned().add(heat.getFileName());
525 addNestedToFileDataStructure(heat, structure);
527 if (!Objects.isNull(heat.getEnv())) {
528 usedEnvFiles.add(heat.getEnv() == null ? null : heat.getEnv().getFileName());
531 structure.setModules(modules);
535 private boolean isFileModuleFile(String fileName, Set<String> modulesFileNames) {
536 return modulesFileNames.contains(fileName);
539 private boolean isFileBaseFile(String fileName) {
540 return manifestCreator.isFileBaseFile(fileName);
543 private void handleSingleHeat(FilesDataStructure structure, List<Module> modules,
544 HeatStructureTree heat,
545 Map<String, List<ErrorMessage>> uploadErrors) {
548 mdcDataDebugMessage.debugEntryMessage(null);
550 Module module = new Module();
551 module.setYaml(heat.getFileName());
552 module.setIsBase(heat.getBase());
553 addNestedToFileDataStructure(heat, structure);
554 Set<HeatStructureTree> volumeSet = heat.getVolume();
556 if (Objects.nonNull(volumeSet)) {
557 handleVolumes(module, volumeSet, structure, inx, uploadErrors);
559 handleEnv(module, heat, false, structure);
562 mdcDataDebugMessage.debugExitMessage(null);
565 private void handleVolumes(Module module, Set<HeatStructureTree> volumeSet,
566 FilesDataStructure structure, int inx,
567 Map<String, List<ErrorMessage>> uploadErrors) {
570 mdcDataDebugMessage.debugEntryMessage(null);
572 for (HeatStructureTree volume : volumeSet) {
574 ErrorsUtil.addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE,
575 new ErrorMessage(ErrorLevel.WARNING,
576 Messages.MORE_THEN_ONE_VOL_FOR_HEAT.getErrorMessage()), uploadErrors);
579 handleArtifactsFromTree(volume, structure);
580 module.setVol(volume.getFileName());
581 handleEnv(module, volume, true, structure);
584 mdcDataDebugMessage.debugExitMessage(null);
587 private void handleEnv(Module module, HeatStructureTree tree, boolean isVolEnv,
588 FilesDataStructure structure) {
591 mdcDataDebugMessage.debugEntryMessage(null);
593 if (Objects.nonNull(tree.getEnv())) {
595 module.setVolEnv(tree.getEnv().getFileName());
597 module.setEnv(tree.getEnv().getFileName());
599 handleArtifactsFromTree(tree.getEnv(), structure);
602 mdcDataDebugMessage.debugExitMessage(null);
605 private void addNestedToFileDataStructure(HeatStructureTree heat, FilesDataStructure structure) {
606 Set<HeatStructureTree> nestedSet = heat.getNested();
607 if (Objects.isNull(nestedSet)) {
610 for (HeatStructureTree nested : nestedSet) {
611 if (structure.getNested().contains(nested.getFileName())) {
614 structure.getNested().add(nested.getFileName());
615 if (CollectionUtils.isNotEmpty(nested.getArtifacts())) {
616 handleArtifactsFromTree(nested, structure);
618 addNestedToFileDataStructure(nested, structure);