2 * Copyright © 2016-2018 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.filedatastructuremodule;
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;
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;
59 import java.util.stream.Collectors;
60 import java.util.zip.ZipEntry;
61 import java.util.zip.ZipInputStream;
62 import java.util.zip.ZipOutputStream;
64 import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters;
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;
72 public CandidateServiceImpl(ManifestCreator manifestCreator,
73 OrchestrationTemplateCandidateDao orchestrationTemplateCandidateDao) {
74 this.manifestCreator = manifestCreator;
75 this.orchestrationTemplateCandidateDao = orchestrationTemplateCandidateDao;
78 public CandidateServiceImpl() {
82 public Optional<ErrorMessage> validateNonEmptyFileToUpload(InputStream fileToUpload,
85 getErrorWithParameters(Messages.NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(),
88 if (Objects.isNull(fileToUpload)) {
89 return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
93 int available = fileToUpload.available();
95 return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
98 } catch (IOException e) {
99 logger.debug(e.getMessage(), e);
100 return Optional.of(new ErrorMessage(ErrorLevel.ERROR,
104 return Optional.empty();
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(),
115 return Optional.empty();
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);
135 return JsonUtil.object2Json(structure);
138 private boolean isNotStrctureArtifact(List<String> structureArtifacts, String artifact) {
139 return !structureArtifacts.contains(artifact);
143 public OrchestrationTemplateCandidateData createCandidateDataEntity(
144 CandidateDataEntityTo candidateDataEntityTo, InputStream zipFileManifest,
145 AnalyzedZipHeatFiles analyzedZipHeatFiles) {
146 FileContentHandler zipContentMap = candidateDataEntityTo.getContentMap();
147 FilesDataStructure filesDataStructure;
148 String dataStructureJson;
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);
164 // create data structure from based on naming convention
166 heatStructureTreeToFileDataStructure(candidateDataEntityTo.getTree(), zipContentMap,
167 candidateDataEntityTo.getErrors(), analyzedZipHeatFiles);
170 OrchestrationTemplateCandidateData candidateData = new OrchestrationTemplateCandidateData();
171 candidateData.setContentData(ByteBuffer.wrap(candidateDataEntityTo.getUploadedFileData()));
172 candidateData.setFilesDataStructure(dataStructureJson);
173 return candidateData;
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)) {
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());
193 } else if (Objects.nonNull(module.getVol()) && !zipFileList.contains(module.getVol())) {
196 .addIgnoreNull(filesDataStructure.getUnassigned(), module.getVolEnv());
198 if (filesDataStructure.getNested().contains(module.getYaml())) {
199 moveModuleFileToNested(filesDataStructure, i--, module);
205 private void addFileToUnassigned(FilesDataStructure filesDataStructure, Set<String> zipFileList,
207 if (isFileExistInZipContains(zipFileList, fileName)) {
208 filesDataStructure.getUnassigned().add(fileName);
212 private boolean isFileExistInZipContains(Set<String> zipFileList, String fileName) {
213 return Objects.nonNull(fileName) && zipFileList.contains(fileName);
216 private void moveModuleFileToNested(FilesDataStructure filesDataStructure, int i,
218 if (!filesDataStructure.getNested().contains(module.getYaml())) {
219 filesDataStructure.getNested().add(module.getYaml());
221 if (Objects.nonNull(module.getEnv())) {
222 filesDataStructure.getNested().add(module.getEnv());
224 if (Objects.nonNull(module.getVol())) {
225 filesDataStructure.getNested().add(module.getVol());
227 if (Objects.nonNull(module.getVolEnv())) {
228 filesDataStructure.getNested().add(module.getVolEnv());
230 filesDataStructure.getModules().remove(i);
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());
243 fileNames.addAll(filesDataStructure.getArtifacts());
244 fileNames.addAll(filesDataStructure.getNested());
245 fileNames.addAll(filesDataStructure.getUnassigned());
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());
266 structure.getArtifacts().add(fileData.getFile());
272 private void addHeatDependenciesToModule(Module module, List<FileData> data) {
273 if (CollectionUtils.isEmpty(data)) {
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());
287 throw new CoreException((new ErrorCode.ErrorCodeBuilder())
288 .withMessage(Messages.ILLEGAL_MANIFEST.getErrorMessage())
289 .withId(Messages.ILLEGAL_MANIFEST.getErrorMessage())
290 .withCategory(ErrorCategory.APPLICATION).build());
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());
303 public void updateCandidateUploadData(String vspId, Version version,
304 OrchestrationTemplateCandidateData uploadData) {
305 orchestrationTemplateCandidateDao.update(vspId, version, uploadData);
309 public Optional<FilesDataStructure> getOrchestrationTemplateCandidateFileDataStructure(
310 String vspId, Version version) {
311 Optional<String> jsonFileDataStructure =
312 orchestrationTemplateCandidateDao.getStructure(vspId, version);
314 if (jsonFileDataStructure.isPresent() && JsonUtil.isValidJson(jsonFileDataStructure.get())) {
316 .of(JsonUtil.json2Object(jsonFileDataStructure.get(), FilesDataStructure.class));
318 return Optional.empty();
323 public void updateOrchestrationTemplateCandidateFileDataStructure(String vspId, Version version,
324 FilesDataStructure fileDataStructure) {
325 OrchestrationTemplateCandidateDaoFactory.getInstance().createInterface()
326 .updateStructure(vspId, version, fileDataStructure);
330 public Optional<OrchestrationTemplateCandidateData> getOrchestrationTemplateCandidate(String vspId,
332 return orchestrationTemplateCandidateDao.get(vspId, version);
336 public Optional<OrchestrationTemplateCandidateData> getOrchestrationTemplateCandidateInfo(
339 return orchestrationTemplateCandidateDao.getInfo(vspId, version);
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())));
350 public Optional<ManifestContent> createManifest(VspDetails vspDetails,
351 FileContentHandler fileContentHandler,
352 AnalyzedZipHeatFiles analyzedZipHeatFiles) {
353 return manifestCreator.createManifest(vspDetails, fileContentHandler, analyzedZipHeatFiles);
357 public Optional<ByteArrayInputStream> fetchZipFileByteArrayInputStream(String vspId,
358 OrchestrationTemplateCandidateData candidateDataEntity,
360 OnboardingTypesEnum type,
361 Map<String, List<ErrorMessage>> uploadErrors) {
363 ByteArrayInputStream byteArrayInputStream = null;
365 file = replaceManifestInZip(candidateDataEntity.getContentData(), manifest, type);
366 byteArrayInputStream = new ByteArrayInputStream(
367 Objects.isNull(file) ? candidateDataEntity.getContentData().array()
369 } catch (IOException e) {
370 ErrorMessage errorMessage =
371 new ErrorMessage(ErrorLevel.ERROR,
372 Messages.CANDIDATE_PROCESS_FAILED.getErrorMessage());
373 logger.error(errorMessage.getMessage(), e);
375 .addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE, errorMessage, uploadErrors);
377 return Optional.ofNullable(byteArrayInputStream);
381 public byte[] replaceManifestInZip(ByteBuffer contentData, String manifest,
382 OnboardingTypesEnum type)
384 ByteArrayOutputStream baos = new ByteArrayOutputStream();
386 try (final ZipOutputStream zos = new ZipOutputStream(baos);
387 ZipInputStream zipStream = new ZipInputStream(
388 new ByteArrayInputStream(contentData.array()))) {
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];
397 while ((len = zipStream.read(buf)) > 0) {
398 zos.write(buf, 0, (len < buf.length) ? len : buf.length);
401 manifestWritten = true;
402 writeManifest(manifest, type, zos);
406 if (!manifestWritten) {
407 writeManifest(manifest, type, zos);
411 return baos.toByteArray();
415 public byte[] getZipData(ByteBuffer contentData)
417 ByteArrayOutputStream baos = new ByteArrayOutputStream();
419 try (final ZipOutputStream zos = new ZipOutputStream(baos);
420 ZipInputStream zipStream = new ZipInputStream(
421 new ByteArrayInputStream(contentData.array()))) {
423 while ((zipEntry = zipStream.getNextEntry()) != null) {
424 ZipEntry locZipEntry = new ZipEntry(zipEntry.getName());
425 zos.putNextEntry(locZipEntry);
426 byte[] buf = new byte[1024];
428 while ((len = zipStream.read(buf)) > 0) {
429 zos.write(buf, 0, (len < buf.length) ? len : buf.length);
434 return baos.toByteArray();
438 public Optional<List<ErrorMessage>> validateFileDataStructure(
439 FilesDataStructure filesDataStructure) {
440 return candidateServiceValidator.validateFileDataStructure(filesDataStructure);
444 public void deleteOrchestrationTemplateCandidate(String vspId, Version versionId) {
445 orchestrationTemplateCandidateDao.delete(vspId, versionId);
449 public void updateValidationData(String vspId, Version version, ValidationStructureList
451 orchestrationTemplateCandidateDao.updateValidationData(vspId, version, validationData);
454 private void writeManifest(String manifest,
455 OnboardingTypesEnum type,
456 ZipOutputStream zos) throws IOException {
458 if (isManifestNeedsToGetWritten(type)) {
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];
467 while ((len = (manifestStream.read(buf))) > 0) {
468 zos.write(buf, 0, (len < buf.length) ? len : buf.length);
473 private boolean isManifestNeedsToGetWritten(OnboardingTypesEnum type) {
474 return type.equals(OnboardingTypesEnum.CSAR);
477 private void handleArtifactsFromTree(HeatStructureTree tree, FilesDataStructure structure) {
479 if (Objects.isNull(tree) || Objects.isNull(tree.getArtifacts())) {
483 if (CollectionUtils.isNotEmpty(tree.getArtifacts())) {
484 structure.getArtifacts().addAll(
487 .map(Artifact::getFileName)
488 .filter(fileName -> !structure.getArtifacts().contains(fileName))
489 .collect(Collectors.toList()));
493 private void handleOtherResources(HeatStructureTree tree, Set<String> usedEnvFiles,
494 FilesDataStructure structure) {
495 Set<HeatStructureTree> others = tree.getOther();
496 if (Objects.isNull(others)) {
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)) {
507 unassigned.add(other.getFileName());
509 artifacts.add(other.getFileName());
511 handleArtifactsFromTree(other, structure);
513 structure.getArtifacts().addAll(artifacts);
514 structure.getUnassigned().addAll(unassigned);
517 private boolean isEnvFileUsedByHeatFile(Set<String> usedEnvFiles, HeatStructureTree other) {
518 return HeatFileAnalyzer.isEnvFile(other.getFileName()) &&
519 usedEnvFiles.contains(other.getFileName());
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)) {
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);
538 structure.getUnassigned().add(heat.getFileName());
539 addNestedToFileDataStructure(heat, structure);
541 if (!Objects.isNull(heat.getEnv())) {
542 usedEnvFiles.add(heat.getEnv() == null ? null : heat.getEnv().getFileName());
545 structure.setModules(modules);
549 private boolean isFileModuleFile(String fileName, Set<String> modulesFileNames) {
550 return modulesFileNames.contains(fileName);
553 private boolean isFileBaseFile(String fileName) {
554 return manifestCreator.isFileBaseFile(fileName);
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();
566 if (Objects.nonNull(volumeSet)) {
567 handleVolumes(module, volumeSet, structure, inx, uploadErrors);
569 handleEnv(module, heat, false, structure);
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!");
579 ErrorsUtil.addStructureErrorToErrorMap(SdcCommon.UPLOAD_FILE,
580 new ErrorMessage(ErrorLevel.WARNING,
581 Messages.MORE_THEN_ONE_VOL_FOR_HEAT.getErrorMessage()), uploadErrors);
584 handleArtifactsFromTree(volume, structure);
585 module.setVol(volume.getFileName());
586 handleEnv(module, volume, true, structure);
587 addNestedToFileDataStructure(volume, structure);
591 private void handleEnv(Module module, HeatStructureTree tree, boolean isVolEnv,
592 FilesDataStructure structure) {
593 if (Objects.nonNull(tree.getEnv())) {
595 module.setVolEnv(tree.getEnv().getFileName());
597 module.setEnv(tree.getEnv().getFileName());
599 handleArtifactsFromTree(tree.getEnv(), structure);
603 private void addNestedToFileDataStructure(HeatStructureTree heat,
604 FilesDataStructure structure) {
605 Set<HeatStructureTree> nestedSet = heat.getNested();
606 if (Objects.isNull(nestedSet)) {
609 for (HeatStructureTree nested : nestedSet) {
610 if (structure.getNested().contains(nested.getFileName())) {
613 structure.getNested().add(nested.getFileName());
614 if (CollectionUtils.isNotEmpty(nested.getArtifacts())) {
615 handleArtifactsFromTree(nested, structure);
617 addNestedToFileDataStructure(nested, structure);