Fix isPmDictionary nullsafety
[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 / ManifestCreatorNamingConventionImpl.java
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  * Modifications copyright (c) 2021 Nokia
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.filedatastructuremodule;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Objects;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.regex.Pattern;
29 import org.apache.commons.collections4.CollectionUtils;
30 import org.openecomp.core.utilities.file.FileContentHandler;
31 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
32 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
33 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
34 import org.openecomp.sdc.vendorsoftwareproduct.services.HeatFileAnalyzer;
35 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.ManifestCreator;
36 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.AnalyzedZipHeatFiles;
37 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Constants;
38 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure;
39 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 public class ManifestCreatorNamingConventionImpl implements ManifestCreator {
44
45     protected static final Logger logger = LoggerFactory.getLogger(ManifestCreatorNamingConventionImpl.class);
46     private static final String CLOUD_SPECIFIC_FIXED_KEY_WORD = "cloudtech";
47     private static final String[][] CLOUD_SPECIFIC_KEY_WORDS = {{"k8s", "azure", "aws"}, /* cloud specific technology */
48         {"charts", "day0", "configtemplate"} /*cloud specific sub type*/};
49     private static final String CONTROLLER_BLUEPRINT_ARCHIVE_FIXED_KEY_WORD = "CBA";
50     private static final String HELM_KEY_WORD = "HELM";
51
52     @Override
53     public Optional<ManifestContent> createManifest(VspDetails vspDetails, FilesDataStructure filesDataStructure) {
54         if (Objects.isNull(filesDataStructure)) {
55             return Optional.empty();
56         }
57         List<FileData> fileDataList = new ArrayList<>();
58         addModulesToManifestFileDataList(filesDataStructure, fileDataList);
59         addNestedToManifest(filesDataStructure, fileDataList);
60         addArtifactsToManifestFileDataList(filesDataStructure, fileDataList);
61         ManifestContent manifestContent = createManifest(vspDetails, fileDataList);
62         return Optional.of(manifestContent);
63     }
64
65     @Override
66     public Optional<ManifestContent> createManifestFromExisting(VspDetails vspDetails, FilesDataStructure filesDataStructure,
67                                                                 ManifestContent existingManifest) {
68         if (Objects.isNull(filesDataStructure)) {
69             return Optional.empty();
70         }
71         List<FileData> fileDataList = new ArrayList<>();
72         addModulesToManifestFileDataList(filesDataStructure, fileDataList);
73         addNestedToManifest(filesDataStructure, fileDataList);
74         addArtifactsToManifestFileDataList(filesDataStructure, fileDataList, existingManifest);
75         ManifestContent manifestContent = createManifest(vspDetails, fileDataList);
76         return Optional.of(manifestContent);
77     }
78
79     private void addArtifactsToManifestFileDataList(FilesDataStructure filesDataStructure, List<FileData> fileDataList,
80                                                     ManifestContent existingManifest) {
81         Collection<String> forArtifacts = CollectionUtils.union(filesDataStructure.getArtifacts(), filesDataStructure.getUnassigned());
82         if (CollectionUtils.isNotEmpty(forArtifacts)) {
83             for (String artifact : forArtifacts) {
84                 if (isCloudSpecificArtifact(artifact)) {
85                     fileDataList.add(createBaseFileData(FileData.Type.CLOUD_TECHNOLOGY_SPECIFIC_ARTIFACT, artifact));
86                 } else if (isControllerBlueprintArchive(artifact)) {
87                     fileDataList.add(createBaseFileData(FileData.Type.CONTROLLER_BLUEPRINT_ARCHIVE, artifact));
88                 } else if (isHelm(artifact)) {
89                     fileDataList.add(createBaseFileData(FileData.Type.HELM, artifact));
90                 } else if (isPmDictionary(artifact, existingManifest)) {
91                     fileDataList.add(createBaseFileData(FileData.Type.PM_DICTIONARY, artifact));
92                 } else {
93                     fileDataList.add(createBaseFileData(FileData.Type.OTHER, artifact));
94                 }
95             }
96         }
97     }
98
99     private boolean isPmDictionary(String artifact, ManifestContent existingManifest) {
100         return existingManifest.getData().stream().filter(fileData -> FileData.Type.PM_DICTIONARY.equals(fileData.getType())).map(FileData::getFile)
101             .anyMatch(pmDictionaryFile -> pmDictionaryFile.equals(artifact));
102     }
103
104     private void addNestedToManifest(FilesDataStructure filesDataStructure, List<FileData> fileDataList) {
105         if (CollectionUtils.isNotEmpty(filesDataStructure.getNested())) {
106             for (String nested : filesDataStructure.getNested()) {
107                 fileDataList.add(createBaseFileData(FileData.Type.HEAT, nested));
108             }
109         }
110     }
111
112     @Override
113     public Optional<ManifestContent> createManifest(VspDetails vspDetails, FileContentHandler fileContentHandler,
114                                                     AnalyzedZipHeatFiles analyzedZipHeatFiles) {
115         logger.info("Trying to generate manifest");
116         if (Objects.isNull(fileContentHandler) || CollectionUtils.isEmpty(fileContentHandler.getFileList())) {
117             logger.info("fileContentHandler or filesList is empty. ManifestContent will not be created");
118             return Optional.empty();
119         }
120         Map<String, byte[]> files = fileContentHandler.getFiles();
121         List<FileData> fileDataList = createFileDataListFromZipFiles(fileContentHandler, files, analyzedZipHeatFiles.getFilesNotEligbleForModules());
122         ManifestContent manifestContent = createManifest(vspDetails, fileDataList);
123         return Optional.of(manifestContent);
124     }
125
126     private ManifestContent createManifest(VspDetails vspDetails, List<FileData> fileDataList) {
127         ManifestContent manifestContent = new ManifestContent();
128         manifestContent.setName(vspDetails.getName());
129         manifestContent.setDescription(vspDetails.getDescription());
130         manifestContent.setVersion(vspDetails.getVersion() == null ? null : vspDetails.getVersion().toString());
131         // vsp version, need to check in confluence
132         manifestContent.setData(fileDataList);
133         return manifestContent;
134     }
135
136     private List<FileData> createFileDataListFromZipFiles(FileContentHandler fileContentHandler, Map<String, byte[]> files,
137                                                           Collection<String> filesNotEligibleForModules) {
138         Set<String> processedFiles = new HashSet<>();
139         List<FileData> fileDataList = new ArrayList<>();
140         for (String fileName : files.keySet()) {
141             if (processedFiles.contains(fileName)) {
142                 continue;
143             }
144             if (isFileBaseFile(fileName)) {
145                 fileDataList.add(createModuleFileData(fileName, true, processedFiles, fileContentHandler.getFileList(), fileDataList));
146             } else if (isFileModuleFile(fileName, filesNotEligibleForModules)) {
147                 fileDataList.add(createModuleFileData(fileName, false, processedFiles, fileContentHandler.getFileList(), fileDataList));
148             } else {
149                 if (HeatFileAnalyzer.isYamlFile(fileName)) {
150                     fileDataList.add(createBasicFileData(fileName, FileData.Type.HEAT, null));
151                 } else if (HeatFileAnalyzer.isEnvFile(fileName)) {
152                     fileDataList.add(createBasicFileData(fileName, FileData.Type.HEAT_ENV, null));
153                 } else {
154                     fileDataList.add(createBasicFileData(fileName, FileData.Type.OTHER, null));
155                 }
156             }
157         }
158         return fileDataList;
159     }
160
161     private boolean isFileModuleFile(String fileName, Collection<String> filesCannotBeModule) {
162         return !filesCannotBeModule.contains(fileName);
163     }
164
165     @Override
166     public boolean isFileBaseFile(String fileName) {
167         return Pattern.matches(Constants.BASE_HEAT_REGEX, fileName) && !isVolFile(fileName);
168     }
169
170     protected boolean isCloudSpecificArtifact(String artifact) {
171         if (artifact.contains(CLOUD_SPECIFIC_FIXED_KEY_WORD)) {
172             for (int i = 0; i < CLOUD_SPECIFIC_KEY_WORDS.length; i++) {
173                 if (Arrays.stream(CLOUD_SPECIFIC_KEY_WORDS[i]).noneMatch(str -> artifact.contains(str))) {
174                     return false;
175                 }
176             }
177             return true;
178         } else {
179             return false;
180         }
181     }
182
183     private boolean isControllerBlueprintArchive(String artifact) {
184         return artifact.toUpperCase().contains(CONTROLLER_BLUEPRINT_ARCHIVE_FIXED_KEY_WORD);
185     }
186
187     private boolean isHelm(String artifact) {
188         return artifact.toUpperCase().contains(HELM_KEY_WORD);
189     }
190
191     private void addArtifactsToManifestFileDataList(FilesDataStructure filesDataStructure, List<FileData> fileDataList) {
192         Collection<String> forArtifacts = CollectionUtils.union(filesDataStructure.getArtifacts(), filesDataStructure.getUnassigned());
193         if (CollectionUtils.isNotEmpty(forArtifacts)) {
194             for (String artifact : forArtifacts) {
195                 if (isCloudSpecificArtifact(artifact)) {
196                     fileDataList.add(createBaseFileData(FileData.Type.CLOUD_TECHNOLOGY_SPECIFIC_ARTIFACT, artifact));
197                 } else if (isControllerBlueprintArchive(artifact)) {
198                     fileDataList.add(createBaseFileData(FileData.Type.CONTROLLER_BLUEPRINT_ARCHIVE, artifact));
199                 } else if (isHelm(artifact)) {
200                     fileDataList.add(createBaseFileData(FileData.Type.HELM, artifact));
201                 } else {
202                     fileDataList.add(createBaseFileData(FileData.Type.OTHER, artifact));
203                 }
204             }
205         }
206     }
207
208     private void addModulesToManifestFileDataList(FilesDataStructure filesDataStructure, List<FileData> fileDataList) {
209         if (CollectionUtils.isNotEmpty(filesDataStructure.getModules())) {
210             for (Module module : filesDataStructure.getModules()) {
211                 FileData.Type type = module.getType();
212                 if (type == null) {
213                     type = FileData.Type.HEAT;
214                 }
215                 FileData fileData = createBaseFileData(type, module.getYaml());
216                 fileData.setBase(module.getIsBase());
217                 addEnv(module, fileData);
218                 addVolume(module, fileData);
219                 fileDataList.add(fileData);
220             }
221         }
222     }
223
224     private void addEnv(Module module, FileData fileData) {
225         if (Objects.nonNull(module.getEnv())) {
226             FileData env = createBaseFileData(FileData.Type.HEAT_ENV, module.getEnv());
227             fileData.addFileData(env);
228         }
229     }
230
231     private void addVolume(Module module, FileData fileData) {
232         String volModule = module.getVol();
233         if (Objects.nonNull(volModule)) {
234             FileData vol = createBaseFileData(FileData.Type.HEAT_VOL, volModule);
235             if (Objects.nonNull(module.getVolEnv())) {
236                 vol.addFileData(createBaseFileData(FileData.Type.HEAT_ENV, module.getVolEnv()));
237             }
238             fileData.addFileData(vol);
239         }
240     }
241
242     private FileData createBaseFileData(FileData.Type heat, String yaml) {
243         FileData fileData = new FileData();
244         fileData.setType(heat);
245         fileData.setFile(yaml);
246         return fileData;
247     }
248
249     private FileData createModuleFileData(String moduleFileName, boolean isBase, Set<String> processedFiles, Set<String> fileNames,
250                                           List<FileData> fileDataList) {
251         FileData moduleFileData = createBasicFileData(moduleFileName, FileData.Type.HEAT, isBase);
252         Optional<String> volFile = fetchRelatedVolume(moduleFileName, fileNames);
253         volFile.ifPresent(vol -> {
254             markFileAsProcessed(vol, processedFiles);
255             removeFromFileDataListIfAlreadyProcessed(fileDataList, vol);
256             FileData volFileData = createBasicFileData(vol, FileData.Type.HEAT_VOL, null);
257             Optional<String> envFile = fetchRelatedEnv(vol, fileNames);
258             envFile.ifPresent(env -> {
259                 markFileAsProcessed(env, processedFiles);
260                 removeFromFileDataListIfAlreadyProcessed(fileDataList, env);
261                 FileData envFileData = createBasicFileData(env, FileData.Type.HEAT_ENV, null);
262                 volFileData.addFileData(envFileData);
263             });
264             moduleFileData.addFileData(volFileData);
265         });
266         Optional<String> envFile = fetchRelatedEnv(moduleFileName, fileNames);
267         envFile.ifPresent(env -> {
268             markFileAsProcessed(env, processedFiles);
269             FileData envFileData = createBasicFileData(env, FileData.Type.HEAT_ENV, null);
270             moduleFileData.addFileData(envFileData);
271         });
272         return moduleFileData;
273     }
274
275     private void removeFromFileDataListIfAlreadyProcessed(List<FileData> fileDataList, String vol) {
276         fileDataList.removeIf(fileData -> fileData.getFile().equals(vol));
277     }
278
279     private FileData createBasicFileData(String fileName, FileData.Type type, Boolean isBase) {
280         FileData fileData = new FileData();
281         if (isBase != null) {
282             fileData.setBase(isBase);
283         }
284         fileData.setType(type);
285         fileData.setFile(fileName);
286         return fileData;
287     }
288
289     private Optional<String> fetchRelatedEnv(String fileName, Set<String> fileNames) {
290         String envFileName = fileName.substring(0, fileName.lastIndexOf(".")) + Constants.ENV_FILE_EXTENSION;
291         return fileNames.contains(envFileName) ? Optional.of(envFileName) : Optional.empty();
292     }
293
294     private Optional<String> fetchRelatedVolume(String fileName, Set<String> fileNames) {
295         String volFile1stExt = extractVolFileName(fileName, ".yaml");
296         String volFile2ndExt = extractVolFileName(fileName, ".yml");
297         if (fileNames.contains(volFile1stExt)) {
298             return Optional.of(volFile1stExt);
299         }
300         if (fileNames.contains(volFile2ndExt)) {
301             return Optional.of(volFile2ndExt);
302         }
303         return Optional.empty();
304     }
305
306     private String extractVolFileName(String fileName, String fileExt) {
307         return fileName.substring(0, fileName.lastIndexOf(".")) + Constants.VOL_FILE_NAME_SUFFIX + fileExt;
308     }
309
310     private boolean isVolFile(String fileName) {
311         return fileName.endsWith(Constants.VOL_FILE_NAME_SUFFIX + ".yaml") || fileName.endsWith(Constants.VOL_FILE_NAME_SUFFIX + ".yml");
312     }
313
314     private void markFileAsProcessed(String fileName, Set<String> processedFiles) {
315         processedFiles.add(fileName);
316     }
317 }